如何在文件解密期间解决“EVP_DecryptFinal_ex:错误解密”

Posted

技术标签:

【中文标题】如何在文件解密期间解决“EVP_DecryptFinal_ex:错误解密”【英文标题】:How to resolve the "EVP_DecryptFInal_ex: bad decrypt" during file decryption 【发布时间】:2016-03-22 03:35:15 【问题描述】:

我有以下问题。谁能给我建议一个解决方案。

我是第一次做文件的加密和解密工作。

我已使用以下命令通过命令提示符加密文件:

openssl enc -aes-256-cbc -in file.txt -out file.enc -k "key value" -iv "iv value"

我必须以编程方式对其进行解密。所以我已经为它编写了程序,但是它抛出了以下错误:

./exe_file enc_file_directory
...
error: 06065064: digital envelope routines: EVP_DecryptFInal_ex: bad decrypt: evp_enc.c

下面的程序将输入作为目录路径并搜索加密文件“.enc”并尝试将其解密并读入缓冲区。

代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <libxml/globals.h>

void handleErrors(char *msg)

    
        ERR_print_errors_fp(stderr);
        printf("%s", msg);
        abort(); 
    


void freeMemory(char *mem)

    if (NULL != mem)
    
        free(mem);
        mem = NULL;
    


/* Function to decrypt the XML files */

int decryptXML(unsigned char *indata, unsigned char *outdata, int fsize)


    int outlen1 = 0, outlen2 = 0;

    unsigned char iv[] = "b63e541bc9ece19a1339df4f8720dcc3";
    unsigned char ckey[] = "70bbc518c57acca2c2001694648c40ddaf19e3b4fe1376ad656de8887a0a5ec2" ;

    if (NULL == indata)
    
        printf ("input data is empty\n");
        return 0;
    

    if (0 >= fsize)
    
        printf ("file size is zero\n");
        return 0;
    

    outdata = (char *) malloc (sizeof (char) * fsize * 2);

    EVP_CIPHER_CTX ctx;

    EVP_CIPHER_CTX_init(&ctx);

    if (! EVP_DecryptInit_ex (&ctx, EVP_aes_256_cbc(), NULL, ckey, iv))
    
        EVP_CIPHER_CTX_cleanup(&ctx);
    handleErrors("DInit");
    

    if (! EVP_DecryptUpdate (&ctx, outdata, &outlen1, indata, fsize))
    
        EVP_CIPHER_CTX_cleanup(&ctx);
        handleErrors("DUpdate");
    

    if (! EVP_DecryptFinal_ex (&ctx, outdata + outlen1, &outlen2))
    

        EVP_CIPHER_CTX_cleanup(&ctx);
        handleErrors("DFinal");
    

    EVP_CIPHER_CTX_cleanup(&ctx);

    return outlen1+outlen2;



int isDirectory(char *path)

    DIR *dir = NULL;
    FILE *fin = NULL, *fout = NULL;
    int enc_len = 0, dec_len = 0, fsize = 0, ksize = 0;
    unsigned char *indata = NULL, *outdata = NULL;
    char buff[BUFFER_SIZE], file_path[BUFFER_SIZE], cur_dir[BUFFER_SIZE];

    struct dirent *in_dir;
    struct stat s;

    if (NULL == (dir = opendir(path)))
    
        printf ("ERROR: Failed to open the directory %s\n", path);
        perror("cannot open.");
        exit(1);
    

    while (NULL != (in_dir = readdir(dir)))
    

        if (!strcmp (in_dir->d_name, ".") || !strcmp(in_dir->d_name, ".."))
            continue;

        sprintf (buff, "%s/%s", path, in_dir->d_name);

        if (-1 == stat(buff, &s))
        
            perror("stat");
            exit(1);
        

        if (S_ISDIR(s.st_mode))
        

            isDirectory(buff);
        
        else
        
            strcpy(file_path, buff);

            if (strstr(file_path, ".enc"))
            

                /* File to be decrypted */

                fout = fopen(file_path,"rb"); 

                fseek (fout, 0L, SEEK_END);
                fsize = ftell(fout);
                fseek (fout, 0L, SEEK_SET);

                indata = (char*)malloc(fsize);

                fread (indata, sizeof(char), fsize, fout);

                if (NULL == fout)
                
                    perror("Cannot open enc file: ");
                    return 1;
                


                dec_len = decryptXML (indata, outdata, fsize);
                outdata[dec_len] = '\0';
                printf ("%s\n", outdata);
                fclose (fin);
                fclose (fout);

            
        
    



    closedir(dir);
    freeMemory(outdata);
    freeMemory(indata);

    return 1; 



