无法解密使用AesManaged加密的文件

本文关键字:加密 文件 AesManaged 解密 密使 | 更新日期: 2023-09-27 18:14:03

我正在尝试使用System.Security.Cryptography.AesManaged加密我的。net应用程序中的文件。它需要在嵌入式Linux环境中解密,所以。net库对我来说不可用。

我现在的代码看起来像这样:

string encPassword = "ABCDABCDABCDABCDABCDABCDABCDABCD";
string sourceFile = "myFile.txt";
string targetFile = "myFile.encrypted.txt";
FileStream fsInput = = new FileStream(sourceFile, FileMode.Open, FileAccess.Read);
FileStream fsOutput = new FileStream(targetFile, FileMode.OpenOrCreate, FileAccess.Write);
CryptoStream cryptoStream = null;
try
{
    byte[] key = Encoding.ASCII.GetBytes(encPasswd);
    byte[] IV = new byte[16];
    Array.Copy(key, 0, IV, 0, 16);
    AesManaged aes = new AesManaged();
    aes.Key = key;
    aes.IV = IV;
    aes.BlockSize = 128;
    aes.KeySize = 256;
    aes.Mode = CipherMode.CBC;
    ICryptoTransform encryptor = aes.CreateEncryptor();
    cryptoStream = new CryptoStream(fsOutput, encryptor, CryptoStreamMode.Write);
    byte[] buffer = new byte[BUFFER_LENGTH];
    long bytesProcessed = 0;
    long fileLength = fsInput.Length;
    int bytesInCurrentBlock;
    do
    {
        bytesInCurrentBlock = fsInput.Read(buffer, 0, BUFFER_LENGTH);
        cryptoStream.Write(buffer, 0, bytesInCurrentBlock);
        bytesProcessed = bytesProcessed + bytesInCurrentBlock;
    }
    while (bytesProcessed < fileLength);
    return true;
}
// ...

这可以加密文件。现在我正在尝试使用Windows上的第三方实用程序解密该文件,该实用程序也支持Linux,让我相信Linux开发人员能够解密它。

在SourceForge上快速搜索让我可以加密。但是,如果我像这样在加密文件上使用Enqrypt:

enqrypt.exe -d -aes -256 -cbc -k ABCDABCDABCDABCDABCDABCDABCDABCD myFile.encrypted.txt

其中-d表示解密,-256表示密钥大小,-cbc表示模式,-k在密钥前面。

它没有给我原始文件。

我已经尝试了一些第三方工具,但我似乎无法解密它。

是否有任何明显的错误与我如何试图加密和解密这个文件?

更新

响应@Paŭlo的建议,我现在有以下测试代码(别担心,我计划将key和IV更改为不同):

byte[] key = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };
byte[] IV =  { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88 };

块大小仍然是128,密钥大小仍然是256。

我现在尝试使用openssl解密文件,像这样:

openssl enc -d -aes-256-cbc -in c:'encrypted.txt -out c:'decrypted.txt -K 11223344556677881122334455667788 -iv 11223344556677881122334455667788

这会导致以下错误:

bad decrypt 11452:error:06065064:digital envelope routines:EVP_DecryptFinal:bad decrypt:evp_enc.c:450:

你知道我做错了什么吗?

无法解密使用AesManaged加密的文件

我找到了使用openssl解密问题的解决方案(在问题的Update部分)。

首先,我的密钥长度错误(如@Paŭlo Ebermann所建议的)-它应该是256位。

但是最后的问题是我在键 之后设置了键的大小
AesManaged aes = new AesManaged();
aes.Key = key;
aes.IV = IV;
aes.BlockSize = 128;
aes.KeySize = 256;
aes.Mode = CipherMode.CBC;

如果我将上面的代码更改为以下代码,我可以使用openssl解密它:

AesManaged aes = new AesManaged();
aes.BlockSize = 128;
aes.KeySize = 256;
aes.Key = key;
aes.IV = IV;
aes.Mode = CipherMode.CBC;

感谢这个答案把我引向正确的方向,并感谢其他人的答案!

这个加密工具看起来很傻:

  • 只允许直接输入密钥,不允许base64或十六进制编码,不允许任何非base64或十六进制编码的密钥在所使用的编码中可表示的(或不容易作为命令行参数输入的)。
  • 使用固定的初始化向量DUMMY_DUMMY_DUMM

对于CBC,初始化向量本质上应该是随机的,如果您对多个消息使用相同的密钥,则任何攻击者都无法预测。

您可以解决固定IV的问题:只需在明文前加上一个块(128位=16字节)的随机数据,使用固定的初始化向量进行加密,并在解密后再次剥离第一个块。由于每个块的密文被用作下一个块的初始化向量,这应该为实际数据提供足够的随机化。

但是由于enqrypt只是一个简单的示范命令行工具,我认为您应该使用openssl命令行工具,如sarnold推荐的那样,或者直接使用OpenSSL库函数(如果您正在那里编写程序)。

enqrypt可能会因为没有初始化IV而抛出某种类型的错误——你可能在加密时使用了全零字节的IV(假设c#为你初始化内存为零),所以你也应该在解密时尝试使用全零字节。(请务必将IV设置为实际使用)

感谢包含确切的用法声明——它使我足够好奇查看 enqrypt源代码,它有解决方案:

// dummy data, can be used as iv/key
unsigned char *gDummy = (unsigned char*)"DUMMY_DUMMY_DUMMY_DUMMY_DUMMY_DUMMY_DUMMY";
/* ... */
    if (ALGO_AES == gAlgorithm) {
        unsigned char *iv = (unsigned char*)malloc(AES_BLOCK_SIZE);
        memcpy(iv, gDummy, AES_BLOCK_SIZE);
        int rc, num=0;
        if ((!gMem) && (gMode <= MODE_CBC)) {
            // insert padding info for ECB/CBC modes
            tblk[0] = gSize % AES_BLOCK_SIZE;
            fwrite(tblk, 1, 1, ftar);
        }
        while (0 != (rc = fread(sblk, 1, AES_BLOCK_SIZE, fsrc))) {
            switch (gMode) {
            default:
            case MODE_ECB:                           // AES ECB encrypt
                AES_ecb_encrypt(sblk, tblk, &gEncAesKey, AES_ENCRYPT);
                if (!gMem) fwrite(tblk, 1, AES_BLOCK_SIZE, ftar);
                break;
            case MODE_CBC:                            // AES CBC encrypt
                AES_cbc_encrypt(sblk, tblk, AES_BLOCK_SIZE, &gEncAesKey, iv, AES_ENCRYPT);
                if (!gMem) fwrite(tblk, 1, AES_BLOCK_SIZE, ftar);
                break;
/* ... */

你从来没有机会,因为enqrypt的作者已经硬编码了IV(不是一个好主意)到DUMMY_DUMMY_DUMM