C#解密OpenSSL AES-128-ECB加密串报错:输入数据块不完整
问题:OpenSSL可正常解密,但C#解密抛出"The input data is not a complete block"异常
一、OpenSSL解密成功的命令
使用以下OpenSSL命令可成功解密encrypted.msg文件,得到与原内容一致的明文:
openssl enc -d -aes-128-ecb -in "C:\encrypted.msg" -out "c:\temp\decrypted.msg" -K "e2fc714c4727ee9395f324cd2e7f331f" -nopad
二、C#解密异常情况
使用.NET 7的C#代码解密同一加密文件时,始终抛出异常:The input data is not a complete block。以下是原解密代码:
private static string GetHASH(byte[] RawBytes, HashAlgorithm AlgoritmoDiHASH) { if (RawBytes is not { LongLength: > 0 }) return ""; var bytes = AlgoritmoDiHASH.ComputeHash(RawBytes); var builder = new StringBuilder(); foreach (var t in bytes) { builder.Append(t.ToString("x2")); } return builder.ToString(); } public static string GetMd5(string rawData) { if (string.IsNullOrEmpty(rawData)) { throw new Exception(); } return GetHASH(Encoding.UTF8.GetBytes(rawData), MD5.Create()); } public static byte[] AESByteArrayDecryption(byte[] encryptedBytes, string key, CipherMode cipherMode = CipherMode.CBC, PaddingMode paddingMode = PaddingMode.PKCS7, int blockSize = 128, int keySize = 256) { if (string.IsNullOrEmpty(key)) { throw new Exception("Chiave di decrittazione non valida"); } if (encryptedBytes.LongLength == 0) { throw new Exception("Dati da decrittografare non validi"); } var keyB = new byte[32]; var tmp = Encoding.UTF8.GetBytes(key); Buffer.BlockCopy(tmp, 0, keyB, 0, Math.Min(tmp.Length, 32)); using (var rm = Aes.Create()) { rm.BlockSize = blockSize; rm.KeySize = keySize; rm.Mode = cipherMode; rm.Padding = paddingMode; using (var dencryptor = rm.CreateDecryptor(keyB, (cipherMode != CipherMode.ECB ? new byte[blockSize / 8] : null))) { using (var dencryptStream = new MemoryStream(encryptedBytes)) { using (var cryptoStream = new CryptoStream(dencryptStream, dencryptor, CryptoStreamMode.Read)) { var decryptBytes = new byte[encryptedBytes.Length]; cryptoStream.Read(decryptBytes, 0, decryptBytes.Length); return decryptBytes; } } } } } // 调用代码 var cipherMode = CipherMode.ECB; var paddingMode = PaddingMode.None; var blockSize = 128; var keySize = 256; var pwdMD5 = CryptographyUtil.GetMd5("abcd"); var decriptedData = CryptographyUtil.AESByteArrayDecryption(criptedData, pwdMD5, cipherMode, paddingMode, blockSize, keySize); var decriptedDataString = Encoding.UTF8.GetString(decriptedData);
注:用于生成MD5的字符串为abcd,对应的十六进制结果正是OpenSSL命令中使用的e2fc714c4727ee9395f324cd2e7f331f。
三、加密文件内容
j›}2}0‹ÂN_’-#€6µC÷úð+|™wyh”–Ú`WŽ µÄîôZÌ¢Cü‘Êœœ4zw=-á¶(ör»”qÛ‰ ÀðMl}Ï„%ðŸ9]˰ $„üÌR†E)zÆÝ‚¦”J4-¸–éÇ æ&þ`:¯ê—ç‹ß<+K/´ö#Ë‘’Âé·_NFò‚øCUk³`Ú¾µh-ïQõ£®®èá}R±}å,M\™û‡Í°öç/–ÌàOÙ”ÒšßN¥þÀP ø'†èì—Nh #Ä›á•ÆöjȦJæËãJ’^_«.ÂK¯‚ýR*ËdîdtÍB¶ÆpçZÑŸ·oM°Ž7I}ŠÏáˆjS½Ð4Æ=ßÙ¿ré(»²”=[ˆÿjй„cÕ.W®ºïI±PB/úuÓŸic¸D®_¾c£3D‰Èwë‚áJì&ÛÂÙû}Cùô —ÆÀËl¬~ЧԲÈyÇα ÈÆhbSê¾ ç»ûg¢çð²POêA–Á“üïbV|Ë "Æ‘G&éýù>ü µr ÒÅ/Í)®8XU›M}1E2ÚÀúaâ³’d¾¦Ý»TV‘°ŠÖÀñÁa ¤×}:*ØÎ¯ßLÿklÌÐÄàæ4úN››w—ÊÑ ù=Pzf›ÿ%J µµ¾Nf‚{eÔleÊs‹ðý…©m¤¸ò¬†0Ñü*D‰ÀøÖˆ’…RòÒ‰013¾QYó ,&Ñ»§<»J{«»"©‡ÆÐñ,¦®â…òž~ËkAž<ꈘ]8i8ÿ0ãÚÔFÙ™ö\®ŠM—zOÓ¶·è”Y
四、明文文件内容
<reading version="2"><cam><name>Test-Road</name><serial>682719AE6F5E</serial><mac></mac></cam><date>2024-01-19T09:14:06.230Z</date><timestamp>1705655646230</timestamp><plate><adr><kemler>33</kemler><onu>1203</onu></adr><value>ABCDE123</value><direction>-1</direction><country>ITA</country><vehicle>truck</vehicle><speed>20</speed><x>1419</x><y>387</y><width>197</width><height>46</height></plate><images><ocr><url>http://localhost:7572/img/2024/01/19/10/2024-01-19-10-14-06-FG050EE_full.jpg</url></ocr><context><url>http://localhost:7572/img/2024/01/19/10/2024-01-19-10-14-06-FG050EE_ctx.jpg</url></context></images></reading>
问题根源与修正方案
1. 密钥处理错误(核心问题)
OpenSSL使用的是128位密钥(e2fc714c4727ee9395f324cd2e7f331f是32个十六进制字符,对应16字节=128位),但原C#代码存在两处错误:
- 将MD5生成的十六进制字符串转成UTF-8字节数组,再填充到32字节数组中,这会导致密钥完全不匹配。正确做法是将十六进制字符串直接解析为字节数组。
- 设置
keySize=256,但实际使用的是AES-128,需改为keySize=128。
2. CryptoStream读取方式错误
cryptoStream.Read无法保证一次性读取所有解密后的数据,需改用循环读取或CopyTo方法获取完整数据。
3. 加密数据长度验证
当设置PaddingMode.None时,.NET要求加密数据长度必须是块大小(16字节)的整数倍。若加密文件长度不符合,需确认是否读取文件时出现截断,或加密时是否确实未添加填充。
修正后的代码
private static string GetHASH(byte[] RawBytes, HashAlgorithm AlgoritmoDiHASH) { if (RawBytes is not { LongLength: > 0 }) return ""; var bytes = AlgoritmoDiHASH.ComputeHash(RawBytes); var builder = new StringBuilder(); foreach (var t in bytes) { builder.Append(t.ToString("x2")); } return builder.ToString(); } public static string GetMd5(string rawData) { if (string.IsNullOrEmpty(rawData)) { throw new ArgumentException("原始数据不能为空"); } return GetHASH(Encoding.UTF8.GetBytes(rawData), MD5.Create()); } // 新增:十六进制字符串转字节数组方法 private static byte[] HexStringToByteArray(string hex) { if (hex.Length % 2 != 0) throw new ArgumentException("十六进制字符串长度必须为偶数"); byte[] bytes = new byte[hex.Length / 2]; for (int i = 0; i < hex.Length; i += 2) { bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); } return bytes; } public static byte[] AESByteArrayDecryption(byte[] encryptedBytes, string hexKey, CipherMode cipherMode = CipherMode.CBC, PaddingMode paddingMode = PaddingMode.PKCS7, int blockSize = 128, int keySize = 128) { if (string.IsNullOrEmpty(hexKey)) { throw new ArgumentException("解密密钥无效"); } if (encryptedBytes.LongLength == 0) { throw new ArgumentException("待解密数据无效"); } // 将十六进制密钥解析为字节数组 byte[] keyB = HexStringToByteArray(hexKey); using (var rm = Aes.Create()) { rm.BlockSize = blockSize; rm.KeySize = keySize; rm.Mode = cipherMode; rm.Padding = paddingMode; rm.Key = keyB; // ECB模式不需要IV if (cipherMode != CipherMode.ECB) rm.IV = new byte[blockSize / 8]; using (var dencryptor = rm.CreateDecryptor()) using (var dencryptStream = new MemoryStream(encryptedBytes)) using (var cryptoStream = new CryptoStream(dencryptStream, dencryptor, CryptoStreamMode.Read)) using (var resultStream = new MemoryStream()) { // 读取所有解密后的数据 cryptoStream.CopyTo(resultStream); return resultStream.ToArray(); } } } // 调用代码 var cipherMode = CipherMode.ECB; var paddingMode = PaddingMode.None; var blockSize = 128; var keySize = 128; var pwdMD5 = CryptographyUtil.GetMd5("abcd"); var decriptedData = CryptographyUtil.AESByteArrayDecryption(criptedData, pwdMD5, cipherMode, paddingMode, blockSize, keySize); var decriptedDataString = Encoding.UTF8.GetString(decriptedData);
内容的提问来源于stack exchange,提问作者Daniele Frisenna
相关产品推荐
相关产品推荐

