简体   繁体   English

OpenSSL RSA:无法加密/解密长度超过16个字节的消息

[英]OpenSSL RSA: Unable to encrypt/decrypt messages longer than 16 bytes

I'm working on a simple program that uses OpenSSL to do basic RSA encryption and decryption. 我正在研究一个使用OpenSSL进行基本RSA加密和解密的简单程序。 It is working fine for small messages (<16 bytes), but fails for anything over that. 它对于小消息(<16字节)工作正常,但对于任何事情都失败了。 I understand that a limitation of public key cryptography is that you cannot encrypt anything longer than the key size. 我知道公钥加密的局限性在于您无法加密任何比密钥大小更长的内容。 In my case, I'm using a 1024bit key, so I should have 128bytes to work with (maybe slightly less due to padding), correct? 在我的情况下,我使用的是1024位密钥,因此我应该使用128字节(由于填充可能会略微减少),对吗? If so, that's not what I'm experiencing. 如果是这样,那不是我正在经历的。

Here's the output from my program with 15 bytes: 这是我的程序的输出,有15个字节:

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

And with 16 bytes: 并且有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)

It seems that no matter what, only a total of 16 bytes are encrypted. 似乎无论如何,只加密了16个字节。

My encryption function (updated with fix): 我的加密功能(通过修复更新):

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;
}

The corresponding decryption function (updated with fix): 相应的解密功能(用修复更新):

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;
}

The key generation function: 密钥生成功能:

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;
}

And finally, my main: 最后,我的主要内容:

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;
}

Any help is greatly appreciated! 任何帮助是极大的赞赏! Thank you. 谢谢。

EDIT: As pointed out by math below, it seems that the answer to my mistake was hiding in the OpenSSL here: https://www.openssl.org/docs/crypto/EVP_EncryptInit.html# 编辑:正如下面的数学指出,似乎我的错误的答案隐藏在这里的OpenSSL: https//www.openssl.org/docs/crypto/EVP_EncryptInit.html#

This is because you do not properly handle out and outl parameters in EVP_SealUpdate() , EVP_SealFinal() , EVP_OpenUpdate() and EVP_OpenFinal() . 这是因为您没有正确处理EVP_SealUpdate()EVP_SealFinal()EVP_OpenUpdate()EVP_OpenFinal() outoutl参数。

Each EVP_XxxxUpdate() and EVP_XxxxFinal() call will contribute to the output buffer. 每个EVP_XxxxUpdate()EVP_XxxxFinal()调用都将对输出缓冲区EVP_XxxxFinal() So, you are required to keep track of the seal/open process by summing each outl returned and providing the expected buffer each time (start of buffer + already handled bytes). 因此,您需要通过将每个返回的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;
  ...
}

The program was working with 15-bytes buffer because in that case, the EVP_XxxxUpdate() call is returning 0 in outl (not enough data to seal/open a block), hiding the problem in your code logic. 该程序使用15字节缓冲区,因为在这种情况下, EVP_XxxxUpdate()调用在outl返回0(没有足够的数据来密封/打开块),将问题隐藏在代码逻辑中。

Note: The data is not directly encrypted using the RSA key but using a generated symetric key (AES-128 in your case). 注意:数据不是使用RSA密钥直接加密,而是使用生成的对称密钥(在您的情况下为AES-128)。 This is why the block size is 16 bytes. 这就是块大小为16字节的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM