2017-06-19 470 views
0

以下是使用openssl EVP进行加密和解密的示例代码。当我执行加密和解密时,它似乎工作正常。当我写的encryted字符串中的文件,并从decript文件我收到错误Openssl EVP从文件加密和解密

encrypt.c

#include <openssl/conf.h> 
#include <openssl/evp.h> 
#include <openssl/err.h> 
#include <openssl/bio.h> 
#include <string.h> 
#include <iostream> 
#include <fstream> 
#include <stdint.h> 
#include <assert.h> 

void handleErrors(void) 
{ 
    ERR_print_errors_fp(stderr); 
    abort(); 
} 

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, 
    unsigned char *iv, unsigned char *ciphertext) 
{ 
    EVP_CIPHER_CTX *ctx; 

    int len; 

    int ciphertext_len; 

    /* Create and initialise the context */ 
    if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); 

    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, iv)) 
    handleErrors(); 

    if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) 
    handleErrors(); 
    ciphertext_len = len; 

    if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors(); 
    ciphertext_len += len; 

    /* Clean up */ 
    EVP_CIPHER_CTX_free(ctx); 

    return ciphertext_len; 
} 

int main (int argc, char *argv[]) 
{ 
    if (argc != 2) 
    { 
     printf("Usage: <process> <file>\n"); 
     exit(0); 
    } 
    /* A 256 bit key */ 
    unsigned char *key = (unsigned char *) "key"; 

    /* A 128 bit IV Should be hardcoded in both encrypt and decrypt. */ 
    unsigned char *iv = (unsigned char *)"iv"; 

    /* Message to be encrypted */ 
    unsigned char *plaintext = 
       (unsigned char *)"Password"; 

    unsigned char ciphertext[128],base64[128]; 

    /* Buffer for the decrypted text */ 
    unsigned char decryptedtext[128]; 

    int decryptedtext_len, ciphertext_len; 

    /* Initialise the library */ 
    ERR_load_crypto_strings(); 
    OpenSSL_add_all_algorithms(); 
    OPENSSL_config(NULL); 

    /* Encrypt the plaintext */ 
    ciphertext_len = encrypt (plaintext, strlen ((char *)plaintext), key, iv, 
          ciphertext); 

    /* Do something useful with the ciphertext here */ 
    printf("Ciphertext is:\n"); 
    BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len); 

    printf("%d %s\n", ciphertext_len, ciphertext); 
    int encode_str_size = EVP_EncodeBlock(base64, ciphertext, ciphertext_len); 
    printf("%d %s\n", encode_str_size, base64); 

    std::ofstream outFile (argv[1]); 
    outFile << base64; 
    outFile.close(); 

    /* Clean up */ 
    EVP_cleanup(); 
    ERR_free_strings(); 

    return 0; 
} 

decrypt.c

#include <openssl/conf.h> 
#include <openssl/evp.h> 
#include <openssl/err.h> 
#include <string.h> 
#include <iostream> 
#include <fstream> 
using namespace std; 

void handleErrors(void) 
{ 
    ERR_print_errors_fp(stderr); 
    abort(); 
} 

int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, 
    unsigned char *iv, unsigned char *plaintext) 
{ 
    EVP_CIPHER_CTX *ctx; 

    int len; 

    int plaintext_len; 

    /* Create and initialise the context */ 
    if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors(); 

    if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, iv)) 
    handleErrors(); 

    if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) 
    handleErrors(); 
    plaintext_len = len; 

    if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors(); 
    plaintext_len += len; 

    /* Clean up */ 
    EVP_CIPHER_CTX_free(ctx); 

    return plaintext_len; 
} 

int main (int argc, char *argv[]) 
{ 
    if (argc != 2) 
     { 
       printf("Usage: <process> <file>\n"); 
       exit(0); 
     } 

    /* A 256 bit key */ 
    unsigned char *key = (unsigned char *)"key"; 

    /* A 128 bit IV */ 
    unsigned char *iv = (unsigned char *)"iv"; 

    unsigned char ciphertext[128] = "", base64_in[128] = "", base64_out[128] = ""; 

    /* Buffer for the decrypted text */ 
    unsigned char decryptedtext[128]=""; 

    int decryptedtext_len, ciphertext_len; 

    /* Initialise the library */ 
    ERR_load_crypto_strings(); 
    OpenSSL_add_all_algorithms(); 
    OPENSSL_config(NULL); 

    /* Encrypt the plaintext */ 
    char fileBuffer[128] = ""; 
    ifstream infile (argv[1], ios::binary); 
    infile.getline(fileBuffer, sizeof(fileBuffer)); 
    infile.close(); 

    strcpy((char *)base64_in, fileBuffer); 
    ciphertext_len = (strlen(reinterpret_cast<const char *>(base64_in))); 
    printf("%d %s\n",ciphertext_len, base64_in); 

    int length = EVP_DecodeBlock(base64_out, base64_in, ciphertext_len); 
    while(base64_in[--ciphertext_len] == '=') length--; 
    printf("%d %s\n", length,base64_out); 

    BIO_dump_fp (stdout, (const char *)base64_out, length); 

    decryptedtext_len = decrypt(base64_out, length, key, iv, 
    decryptedtext); 

    /* Add a NULL terminator. We are expecting printable text */ 
    decryptedtext[decryptedtext_len] = '\0'; 

    /* Show the decrypted text */ 
    printf("Decrypted text is:\n"); 
    printf("%d %s\n", decryptedtext_len ,decryptedtext); 

    /* Clean up */ 
    EVP_cleanup(); 
    ERR_free_strings(); 

    return 0; 
} 

