Вопрос по openssl, c – OpenSSL RSA: невозможно зашифровать / расшифровать сообщения длиннее 16 байт

7

Я работаю над простой программой, которая использует OpenSSL для базового шифрования и дешифрования RSA. Он отлично работает для небольших сообщений (& lt; 16 байт), но не работает ни с чем из этого. Я понимаю, что ограничение криптографии с открытым ключом состоит в том, что вы не можете зашифровать что-либо более длинное, чем размер ключа. В моем случае я использую 1024-битный ключ, поэтому у меня должно быть 128 байт для работы (возможно, немного меньше из-за заполнения), правильно? Если так, то это не то, что я испытываю.

Вот вывод из моей программы с 15 байтами:

Generating RSA keypair...done.
Message to encrypt: 0123456789ABCDE
16 bytes encrypted
Decrypted message: 0123456789ABCDE

И с 16 байтами:

Generating RSA keypair...done.
Message to encrypt: 0123456789ABCDEF
16 bytes encrypted
140153837057696:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad     decrypt:evp_enc.c:467:
Decrypted message: (null)

Кажется, что несмотря ни на что, всего 16 байтов зашифрованы.

Моя функция шифрования (обновлено с исправлением):

unsigned char* rsa_seal(EVP_PKEY *pub_key, unsigned char *msg, size_t **enc_msg_len, unsigned char **sym_key, int *sym_key_len, unsigned char **iv) {
    size_t msg_len = strlen((char*)msg);
    unsigned char *encrypt = malloc(EVP_PKEY_size(pub_key));

    EVP_CIPHER_CTX *ctx = malloc(sizeof(EVP_CIPHER_CTX));
    EVP_CIPHER_CTX_init(ctx);

    *sym_key = malloc(EVP_PKEY_size(pub_key));
    *iv = malloc(EVP_MAX_IV_LENGTH);

    **enc_msg_len = 0;

    if(!EVP_SealInit(ctx, EVP_aes_128_cbc(), sym_key, sym_key_len, *iv, &pub_key, 1)) {
        ERR_print_errors_fp(stderr);
        encrypt = NULL;
        goto return_free;
    }

    if(!EVP_SealUpdate(ctx, encrypt, (int*)*enc_msg_len, msg, (int)msg_len)) {
        ERR_print_errors_fp(stderr);
        encrypt = NULL;
        goto return_free;
    }

    if(!EVP_SealFinal(ctx, encrypt, (int*)*enc_msg_len)) {
        ERR_print_errors_fp(stderr);
        encrypt = NULL;
        goto return_free;
    }

    return_free:
    EVP_CIPHER_CTX_cleanup(ctx);
    free(ctx);
    ctx = NULL;

    return encrypt;
}

Соответствующая функция дешифрования (обновлено с исправлением):

char* rsa_open(EVP_PKEY *pri_key, unsigned char *enc_msg, size_t *enc_msg_len, unsigned char *sym_key, int sym_key_len, unsigned char *iv) {
    size_t dec_len = 0;
    unsigned char *decrypt = malloc((*enc_msg_len) + EVP_MAX_IV_LENGTH);
    if(decrypt == NULL) return NULL;

    EVP_CIPHER_CTX *ctx = malloc(sizeof(EVP_CIPHER_CTX));
    EVP_CIPHER_CTX_init(ctx);

    if(!EVP_OpenInit(ctx, EVP_aes_128_cbc(), sym_key, sym_key_len, iv, pri_key)) {
        ERR_print_errors_fp(stderr);
        decrypt = NULL;
        goto return_free;
    }

    if(!EVP_OpenUpdate(ctx, decrypt, (int*)&dec_len, enc_msg, (int)*enc_msg_len)) {
        ERR_print_errors_fp(stderr);
        decrypt = NULL;
        goto return_free;
    }

    if(!EVP_OpenFinal(ctx, decrypt, (int*)&dec_len)) {
        ERR_print_errors_fp(stderr);
        decrypt = NULL;
        goto return_free;
    }

    decrypt[dec_len] = '\0';

    return_free:
    EVP_CIPHER_CTX_cleanup(ctx);
    free(ctx);
    ctx = NULL;

    return (char*)decrypt;
}

Функция генерации ключей:

