使用AesCryptoServiceProvider获取不正确的解密值 [英] Getting incorrect decryption value using AesCryptoServiceProvider

查看:843
本文介绍了使用AesCryptoServiceProvider获取不正确的解密值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码,使用 AesCryptoServiceProvider 进行加密和解密。对于加密和解密,使用的 iv 键是相同的。

I have following code that uses AesCryptoServiceProvider for encrypting and decrypting. The iv and key used are same for both encryption and decryption. Still the decrypted value differ from the source string.


  1. 解密后需要更正的值才能得到原始值?

  2. inputValue = valid128BitString 时,此代码正在工作。但是当 inputString =Test我得到以下异常 Padding无效并且无法删除。我们如何更正?

  1. What need to be corrected to get the original value after decrypt?
  2. This code is working when inputValue = valid128BitString. But when the inputString = "Test" I am getting the following exception Padding is invalid and cannot be removed.. How can we correct it?

UPDATED QUESTION

以下将根据@jbtule的答案来做。

The following will do the trick based on @jbtule answer.

encyptedValue.IV = result.IV;

加密结果中的 IV 值会更改。假设加密是在单独的过程中完成的,我们如何知道解密的IV?有没有办法让它恒定或已知?

The IV value from encryption result changes. Suppose encryption is done in a separate process, how can we know the IV for decryption? Is there a way to make it constant or known?

答案:你的另一个选择是通过一个IV在加密和分配它,在你开始你的加密转换,而不是让aesProvider为你生成一个随机的。 - @Scott Chamberlain

Answer: Your other option is pass a IV in to Encrypt and assign it before you begin your crypto transform, instead of letting aesProvider generate a random one for you. – @Scott Chamberlain

 aesProvider.IV = Convert.FromBase64String("4uy34C9sqOC9rbV4GD8jrA==");

更新:请参阅如何为Base64应用填充。我们可以使用 UTF8 来编码源输入和结果输出。键和IV可以保留在 Base64 中。

Update: Refer How to apply padding for Base64. We can use UTF8 for encoding the source input and result output. The key and IV may remain in Base64.

使用Base64进行源输入会导致某些值出现问题,例如,MyTest,其中字符串的长度不是4的倍数

Using Base64 for source input will cause issues with some values, for example, "MyTest" where length of string is not a multiple of 4

相关要点:


要解密使用对称算法类,您必须将Key属性和IV属性设置为用于加密的相同值。

To decrypt data that was encrypted using one of the SymmetricAlgorithm classes, you must set the Key property and IV property to the same values that were used for encryption.

SymmetricAlgorithm.IV属性:来自前一个块的信息混合加密下一个块的过程。因此,两个相同的纯文本块的输出是不同的。因为该技术使用前一块来加密下一块,所以需要初始化向量来加密第一数据块。 (根据 SymmetricAlgorithm.IV属性 MSDN文章)

SymmetricAlgorithm.IV Property: Information from the previous block is mixed into the process of encrypting the next block. Thus, the output of two identical plain text blocks is different. Because this technique uses the previous block to encrypt the next block, an initialization vector is needed to encrypt the first block of data. (As per SymmetricAlgorithm.IV Property MSDN article)

有效的密钥大小为:128,192,256位(根据为我的AES方法创建一个字节数组的字符数?

The valid Key sizes are: 128, 192, 256 bits (as per How many characters to create a byte array for my AES method?)

主程式

class Program
{
    static void Main(string[] args)
    {
        string valid128BitString = "AAECAwQFBgcICQoLDA0ODw==";
        string inputValue = valid128BitString;
        string keyValue = valid128BitString;
        string iv = valid128BitString;

        byte[] byteValForString = Convert.FromBase64String(inputValue);
        EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue);
        EncryptResult encyptedValue = new EncryptResult();
        encyptedValue.IV = iv;
        encyptedValue.EncryptedMsg = result.EncryptedMsg;

        string finalResult = Convert.ToBase64String(Aes128Utility.DecryptData(encyptedValue, keyValue));
        Console.WriteLine(finalResult);

        if (String.Equals(inputValue, finalResult))
        {
            Console.WriteLine("Match");
        }
        else
        {
            Console.WriteLine("Differ");
        }

        Console.ReadLine();
    }
}

AES Utility p>

AES Utility

public static class Aes128Utility
{
    private static byte[] key;

    public static EncryptResult EncryptData(byte[] rawData, string strKey)
    {
        EncryptResult result = null;
        if (key == null)
        {
            if (!String.IsNullOrEmpty(strKey))
            {
                key = Convert.FromBase64String((strKey));
                result = Encrypt(rawData);
            }
        }
        else
        {
            result = Encrypt(rawData);
        }

        return result; 

    }

