C# - AESCng为什么加密/解密大于127的字节数组错误?

时间:2018-06-05 05:30:49

标签: c# aes

当我通过AES加密和解密字节[128] {1,2,...,126,127}时,一切都很好:

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

decrypted将输出byte [128] {1,2,...,126,127}。 但当我将raw [127] {128,129,...,253,254}更改为相同的加密/解密逻辑时,结果变为byte [381],内部是[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}

一开始我认为超过127是不同的,直到我发现以下字节数组也起作用:

// Create Key & iv
byte[] key = GenerateKey();
byte[] iv = GenerateIV();

// Create raw byte array from Poruguese ÇÃ
string rawPortuguese = "ÇÃ";
byte[] raw = Encoding.UTF8.GetBytes(rawPortuguese);

现在raw是byte [4] {195,135,195,131},每个数字都大于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}无法正确解密?

Key / IV / Encrypt / Decrypt代码:

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

1 个答案:

答案 0 :(得分:2)

这是问题所在:

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。

除非您知道数据是有效文本,否则您不应将其视为文本 - 这总会导致此类问题。名称&#34;纯文本&#34;在这种情况下,并不意味着 text - 这是一个不幸的术语。它只是意味着&#34;未加密的数据&#34;。

如果您只想有效地从任意流中读取并从中创建数组,请使用另一个MemoryStream,将数据复制到该数据,然后使用MemoryStream.ToArray将其转换为{{1 }}:

byte[]