I met a blocking issue when I tried to immigrate my project from Windows Phone Silverlight 8.1 to Windows Runtime. In Windows Runtime the AES-encrypted string is not the same as the one on Silverlight before.
In Silverlight:
public static string EncryptAES(string encryptString)
{
AesManaged aes = null;
MemoryStream ms = null;
CryptoStream cs = null;
string encryptKey = "testtest123";
string salt = "abcabcabcd";
try
{
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(encryptKey, Encoding.UTF8.GetBytes(salt));
aes = new AesManaged();
aes.Key = rfc2898.GetBytes(aes.KeySize / 8);
aes.IV = rfc2898.GetBytes(aes.BlockSize / 8);
ms = new MemoryStream();
cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write);
byte[] data = Encoding.UTF8.GetBytes(encryptString);
cs.Write(data, 0, data.Length);
cs.FlushFinalBlock();
return Convert.ToBase64String(ms.ToArray());
}
catch
{
return encryptString;
}
finally
{
if (cs != null)
cs.Close();
if (ms != null)
ms.Close();
if (aes != null)
aes.Clear();
}
}
In Windows Runtime:
public static string EncryptAES(string plainText)
{
string pw = "testtest123";
string salt = "abcabcabcd";
IBuffer plainBuffer = CryptographicBuffer.ConvertStringToBinary(plainText, BinaryStringEncoding.Utf8);
IBuffer saltBuffer = CryptographicBuffer.ConvertStringToBinary(salt, BinaryStringEncoding.Utf8);
IBuffer pwBuffer = CryptographicBuffer.ConvertStringToBinary(pw, BinaryStringEncoding.Utf8);
KeyDerivationAlgorithmProvider keyDerivationProvider = Windows.Security.Cryptography.Core.KeyDerivationAlgorithmProvider.OpenAlgorithm(KeyDerivationAlgorithmNames.Pbkdf2Sha256);
// using salt and 1000 iterations
KeyDerivationParameters pbkdf2Parms = KeyDerivationParameters.BuildForPbkdf2(saltBuffer, 1000);
// create a key based on original key and derivation parmaters
CryptographicKey keyOriginal = keyDerivationProvider.CreateKey(pwBuffer);
IBuffer keyMaterial = CryptographicEngine.DeriveKeyMaterial(keyOriginal, pbkdf2Parms, 32);
CryptographicKey derivedPwKey = keyDerivationProvider.CreateKey(pwBuffer);
// derive buffer to be used for encryption salt from derived password key
IBuffer saltMaterial = CryptographicEngine.DeriveKeyMaterial(derivedPwKey, pbkdf2Parms, 16);
// display the buffers - because KeyDerivationProvider always gets cleared after each use, they are very similar unforunately
string keyMaterialString = CryptographicBuffer.EncodeToBase64String(keyMaterial);
string saltMaterialString = CryptographicBuffer.EncodeToBase64String(saltMaterial);
//AES_CBC_PKCS7
SymmetricKeyAlgorithmProvider symProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm("AES_CBC_PKCS7");
// create symmetric key from derived password key
CryptographicKey symmKey = symProvider.CreateSymmetricKey(keyMaterial);
// encrypt data buffer using symmetric key and derived salt material
IBuffer resultBuffer = CryptographicEngine.Encrypt(symmKey, plainBuffer, saltMaterial);
string result = CryptographicBuffer.EncodeToBase64String(resultBuffer);
return result;
}
In Silverlight Project, string "123456" encrypted by AES is "4UfdhC/0MFQlMhl7N7gqLg=="; While in Windows Runtime Project, the AES-encrypted string is "jxsR5EuhPXgRsHLs4N3EGQ=="
So how can I get the same string on WinRT as the one on Silverlight ?
The AES classes default to a random IV on the Microsoft runtimes. To get the same ciphertext you'll need to use a static IV. That's however not secure. Instead you should just check if you get the same key bytes and let the ciphertext differ for each run. Otherwise you can clearly distinguish identical plaintext.
You also seem to be using the wrong hash algorithm,
Rfc2898DeriveBytes
uses SHA-1 instead of SHA-256 as underlying hash function.I've created class which works for me as replacement for System.Security.Cryptography.Rfc2898DeriveBytes: