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

问题描述

我有以下代码,使用 AesCryptoServiceProvider 进行加密和解密。对于加密和解密,使用的 iv key 是相同的。仍然解密的值与源字符串不同。


  1. 解密后需要更正以获取原始值?

  2. inputValue = valid128BitString 时,此代码正常工作。但是当 inputString =Test时,我收到以下异常填充无效,无法删除。。如何纠正?

更新问题



以下将基于@jbtule答案进行伎俩。

  encyptedValue.IV = result.IV; 

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



答案:你的另一个选项是通过一个IV加密和分配它,然后再开始加密转换,而不是让aesProvider为您生成一个随机的。 - @Scott张伯伦

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

更新:参考。我们可以使用 UTF8 来编码源输入和结果输出。 Key和IV可以保留在 Base64 中。



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



相关要点:

主程序

  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实用程序 p>

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

返回结果;

}

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

返回origData;


private static EncryptResult Encrypt(byte [] rawData)
{
using(AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
{
aesProvider.Key = key;
aesProvider.Mode = CipherMode.CBC;
aesProvider.Padding = PaddingMode.PKCS7;
使用(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;
使用(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类

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

参考








解决方案

使用加密原语,人们很容易实现错误一直以来,最好使用,如果可以的话。 / p>

我有一个,我试图保持审查和上到目前为止,这个工作非常接近你正在做的事情。它也对密文进行身份验证,我建议如果无论如何,对手可以将选择的密文发送到您的解密实现中,则有许多与修改密文相关的边信道攻击。



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

  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; //< - 非常重要
encyptedValue.EncryptedMsg = result.EncryptedMsg;

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

所以你使用相同的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. 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

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

encyptedValue.IV = result.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?

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==");

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.

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

Relevant points:

Main Program

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

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 Class

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

References

  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.

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

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

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

10-19 06:57