C# - AESCng Why Encrypt/Decrypt byte array greater than 127 incorrectly?

孤者浪人 提交于 2019-12-11 12:57:14

问题


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

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

now decrypted will output byte[381] { 239, 191, 189, ..., 239, 191, 189 }

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

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

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?

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

回答1:


This is the problem:

using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
    plaintext = srDecrypt.ReadToEnd();
}
plainData = Encoding.UTF8.GetBytes(plaintext);

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.

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".

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


来源:https://stackoverflow.com/questions/50692651/c-sharp-aescng-why-encrypt-decrypt-byte-array-greater-than-127-incorrectly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!