我有以下使用AesCryptoServiceProvider
进行加密和解密的代码。加密和解密使用的iv
和key
相同。解密值仍然与源字符串不同。
inputValue = valid128BitString
时有效。但是当inputString = “Test”
我收到以下异常Padding is invalid and cannot be removed.
时。我们如何纠正它?更新的问题
以下将根据@jbtule答案进行操作。
encyptedValue.IV = result.IV;
加密结果中的IV
值发生了变化。假设加密是在一个单独的过程中完成的,我们怎么知道IV用于解密?有没有办法让它保持不变或已知?
答案:您的另一个选择是将IV传入加密并在开始加密转换之前分配它,而不是让aesProvider为您生成随机的。 - @Scott Chamberlain
aesProvider.IV = Convert.FromBase64String("4uy34C9sqOC9rbV4GD8jrA==");
更新:参考How to apply padding for Base64。我们可以使用UTF8
来编码源输入和结果输出。密钥和IV可以保留在Base64
中。
使用Base64进行源输入会导致某些值出现问题,例如“MyTest”,其中string的长度不是4的倍数
相关要点:
要解密使用其中一个SymmetricAlgorithm类加密的数据,必须将Key属性和IV属性设置为用于加密的相同值。
SymmetricAlgorithm.IV属性:来自前一个块的信息被混合到加密下一个块的过程中。因此,两个相同的纯文本块的输出是不同的。因为该技术使用前一个块来加密下一个块,所以需要初始化向量来加密第一个数据块。 (根据SymmetricAlgorithm.IV Property MSDN文章)
有效密钥大小为:128,192,256位(根据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实用程序
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课程
public class EncryptResult
{
public string EncryptedMsg { get; set; }
public string IV { get; set; }
}
参考文献
答案 0 :(得分:3)
使用加密原语很容易出现实施错误,人们会一直这样做,如果可以的话,最好使用high level library。
我有一个snippet我尝试不断检查和更新,这与你正在做的非常接近。它还对密文进行身份验证,如果无论如何攻击者都可以将选择的密文发送到您的解密实现,我会建议这样做,有很多与修改密文相关的辅助通道攻击。
然而,你遇到的问题与填充没有任何关系,如果你的密文与你的密钥和iv不匹配,而你没有验证你的iv和密文,你通常会得到填充错误(如果这是冒充客户端,则称为padding oracle)。您需要将主要声明更改为:
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进行解密,就像加密一样。