int main(int argc, char *argv[])

    int result;

    if (argc != 2)
    
        printf ("Usage: <executable> path_of_the_files\n");
        return -1;
    

    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    OPENSSL_config(NULL);

    /* Checking for the directory existance */

    result = isDirectory(argv[1]);

    EVP_cleanup();
    ERR_free_strings();

    if (0 == result)
        return 1;
    else
       return 0;

谢谢。

【问题讨论】:

CBC 模式只提供机密性,您通常必须添加 MAC 才能安全地使用 CBC 模式。您可能应该使用经过身份验证的加密,因为它提供 机密性和真实性。请参阅 OpenSSL wiki 上的 EVP Authenticated Encryption and Decryption。 简化您的代码。取消所有文件系统读取。加密一个文件并尝试解密该文件。这样调试就容易多了。 感谢您的回复。你的意思是从程序中使用系统调用吗? 【参考方案1】:

我的情况是,服务器在禁用填充的情况下进行加密。但客户端试图在启用填充的情况下解密。

使用 EVP_CIPHER* 时,默认情况下启用填充。要明确禁用,我们需要这样做

EVP_CIPHER_CTX_set_padding(context, 0);

所以不匹配的填充选项可能是一个原因。

【讨论】:

【参考方案2】:

错误: “错误的加密/解密” "gitencrypt_smudge: FAILURE: openssl 错误解密文件"

根据各自的版本和场景,openssl 会抛出各种错误字符串。以下是我在遇到 openssl 相关问题时使用的清单:

    理想情况下,openssl 能够仅使用相同的密钥(+盐)和加密算法进行加密/解密。

    确保 openssl 版本(用于加密/解密)兼容。例如。 openssl 中使用的哈希值在 1.1.0 版本中从 MD5 更改为 SHA256。这会从相同的密码生成不同的密钥。 使固定: 在 1.1.0 中添加“-md md5”以解密来自较低版本的数据,以及 在较低版本中添加“-md sha256 以解密来自 1.1.0 的数据

    确保您的计算机中安装了一个 openssl 版本。如果同时安装了多个版本(在我的机器上,安装了这些版本:-'LibreSSL 2.6.5' 和 'openssl 1.1.1d'),请确保只有所需的版本出现在您的 PATH 变量中。

【讨论】:

C API 中指定的等价物是什么?【参考方案3】:

当您使用不兼容的 openssl 版本进行加密和解密时,也会出现此消息 digital envelope routines: EVP_DecryptFInal_ex: bad decrypt

我遇到的问题是我在具有 1.1.0 版本的 Windows 上加密,然后在具有 1.0.2g 的通用 Linux 系统上解密。

这不是一个很有帮助的错误消息!


工作解决方案:

@AndrewSavinykh 的一个可能的解决方案适用于许多人(参见 cmets):

这些版本之间的默认摘要已从 md5 更改为 sha256。可以在命令行中分别指定默认摘要为-md sha256-md md5

【讨论】:

参见此处:***.com/a/39641378/284111 这些版本之间的默认摘要已从 md5 更改为 sha256。可以将命令行上的默认摘要分别指定为-md sha256-md md5 我刚从 Kubuntu artful 升级到 Kubuntu bionic,将 openssl 从 1.0.2g 更新到 1.1.0g,我无法解密一些文件。 openssl enc 用于基于密码的密钥派生的默认哈希在 1.1.0 中更改为 SHA256,而在较低版本 (source) 中更改为 MD5。我的解决方案是download the older openssl package,使用dpkg 强制安装,解密文件,从存储库强制更新openssl 包(例如使用Synaptic)并再次加密文件。 @AndrewSavinykh 请将您的评论作为答案,以便我投票。 @AndrewSavinykh 请将其发布为答案。因为它是 感谢您的回答!无论如何,必须说 - 来自 openssl 的人完全是土包子。这不是玩具程序,也不是计算器或游戏,说真的……像我这样的人有重要的东西用这个程序加密。金融和法律的东西!因此,当我几年前突然需要加密文档而不是文档,或者至少是信息“使用带有版本 X 的 openssl 解密”时,我收到了一些愚蠢的“错误解密”消息,就像心脏病发作一样。【参考方案4】:

我在使用 openssl 命令行界面时遇到了类似的错误回复,但具有正确的二进制密钥 (-K)。选项“-nopad”解决了这个问题:

产生错误的例子:

