Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
OpenSSL EVP API:如何使用对称密钥文件解密加密文件_Openssl_Symmetric Key_Evp Cipher - Fatal编程技术网

OpenSSL EVP API:如何使用对称密钥文件解密加密文件

OpenSSL EVP API:如何使用对称密钥文件解密加密文件,openssl,symmetric-key,evp-cipher,Openssl,Symmetric Key,Evp Cipher,嗨,我正在Linux上使用C 我有一个关于对称密钥解密的查询 我使用下面的命令生成了一个对称密钥 openssl rand base64 512>sym.key 使用这个密钥(sym.key)我用下面的命令加密了一个文件 openssl enc-aes-256-cbc-in temp.txt-out temp.enc-kfile sym.key 它已生成一个加密文件temp.enc 现在,我必须使用与EVP Decrypt API相同的密钥(sym.key),并且必须解密此加密文件 有谁能给我建

嗨,我正在Linux上使用C

我有一个关于对称密钥解密的查询

我使用下面的命令生成了一个对称密钥

openssl rand base64 512>sym.key

使用这个密钥(sym.key)我用下面的命令加密了一个文件

openssl enc-aes-256-cbc-in temp.txt-out temp.enc-kfile sym.key

它已生成一个加密文件temp.enc

现在,我必须使用与EVP Decrypt API相同的密钥(sym.key),并且必须解密此加密文件

有谁能给我建议一个更好的方法吗

这是密码

unsigned char* decode (unsigned char *key, int len)
{

   BIO *b64, *bmem;

   char *buffer = (char *)malloc(len);
   memset (buffer, 0, len);

   b64 = BIO_new(BIO_f_base64());
   bmem = BIO_new_mem_buf(key, len);
   bmem = BIO_push(b64, bmem);

   BIO_read(bmem, buffer, len);

   BIO_free_all(bmem);

    return buffer;
}

void decrypt(char *file_name, char *key_file)
{   

    unsigned char *inbuff = NULL, *outbuff = NULL, *ckey = NULL;
    char *buff = NULL;
    unsigned int flen = 0, outlen2 = 0, outlen1 = 0, klen = 0;

    FILE *fp = NULL, *kfp = NULL;
        unsigned char iv[16] = {};

    fp = fopen (file_name, "r");

    if (NULL == fp)
    {
        printf ("Cannot open file : %s\n", file_name);
        exit(1);
    }

    fseek (fp, 0, SEEK_END);
    flen = ftell (fp);
    rewind (fp);

    kfp = fopen (key_file, "r");

    if (NULL == kfp)
    {
        printf ("Cannot open file : %s\n", key_file);
        exit(1);
    }

    fseek (kfp, 0, SEEK_END);
    klen = ftell (kfp);
    rewind (kfp);

    inbuff = (unsigned char *)malloc(flen);
    outbuff = (unsigned char *)malloc(flen * 2);
    ckey = (unsigned char *)malloc(klen);
    buff = (char *)malloc(klen);

    fread (inbuff, sizeof(char), flen, fp);
    fread (buff, sizeof(char), klen, kfp);

    ckey = decode(buff, klen);

    EVP_CIPHER_CTX ctx;

#if 1
    if (! EVP_DecryptInit (&ctx, EVP_aes_256_cbc(), ckey, iv))
    {
        ERR_print_errors_fp(stderr);
        EVP_CIPHER_CTX_cleanup(&ctx);
        printf ("Error in Init\n");
        exit(1);
    }

    if (! EVP_DecryptUpdate (&ctx, outbuff, &outlen1, inbuff, flen))
    {
        ERR_print_errors_fp(stderr);
        EVP_CIPHER_CTX_cleanup(&ctx);
        printf ("Error in Init\n");
        exit(1);
    }

    if (! EVP_DecryptFinal (&ctx, outbuff + outlen1, &outlen2))
    {
        ERR_print_errors_fp(stderr);
        EVP_CIPHER_CTX_cleanup(&ctx);
        printf ("Error in Init\n");
        exit(1);
    }

    EVP_CIPHER_CTX_cleanup(&ctx);
#endif

    free (inbuff);
    free (outbuff);
    free (ckey);
    fclose (fp);
    fclose (kfp);

    printf ("Outbuff:\n %s\n", outbuff);

}
多谢各位

使用这个密钥(sym.key),我用下面的命令加密了一个文件。
openssl enc-aes-256-cbc-in temp.txt-out temp.enc-kfile sym.key

不完全是
openssl enc-kfile
读取文件的第一行,并且仅读取第一行,并将其用作密码,这与密钥不同
enc
有三个输入密码的选项,然后通过密钥派生过程使用随机salt运行密码,以生成实际密钥和IV(对于使用IV的密码,AES-CBC会)。然后,它将包含salt的头文件(后跟密文)写入输出文件。这称为基于密码的加密(PBE),有时也称为基于密码的密钥派生函数(PBKDF)

根据您实际想要做的事情,有两种方法

解密您拥有的文件 将
sym.key
中的第一行(不包括行终止符)作为字符(而不是base64)读取,然后将盐从
temp.enc
输入到
EVP\u BytesToKey
中,类似如下:

