Невозможно расшифровать файл, зашифрованный с помощью AesManaged - PullRequest
3 голосов
/ 11 ноября 2011

Я пытаюсь использовать 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 для зашифрованного файла, как это:

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

, где -d обозначает дешифрование, -256 обозначает размер ключа, -cbc режим и -k перед клавишей.

это не дает мне оригинальный файл.

Я пробовал это с несколькими сторонними утилитами, но не могу расшифровать его.

Существуют ли очевидные ошибки при попытке зашифровать и расшифровать этот файл?

Обновление

В ответ на рекомендации @ Paŭlo у меня теперь есть следующий тестовый код (не волнуйтесь, я планирую изменить ключ и 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:

Есть идеи, что я делаю не так?

Ответы [ 3 ]

5 голосов
/ 14 ноября 2011

Я нашел решение моей проблемы с расшифровкой, используя openssl (в разделе Обновление вопроса).

Во-первых, моя длина ключа была неправильной (как предположил @ 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;

Благодаря этому ответу , который привел меня в правильном направлении, и спасибо всем остальным за ответы!

4 голосов
/ 12 ноября 2011

Этот инструмент enqrypt выглядит довольно глупо:

  • Это позволяет только прямой ввод ключа, без base64 или шестнадцатеричного кодирования, что запрещает любые ключи, которые не являются представляемый (или не легко вводимый в качестве параметров командной строки) в используемой кодировке.
  • Используется фиксированный вектор инициализации DUMMY_DUMMY_DUMM.

Для CBC вектор инициализации должен быть по существу случайным и не предсказуемым для любого злоумышленника, если вы используете один и тот же ключ для нескольких сообщений.

Вы можете обойти проблему с фиксированным IV: просто добавьте ваш открытый текст одним блоком (128 бит = 16 байт) случайных данных, зашифруйте с фиксированным вектором инициализации и снова удалите этот первый блок после дешифрования. Поскольку зашифрованный текст каждого блока используется как вектор инициализации для следующего блока, это должно дать достаточно рандомизации для реальных данных.

Но поскольку enqrypt - это только Простой демонстрационный инструмент командной строки , я думаю, что вместо этого вам следует использовать либо инструмент командной строки openssl, как рекомендует sarnold, либо использовать функции библиотеки OpenSSL напрямую (если вы там пишите программу).

3 голосов
/ 11 ноября 2011

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.

...