c# - 据称在 .NET 中使用 AES-256 CBC 解密文件的问题
问题描述
我正在尝试解密在 Java 程序中加密的文件,据称使用带有默认 IV 的 AES-256 CBC。
如果我使用通用解密方法(DecryptAesCbc),唯一的第一个块被成功解密。
如果我使用 Java 开发人员建议的解密方法 (Decrypt),则所有文本都已成功解密 + 最后附加了一些字符(可能是填充?)。
- 如果我理解正确,没有正确使用 CBC 密码模式(视觉示例),因为每个块都与 IV 异或而不是与前一个密文块?
- 如果我使用 Decrypt 方法,从最后一个块中删除(和检测)可能的垃圾字节(垃圾字节值因文件而异)的最佳方法是什么?我应该尝试从最后一个块的末尾删除任何重复的字节吗?
工作示例: https ://dotnetfiddle.net/M1zQbS
using System;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
/*
Original text:
It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. The point of using Lorem Ipsum is that it has a more-or-less normal distribution of letters, as opposed to using 'Content here, content here', making it look like readable English. Many desktop publishing packages and web page editors now use Lorem Ipsum as their default model text, and a search for 'lorem ipsum' will uncover many web sites still in their infancy. Various versions have evolved over the years, sometimes by accident, sometimes on purpose (injected humour and the like).
Alleged encryption algorithm: AES CBC 256bit key (default IV) - file was encrypted in Java program.
*/
public class Program
{
//BASE64 encoded cyphertext
public static string encryptedFileBase64 = "k+8W4j0bec7AlcuxQ017lcSuZesp6hroADqN6nsYfMJyvpzrPQEGplGvcWd9Th7buerMkkpXYRGXJm+J4rVdwxi8nMZkithPrweUpHn27I/Td1ETuVJDQCfo/3ZG0/Hya/zvvq+A8YOgreC1qDkg/ap/Wci7RfVdBD1RXzhrLLD6PcdyZW34AWwjvGAnqrR5KLBeGxT6txTjx/V9SR21rD5LLz12QB4g6A6nulLfZiOHKhRydr9XpJzbISjjAh8/RAGDQHtEwdvbWngH/c7zmrZDL1gsC9e7Ia2wLeTQXSQkb6DAeb7XFyjHObX099xeMpjT9ZnELe/W1eCayC881iEoIVsB1mQA8FktOxyPHwDqU0cLMDjpLtu/1BzW838nCZEKExCKeRjeEDDtixU+KLl/BtDCXMGKXQPPaJk8gK9Ytb7+KCE+h4qAatUBydqIu9wtULu6qsk08S7tWhYHdDJiBToyizogNSUgsLQt89ssLYeb2Iof/ybHDXGi8UlgUohSuvzARUffhtYtmm4cljO92XdS+6bPOX7oW4Od3jPldXOnITZyj95lD3pZf2ss3xIan8UZ3MJNyIvnVR/FGqF/lBxyNIcbRWaMXheb+QBKEQsmphSrbR5AMdo7GsTSw32o7wJ1dqBrK0Sl5fsUjtY4ivV88TWqkoSsyT1XczDK8IsOgXFBGp/NxDcBrQV0HyTkN7AchNdVj7b5LRDwBOKag4jGwb87pyFdCjtAEd4XdS7asvMOoEBQNSL/B0NXFqWB5SyFHhHZYK7ewT9P38zsB8zHxYDcfaSujwmaS5YOVw8/ltO3qQfy02zy/3K+";
//BASE64 encoded AES key
public static string aesKeyBase64 = "lAw0kowr1i//T6Bci78bRX/lIRIwwKeGUz4pHDz0jjo=";
public static string encryptedFileBase64_2 = "0S0tQ2jupE7bHbVspWCOOSWs/hEm/da+oFSVEU1XkzenZmb+OXWM7+4WUNAUU2hZ4IWJULl34Ha8pIb2btLOuv+KSOmFG5wX+rRMd2y66/HLDcHgOkZUPG3c+MV6261q3U2cFad6kZzRx1td3eXiD2vNljP1VKT1Fcr2c8sVVH2Fo1tQEm21YAjxgvcl3k6r6B0zigL1iAYH5liC65LQLihUyrcPLZ7vy2Wt2tKeFUE/kVXwX9/KHQEsY+j9HCE8zPEGkjieimxY8uaxKvEZBVYZ1EAT92YIpOAaVOX8q61uQOurXqJFJ2COLD3MXH0/Cnp3aSQll/l2LmfiS396JbHw6NYn7GC+2eGiMbXeQs0Wo7b17hkQeSLtsB8U+Wdx";
public static string aesKeyBase64_2 = "TL9wAPaCWj53zdbAVDdrtpAUtlKxDtySI4QtKQ5KstA=";
public static void Main()
{
byte[] key = Convert.FromBase64String(aesKeyBase64);
//IV
byte[] iv = new byte[16] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
Console.WriteLine("------------------First file-----------------\n\n");
string decrypted = AesUtils.Decrypt(Convert.FromBase64String(encryptedFileBase64), key, iv);
Console.WriteLine("------------------Proposed decryption process-----------------");
Console.WriteLine(decrypted);
Console.WriteLine("\n---------------AES CBC decryption process--------------------");
string decrypted2 = AesUtils.DecryptAesCbc(Convert.FromBase64String(encryptedFileBase64), key, iv);
Console.WriteLine(decrypted2);
Console.WriteLine("\n\n------------------Second file-----------------\n\n");
key = Convert.FromBase64String(aesKeyBase64_2);
decrypted = AesUtils.Decrypt(Convert.FromBase64String(encryptedFileBase64_2), key, iv);
Console.WriteLine("------------------Proposed decryption process-----------------");
Console.WriteLine(decrypted);
Console.WriteLine("\n---------------AES CBC decryption process--------------------");
decrypted2 = AesUtils.DecryptAesCbc(Convert.FromBase64String(encryptedFileBase64_2), key, iv);
Console.WriteLine(decrypted2);
}
}
public static class AesUtils
{
public static string Decrypt(byte[] cipherBytes, byte[] key, byte[] iv)
{
using (Aes encryptor = GetCryptoAlgorithm())
{
encryptor.Key = key;
encryptor.IV = iv;
using (MemoryStream memoryStream = new MemoryStream(cipherBytes.Length))
{
string plainText = String.Empty;
for (int i = 0; i < cipherBytes.Length; i = i + 16)
{
encryptor.IV = iv;
ICryptoTransform aesDecryptor = encryptor.CreateDecryptor();
CryptoStream cryptoStream = new CryptoStream(memoryStream, aesDecryptor, CryptoStreamMode.Write);
cryptoStream.Write(cipherBytes, i, 16);
cryptoStream.FlushFinalBlock();
}
byte[] plainBytes2 = memoryStream.ToArray();
plainText = Encoding.UTF8.GetString(plainBytes2, 0, plainBytes2.Length);
return plainText;
}
}
}
public static string DecryptAesCbc(byte[] inputArray, byte[] key, byte[] iv)
{
using (Aes aes = GetCryptoAlgorithm())
{
aes.Key = key;
aes.IV = iv;
ICryptoTransform cTransform = aes.CreateDecryptor();
byte[] resultArray = cTransform.TransformFinalBlock(inputArray, 0, inputArray.Length);
aes.Clear();
return Encoding.UTF8.GetString(resultArray);
}
}
private static Aes GetCryptoAlgorithm()
{
Aes algorithm = Aes.Create();
algorithm.Padding = PaddingMode.None;
algorithm.Mode = CipherMode.CBC;
algorithm.KeySize = 256;
algorithm.BlockSize = 128;
return algorithm;
}
}
解决方案
加密是ECB模式下的 AES,带有PKCS7-padding。
如果您使用此配置,它将正确解密并删除填充:
private static Aes GetCryptoAlgorithm()
{
Aes algorithm = Aes.Create();
algorithm.Padding = PaddingMode.PKCS7;
algorithm.Mode = CipherMode.ECB;
algorithm.KeySize = 256;
algorithm.BlockSize = 128;
return algorithm;
}
推荐阅读
- css - React w Gatsby:为什么我的字体文件有时会下载两次
- ios - pattern.firstMatch 得到错误:表达式类型“@lvalue 字符串?” 没有更多上下文是模棱两可的
- javascript - 当我使用 ng build 进行部署时,如何解决 Angular 项目中 vendor.js 中的错误语法
- unity3d - 使用行进立方体算法(体素)实现多纹理着色
- android - 如何检查是否为 TTS 下载了语言
- xslt - XSLT/XPath - 计算相邻节点
- java - 如何在 android 中将特定的用户代理与 (Magical) ExoPlayer 一起使用?
- python - 有没有办法使用 Selenium Python 的鼠标滚轮滚动网页?
- python - 如何使用 RecycleGridLayout 在 RecycleView 中使加载的小部件可滚动?
- php - 如何告诉正则表达式不要忽略嵌套匹配?