【问题标题】:AEAD Decryption with OpenSSL in C在 C 中使用 OpenSSL 进行 AEAD 解密
【发布时间】:2019-11-14 19:37:04
【问题描述】:

我有以下代码来解密一些 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;
}

我的问题是EVP_DecryptFinal_ex() 函数总是失败但没有打印任何错误。 我的plaintext_password 解密出来但最后有 16 个字节的垃圾,因为EVP_DecryptUpdate() 函数没有返回好的plaintext_password_len。 起初我以为是因为填充,我的 cipher_password 通常是 24-25 字节长,所以我尝试添加一些,正如我们在不同的 cmets 中看到的那样,但没有成功。 (我也知道我传递了一些我不使用的参数,但这不是这里重要的)。 我不知道问题可能出在哪里,而且我对 OpenSSL 库不太熟悉。

【问题讨论】:

  • 我认为问题是 no authentication 实际上是在当前代码中实现的。为此,必须首先注释代码if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) {...},并且必须使用加密期间确定的标记。然后,如果认证成功,EVP_DecryptFinal_ex也执行成功。与身份验证相比,附加身份验证数据 (AAD) 的使用是可选的,s。 here.
  • 感谢您的回答,但在我的示例中,数据是使用空标签 ("") 加密的。那么需要设置标签吗?
  • 一般来说,标签是在加密过程中自动生成的。如果标签为空,我会怀疑加密过程中存在问题。您是否将标签与附加的认证数据 (AAD) 混淆了?这些是可选的,即不需要设置它们。 Here 您可以找到一个 OpenSSL 代码,用于使用 AES-GCM 进行加密,它还显示了标签和 AAD 的正确使用。还要检查使用的 OpenSSL 版本是否已经支持 AES-GCM(据我所知,从 1.0.1 开始)。
  • 哦,我明白了。但是密码数据中的标签数据在哪里?在我的示例中,标签大小是默认大小,即 16 字节(我认为)。是附在最后吗?这将解决问题,因为我将能够验证我的数据
  • 没关系,谢谢你的回答!

标签: c encryption openssl


【解决方案1】:

知道了,我实际上是在混淆 aad 和 tag 值。在经过身份验证的加密中,始终会生成标记值(不能为空)。在我的示例中,它是默认大小:16 字节。然后将标记值附加到密码数据中。您可以使用它来验证您的解密数据。

这是我的固定代码:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 1970-01-01
    • 2018-08-17
    • 2013-11-22
    • 2011-07-05
    • 1970-01-01
    相关资源
    最近更新 更多