FILE * pwfile = fopen (key_file, "r"); 
if(!pwfile) error_handling 
char pwline [70]; 
fgets (pwline, sizeof pwline, pwfile);
int pwlen = strlen (pwline); 
if(pwlen==0 || pwline[pwlen-1]!='\n') error_handling
pwline[--pwlen] = '\0';

// Open file_name and read into inbuff for flen as you have now 
// Optionally confirm the first 8 bytes are "Salted__"
// If on Windows must fopen with mode "rb" to get all bytes correctly;
// on Unix it is clearer to specify this but not actually needed
// because on Unix binary files and text files are treated the same

unsigned char key [256/8]; // AES-256 key is 32 bytes
unsigned char iv [128/8]; // AES IV is 16 bytes (regardless of key)
EVP_BytesToKey(EVP_aes_256_cbc(), EVP_md5(), inbuff+8, /* the salt! */
    (unsigned char*)pwline, pwlen, 1, key, iv);

// Now continue as you have with EVP_Encrypt{Init,Update,Final}
// using key,iv except use buffer inbuff+16 for length flen-16 .
// (And do something with the output, which you don't now!)
创建您显然想要的文件 要使用
enc
创建使用直接密钥加密的文件,必须使用命令行上的
-K
选项(大写K)以十六进制形式传递该文件。然而,在C程序中处理十六进制是一件麻烦事,因此我会在加密端处理它,比如:

openssl rand 32 >sym.key # AES-256 key must be exactly 32 bytes, not more
openssl enc -aes-256-cbc -in temp.txt -out temp.enc \
  -K $(od -An -tx1 sym.key | sed 's/ //g') -iv 00000000000000000000000000000000
然后在您的C程序中读取
sym.key
(至少在Windows上是二进制的)并按原样使用它,现在的IV为16 0

或者,让
rand
write hex并按原样使用

openssl rand -hex 32 >sym.key
openssl enc -aes-256-cbc -in temp.txt -out temp.enc -K $(cat sym.key) -iv (same)
然后在C程序中读取
sym.key
(作为文本行),并将其从64个十六进制字符转换为
无符号字符键[32]

其他要点 如果您确实需要解码base64文件,则不需要先将其读入内存,然后将b64BIO推送到memBIO上;您可以在读取文件的fileBIO上推送b64BIO

您不需要为
exputff
分配
flen*2
。解密的明文永远不会比密文长。(对于salted PBE表单,它实际上是
flen-16
,如上所述。)加密可以扩展数据,然后只扩展一个块(对于AES,16字节)

最好的做法是检查
malloc
在使用前没有返回
NULL
。这种情况在现代系统上很少发生,但如果从较大的程序调用类似这样的简单代码,并且程序的某些其他部分存在耗尽内存的错误,或者可能存在被拒绝服务攻击利用的漏洞,则这种情况也会发生


如果您想支持不适合可用内存的大型文件,或者可能不支持,请迭代读取块,将每个块馈送到
DecryptUpdate
,写出结果(将延迟约一个块),然后在EOF调用
DecryptFinal
并输出任何最后的部分块。

Hi的可能重复。我找不到你。关于你的建议,你能再给我简单介绍一下吗?有很多EVP加密/解密的例子。比如这里:如果您有更具体的问题和示例代码,我很乐意提供帮助。谢谢您的快速回复。我已经提到了这个例子。在这里,我们看到他们使用的是钥匙和IV组合钥匙,这是硬编码的。我真正关心的是,我在openSSL中使用rand选项生成了一个随机密钥,并将结果保存为sym.key,如openSSL rand base64 512>sym.key**所示。使用此密钥文件,我通过命令提示符将一个文件加密为**openSSL enc-aes-256-cbc-in temp.txt-out temp.enc-kfile sym.key,现在使用相同的密钥文件,我必须通过任何EVP API对文件进行解密。如果你不希望你的密钥被硬编码(这是一个很好的方法),那么你的程序将不得不从一个文件中读取。我想你可以自己做。接下来,您必须从Base64解码您的文件(这里将详细介绍)。最后,将参数传递给decryption init函数,只需按照第一个链接的其余部分操作即可。嗨,Dave,感谢您提供了宝贵的解决方案。这对我帮助很大。我已经按照你的建议尝试了上述场景。我解密成功了98%。我面临以下错误。通过使用EVP_BytesToKey这个逻辑(第一个解决方案),我能够解密文件。但除此之外,它还打印一些垃圾值。通过使用下一种方法将十六进制转换为无符号字符。它已解密了整个文件。但它没有打印第一个字符。你能在这方面指导我吗?@Sai(1)第一种方法对我很有效。您确定只使用了
exputff
的有效部分,即
outlen1+outlen2
字节吗?之后的任何字节都可能是分配缓冲区之前的垃圾剩余。特别是,解密后的数据后面没有空字节,因此将其作为C字符串处理,例如使用
strlen strcpy printf(“%s”)
std::string(exputff)
是错误的<代码>标准::字符串(outgroff,outlen1+outlen2)或
printf(“%s”,outlen1+outlen2,outgroff)
正确。。。。。