Rijndael填充错误

您好我正在尝试通过Rijaendal加密/解密字符串。 我根本无法弄清楚为什么解密会爆炸。 我总是以不正确的填充错误结束。 抛弃我的一件事是我的加密结果,我将其作为HEX数组返回。 它的长度为14个字节。 在我的解密函数中,相同的字节数组在从HEX转换时最终具有16个字节。

任何帮助,将不胜感激:

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

您不应该使用ASCII字符编码作为中间步骤; 你应该改变从hex到ASCII(再返回)的函数,改为从byte[]到hex(再返回)。

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

作为旁注,你是否有理由寻找数组的hex表示forms而不是像Base64那样更紧凑? 您在示例中使用Base64来传输密钥和IV,因此我只是想知道是什么让您想要将加密数据作为hex返回。

无论如何,这里应该适合你:

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

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

 string encryptValue = ConvertToHex(ASCIIEncoding.ASCII.GetString(encBuffer)); 

一旦你有一个ASCII字符串,为什么你需要将其转换为hex? 它已经是文字了! 但到那时你已经丢失了数据。 除非你真的需要hex(在这种情况下遵循Adam的建议并改变你的HexToAscii方法来取一个byte []而不是字符串)你应该只使用Convert.ToBase64String:

 string encryptValue = Convert.ToBase64String(encBuffer); 

在解密时,在另一端使用Convert.FromBase64String 。 然后,您可以完全摆脱hex方法。

哦,一般情况下我不会使用Encoding.ASCII开始…我几乎总是使用Encoding.UTF8 。 目前,您将无法加密(正确)包含非ASCII字符(如重音符号)的任何字符串。

这是您的测试程序的重新安装版本,其中包含一些更改。 请注意,名称“密文”和“纯文本”是加密方面的…它们仍然是二进制数据而不是文本!

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

你可以避免使用Decypting / Encrypting和使用System.Text.Encoding的问题并避免使用Base64编码,通过添加一些完全绕过System.Text.Encoding中微软不匹配转换的方法,允许你加密真实内存中的字节没有任何翻译。

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

  private static Byte[] GetBytes(String SomeString) { Char[] SomeChars = SomeString.ToCharArray(); Int32 Size = SomeChars.Length * 2; List TempList = new List(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 TempList = new List(Size); for (Int32 i = 0; i < ByteArray.Length; i += 2) { TempList.Add(BitConverter.ToChar(ByteArray, i)); } return new String(TempList.ToArray()); } 

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

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