openssl EVP_CipherFinal_ex失败

问题描述 投票:3回答:1

我获得了下面的函数file_encrypt_decrypt,该函数用于使用AES256 CBC from here进行文件的加密和解密。如果我同时从同一程序进行加密和解密,(最后给出主要功能)加密和解密工作正常。尽管同时调用了相同的函数并再次启动了ctx。

如果我评论加密部分,并传递上面创建的cryptod_file,则解密失败,并显示错误:错误:EVP_CipherFinal_ex失败。 OpenSSL错误:错误:06065064:lib(6):func(101):原因(100)[[有意义]] OpenSSL错误:错误:06065064:数字信封例程:EVP_DecryptFinal_ex:不良解密

[有人在谈论某些填充长度问题。但我无法正确解决。另外,如果在同一程序中执行加密但单独进行加密,则同一功能将如何正常运行?

一些指导将不胜感激。

PS:我没有尝试使用通用功能,而是尝试使用EVP_DecryptInit_ex()EVP_DecryptUpdate()EVP_DecryptFinal_ex()进行单独的加密和解密功能,但对于加密却没有效果,类似功能。

完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/aes.h>
#include <openssl/rand.h>

#define ERR_EVP_CIPHER_INIT -1
#define ERR_EVP_CIPHER_UPDATE -2
#define ERR_EVP_CIPHER_FINAL -3
#define ERR_EVP_CTX_NEW -4

#define AES_256_KEY_SIZE 32
#define AES_BLOCK_SIZE 16
#define BUFSIZE 1024

typedef struct _cipher_params_t{
    unsigned char *key;
    unsigned char *iv;
    unsigned int encrypt;
    const EVP_CIPHER *cipher_type;
}cipher_params_t;

void cleanup(cipher_params_t *params, FILE *ifp, FILE *ofp, int rc){
    free(params);
    fclose(ifp);
    fclose(ofp);
    exit(rc);
}
void file_encrypt_decrypt(cipher_params_t *params, FILE *ifp, FILE *ofp){
    // Allow enough space in output buffer for additional block 
    int cipher_block_size = EVP_CIPHER_block_size(params->cipher_type);
    unsigned char in_buf[BUFSIZE], out_buf[BUFSIZE + cipher_block_size];

    int num_bytes_read, out_len;
    EVP_CIPHER_CTX *ctx;

    ctx = EVP_CIPHER_CTX_new();
    if(ctx == NULL){
        fprintf(stderr, "ERROR: EVP_CIPHER_CTX_new failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
        cleanup(params, ifp, ofp, ERR_EVP_CTX_NEW);
    }

    // Don't set key or IV right away; we want to check lengths 
    if(!EVP_CipherInit_ex(ctx, params->cipher_type, NULL, NULL, NULL, params->encrypt)){
        fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
        cleanup(params, ifp, ofp, ERR_EVP_CIPHER_INIT);
    }

    OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == AES_256_KEY_SIZE);
    OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == AES_BLOCK_SIZE);

    // Now we can set key and IV 
    if(!EVP_CipherInit_ex(ctx, NULL, NULL, params->key, params->iv, params->encrypt)){
        fprintf(stderr, "ERROR: EVP_CipherInit_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
        EVP_CIPHER_CTX_cleanup(ctx);
        cleanup(params, ifp, ofp, ERR_EVP_CIPHER_INIT);
    }

    while(1){
        // Read in data in blocks until EOF. Update the ciphering with each read.
        num_bytes_read = fread(in_buf, sizeof(unsigned char), BUFSIZE, ifp);
        if (ferror(ifp)){
            fprintf(stderr, "ERROR: fread error: %s\n", strerror(errno));
            EVP_CIPHER_CTX_cleanup(ctx);
            cleanup(params, ifp, ofp, errno);
        }
        if(!EVP_CipherUpdate(ctx, out_buf, &out_len, in_buf, num_bytes_read)){
            fprintf(stderr, "ERROR: EVP_CipherUpdate failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
            EVP_CIPHER_CTX_cleanup(ctx);
            cleanup(params, ifp, ofp, ERR_EVP_CIPHER_UPDATE);
        }
        fwrite(out_buf, sizeof(unsigned char), out_len, ofp);
        if (ferror(ofp)) {
            fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
            EVP_CIPHER_CTX_cleanup(ctx);
            cleanup(params, ifp, ofp, errno);
        }
        if (num_bytes_read < BUFSIZE) {
            // Reached End of file 
            break;
        }
    }

    // Now cipher the final block and write it out to file 
    if(!EVP_CipherFinal_ex(ctx, out_buf, &out_len)){
        fprintf(stderr, "ERROR: EVP_CipherFinal_ex failed. OpenSSL error: %s\n", ERR_error_string(ERR_get_error(), NULL));
        EVP_CIPHER_CTX_cleanup(ctx);
        cleanup(params, ifp, ofp, ERR_EVP_CIPHER_FINAL);
    }
    fwrite(out_buf, sizeof(unsigned char), out_len, ofp);
    if (ferror(ofp)) {
        fprintf(stderr, "ERROR: fwrite error: %s\n", strerror(errno));
        EVP_CIPHER_CTX_cleanup(ctx);
        cleanup(params, ifp, ofp, errno);
    }
    EVP_CIPHER_CTX_cleanup(ctx);
}


int main(int argc, char *argv[]) {
    FILE *f_input, *f_enc, *f_dec;

    // Make sure user provides the input file 
    if (argc != 2) {
        printf("Usage: %s /path/to/file\n", argv[0]);
        return -1;
    }

    cipher_params_t *params = (cipher_params_t *)malloc(sizeof(cipher_params_t));
    if (!params) {
        // Unable to allocate memory on heap
        fprintf(stderr, "ERROR: malloc error: %s\n", strerror(errno));
        return errno;
    }

    // Key to use for encrpytion and decryption 
    unsigned char key[AES_256_KEY_SIZE];

    // Initialization Vector 
    unsigned char iv[AES_BLOCK_SIZE];

    // Generate cryptographically strong pseudo-random bytes for key and IV 
    if (!RAND_bytes(key, sizeof(key)) || !RAND_bytes(iv, sizeof(iv))) {
        // OpenSSL reports a failure, act accordingly 
        fprintf(stderr, "ERROR: RAND_bytes error: %s\n", strerror(errno));
        return errno;
    }
    params->key = key;
    params->iv = iv;

    // Indicate that we want to encrypt 
    params->encrypt = 1;

    // Set the cipher type you want for encryption-decryption 
    params->cipher_type = EVP_aes_256_cbc();

    // Open the input file for reading in binary ("rb" mode) 
    f_input = fopen(argv[1], "rb");
    if (!f_input) {
        // Unable to open file for reading 
        fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
        return errno;
    }

    // Open and truncate file to zero length or create ciphertext file for writing 
    f_enc = fopen("encrypted_file", "wb");
    if (!f_enc) {
        // Unable to open file for writing 
        fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
        return errno;
    }

    // Encrypt the given file 
    file_encrypt_decrypt(params, f_input, f_enc);

    // Encryption done, close the file descriptors 
    fclose(f_input);
    fclose(f_enc);

    // Decrypt the file 
    // Indicate that we want to decrypt 
    params->encrypt = 0;

    // Open the encrypted file for reading in binary ("rb" mode) 
    f_input = fopen("encrypted_file", "rb");
    if (!f_input) {
        // Unable to open file for reading 
        fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
        return errno;
    }

    // Open and truncate file to zero length or create decrypted file for writing 
    f_dec = fopen("decrypted_file", "wb");
    if (!f_dec) {
        // Unable to open file for writing 
        fprintf(stderr, "ERROR: fopen error: %s\n", strerror(errno));
        return errno;
    }

    // Decrypt the given file 
    file_encrypt_decrypt(params, f_input, f_dec);

    // Close the open file descriptors 
    fclose(f_input);
    fclose(f_dec);

    // Free the memory allocated to our structure 
    free(params);

    return 0;
}
c openssl aes encryption-symmetric evp-cipher
1个回答
0
投票

该代码将生成一个新的密钥,并运行each生成一个新的IV。因此,如果仅注释掉加密部分,则将生成两个different密钥/ IV对,并用于加密和解密,这将导致观察到错误消息。如果出于测试目的使用固定密钥/ IV对,而不是每次使用新生成的对,则代码将按预期工作。

通常,用于加密的密钥/ IV对也必须用于解密。关于IV,实际上,通常在加密期间生成。使用完后,只需将其添加到密文前面(因为IV不是秘密的),以便可以在解密过程中对其进行重构和使用。

© www.soinside.com 2019 - 2024. All rights reserved.