简体   繁体   English

C 中的 OpenSSL AEAD 解密

[英]AEAD Decryption with OpenSSL in C

I have the following code to decrypt some AEAD encrypted password:我有以下代码来解密一些 AEAD 加密密码:

int aead_decrypt(char *cipher_password, int len_cipher_password, char *tag, char *key, char *iv, int len_iv, char **plaintext_password) {
    EVP_CIPHER_CTX *ctx;
    int len;
    int plaintext_len;

    // Cipher_password len always greater or equal to plaintext
    *plaintext_password = (unsigned char *)malloc(len_cipher_password);
    if(*plaintext_password == 0) {
        fprintf(stderr, "malloc() failure\n");
        free(*plaintext_password);
        return -1;
    }

    if(!(ctx = EVP_CIPHER_CTX_new())) {
        fprintf(stderr, "EVP_CIPHER_CTX_new() failure\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) {
        fprintf(stderr, "EVP_DecryptInit_ex() failure\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) {
        fprintf(stderr, "EVP_DecryptInit_ex() failure\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(!EVP_DecryptUpdate(ctx, *plaintext_password, &len, cipher_password, len_cipher_password)) {
        //if(!EVP_DecryptUpdate(ctx, *plaintext_password, &len, padded_cipher_password, len_padded_cipher_password)) {
        fprintf(stderr, "EVP_DecryptUpdate() failure\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(1!=EVP_DecryptFinal_ex(ctx, *plaintext_password+len, &len)) {
        fprintf(stderr, "EVP_DecryptFinal_ex() failure\n");
        ERR_print_errors_fp(stderr);
        ERR_print_errors_fp(stdout);
        return -1;
    }

    plaintext_len += len;
    (*plaintext_password)[plaintext_len] = '\0';
    EVP_CIPHER_CTX_free(ctx);

    return 1;
}

My problem is that the EVP_DecryptFinal_ex() function always fail but without printing any errors.我的问题是EVP_DecryptFinal_ex() function 总是失败但没有打印任何错误。 My plaintext_password comes out decrypted but with 16 bytes of garbage at the end because the EVP_DecryptUpdate() function doesn't return the good plaintext_password_len .我的plaintext_password出来了,但最后有 16 个字节的垃圾,因为EVP_DecryptUpdate() function 没有返回好的plaintext_password_len I thought at first it was because of padding, my cipher_password is often 24-25 bytes long, so i tried adding some as we can see in the different comments but it did not worked out.起初我以为是因为填充,我的 cipher_password 通常是 24-25 字节长,所以我尝试添加一些,正如我们在不同的评论中看到的那样,但没有成功。 (Also i know i pass some parameters i don't use but that's not what's important here). (我也知道我传递了一些我不使用的参数,但这不是这里重要的)。 I don't know where the problem could be and i'm not that familiar with the OpenSSL library.我不知道问题可能出在哪里,而且我对 OpenSSL 库不太熟悉。

Got it, i was actually confusing aad and tag values.明白了,我实际上混淆了 aad 和标签值。 In Authenticated encryption the tag value is always generated (can't be null).在经过身份验证的加密中,始终会生成标记值(不能为空)。 In my example it was the default size: 16 bytes.在我的示例中,它是默认大小:16 字节。 Tag value is then appended to the cipher data.然后将标记值附加到密码数据中。 You can use it to authenticate your decrypted data.您可以使用它来验证您的解密数据。

Here is my fixed code:这是我的固定代码:

int aead_decrypt(char *cipher_password, int len_cipher_password, char *key, char *iv, int len_iv, char **plaintext_password) {
    EVP_CIPHER_CTX *ctx;
    int len;
    int plaintext_len;

    // The tag is appended at the end of the cipher data
    int tag_offset = len_cipher_password-16;

    // Cipher_password len always greater or equal to plaintext
    *plaintext_password = (unsigned char *)malloc(len_cipher_password);
    if(*plaintext_password == 0) {
            fprintf(stderr, "malloc() failure\n");
            free(*plaintext_password);
            return -1;
    }

    if(!(ctx = EVP_CIPHER_CTX_new())) {
            fprintf(stderr, "EVP_CIPHER_CTX_new() failure\n");
            ERR_print_errors_fp(stderr);
            return -1;
    }

    if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL)) {
            fprintf(stderr, "EVP_DecryptInit_ex() failure\n");
            ERR_print_errors_fp(stderr);
            return -1;
    }

    if(!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) {
            fprintf(stderr, "EVP_DecryptInit_ex() failure\n");
            ERR_print_errors_fp(stderr);
            return -1;
    }

    // Set the expected tag value for authenticated data
    if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, cipher_password+tag_offset)) {
            fprintf(stderr, "EVP_CIPHER_CTX_ctrl() failure\n");
            ERR_print_errors_fp(stderr);
            return -1;
    }

    if(!EVP_DecryptUpdate(ctx, *plaintext_password, &len, cipher_password, tag_offset)) {
            fprintf(stderr, "EVP_DecryptUpdate() failure\n");
            ERR_print_errors_fp(stderr);
            return -1;
    }

    plaintext_len = len;

    if(1!=EVP_DecryptFinal_ex(ctx, *plaintext_password+len, &len)) {
            fprintf(stderr, "EVP_DecryptFinal_ex() failure\n");
            ERR_print_errors_fp(stderr);
            ERR_print_errors_fp(stdout);
    }

    plaintext_len += len;
    (*plaintext_password)[plaintext_len] = '\0';
    EVP_CIPHER_CTX_free(ctx);

    return 1;}

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

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