问题描述
当我通过AES加密和解密byte [128] {1,2,...,126,127}时,一切都很好:
when I encrypt and decrypt byte[128] { 1, 2, ..., 126, 127 } by AES, everything is fine:
// Create Key & iv
byte[] key = GenerateKey();
byte[] iv = GenerateIV();
// Create raw byte array 0-127
byte[] raw = new byte[128];
for (byte i = 0; i < 128; i++)
{
raw[i] = i;
}
// Encrypt
var encrypted = Encrypt(raw, key, iv);
// Decrypt
var decrypted = Decrypt(encrypted, key, iv);
解密后的
将输出字节[128] {1,2,...,126,127}.但是当我将raw更改为byte [127] {128,129,...,253,254}更改为相同的加密/解密逻辑时,结果变为byte [381],内部是[239,191,189]循环:
decrypted will output byte[128] { 1, 2, ..., 126, 127 }.but when I change raw to byte[127] { 128, 129, ..., 253, 254 } to the same encrypt/decrypt logic, result becomes to byte[381], inside is loops of [239, 191, 189]:
// Create Key & iv
byte[] key = GenerateKey();
byte[] iv = GenerateIV();
// Create raw byte array 128-254
byte[] raw = new byte[127];
for (byte i = 128; i <= 254; i++)
{
raw[i-128] = i;
}
// Encrypt
var encrypted = Encrypt(raw, key, iv);
// Decrypt
var decrypted = Decrypt(encrypted, key, iv);
现在解密后将输出字节[381] {239,191,189,...,239,191,189}
now decrypted will output byte[381] { 239, 191, 189, ..., 239, 191, 189 }
起初,我认为超过127种是不同的,直到我发现以下字节数组也有效:
at start I thought that over 127 is different, until I've found the following byte array also work:
// Create Key & iv
byte[] key = GenerateKey();
byte[] iv = GenerateIV();
// Create raw byte array from Poruguese ÇÃ
string rawPortuguese = "ÇÃ";
byte[] raw = Encoding.UTF8.GetBytes(rawPortuguese);
现在原始数据是字节[4] {195,135,195,131},每个数字都大于127.
now the raw is byte[4] { 195, 135, 195, 131 }, every digit is greater than 127.
// Encrypt
var encrypted = Encrypt(raw, key, iv);
// Decrypt
var decrypted = Decrypt(encrypted, key, iv);
但也可以正确解密,解密后为byte [4] {195,135,195,131}现在我完全感到困惑,为什么原始数据字节[127] {128,129,...,253,254}无法正确解密?
but also can decrypt correctly, decrypted is byte[4] { 195, 135, 195, 131 }now I totally confused, why raw data byte[127] { 128, 129, ..., 253, 254 } cannot decrypt correctlly?
密钥/IV/加密/解密代码:
Key/IV/Encrypt/Decrypt code:
static byte[] GenerateKey()
{
using (AesCng cng = new AesCng())
{
cng.GenerateKey();
return cng.Key;
}
}
static byte[] GenerateIV()
{
using (AesCng cng = new AesCng())
{
cng.GenerateIV();
return cng.IV;
}
}
static byte[] Encrypt(byte[] raw, byte[] key, byte[] iv, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
byte[] encrypted;
using (AesCng cng = new AesCng())
{
cng.Mode = mode;
cng.Padding = padding;
cng.Key = key;
cng.IV = iv;
using (ICryptoTransform encryptor = cng.CreateEncryptor())
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
csEncrypt.Write(raw, 0, raw.Length);
}
encrypted = msEncrypt.ToArray();
}
}
return encrypted;
}
static byte[] Decrypt(byte[] encrypted, byte[] key, byte[] iv, CipherMode mode = CipherMode.CBC, PaddingMode padding = PaddingMode.PKCS7)
{
byte[] decryptedData;
string plaintext = null;
byte[] plainData = null;
using (AesCng cng = new AesCng())
{
cng.Mode = mode;
cng.Padding = padding;
cng.Key = key;
decryptedData = encrypted;
cng.IV = iv;
using (ICryptoTransform decryptor = cng.CreateDecryptor())
{
using (MemoryStream msDecrypt = new MemoryStream(decryptedData))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
plainData = Encoding.UTF8.GetBytes(plaintext);
}
}
}
}
return plainData;
}
推荐答案
这是问题所在
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
plaintext = srDecrypt.ReadToEnd();
}
plainData = Encoding.UTF8.GetBytes(plaintext);
您正在将纯文本数据视为UTF-8,将其转换为字符串,然后将其转换回字节(再次使用UTF-8).如果纯文本数据确实是 UTF-8编码的文本(如您的葡萄牙语示例),那很好,但是对于任意字节数组则不是这种情况.字节序列0x80、0x81、0x82、0x83 ... 0xff无效的UTF-8.
You're treating the plain-text data as if it's UTF-8, converting it to a string, then converting it back to bytes (using UTF-8 again). That's fine if the plain-text data really is UTF-8-encoded text (as it is in your Portuguese example), but that's not the case for an arbitrary byte array. The byte sequence 0x80, 0x81, 0x82, 0x83...0xff isn't valid UTF-8.
除非您知道数据是有效的文本,否则不应将其视为文本-总是会导致此类问题.在这种情况下,纯文本"这个名称实际上并不表示 text -这是一个不幸的术语.它只是表示未加密的数据".
Unless you know that data is valid text, you shouldn't treat it as text - that always leads to problems like this. The name "plain text" in this case doesn't really mean text - it's an unfortunate bit of terminology. It just means "not-encrypted data".
如果只想有效地读取任意流并从中创建一个数组,请使用另一个MemoryStream
,将数据复制到该流,然后使用MemoryStream.ToArray
将其转换为byte[]
:
If you just want to effectively read from an arbitrary stream and create an array from it, use another MemoryStream
, copy the data to that, then use MemoryStream.ToArray
to convert it to a byte[]
:
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var plainData = new MemoryStream())
{
csDescrypt.CopyTo(plainData);
return plainData.ToArray();
}
}
这篇关于C#-AESCng为什么不正确地加密/解密大于127的字节数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!