I'm working on a project where I have to encrypt and decrypt chosen files by user. How can I use a password from user as a key for AES encryption/decryption? Right now they can enter passwords of 8 or 16 characters long. I don't want to force the user to specify a password of 8 or 16 characters.
public static void EncryptFile(string file, string password)
{
try
{
string outputFile = Path.GetFileNameWithoutExtension(file) + "-encrypted" + Path.GetExtension(file);
byte[] fileContent = File.ReadAllBytes(file);
UnicodeEncoding UE = new UnicodeEncoding();
using (AesCryptoServiceProvider AES = new AesCryptoServiceProvider())
{
AES.Key = UE.GetBytes(password);
AES.IV = new byte[16];
AES.Mode = CipherMode.CBC;
AES.Padding = PaddingMode.PKCS7;
using (MemoryStream memoryStream = new MemoryStream())
{
CryptoStream cryptoStream = new CryptoStream(memoryStream, AES.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(fileContent, 0, fileContent.Length);
cryptoStream.FlushFinalBlock();
File.WriteAllBytes(outputFile, memoryStream.ToArray());
}
}
}
catch (Exception ex)
{
MessageBox.Show("Exception thrown while encrypting the file!" + "\n" + ex.Message);
}
}
AES in .net uses by default a 256 bit key and a 128 bit IV .
SHA256 and MD5 hash algorithms create a 256 bit and a 128 bit hash respectively.
Hmmm.
byte[] passwordBytes = UE.GetBytes(password);
byte[] aesKey = SHA256Managed.Create().ComputeHash(passwordBytes);
byte[] aesIV = MD5.Create().ComputeHash(passwordBytes);
AES.Key = aesKey;
AES.IV = aesIV;
AES.Mode = CipherMode.CBC;
AES.Padding = PaddingMode.PKCS7;
Related
Python Encryption:
salt = 16 * b'\0'
keyIV = PBKDF2(Config.SECRET, salt).read(48)
key = keyIV[:32]
iv = keyIV[-16:]
aes = AES.new(key, AES.MODE_CBC, iv)
# padding
length = 16 - (len(textToEncrypt) % 16)
print(len(textToEncrypt))
textToEncrypt += length * b'\0'
encrypted = aes.encrypt(textToEncrypt)
encoded = base64.b64encode(encrypted)
return encoded
And here is my C# decryption:
textToDecrypt = textToDecrypt.Replace(" ", "+");
byte[] bytesToDecrypt = Convert.FromBase64String(textToDecrypt);
string decryptedText;
using (Aes aes = Aes.Create())
{
byte[] salt = new byte[16];
Rfc2898DeriveBytes crypto = new Rfc2898DeriveBytes(Config.SECRET, salt);
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
aes.Key = crypto.GetBytes(32);
aes.IV = crypto.GetBytes(16);
using (MemoryStream mStream = new MemoryStream())
{
using (CryptoStream cStream = new CryptoStream(mStream, aes.CreateDecryptor(), CryptoStreamMode.Write))
{
cStream.Write(bytesToDecrypt, 0, bytesToDecrypt.Length);
}
decryptedText = Encoding.Unicode.GetString(mStream.ToArray());
}
}
return decryptedText;
EDIT
Following #kelalaka answer, I'm now able to encrypt from C# and decrypt that string in python successfully, but not vice versa. That is, if I encrypt a string in python, and try to decrypt that encryption in C# I get an exception: "Bad PKCS7 padding. Invalid length 0". My python encryption is much shorter than what I get in C# using the same cipherText, iv, and key.
I'm working on AES encryption/decryption. I want to encrypt request from my angular app and send it to .net api and decrypt at api then encrypt the response from api side and send it to angular app and decrypt using AES.
But sometimes it gives me 'padding is invalid and cannot be removed' exception at api side.
Here is my angular typescript crypto service code:
aesEncrypt(keys: string, value: string) { // encrypt api request parameter with aes secretkey
var key = CryptoJS.enc.Utf8.parse(keys);
var iv = CryptoJS.enc.Utf8.parse(keys);
var encrypted = CryptoJS.AES.encrypt(JSON.stringify(value), key,
{
keySize: 128 / 8,
//keySize: 128,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7,
});
return encrypted.toString();
}
aesDecrypt(keys: string, value: any) { // decrypt api response parameter with aes secretkey
var key = CryptoJS.enc.Utf8.parse(keys);
var iv = CryptoJS.enc.Utf8.parse(keys);
var decrypted = CryptoJS.AES.decrypt(value, key, {
keySize: 128 / 8,
//keySize: 128,
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8));
}
Here is my api crypto filter code:
Way 1:
public static string Encrypt(string key, string data)
{
byte[] encryptedBytes = new UTF8Encoding().GetBytes(data);
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
ICryptoTransform crypto = aes.CreateEncryptor(aes.Key, aes.IV);
byte[] secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
crypto.Dispose();
return Convert.ToBase64String(secret);
}
public static string Decrypt(string key, string encrypted)
{
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
ICryptoTransform crypto = aes.CreateDecryptor(aes.Key, aes.IV);
byte[] secret = crypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
crypto.Dispose();
return Encoding.UTF8.GetString(secret);
}
private static AesCryptoServiceProvider AesCryptoServiceProvider(string key)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
//aes.BlockSize = 128; //Not Required
//aes.KeySize = 256; //Not Required
//aes.KeySize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.UTF8.GetBytes(key); //PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0 =
aes.IV = Encoding.UTF8.GetBytes(key); //2314345645678765
return aes;
}
Way 2:
public static string Encrypt(string key, string data)
{
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
ICryptoTransform encryptor = aes.CreateEncryptor();
MemoryStream ms = new MemoryStream();
CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write);
StreamWriter streamWriter = new StreamWriter(cs);
streamWriter.Write(data);
streamWriter.Flush();
cs.FlushFinalBlock();
byte[] cypherTextBytes = ms.ToArray();
ms.Close();
return Convert.ToBase64String(cypherTextBytes);
}
public static string Decrypt(string key, string encrypted)
{
AesCryptoServiceProvider aes = AesCryptoServiceProvider(key);
byte[] encryptedBytes = Convert.FromBase64String(encrypted);
ICryptoTransform decryptor = aes.CreateDecryptor();
byte[] plainText = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return Encoding.UTF8.GetString(plainText);
}
private static AesCryptoServiceProvider AesCryptoServiceProvider(string key)
{
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
//aes.BlockSize = 128; //Not Required
//aes.KeySize = 256; //Not Required
//aes.KeySize = 128;
aes.Mode = CipherMode.CBC;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Encoding.UTF8.GetBytes(key); //PSVJQRk9QTEpNVU1DWUZCRVFGV1VVT0 =
aes.IV = Encoding.UTF8.GetBytes(key); //2314345645678765
return aes;
}
I tried both the ways at api level but still it is giving me padding issue (sometimes, not always)
I'm trying to create methods for very strong Rijndael 256 string encryption that I can use for passwords but I get an error saying Padding is invalid and cannot be removed. when I read the CryptoStream and get the decrypted string. Here are my encrypt and decrypt methods:
private string AES256EncryptString(string key, string plainText)
{
try
{
using (RijndaelManaged rijndael = new RijndaelManaged())
{
rijndael.KeySize = 256;
rijndael.BlockSize = 128;
rijndael.Key = Encoding.UTF8.GetBytes(key);
rijndael.GenerateIV();
rijndael.Mode = CipherMode.CBC;
rijndael.Padding = PaddingMode.PKCS7;
ICryptoTransform encryptor = rijndael.CreateEncryptor(rijndael.Key, rijndael.IV);
MemoryStream memoryStream = new MemoryStream();
memoryStream.Write(rijndael.IV, 0, rijndael.IV.Length);
CryptoStream crypoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
crypoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
crypoStream.FlushFinalBlock();
crypoStream.Close();
byte[] encryptedBytes = memoryStream.ToArray();
memoryStream.Close();
string encryptedText = Convert.ToBase64String(encryptedBytes);
return encryptedText;
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return null;
}
}
private string AES256DecryptString(string key, string encryptedText)
{
try
{
using (RijndaelManaged rijndael = new RijndaelManaged())
{
rijndael.KeySize = 256;
rijndael.BlockSize = 128;
rijndael.Key = Encoding.UTF8.GetBytes(key);
byte[] encryptedTextBytes = Encoding.UTF8.GetBytes(encryptedText);
byte[] iv = new byte[16];
Array.Copy(encryptedTextBytes, iv, iv.Length);
rijndael.IV = iv;
rijndael.Mode = CipherMode.CBC;
rijndael.Padding = PaddingMode.PKCS7;
ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV);
MemoryStream memoryStream = new MemoryStream();
byte[] encryptedTextWithoutIVBytes = new byte[encryptedTextBytes.Length - iv.Length];
Array.Copy(encryptedTextBytes, 16, encryptedTextWithoutIVBytes, 0, encryptedTextWithoutIVBytes.Length);
memoryStream.Write(encryptedTextWithoutIVBytes, 0, encryptedTextWithoutIVBytes.Length);
CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
StreamReader streamReader = new StreamReader(cryptoStream);
string decryptedText = streamReader.ReadToEnd();
cryptoStream.FlushFinalBlock();
cryptoStream.Close();
memoryStream.Close();
return decryptedText;
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return null;
}
}
As you can see I add the initialization vector before the encrypted string before adding the encrypted bit because I know that IVs should be random and I've seen this is a good strategy to use. I make sure to remove the IV before decrypting.
Is there a way to fix this without changing the padding mode (I've seen that PKCS7 padding is very secure)?
Problems:
You should use a proper password-based KDF for passwords and similar low-entropy keys. .NET has the Rfc2898DeriveBytes (PBKDF2) class to make this relatively easy.
You are not base64 decoding your ciphertext in your decryptor. Instead of
byte[] encryptedTextBytes = Encoding.UTF8.GetBytes(encryptedText);
you should have
byte[] encryptedTextBytes = Convert.FromBase64String(encryptedText);
You need to reset the position of the MemoryStream after you populate it with ciphertext bytes. After
memoryStream.Write(encryptedTextWithoutIVBytes, 0, encryptedTextWithoutIVBytes.Length);
you need to insert
memoryStream.Seek(0, SeekOrigin.Begin);
I have c sharp code snippet for encryption which uses .Key file for key and my requirement is to decrypt the encrypted text using same key in android, having problem
public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes) {
byte[] encryptedBytes = null;
// Set your salt here, change it to meet your flavor:
// The salt bytes must be at least 8 bytes.
byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
using (MemoryStream ms = new MemoryStream())
{
using (RijndaelManaged AES = new RijndaelManaged())
{
AES.KeySize = 256;
AES.BlockSize = 128;
var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
AES.Key = key.GetBytes(AES.KeySize / 8);
AES.IV = key.GetBytes(AES.BlockSize / 8);
AES.Mode = CipherMode.CBC;
using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
cs.Close();
}
encryptedBytes = ms.ToArray();
}
}
return encryptedBytes;
}
If you want to decrypt some data with AES you can use this method:
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
for complete code look at : android encryption/decryption with AES
I want to encrypt a string using AES 256-bit encryption algorithm with ECB and PKCS7Padding. I had gone through many sites but none of them were suitable.
Please suggest a solution
public static string Encrypt(string PlainText, string Password,
string Salt = "Kosher", string HashAlgorithm = "SHA1",
int PasswordIterations = 2, string InitialVector = "OFRna73m*aze01xY",
int KeySize = 256)
{
if (string.IsNullOrEmpty(PlainText))
return "";
byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);
PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
RijndaelManaged SymmetricKey = new RijndaelManaged();
SymmetricKey.Mode = CipherMode.CBC;
byte[] CipherTextBytes = null;
using (ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes))
{
using (MemoryStream MemStream = new MemoryStream())
{
using (CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write))
{
CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
CryptoStream.FlushFinalBlock();
CipherTextBytes = MemStream.ToArray();
MemStream.Close();
CryptoStream.Close();
}
}
}
SymmetricKey.Clear();
return Convert.ToBase64String(CipherTextBytes);
}
source
Note: you can change the mode by changing SymmetricKey.Mode = CipherMode.CBC;
and you can add SymmetricKey.Padding = PaddingMode.PKCS7; for padding
with bounty castle you should be able to do this :
cipher = CipherUtilities.GetCipher("AES/ECB/PKCS7");
cipher.Init(false, new KeyParameter(key));