RijndaelManaged,对于特定输入,两组不同的密钥都可以解密

问题描述

加密和解密方法来自Microsoft documentation

我有两组不同的钥匙。当我使用key1进行加密并使用key2进行解密时,我希望抛出CryptographicException,但这实际上是乱码。

class Program
{
    private static readonly byte[] key1 = new byte[] { 0xAC,0x1F,0xC4,0x8F,0x4C,0x79,0x10,0xA1,0x11,0xD6,0x7D,0x24,0xCE,0x73,0x6C,0xE7,0x8E,0xD2,0x97,0xC2,0x90,0x21,0x27,0xE9,0x68,0x3F,0x50,0x5B,0x92,0x40,0x6D,0xC9 };
    private static readonly byte[] iv1 = new byte[] { 0xF8,0x14,0x77,0xFE,0xFC,0x84,0x66,0x82,0x58,0x01,0x43,0x12,0xD8,0x6F };

    private static readonly byte[] key2 = new byte[] { 0x9D,0x5D,0xA4,0x60,0x89,0xB6,0xAF,0x2B,0xE5,0x0B,0xDF,0x55,0x26,0x37,0x6F,0x9A,0xB4,0xD7,0x08,0xEA,0xC6,0xB9 };
    private static readonly byte[] iv2 = new byte[] { 0x4D,0x83,0x94,0x3D,0x29,0x86,0x7F,0x3A,0x4F,0x87,0x8E };

    static void Main(string[] args)
    {
        var ticks = 637375909118731913;
        string original = JsonConvert.SerializeObject(new DateTime(ticks,DateTimeKind.Utc));

        using (RijndaelManaged myRijndael = new RijndaelManaged())
        {
            byte[] encrypted = EncryptStringToBytes(original,key1,iv1);
            Console.WriteLine("Original:   {0}",original);

            string roundtrip = DecryptStringFromBytes(encrypted,iv1);
            Console.WriteLine("Round Trip: {0}",roundtrip);

            try
            {
                string roundtrip2 = DecryptStringFromBytes(encrypted,key2,iv2);
                Console.WriteLine("Round Trip2: {0}",roundtrip2);
            }
            catch (CryptographicException e)
            {
                Console.WriteLine("Round Trip2: Unable to decrypt,expected.");
            }
        }
    }

    static byte[] EncryptStringToBytes(string plainText,byte[] Key,byte[] IV)
    {
        byte[] encrypted;

        using (RijndaelManaged rijAlg = new RijndaelManaged())
        {
            rijAlg.Key = Key;
            rijAlg.IV = IV;

            ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key,rijAlg.IV);

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt,encryptor,CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {

                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }

        return encrypted;
    }

    static string DecryptStringFromBytes(byte[] cipherText,byte[] IV)
    {
        string plaintext = null;

        using (RijndaelManaged rijAlg = new RijndaelManaged())
        {
            rijAlg.Key = Key;
            rijAlg.IV = IV;

            ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key,rijAlg.IV);

            using (MemoryStream msDecrypt = new MemoryStream(cipherText))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt,decryptor,CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }
        }

        return plaintext;
    }
}

输出

Original:   "2020-10-06T14:21:51.8731913Z"
Round Trip: "2020-10-06T14:21:51.8731913Z"
Round Trip2: 7cB?]?wV???DFI?|hgY?Q?&x

期望:

Original:   "2020-10-06T14:21:51.8731913Z"
Round Trip: "2020-10-06T14:21:51.8731913Z"
Round Trip2: Unable to decrypt,expected.

如果更改滴答声值,只会在特定输入中发生

var ticks = 637375909118731914;

一切正常。

我犯了什么错误

注意:

还有许多其他输入值可能导致这种情况,这在我的应用程序中导致了意外错误

解决方法

我的解决方案是确定字符串是否为json格式。

if(IsJson(roundtrip))
{
   Console.WriteLine("Round Trip: {0}",roundtrip);
}
else
{
   Console.WriteLine("Round Trip: Unable to decrypt.");
}