首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Rijndael填充错误

Rijndael填充错误
EN

Stack Overflow用户
提问于 2011-02-08 03:51:27
回答 3查看 4.6K关注 0票数 4

你好,我正在尝试通过Rijaendal加密/解密字符串。我就是搞不懂为什么解密会失败。我总是以错误的填充错误结束。有一件事让我大吃一惊,那就是我的加密结果,我将其作为十六进制数组返回。它的长度为14个字节。在我的解密函数中,相同的字节数组在从十六进制转换后最终有16个字节。

如有任何帮助,我们将不胜感激:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace rjandal
{
    class Program
    {
        static void Main(string[] args)
        {
            string DataForEncrypting = "this is a test";

            string key = string.Empty;
            string iv = string.Empty;

            using (System.Security.Cryptography.RijndaelManaged rmt = new System.Security.Cryptography.RijndaelManaged())
            {
                rmt.KeySize = 256;
                rmt.BlockSize = 128;
                rmt.Mode = System.Security.Cryptography.CipherMode.CBC;
                rmt.Padding = System.Security.Cryptography.PaddingMode.ISO10126;
                rmt.GenerateKey();
                rmt.GenerateIV();
                key = Convert.ToBase64String(rmt.Key);
                iv = Convert.ToBase64String(rmt.IV);
            }

            string encryptedData = _encrypt(DataForEncrypting, key, iv);
            string unencryptedData = _decrypt(key, iv, HexString2Ascii(encryptedData));

            Console.WriteLine(unencryptedData);
            Console.WriteLine(encryptedData);
            Console.ReadKey();
        }

        private static string _encrypt(string value, string key, string initVector)
        {
            byte[] buffer = ASCIIEncoding.ASCII.GetBytes(value);
            byte[] encBuffer;
            using (System.Security.Cryptography.RijndaelManaged rmt = new System.Security.Cryptography.RijndaelManaged())
            {
                rmt.KeySize = 256;
                rmt.BlockSize = 128;
                rmt.Mode = System.Security.Cryptography.CipherMode.CBC;
                rmt.Padding = System.Security.Cryptography.PaddingMode.ISO10126;
                encBuffer = rmt.CreateEncryptor(Convert.FromBase64String(key),
                    Convert.FromBase64String(initVector)).TransformFinalBlock(buffer, 0, buffer.Length);
            }
            string encryptValue = ConvertToHex(ASCIIEncoding.ASCII.GetString(encBuffer));
            return encryptValue;
        }

        private static string _decrypt(string key, string initVector, string value)
        {
            byte[] hexBuffer = ASCIIEncoding.ASCII.GetBytes(value);
            byte[] decBuffer;
            using (System.Security.Cryptography.RijndaelManaged rmt = new System.Security.Cryptography.RijndaelManaged())
            {
                rmt.KeySize = 256;
                rmt.BlockSize = 128;
                rmt.Mode = System.Security.Cryptography.CipherMode.CBC;
                rmt.Padding = System.Security.Cryptography.PaddingMode.ISO10126;
                decBuffer = rmt.CreateDecryptor(Convert.FromBase64String(key),
                    Convert.FromBase64String(initVector)).TransformFinalBlock(hexBuffer, 0, hexBuffer.Length);
            }

            return System.Text.ASCIIEncoding.ASCII.GetString(decBuffer);
        } 

        private static string ConvertToHex(string asciiString)
        {
            string hex = "";
            foreach (char c in asciiString)
            {
                int tmp = c;
                hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(tmp.ToString()));
            }
            return hex;
        }

        private static string HexString2Ascii(string hexString)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i <= hexString.Length - 2; i += 2)
            {
                sb.Append(Convert.ToString(Convert.ToChar(Int32.Parse(hexString.Substring(i, 2), System.Globalization.NumberStyles.HexNumber))));
            }
            return sb.ToString();
        }

    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-02-08 03:55:40

您不应该使用ASCII字符编码作为中间步骤;您应该将从十六进制转换为ASCII (然后再转换回来)的函数改为从byte[]转换为十六进制(再转换回来)。