    public static byte[] DecryptData(EncryptResult encryptResult, string strKey)
    {
        byte[] origData = null;
        if (key == null)
        {
            if (!String.IsNullOrEmpty(strKey))
            {
                key = Convert.FromBase64String(strKey);
                origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV));
            }
        }
        else
        {
            origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV));
        }

        return origData; 
    }

    private static EncryptResult Encrypt(byte[] rawData)
    {
        using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
        {
            aesProvider.Key = key;
            aesProvider.Mode = CipherMode.CBC;
            aesProvider.Padding = PaddingMode.PKCS7;
            using (MemoryStream memStream = new MemoryStream())
            {
                CryptoStream encStream = new CryptoStream(memStream, aesProvider.CreateEncryptor(), CryptoStreamMode.Write);
                encStream.Write(rawData, 0, rawData.Length);
                encStream.FlushFinalBlock();
                EncryptResult encResult = new EncryptResult();
                encResult.EncryptedMsg = Convert.ToBase64String(memStream.ToArray());
                encResult.IV = Convert.ToBase64String(aesProvider.IV);
                return encResult;
            }
        }
    }

    private static byte[] Decrypt(byte[] encryptedMsg, byte[] iv)
    {
        using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
        {
            aesProvider.Key = key;
            aesProvider.IV = iv;
            aesProvider.Mode = CipherMode.CBC;
            aesProvider.Padding = PaddingMode.PKCS7;
            using (MemoryStream memStream = new MemoryStream())
            {
                CryptoStream decStream = new CryptoStream(memStream, aesProvider.CreateDecryptor(), CryptoStreamMode.Write);
                decStream.Write(encryptedMsg, 0, encryptedMsg.Length);
                decStream.FlushFinalBlock();
                return memStream.ToArray();
            }
        }
    }

}

DTO类

DTO Class

public class EncryptResult
{
    public string EncryptedMsg { get; set; }
    public string IV { get; set; }
}

参考 b


  1. 为我的AES方法创建一个字节数组的字符数?

  2. 指定密钥不是此算法的有效大小

  3. 使用AES-256和初始化向量进行加密

  4. Base-64字符数组的长度无效

  5. UTF8 / UTF16和Base64在编码方面有什么区别

  1. How many characters to create a byte array for my AES method?
  2. Specified key is not a valid size for this algorithm
  3. Encryption with AES-256 and the Initialization Vector
  4. Invalid length for a Base-64 char array
  5. What's the difference between UTF8/UTF16 and Base64 in terms of encoding


推荐答案

使用加密原语很容易导致实现错误,人们总是这么做,最好使用高级库

It is easy to make implementation mistakes with cryptographic primitives, people do it all the time, it's best to use a high level library if you can.

我有一个代码段,我试图保持审查和更新,这是非常接近你在做什么。它也对密文进行认证,我建议如果有对手可以发送选择的密文到您的解密实现,有很多侧信道攻击与修改密文相关。

I have a snippet that I try to keep reviewed and up to date, that works pretty close to what you're doing. It also does authentication on the cipher text, which I would recommend if there is anyway an adversary could send chosen ciphertext to your decryption implementation, there are a lot of side channel attacks related to modifying the ciphertext.

然而,你所遇到的问题与填充没有任何关系,如果你的密文不匹配你的密钥和iv, t验证你的iv和密文,你通常会得到一个填充错误(如果这是冒泡的客户端它被称为 padding oracle )。您需要将主要语句更改为:

However, the problem you're having does not have any thing to do with padding, if your ciphertext doesn't matchup to your key and iv, and you didn't authenticate your iv and ciphertext, you'll typically get a padding error (if this is bubbled up a client it's called a padding oracle). You need to change your main statement to:

    string valid128BitString = "AAECAwQFBgcICQoLDA0ODw==";
    string inputValue = "Test";
    string keyValue = valid128BitString;


    byte[] byteValForString = Encoding.UTF8.GetBytes(inputValue);
    EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue);
    EncryptResult encyptedValue = new EncryptResult();
    encyptedValue.IV = result.IV; //<--Very Important
    encyptedValue.EncryptedMsg = result.EncryptedMsg;

    string finalResult =Encoding.UTF8.GetString(Aes128Utility.DecryptData(encyptedValue, keyValue));

因此,您使用相同的IV解密,就像加密一样。

So you use the same IV to decrypt as you did to encrypt.

这篇关于使用AesCryptoServiceProvider获取不正确的解密值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