2017-06-19 153 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

感謝您的「填充零字節不是擴展密鑰的方式」。 –