.NET AES-128解密返回空字符串

时间:2014-04-21 16:19:26

标签: .net encryption aes

我在解析示例应用程序中的简单值时遇到问题。该值使用相同的示例应用程序加密。我已经列出了下面的代码。

当代码块完成时,结果是plain是一个空字符串。没有例外。

string plain = null;

using (AesManaged alg = new AesManaged())
{
    // Extract the initialization vector from the entire ciphertext
    byte[] IV = new byte[alg.IV.Length];
    Buffer.BlockCopy(cipherText, 0, IV, 0, alg.IV.Length);

    alg.IV = IV;
    alg.Key = GetKey();

    ICryptoTransform transform = alg.CreateDecryptor();

    // Extract the encrypted value from the entire ciphertext
    byte[] encrypted = new byte[cipherText.Length - alg.IV.Length];
    Buffer.BlockCopy(cipherText, alg.IV.Length, encrypted, 0, cipherText.Length - alg.IV.Length);

    using (MemoryStream ms = new MemoryStream(encrypted))
    {
        using (CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Read))
        {
            using (StreamReader r = new StreamReader(cs))
            {
                cs.Flush();
                plain = r.ReadToEnd();
            }
        }
    }
}

我已经验证cipherText(作为参数传递的32字节byte [])具有与加密产生的值相同的字节。 IV和Key也是逐字节的相同。注意:加密逻辑将IV加在加密值之前。这就是为什么第一行从代码块中提取它。

我还验证了encrypted byte []的内容与加密例程中的内容相同。内容只有16个字节。

我已经验证了MemoryStream Position中的ms是0.在例程之后,它是16.所以看起来MemoryStream被读取了。我的怀疑是我错误地使用StreamReader,但我看不出我犯了错误的地方。

我试图修改加密字节[]中的一个字节,然后按预期我得到一个CryptographicException(填充无效)。因此,从加密的角度来看,似乎所有的都是我的IV,密钥和加密值。出于某种原因,也许它不会一直处理?

感谢您的任何见解。

为完整起见,下面的加密程序如下:     byte [] encrypted = null;

using (AesManaged alg = new AesManaged())
{
    System.Diagnostics.Debug.WriteLine("Key size: {0}", alg.KeySize);

    alg.GenerateIV();
    alg.Key = GetKey();

    ICryptoTransform transform = alg.CreateEncryptor(alg.Key, alg.IV);

    using (MemoryStream ms = new MemoryStream())
    using (CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Write))
    using (StreamWriter w = new StreamWriter(cs))
    {
        w.Write(plainText);
        cs.FlushFinalBlock();

        // Create a byte array big enough to hold the IV and the encrypted value
        encrypted = new byte[alg.IV.Length + ms.Length];
        // Copy the random generated initialization vector to the start of the encrypted bytes
        Buffer.BlockCopy(alg.IV, 0, encrypted, 0, alg.IV.Length);
        // Copy the encrypted value at the end
        Buffer.BlockCopy(ms.ToArray(), 0, encrypted, alg.IV.Length, (int)ms.Length);
    }
}

1 个答案:

答案 0 :(得分:0)

我弄清楚了我犯的错误。我正在使用非常短的字符串进行测试,并且我认为加密的大小总是16个字节并不奇怪。

当我用更长的琴弦测试时,感觉不对。事实证明我的问题出现在加密逻辑中:除了StreamWriter之外,我还需要刷新CryptoStream。以下是我现在正在使用的加密和解密逻辑。

请注意,逻辑的另一个改进是我现在还在密钥生成期间生成随机盐,并且随机盐也被添加到加密字节[]。

private const int SaltLength = 8;

public class KeyPackage
{
    public byte[] KeySalt { get; set; }
    public byte[] Key { get; set; }
}

public KeyPackage GetKey()
{
    // Read the password from the configuration
    string Key = System.Configuration.ConfigurationManager.AppSettings["EncryptionKey"];

    // Generate Key from the password stored in configuration using a random salt
    using (Rfc2898DeriveBytes db = new Rfc2898DeriveBytes(Key, SaltLength))
    {
        // Using AES-128, we need 128 / 8 bytes in the key
        return new KeyPackage() { Key = db.GetBytes(128 / 8), KeySalt = db.Salt };
    }
}

public byte[] GetKey(byte[] keySalt)
{
    // Read the password from the configuration
    string Key = System.Configuration.ConfigurationManager.AppSettings["EncryptionKey"];

    // Generate Key from the password stored in configuration using the known salt
    using (Rfc2898DeriveBytes db = new Rfc2898DeriveBytes(Key, keySalt))
    {
        // Using AES-128, we need 128 / 8 bytes in the key
        return db.GetBytes(128 / 8);
    }
}

/// <summary>
/// Encrypts the specified plain text using the
/// encryption key found in the configuration file.
/// </summary>
/// <param name="plainText">The plain text to encrypted.</param>
/// <returns>The cipher text.</returns>
public byte[] Encrypt(string plainText)
{
    byte[] encrypted = null;

    using (AesManaged alg = new AesManaged())
    {
        System.Diagnostics.Debug.WriteLine("Key size: {0}", alg.KeySize);

        alg.GenerateIV();
        KeyPackage kp = GetKey();
        alg.Key = kp.Key;

        ICryptoTransform transform = alg.CreateEncryptor();

        using (MemoryStream ms = new MemoryStream())
        using (CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Write))
        using (StreamWriter w = new StreamWriter(cs))
        {
            w.Write(plainText);
            w.Flush(); // This was missing from my first post
            cs.FlushFinalBlock();

            // Create a byte array big enough to hold the IV and the encrypted value
            encrypted = new byte[kp.KeySalt.Length + alg.IV.Length + ms.Length];
            // Copy the random generated salt to the start of the encrypted bytes
            Buffer.BlockCopy(kp.KeySalt, 0, encrypted, 0, kp.KeySalt.Length);
            // Copy the random generated initialization vector to the start of the encrypted bytes
            Buffer.BlockCopy(alg.IV, 0, encrypted, kp.KeySalt.Length, alg.IV.Length);
            // Copy the encrypted value at the end
            Buffer.BlockCopy(ms.ToArray(), 0, encrypted, alg.IV.Length + kp.KeySalt.Length, (int)ms.Length);
        }
    }
    return encrypted;
}

/// <summary>
/// 
/// </summary>
/// <param name="cipherText"></param>
/// <returns></returns>
public string Decrypt(byte[] cipherText)
{
    string plain = null;

    using (AesManaged alg = new AesManaged())
    {
        // Extract the initialization vector from the entire ciphertext
        byte[] IV = new byte[alg.IV.Length];
        byte[] KeySalt = new byte[SaltLength];

        Buffer.BlockCopy(cipherText, 0, KeySalt, 0, SaltLength);
        Buffer.BlockCopy(cipherText, SaltLength, IV, 0, alg.IV.Length);

        alg.IV = IV;
        alg.Key= GetKey(KeySalt);

        ICryptoTransform transform = alg.CreateDecryptor();

        // Extract the encrypted value from the entire ciphertext
        int ActualCipherLength = cipherText.Length - alg.IV.Length - SaltLength;
        byte[] encrypted = new byte[ActualCipherLength];
        Buffer.BlockCopy(cipherText, alg.IV.Length + SaltLength, encrypted, 0, ActualCipherLength);

        using (MemoryStream ms = new MemoryStream(encrypted))
        using (CryptoStream cs = new CryptoStream(ms, transform, CryptoStreamMode.Read))
        using (StreamReader r = new StreamReader(cs))
        {
            plain = r.ReadToEnd();
        }
    }
    return plain;
}
}