OpenSSL EVP API:如何使用对称密钥文件解密加密文件 [英] OpenSSL EVP API: How to decrypt the encrypted file using a symmetric key file

查看:143
本文介绍了OpenSSL EVP API:如何使用对称密钥文件解密加密文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Linux上使用C.

Hi I'm working on C on Linux.

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

I have a query related to symmetric key decryption.

我已经使用以下命令生成了对称密钥.

I have generated an symmetric key using the below command.

openssl rand base64 512>符号键

使用此密钥( sym.key ),我已使用以下命令加密了文件.

Using this key (sym.key) I have encrypted a file with below command.

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

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

It has generated an encrypted file temp.enc.

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

Now, I have to use the same key (sym.key) with EVP Decrypt API's and have to decrypt this encrypted file.

有人可以建议我采用一种更好的方法吗?

Could any one suggest me a better approach for this.

这是代码

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

Using this key (sym.key) I have encrypted a file with below command.
openssl enc -aes-256-cbc -in temp.txt -out temp.enc -kfile sym.key

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

Not quite. openssl enc -kfile reads the first line, and only the first line, of the file and uses it as the password, which is not the same thing as the key. enc has three options to enter a password, after which it runs the password with random salt through a key derivation process to produce the actual key and IV (for ciphers that use an IV, and AES-CBC does). It then writes a header containing the salt, followed by the ciphertext, to the output file. This is called Password Based Encryption (PBE) and sometimes a Password Based Key Derivation Function (PBKDF).

根据您实际要执行的操作,有两种方法.

Depending on what you actually want to do there are two approaches.

sym.key中读取第一行(不包括行终止符)作为字符,而不是base64,并用temp.encEVP_BytesToKey的盐填充该行,如下所示:

Read the first line from sym.key (excluding the line terminator) as characters, NOT base64, and feed it with the salt from temp.enc through EVP_BytesToKey something like this:

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程序中处理十六进制是很麻烦的,因此我会在加密方面进行处理,例如:

To create the file you apparently wanted

To use enc to create a file encrypted with a direct key, you must pass it with the -K option (uppercase K) on the commandline in hex. However, it's a nuisance to handle hex in your C program, so I would handle it on the encrypt side something like:

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.

then in your C program read sym.key (as binary on Windows at least) and use it as-is, with an IV of 16 0's as you have now.

或者,让rand写十六进制并按原样使用

Alternatively, have rand write hex and use that as-is

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个十六进制字符转换为unsigned char key [32].

then in your C program read sym.key (as a text line) and convert it from 64 chars of hex to unsigned char key [32].

如果确实需要解码base64文件,则无需先将其读取到内存中,然后将b64BIO推入memBIO即可.您可以将b64BIO推入读取文件的fileBIO.

If you did need to decode a base64 file, you don't need to read it into memory first then push a b64BIO on a memBIO; you can push a b64BIO on a fileBIO that reads the file.

您不需要为outbuff分配flen*2.解密后的明文将永远不会长于密文. (对于Salted-PBE形式,实际上是flen-16,如上所述.)加密可以扩展数据,然后只能扩展一个块(对于AES,为16字节).

You don't need to allocate flen*2 for outbuff. Decrypted plaintext will never be longer than the ciphertext. (Which for the salted-PBE form is actually flen-16 as above.) It is encryption that can expand the data, and then only one block (for AES, 16 bytes).

优良作法是在使用前检查malloc没有返回NULL.在现代系统上,这种情况很少发生,但是,即使从较大的程序中调用了像这样的简单代码,而该程序的其他部分却具有耗尽内存的错误,或者可能是拒绝服务攻击所利用的漏洞,则可能会发生这种情况.

It's good practice to check malloc didn't return NULL before using it. This rarely happens on modern systems, but it can occur if even simple code like this is called from a larger program and some other part of the program has a bug that exhausts memory, or perhaps a vulnerability exploited by a denial-of-service attack.

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

If you want to support large files that don't fit in the memory available, or might not, iteratively read chunks, feed each into DecryptUpdate, write out the results (which will lag about one block), and at EOF call DecryptFinal and output any last partial block.

这篇关于OpenSSL EVP API:如何使用对称密钥文件解密加密文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