代码语言:javascript
复制
    private static string ConvertToHex(byte[] data)
    {
        string hex = "";
        foreach (byte b in data)
        {
            hex += b.ToString("X2");
        }
        return hex;
    }

    private static byte[] HexString2ByteArray(string hexString)
    {
        byte[] output = new byte[hexString.Length / 2];

        for (int i = 0; i <= hexString.Length - 2; i += 2)
        {
             output[i/2] = Convert.ToByte(hexString.Substring(i, 2), 16);
        }
        return output;
    }

顺便说一句,你为什么要寻找十六进制的数组表示,而不是像Base64这样更紧凑的东西?您在示例中使用Base64来传输密钥和IV,所以我很好奇是什么原因使您希望在这里以十六进制返回加密数据。

无论如何,这里有一些对你有用的东西:

代码语言:javascript
复制
    private static string _encrypt(string value, string key, string initVector)
    {
        byte[] buffer = Encoding.Unicode.GetBytes(value);
        byte[] encBuffer;
        using (System.Security.Cryptography.RijndaelManaged rmt = new System.Security.Cryptography.RijndaelManaged())
        {
            rmt.KeySize = 256;
            rmt.BlockSize = 128;
            rmt.Mode = System.Security.Cryptography.CipherMode.CBC;
            rmt.Padding = System.Security.Cryptography.PaddingMode.ISO10126;
            encBuffer = rmt.CreateEncryptor(Convert.FromBase64String(key),
                Convert.FromBase64String(initVector)).TransformFinalBlock(buffer, 0, buffer.Length);
        }
        string encryptValue = ConvertToHex(encBuffer);
        return encryptValue;
    }

    private static string _decrypt(string key, string initVector, string value)
    {
        byte[] hexBuffer = HexString2ByteArray(value);
        byte[] decBuffer;
        using (System.Security.Cryptography.RijndaelManaged rmt = new System.Security.Cryptography.RijndaelManaged())
        {
            rmt.KeySize = 256;
            rmt.BlockSize = 128;
            rmt.Mode = System.Security.Cryptography.CipherMode.CBC;
            rmt.Padding = System.Security.Cryptography.PaddingMode.ISO10126;
            decBuffer = rmt.CreateDecryptor(Convert.FromBase64String(key),
                Convert.FromBase64String(initVector)).TransformFinalBlock(hexBuffer, 0, hexBuffer.Length);
        }

        return Encoding.Unicode.GetString(decBuffer);
    } 
票数 2
EN

Stack Overflow用户

发布于 2011-02-08 03:58:22

基本上,你在文本和数据之间做了太多的转换。例如,看看这个:

代码语言:javascript
复制
string encryptValue = ConvertToHex(ASCIIEncoding.ASCII.GetString(encBuffer));

一旦你得到了一个ASCII字符串,为什么你需要把它转换成十六进制呢?已经是文本了!但到那时,你已经丢失了数据。除非您真的需要十六进制(在这种情况下,遵循Adam的建议,并将您的HexToAscii方法更改为接受byte[]而不是字符串),否则您应该只使用Convert.ToBase64String:

代码语言:javascript
复制
string encryptValue = Convert.ToBase64String(encBuffer);

解密时使用另一端的Convert.FromBase64String。然后你就可以完全摆脱十六进制方法了。

哦,一般来说,我不会使用Encoding.ASCII开始...我几乎总是使用Encoding.UTF8。目前,您将无法(正确地)加密任何包含非ASCII字符的字符串。

以下是您的测试程序的重新组合版本,其中做了一些更改。请注意,名称“密文”和“明文”是在加密方面...它们仍然是二进制数据,而不是文本!

