AES 256加密与结果不匹配

时间:2017-03-07 07:26:27

标签: c# .net encryption

我有一个文件说加密字符串using AES256。根据我的文档有两个值10002:1486703720424 AND HashKey: hpIw4SgN)TxJdoQj=GKo)p83$uHePgoF,它会生成结果1ltQFLRGNif73uCNzi0YEvBqLKiRgx6fWsk5e/GcTQc=但是当我尝试生成结果时,它会从我的代码生成6SKbqJAxbBrg4eU7r/B8gJoJEPg+KjMvGL5L7bfykUU=。你能告诉我我在做什么错误吗?这是我第一次加密,所以我有点迷惑找到我的错误。

string getHashKey1 = EncryptText("10002:1486703720424", "hpIw4SgN)TxJdoQj=GKo)p83$uHePgoF");

public string EncryptText(string input, string password)
{
    string result = "";
    try
    {
        // Get the bytes of the string
        byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
        byte[] passwordBytes = Encoding.UTF8.GetBytes(password);

        // Hash the password with SHA256
        passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

        byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);

        result = Convert.ToBase64String(bytesEncrypted);
    }
    catch (Exception ex)
    {
        ErrorLog errLog = new ErrorLog();
        errLog.LogsWrite(ex, Path.GetDirectoryName(Application.ExecutablePath));

    }

    return result;
}

public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
    byte[] encryptedBytes = null;
    try
    {
        // 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, 23, 234, 37, 48, 134, 63, 248, 4 };

        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();
            }
        }
    }
    catch (Exception ex)
    {
        ErrorLog errLog = new ErrorLog();
        errLog.LogsWrite(ex, Path.GetDirectoryName(Application.ExecutablePath));
    }    

    return encryptedBytes;
}

1 个答案:

答案 0 :(得分:4)

发现......他们使用ECB作为密码模式,因此没有IV。我不会对此的“安全性”发表评论。填充似乎是PKCS7(AES的默认值)。密码“按原样”使用,只需以UTF8(或者甚至是ASCII)编码(因此它必须长度为32个字节)。

public static string EncryptText(string input, string password)
{
    // Get the bytes of the string
    byte[] bytesToBeEncrypted = Encoding.UTF8.GetBytes(input);
    byte[] passwordBytes = Encoding.UTF8.GetBytes(password);

    byte[] bytesEncrypted = AES_Encrypt(bytesToBeEncrypted, passwordBytes);

    string result = Convert.ToBase64String(bytesEncrypted);
    return result;
}

public static byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
    using (MemoryStream ms = new MemoryStream())
    {
        using (Aes aes = Aes.Create())
        {
            aes.Key = passwordBytes;
            aes.Mode = CipherMode.ECB;

            // "zero" IV
            aes.IV = new byte[16];

            using (var cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                cs.Close();
            }
        }

        byte[] encryptedBytes = ms.ToArray();
        return encryptedBytes;
    }
}

@LukePark正确地对这个答案进行了长篇大论,这个答案对OP有用但在更大的世界中毫无用处。我会加粗正确字。出于这个原因,我将解释给予A. Goutam的规范中的“错误”以及“正确”规范必须始终包含的内容。

加密规范应始终包含:使用的算法(例如AES),密钥大小(如果您说AES256然后显然是256位),块模式(CBC,ECB等)。许多块模式(例如CBC)需要IV向量。 ECB的安全性低于其他块模式(例如参见https://crypto.stackexchange.com/questions/225/should-i-use-ecb-or-cbc-encryption-mode-for-my-block-cipher)。如果IV是必要的,那么规范必须包含它(或解释它应该如何生成)。规范必须包含应该使用的填充。仅当要加密的数据可以在加密块中精确细分时才应使用Padding.None(例如,使用AES,PaddingMode.None仅在数据为16,32,64,96时才有效,...字节)。 PaddingMode.Zeros仅适用于文字(我不会使用它,因为它会在文本的末尾添加'\0')。其他填充模式都很好。

键通常不会“按原样”使用,因为例如它是一个字符串。规范应包含如何从字符串键派生加密密钥。密钥上的SHA256是一个弱解决方案。通常,一个好的解决方案是使用强密钥派生函数,如Rfc2898DeriveBytes。如果使用此函数,则规范必须包含有关使用Rfc2898DeriveBytes或类似函数的迭代次数和其他信息。显然,必须包含应该用于密钥(以及要加密的数据,如果它是文本)的编码(UTF8总是一个好主意)。

我要补充说,一个好的规范应该包含一些测试用例。至少一个测试用例的长度应小于加密块的长度,并且至少一个测试用例必须的长度大于加密块但小于两个加密块(或> 2和<2)。 3 ...一些完整的块和一个非完整的块)。通过这种方式,您可以同时测试PaddingModeCipherMode(注意应该/必须:通过测试比加密块更大的内容加上您已经在测试所有内容的不完整块)