int rsa_init(EVP_PKEY **rsa_keypair) {
    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);

    if(!EVP_PKEY_keygen_init(ctx)) {
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(!EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KEY_LENGTH)) {
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(!EVP_PKEY_keygen(ctx, rsa_keypair)) {
        ERR_print_errors_fp(stderr);
        return -1;
    }

    EVP_PKEY_CTX_free(ctx);

    return 0;
}

И напоследок мой главный:

int main() {
    EVP_PKEY      *rsa_keypair = NULL; // RSA keypair 
    char          msg[BUFFER];         // Message to encrypt
    unsigned char *encrypt = NULL;     // Encrypted message
    char          *decrypt = NULL;     // Decrypted message

    // Generate key pair
    printf("Generating RSA keypair...");
    if(rsa_init(&rsa_keypair) == -1) {
        fprintf(stderr, "\nError generating RSA keypair.\n");
        exit(1);
    }
    printf("done.\n");

    // Get the message to encrypt
    printf("Message to encrypt: ");
    fgets(msg, BUFFER-1, stdin);
    msg[strlen(msg)-1] = '\0';

    // Load error strings in anticipation of error
    ERR_load_crypto_strings();

    // Encrypt the message
    size_t *encrypt_len = malloc(sizeof(size_t));
    unsigned char *sym_key = NULL;
    unsigned char *iv = NULL;
    int sym_key_len;
    encrypt = rsa_seal(rsa_keypair, (unsigned char*)msg, &encrypt_len, &sym_key, &sym_key_len, &iv);
    printf("%d bytes encrypted\n", (int)*encrypt_len);

    // Decrypt it
    decrypt = rsa_open(rsa_keypair, (unsigned char*)encrypt, (size_t*)encrypt_len, sym_key, sym_key_len, iv);
    printf("Decrypted message: %s\n", decrypt);

    free(encrypt);
    free(decrypt);
    free(encrypt_len);
    free(sym_key);
    free(iv);
    EVP_PKEY_free(rsa_keypair);

    return 0;
}

Любая помощь с благодарностью! Спасибо.

РЕДАКТИРОВАТЬ: Как указано в математике ниже, кажется, что ответ на мою ошибку был спрятан в OpenSSL здесь:https://www.openssl.org/docs/crypto/EVP_EncryptInit.html#

Ваш Ответ

1   ответ
5

out а такжеoutl параметры вEVP_SealUpdate(), EVP_SealFinal(), EVP_OpenUpdate() а такжеEVP_OpenFinal().

КаждыйEVP_XxxxUpdate() а такжеEVP_XxxxFinal() call внесет вклад в выходной буфер. Таким образом, вы должны следить за процессом печати / открытия путем суммирования каждогоoutl возвращается и предоставляет ожидаемый буфер каждый раз (начало буфера + уже обработанные байты).

unsigned char* rsa_seal(...)
{
  ...
  **enc_msg_len = 0;

  EVP_SealUpdate(ctx, encrypt + **enc_msg_len, &outl, msg, (int)msg_len);
  **enc_msg_len += outl;

  EVP_SealFinal(ctx, encrypt + **enc_msg_len, &outl);
  **enc_msg_len += outl;
  ...
}

char* rsa_open(...)
{
  ...
  dec_len = 0;

  EVP_OpenUpdate(ctx, decrypt + dec_len, &outl, enc_msg, (int)*enc_msg_len);
  dec_len += outl;

  EVP_OpenFinal(ctx, decrypt + dec_len, &outl);
  dec_len += outl;
  ...
}

Программа работала с 15-байтовым буфером, потому что в этом случаеEVP_XxxxUpdate() вызов возвращается 0 вoutl (недостаточно данных, чтобы запечатать / открыть блок), скрывая проблему в логике кода.

Заметка Данные не шифруются напрямую с использованием ключа RSA, а сгенерированного симметричного ключа (AES-128 в вашем случае). Вот почему размер блока составляет 16 байтов.

Большое спасибо! Я бы никогда не понял это сам. Мне нужно бежать на несколько часов, но я быстро проверил ваше предложение, и оно сработало прекрасно. Я верну свой быстро измененный код и обновлю свой исходный код выше, когда вернусь. shanet
НА ТАК, лучше оставить исходный код для дальнейшего использования. Если вы исправите это, вопрос не будет интересовать людей, которые сталкиваются с той же проблемой. math

Похожие вопросы