输出

./encrypt file 
Ciphertext is: 
0000 - 52 6f a3 c6 6b ea 4a aa-a5 e8 9d 26 47 dc e9 b7 Ro..k.J....&G... 
16 Ro��k�J����&G�鷈H�t� 
24 Um+jxmvqSqql6J0mR9zptw== 

./decrypt file 
24 Um+jxmvqSqql6J0mR9zptw== 
16 Ro��k�J����&G��� 
0000 - 52 6f a3 c6 6b ea 4a aa-a5 e8 9d 26 47 dc e9 b7 Ro..k.J....&G... 
140405999580856:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:529: 
Aborted (core dumped) 

核心

Core was generated by `./decrypt file'. 
Program terminated with signal SIGABRT, Aborted. 
#0 0x00007efe46356428 in __GI_raise ([email protected]=6) at ../sysdeps/unix/sysv/linux/raise.c:54 
54 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory. 
(gdb) bt 
#0 0x00007efe46356428 in __GI_raise ([email protected]=6) at ../sysdeps/unix/sysv/linux/raise.c:54 
#1 0x00007efe4635802a in __GI_abort() at abort.c:89 
#2 0x000000000040110e in handleErrors()() 
#3 0x00000000004011eb in decrypt(unsigned char*, int, unsigned char*, unsigned char*, unsigned char*)() 
#4 0x0000000000401485 in main() 

当我写入文件并从文件中读取内容时,我无法解密。

+0

很明显**不是** C,而是C++!让你的文本和文件扩展名正确!并且不要垃圾邮件标签! – Olaf

+1

@Olaf用于加密的所有openssl/evp.h都在c中。 –

+2

使用C库不符合C标签! – Olaf

回答

2

传递给EVP_EncryptInit_exEVP_DecryptInit_ex的密钥和IV不是字符串,而是取决于密码的固定大小的字符数组。

在AES 256的情况下,密钥长度为32字节(256位)和IV 16字节(128位)。您传入的字符串常量不足以满足这些约束。因此,上述函数会读取这些字符串的末尾,并调用undefined behavior

至于什么是最有可能发生,当您从同一个程序中执行加密和解密它的工作原理的原因是因为你可能传球同样缓冲包含密钥和IV这两个函数,所以在每个字符串结束后都读取同一组未知字节。当你在两个不同的程序中做同样的事时,这个未知的数据是不同的,所以你实际上有两组不同的密钥和IV。

声明您的密钥和IV为固定大小并初始化两者。任何未明确初始化的字节将被设置为0,因此您将拥有已知数量。

unsigned char key[32] = (unsigned char *) "key"; 
unsigned char iv[16] = (unsigned char *)"iv"; 
+0

谢谢你会试试 –

+0

阅读了这些openssl/evp的更多内容。通过nw解决。谢谢@dbush –

1

dbush对关键和IV问题做了正确的描述,但是他继续让它运行而不是正确。

如果你想使用密码,那么你应该使用PBKDF:一个基于密码的密钥派生函数。如果您想使用密钥,那么您应该使用16,24或32个字节的密钥 - 具体取决于所需密钥大小为128,192或256位。

OpenSSL提供了一个名为EVP_BytesToKey和PBKDF2的自己的算法。 Here is an example(不受我的支持)如何使用后者,更现代的算法。


最后,AES密钥应该由128位,192位或256位组成,这对于攻击者来说似乎是随机的。如果你不提供AES这样的密钥,那么库应该返回一个错误而不是继续。故意给它提供太少或太多的字节是灾难的秘诀。填充零字节不是扩展密钥的方式。

+0

感谢您的“填充零字节不是扩展密钥的方式”。 –