如何在Windows运行时中实现AES加密(AesManaged Rfc2898DeriveBytes)

时间:2015-04-07 16:53:14

标签: windows-runtime cryptography windows-store-apps windows-phone-8.1 win-universal-app

当我尝试将我的项目从Windows Phone Silverlight 8.1移植到Windows运行时,我遇到了阻塞问题。 在Windows运行时中,AES加密的字符串与Silverlight之前的字符串不同。

在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();
        }
    }

在Windows运行时:

    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;
    }

在Silverlight项目中,AES加密的字符串“123456”为“4UfdhC / 0MFQlMhl7N7gqLg ==”; 在Windows运行时项目中,AES加密的字符串是“jxsR5EuhPXgRsHLs4N3EGQ ==”

那么如何才能在WinRT上获得与Silverlight相同的字符串?

2 个答案:

答案 0 :(得分:1)

AES类默认为Microsoft运行时的随机IV。要获得相同的密文,您需要使用静态IV。然而,这并不安全。相反,您应该检查是否获得相同的关键字节,并让每次运行的密文不同。否则你可以清楚地区分相同的明文。

您似乎也使用了错误的哈希算法,Rfc2898DeriveBytes使用SHA-1而不是SHA-256作为基础哈希函数。

答案 1 :(得分:0)

我已经创建了一个适合我作为System.Security.Cryptography.Rfc2898DeriveBytes替换的课程:

public class Rfc2898DeriveBytes
{
    private readonly string _password;
    private readonly byte[] _salt;

    public Rfc2898DeriveBytes(string password, byte[] salt)
    {
        _password = password;
        _salt = salt;

        IterationCount = 1000;
    }

    public uint IterationCount { get; set; }

    public byte[] GetBytes(uint cb)
    {
        var provider = KeyDerivationAlgorithmProvider.OpenAlgorithm(KeyDerivationAlgorithmNames.Pbkdf2Sha1);

        var buffSecret = CryptographicBuffer.ConvertStringToBinary(_password, BinaryStringEncoding.Utf8);
        var buffsalt = CryptographicBuffer.CreateFromByteArray(_salt);

        var keyOriginal = provider.CreateKey(buffSecret);

        var par = KeyDerivationParameters.BuildForPbkdf2(buffsalt, IterationCount);
        var keyMaterial = CryptographicEngine.DeriveKeyMaterial(keyOriginal, par, cb);

        byte[] result;
        CryptographicBuffer.CopyToByteArray(keyMaterial, out result);

        return result;
    }
}