Расшифровка файла с AES_256_CBC возвращает ошибку «плохой расшифровка» - PullRequest
1 голос
/ 09 апреля 2019

Это следующий вопрос из этого:

OpenSSL EVP_DecryptFinal_ex возвращает ошибку «неправильная конечная длина блока» при расшифровке файла

Я пытаюсь расшифровать файл. Сначала я читал его как файл ASCII вместо двоичного файла. После исправления (надеюсь) и чтения в двоичном виде я всегда получаю ошибку "bad decrypt":

15208:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:crypto\evp\evp_enc.c:570:

Вот пример того, как я шифрую и дешифрую:

Шифрование:

Cipher cipher;
ifstream f("d:/test.YML");
ofstream out("d:/temp.YML");
byte key[KEY_SIZE] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2};
byte iv[BLOCK_SIZE] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};

secure_string line;
secure_string temp;
while (getline(f, line)) {
    cipher.Encrypt(key, iv, line, temp);
    out << temp << endl;
}

Расшифровка:

Cipher cipher;
    ifstream f("d:/temp.YML", ifstream::binary);
    ofstream out("d:/tempDecrypt.YML");
    byte key[KEY_SIZE] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2};
    byte iv[BLOCK_SIZE] = {1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6};

    secure_string temp;
    vector<char> buffer(1024, 0);

    while (!f.eof()) {
        f.read(buffer.data(), buffer.size());
        streamsize dataSize = f.gcount();
        secure_string chunk = { buffer.begin(), buffer.begin() + dataSize };

        cipher.Decrypt(key, iv, chunk, temp);
    }

Теперь я не уверен, с чего начать это расследование:

  1. Есть ли проблема с шифрованием? Зашифрованный файл создан, я не вижу в этом ничего плохого.

  2. Есть ли проблема с тем, как я читаю куски файла и расшифровываю их? Снова я не вижу проблемы здесь. (Ошибка на EVP_DecryptFinal_ex)

  3. Я также слышал, что может быть проблема с заполнением. Я не делаю ничего, связанного с отступом, поэтому не уверен, что это проблема.

  4. Я использую ту же версию OpenSsl, в Windows у меня есть 2 проекта Visual Studio, поэтому не должно быть проблем с несовместимыми библиотеками OpenSsl.

Если у кого-то есть просьбы, дайте мне знать. Я никогда раньше не работал с шифрованием, поэтому некоторые вещи трудно понять.

PS: я не включил методы Encrypt и Decrypt, они такие же, как на сайте Openssl Wiki , дайте мне знать, если мне нужно.

1 Ответ

1 голос
/ 09 апреля 2019

В вашем коде есть ряд проблем ... Назовите несколько:

  • ofstream out("d:/temp.YML"); следует открыть в двоичном режиме.
  • out << temp << endl; повредитдвоичные (зашифрованные) данные путем добавления новых строк без необходимости.
  • Выходной буфер должен содержать достаточно места для размещения (входной буфер + размер_блока).
  • Шифрование / дешифрование в чанках должно следовать за update / final шаблон.Вы не можете шифровать / дешифровать фрагменты независимо друг от друга.
  • IV должен быть случайным и храниться с зашифрованным текстом.

Посмотрите на следующий пример приложения, которое работает:

#include <cstdint>
#include <fstream>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <string.h>
#include <stdio.h>

static const size_t KEY_SIZE = 256 / 8, BLOCK_SIZE = 128 / 8;

class AESBase {
protected:
    const uint8_t *key, *iv;
    EVP_CIPHER_CTX *ctx;
    AESBase(const uint8_t *key, const uint8_t *iv) : key(key), iv(iv) {
        if (!(ctx = EVP_CIPHER_CTX_new()))
            handleErrors();
    }
    ~AESBase() {
        EVP_CIPHER_CTX_free(ctx);
    }
    static void handleErrors(void) {
        ERR_print_errors_fp(stderr);
        abort();
    }
};

class Encrypt : AESBase {
public:
    Encrypt(const uint8_t *key, const uint8_t *iv) : AESBase(key, iv) {
        if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
            handleErrors();
    }
    int update(const char *plaintext, int plaintext_len, char *ciphertext) {
        int len;
        if (1 != EVP_EncryptUpdate(ctx, (uint8_t*)ciphertext, &len, (const uint8_t*)plaintext, plaintext_len))
            handleErrors();
        return len;
    }
    int final(char *ciphertext) {
        int len;
        if (1 != EVP_EncryptFinal_ex(ctx, (uint8_t*)ciphertext, &len))
            handleErrors();
        return len;
    }
};

class Decrypt : AESBase {
public:
    Decrypt(const uint8_t *key, const uint8_t *iv) : AESBase(key, iv) {
        if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
            handleErrors();
    }
    int update(const char *ciphertext, int ciphertext_len, char *plaintext) {
        int len;
        if (1 != EVP_DecryptUpdate(ctx, (uint8_t*)plaintext, &len, (const uint8_t*)ciphertext, ciphertext_len))
            handleErrors();
        return len;
    }
    int final(char *plaintext) {
        int len;
        if (1 != EVP_DecryptFinal_ex(ctx, (uint8_t*)plaintext, &len))
            handleErrors();
        return len;
    }
};

void test_encrypt(const uint8_t *key, const char* in, const char* out) {
    std::ifstream fin(in, std::ios_base::binary);
    std::ofstream fout(out, std::ios_base::binary);
    uint8_t iv[BLOCK_SIZE];
    RAND_bytes(iv, sizeof(iv));

    char buf[1024], temp[sizeof(buf) + BLOCK_SIZE];
    Encrypt aes(key, iv);
    fout.write((char*)iv, sizeof(iv));
    while (fin) {
        fin.read(buf, sizeof(buf));
        int len = (int)fin.gcount();
        if (len <= 0)
            break;
        len = aes.update(buf, len, temp);
        fout.write(temp, len);
    }
    int len = aes.final(temp);
    fout.write(temp, len);
}

void test_decrypt(const uint8_t *key, const char* in, const char* out) {
    std::ifstream fin(in, std::ios_base::binary);
    std::ofstream fout(out, std::ios_base::binary);
    uint8_t iv[BLOCK_SIZE];
    fin.read((char*)iv, sizeof(iv));

    char buf[1024], temp[sizeof(buf) + BLOCK_SIZE];
    Decrypt aes(key, iv);
    while (fin) {
        fin.read(buf, sizeof(buf));
        int len = (int)fin.gcount();
        if (len <= 0)
            break;
        len = aes.update(buf, len, temp);
        fout.write(temp, len);
    }
    int len = aes.final(temp);
    fout.write(temp, len);
}

int main()
{
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    OPENSSL_config(NULL);

    uint8_t key[KEY_SIZE] = { 1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2 };
    test_encrypt(key, "main.cpp", "main.cpp.enc");
    test_decrypt(key, "main.cpp.enc", "main.cpp.txt");
}
...