【问题标题】:RijdaelManaged Encrypted byte[] different than Decrypted byte[] using same key/ivRijndaelManaged 加密字节 [] 与使用相同密钥/iv 的解密字节 [] 不同
【发布时间】:2017-08-06 10:18:25
【问题描述】:

好的,所以我尝试在传输之前对字节 [] 进行编码并在之后对其进行解码。我首先将“这是一条超级机密消息”转换为 byte[],然后使用 RijdaelManaged 进行加密。加密时它从 byte[30](未加密)变为 byte[16],但是当我尝试对其进行解密时,它变为 byte[13],并且在使用字符串生成器转换为字符串时仅呈现“System.Byte[]” .

编辑:我已经三次检查了 keyIV.Key 和 keyIV.IV 在加密/解密时是否都匹配

调用方法:

    static void Main(string[] args)
    {
        KeyIV keyIV = Encryption.GenerateKeyIV();
        int keyLen = keyIV.Key.Length;
        int ivLen = keyIV.IV.Length;

        string plain = "This is a super secret message";

        byte[] plainArray = Encoding.ASCII.GetBytes(plain);

        byte[] encryptedArray = Encryption.EncryptBytes(ref plainArray, keyIV.Key, keyIV.IV);

        byte[] decryptedArray = Encryption.DecryptBytes(ref encryptedArray, keyIV.Key, keyIV.IV);

        Console.WriteLine("Original Message: {0}\n", plain);
        Console.WriteLine("Byte[{0}] Converted Message: {1}\n", plainArray.Length, BitConverter.ToString(plainArray));
        Console.WriteLine("Byte[{0}] Encrypted Message: {1}\n", encryptedArray.Length, BitConverter.ToString(encryptedArray));
        Console.WriteLine("Byte[{0}] Decrypted Message: {1}\n", decryptedArray.Length, BitConverter.ToString(decryptedArray));

        Console.ReadLine();
    }

加密方法:

        public static byte[] EncryptBytes(ref byte[] input, byte[] key, byte[] iv)
    {
        if (input.Length > 0 && key != null && iv != null)
        {
            using (RijndaelManaged rm = new RijndaelManaged() { Key = key, IV = iv })
            {
                rm.Padding = PaddingMode.PKCS7;

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

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter sw = new StreamWriter(cs)) { sw.Write(input); }
                    }

                    return ms.ToArray();
                }
            }
        }

        return null;
    }

解密方法:

        public static byte[] DecryptBytes(ref byte[] input, byte[] key, byte[] iv)
    {
        if (input != null && key != null && iv != null)
        {
            using (RijndaelManaged rm = new RijndaelManaged() { Key = key, IV = iv })
            {
                ICryptoTransform decryptor = rm.CreateDecryptor(rm.Key, rm.IV);

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)) { cs.Write(input, 0, input.Length); }

                    return ms.ToArray();
                }
            }
        }

        return null;
    }

结果输出:

原始消息:这是一条超级机密消息

字节[30] 转换后的消息:54-68-69-73-20-69-73-20-61-20-73-75-70-65-72-20-73-65-63-72- 65-74-20-6D-65-73-73-61-67-65

字节[16] 加密消息:DD-85-D4-1E-E6-40-AA-44-DB-1A-17-33-A7-73-70-34

字节[13] 解密消息:53-79-73-74-65-6D-2E-42-79-74-65-5B-5D

【问题讨论】:

  • 那么,你的意思是,如果我们查看方法encryptData,res 的长度是 30 字节,enc 的长度是 16 字节?不应该这样,我看不出那是怎么回事。
  • encryptData 从同一类的内部(内存流)读取,它会跳过 62 个字节(因为这是标头的长度),然后读取剩余的字节(在本例中为 30),然后加密它们并返回加密的字节[](在本例中为 16)
  • 嗯,这不可能,所以是时候为数据提供十六进制的二进制数据了,这样您和我们就可以看到正在发生的事情。我敢打赌,最后一个块没有被输出,因为它是最后一个块填充将被添加到它并且加密函数需要知道它是最后一个块。通常有一个最终调用,有时由流代码隐式调用。
  • 编辑了原始问题以提供一个最小、完整且可验证的示例。还包括所述程序的当前输出。仍然导致 byte[30] 变成 byte[16] 变成 byte[13]
  • 添加不可验证,缺少的是key和IV。

标签: c# encryption rijndael rijndaelmanaged


【解决方案1】:

问题是您正在使用StreamWriter(即TextWriter)写入加密流。这样做是选择采用 Object 的 .Write 的重载,并且您正在传递一个数组......当您这样做时,TextWriter 假定您正在传递的对象具有某种智能 .ToString()将返回要写入目标流的字符串值的重载。在这种情况下,您的数组没有,因此您正在加密值“System.Byte[]”。

事实证明,您并不真正需要 StreamWriter。您只想将加密方法提供给 CryptoStream 的数组字节写入。幸运的是,流有一个内置的 Write 方法。请在您的 encrypt 方法的主体中尝试此操作:

                using (MemoryStream ms = new MemoryStream())
                {
                    using (CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                    {
                        cs.Write(input, 0, input.Length);
                        cs.Flush();
                    }

                    return ms.ToArray();
                }

当我比较你的数组的文本输出而不是字节表示时,我知道出了什么问题:

        Console.WriteLine("Original Message: {0}\n", plain);
        Console.WriteLine("Byte[{0}] Converted Message: {1}\n", plainArray.Length, Encoding.ASCII.GetString(plainArray));
        Console.WriteLine("Byte[{0}] Encrypted Message: {1}\n", encryptedArray.Length, Encoding.ASCII.GetString(encryptedArray));
        Console.WriteLine("Byte[{0}] Decrypted Message: {1}\n", decryptedArray.Length, Encoding.ASCII.GetString(decryptedArray));

【讨论】:

  • 天哪,我不敢相信它是如此简单,在你提到流写者只是一个试图写一个字符串但只被赋予一个字节[]的文本作者之后,我完全惊呆了我为什么字符串输出总是 System.Byte[] 我差点撞到自己的头!这是我第一次写这样的加密,非常感谢!
猜你喜欢
  • 2018-11-28
  • 2011-08-30
  • 1970-01-01
  • 2016-02-13
  • 1970-01-01
  • 1970-01-01
  • 2017-06-16
  • 1970-01-01
  • 2012-02-21
相关资源
最近更新 更多