echo -ne "\x32\xc8\xde\x5c\x68\x19\x7e\x53\xa5\x75\xe1\x76\x1d\x20\x16\xb2\x72\xd8\x40\x87\x25\xb3\x71\x21\x89\xf6\xca\x46\x9f\xd0\x0d\x08\x65\x49\x23\x30\x1f\xe0\x38\x48\x70\xdb\x3b\xa8\x56\xb5\x4a\xc6\x09\x9e\x6c\x31\xce\x60\xee\xa2\x58\x72\xf6\xb5\x74\xa8\x9d\x0c" | openssl aes-128-cbc -d -K 31323334353637383930313233343536 -iv 79169625096006022424242424242424 | od -t x1

结果:

bad decrypt
140181876450560:error:06065064:digital envelope 
routines:EVP_DecryptFinal_ex:bad decrypt:../crypto/evp/evp_enc.c:535:
0000000 2f 2f 07 02 54 0b 00 00 00 00 00 00 04 29 00 00
0000020 00 00 04 a9 ff 01 00 00 00 00 04 a9 ff 02 00 00
0000040 00 00 04 a9 ff 03 00 00 00 00 0d 79 0a 30 36 38

结果正确的示例:

echo -ne "\x32\xc8\xde\x5c\x68\x19\x7e\x53\xa5\x75\xe1\x76\x1d\x20\x16\xb2\x72\xd8\x40\x87\x25\xb3\x71\x21\x89\xf6\xca\x46\x9f\xd0\x0d\x08\x65\x49\x23\x30\x1f\xe0\x38\x48\x70\xdb\x3b\xa8\x56\xb5\x4a\xc6\x09\x9e\x6c\x31\xce\x60\xee\xa2\x58\x72\xf6\xb5\x74\xa8\x9d\x0c" | openssl aes-128-cbc -d -K 31323334353637383930313233343536 -iv 79169625096006022424242424242424 -nopad | od -t x1

结果:

0000000 2f 2f 07 02 54 0b 00 00 00 00 00 00 04 29 00 00
0000020 00 00 04 a9 ff 01 00 00 00 00 04 a9 ff 02 00 00
0000040 00 00 04 a9 ff 03 00 00 00 00 0d 79 0a 30 36 38
0000060 30 30 30 34 31 33 31 2f 2f 2f 2f 2f 2f 2f 2f 2f
0000100

【讨论】:

【参考方案5】:

当您指定不正确的解密密码时也可能出现此消息(是的,la脚,但从错误消息中不太明显地意识到这一点,对吧?)。

我正在使用命令行为我的辅助工具解密最近的数据库备份,突然遇到了这个问题。

最后,经过 10 分钟的悲伤和阅读此问题/答案后,我记得密码不同,并且使用正确的密码一切正常。

【讨论】:

这是我的情况。密码错误! 这也是我的情况!绝对应该是对此问题进行验证的第一件事!【参考方案6】:

我认为使用命令行加密和使用程序解密的Key和IV不一样。

请注意,当您使用“-k”(不同于“-K”)时,所输入的输入被视为派生密钥的密码。通常在这种情况下,不需要“-iv”选项,因为密钥和密码都将来自“-k”选项给出的输入。

从您的问题中不清楚,您如何确保加密和解密之间的密钥和 IV 相同。

在我的建议中,最好使用“-K”和“-iv”选项在加密期间明确指定密钥和 IV,并将其用于解密。如果您需要使用“-k”,则使用“-p”选项打印用于加密的密钥和 iv,并在解密程序中使用它们。

更多详情可以在https://www.openssl.org/docs/manmaster/apps/enc.html获取

【讨论】:

谢谢杰。是的!你是对的,它没有得到正确的密钥和 iv 值。它根据您的建议尝试了一个简单的程序(使用 -K、-iv 和 -p 选项)并且它有效。我这里有另一个问题。我已经使用这个命令生成了一个私钥 openssl genrsa -out key.pem 2048 我已经使用这个密钥加密了一个文件,如下所示 openssl enc -aes-256-cbc -in rand_bytes.c -out rand_bytes.enc -kfile key.pem 现在的问题是,我必须读取相同的密钥才能使用 OpenSSL EVP API 解密文件。您能否建议我,如何实现。谢谢。 @Sai:如果这回答了您的特定问题,请将其标记为该线程的答案。另一个答案出于不同的原因很有帮助,但是通过将其标记为您的特定问题的答案,它澄清了该线程与另一个答案上链接的线程不是重复的。

以上是关于如何在文件解密期间解决“EVP_DecryptFinal_ex:错误解密”的主要内容,如果未能解决你的问题,请参考以下文章

解密 Forms cookie 时出现“加密操作期间出错”

如何在shell中加密和解密字符串/文本(linux环境)

RSA SubtleCrypto 解密期间的 DOMException

无法使用 CryptoJS 解密(适用于 Java、Python)

使用 GCP_KMS 和 BYOK 解决方案管理密钥轮换

如何在我的 React 应用程序编译期间解决各种警告?