代码语言:javascript
复制
using System;
using System.Security.Cryptography;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        string DataForEncrypting = "this is a test";

        string key = string.Empty;
        string iv = string.Empty;

        using (RijndaelManaged rmt = new RijndaelManaged())
        {
            rmt.KeySize = 256;
            rmt.BlockSize = 128;
            rmt.Mode = CipherMode.CBC;
            rmt.Padding = PaddingMode.ISO10126;
            rmt.GenerateKey();
            rmt.GenerateIV();
            key = Convert.ToBase64String(rmt.Key);
            iv = Convert.ToBase64String(rmt.IV);
        }

        string encryptedData = _encrypt(DataForEncrypting, key, iv);
        string unencryptedData = _decrypt(key, iv, encryptedData);

        Console.WriteLine(unencryptedData);
        Console.WriteLine(encryptedData);
        Console.ReadKey();
    }

    private static string _encrypt(string value, string key, string initVector)
    {
        using (RijndaelManaged rmt = new RijndaelManaged())
        {
            rmt.KeySize = 256;
            rmt.BlockSize = 128;
            rmt.Mode = CipherMode.CBC;
            rmt.Padding = PaddingMode.ISO10126;
            byte[] plainText = Encoding.UTF8.GetBytes(value);
            byte[] cipherText = rmt.CreateEncryptor(Convert.FromBase64String(key),
                                                    Convert.FromBase64String(initVector))
                                   .TransformFinalBlock(plainText, 0, plainText.Length);
            return Convert.ToBase64String(cipherText);
        }
    }

    private static string _decrypt(string key, string initVector, string value)
    {
        using (RijndaelManaged rmt = new RijndaelManaged())
        {
            rmt.KeySize = 256;
            rmt.BlockSize = 128;
            rmt.Mode = CipherMode.CBC;
            rmt.Padding = PaddingMode.ISO10126;
            byte[] cipherText = Convert.FromBase64String(value);
            byte[] plainText = rmt.CreateDecryptor(Convert.FromBase64String(key),
                                                   Convert.FromBase64String(initVector))
                                  .TransformFinalBlock(cipherText, 0, cipherText.Length);
            return Encoding.UTF8.GetString(plainText);
        }
    }
}
票数 5
EN

Stack Overflow用户

发布于 2012-11-27 07:18:25

您可以避免与解密/加密和usign System.Text.Encoding的问题,并避免使用Base64编码变通,通过添加一些方法,完全绕过微软在System.Text.Encoding中的不匹配转换,允许您加密内存中的实际字节而不进行任何转换。

由于使用了这些方法,我避免了由System.Text.Encoding方法引起的填充错误,也没有使用Base64转换。

代码语言:javascript
复制
    private static Byte[] GetBytes(String SomeString)
    {
        Char[] SomeChars = SomeString.ToCharArray();
        Int32 Size = SomeChars.Length * 2;
        List<Byte> TempList = new List<Byte>(Size);
        foreach (Char Character in SomeChars)
        {
            TempList.AddRange(BitConverter.GetBytes(Character));
        }
        return TempList.ToArray();
    }
    private static String GetString(Byte[] ByteArray)
    {
        Int32 Size = ByteArray.Length / 2;
        List<Char> TempList = new List<Char>(Size);
        for (Int32 i = 0; i < ByteArray.Length; i += 2)
        {
            TempList.Add(BitConverter.ToChar(ByteArray, i));
        }
        return new String(TempList.ToArray());
    }

以及如何将它们与加密一起使用

代码语言:javascript
复制
    private static String Encrypt(String Test1, Byte[] Key, Byte[] IV)
    {
        Byte[] Encrypted;
        using (AesCryptoServiceProvider AesMan = new AesCryptoServiceProvider())
        {
            AesMan.Mode              = CipherMode.CBC;
            AesMan.Padding           = PaddingMode.ISO10126;
            ICryptoTransform EncThis = AesMan.CreateEncryptor(Key, IV);

            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, EncThis, CryptoStreamMode.Write))
                {

                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {
                        //Write all data to the stream.
                        swEncrypt.Write(Test1);
                    }
                    Encrypted = msEncrypt.ToArray();
                }
            }
        };
        return GetString(Encrypted);
    }

    private static String Decrypt(String Data, Byte[] Key, Byte[] IV)
    {
        String Decrypted;
        using (AesCryptoServiceProvider AesMan = new AesCryptoServiceProvider())
        {
            AesMan.Mode              = CipherMode.CBC;
            AesMan.Padding           = PaddingMode.ISO10126;
            ICryptoTransform EncThis = AesMan.CreateDecryptor(Key, IV);

            using (MemoryStream msDecrypt = new MemoryStream(GetBytes(Data)))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, EncThis, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {

                        // Read the decrypted bytes from the decrypting stream 
                        // and place them in a string.
                        Decrypted = srDecrypt.ReadToEnd();
                    }
                }
            }
        }
        return Decrypted;
    }
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4925798

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档