我有以下代码来解密一些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字节长,所以我尝试添加一些内容,正如我们在不同的注释中看到的那样,但是没有成功。
(我也知道我传递了一些我不使用的参数,但这在这里并不重要)。
我不知道问题可能在哪里,我对OpenSSL库也不是很熟悉。
答案 0 :(得分:1)
知道了,我实际上是混淆了aad和tag值。在经过身份验证的加密中,标记值始终会生成(不能为null)。在我的示例中,它是默认大小: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;}