2012-04-30 126 views
2

この場合ファイル(.txt)を読み込み、opensslのEVP apiを使用してAES256CBCで暗号化/復号化しようとしています。 ()(plain.txtを読む - >)(encrypt.txtを作成 - >)(decrypt.txtを作成する)openssl evp api(aes256cbc)を使用してファイルを暗号化する際の問題

# include <stdio.h> 
# include <stdlib.h> 
# include <openssl/evp.h> 
# include <openssl/aes.h> 
# include <sys/types.h> 
# include <sys/stat.h> 
# include <fcntl.h> 
# include <unistd.h> 
# include <string.h> 
# include <assert.h> 
# include <error.h> 
# include "debug.h" 
# define SIZE 32 

char buf[SIZE]; 

int aes_init(unsigned char* pwd, unsigned int pwd_len, unsigned char * salt, EVP_CIPHER_CTX *e_ctx, EVP_CIPHER_CTX *d_ctx) 
{ 
    int i, rounds =5;     /* rounds */ 
    unsigned char key[32], iv[32]; 

    i = EVP_BytesToKey(EVP_aes_256_cbc(),EVP_sha1(),salt,pwd,pwd_len,rounds,key,iv); 
    if(i != 32) 
    { 
     printf("\n Error,Incorrect key size generated:%d:\n",i); 
     return -1; 
    } 

    EVP_CIPHER_CTX_init(e_ctx); 
    EVP_EncryptInit_ex(e_ctx, EVP_aes_256_cbc(), NULL, key, iv); 
    EVP_CIPHER_CTX_init(d_ctx); 
    EVP_DecryptInit_ex(d_ctx, EVP_aes_256_cbc(), NULL, key, iv); 

    return 0; 
} 

unsigned char* aes_encrypt(EVP_CIPHER_CTX *e,unsigned char * plain_text, unsigned int * len) /* this function encryptes the file:fd is passed as parameter */ 
{ 
    int ci_len = (*len) + AES_BLOCK_SIZE; 
    int flen =0; 
    unsigned char * cipher_text = malloc(ci_len); 

    EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL);    /* allows reusing of e for multiple cipher cycles */ 
    EVP_EncryptUpdate(e, cipher_text, &ci_len, plain_text, *len);  /* Update cipher text */ 
    EVP_EncryptFinal_ex(e, cipher_text+ci_len, &flen);   /* updates the remaining bytes */ 
    *len = ci_len + flen; 

    return cipher_text; 
} 

unsigned char* aes_decrypt(EVP_CIPHER_CTX *e, unsigned char * c_text, unsigned int * len) 
{ 
    int pi_len = (*len); 
    int flen = 0; 
    unsigned char * plain_text = malloc(pi_len); 

    EVP_DecryptInit_ex(e, NULL, NULL, NULL, NULL); 
    EVP_DecryptUpdate(e, plain_text, &pi_len, c_text, *len); 
    EVP_DecryptFinal_ex(e, plain_text+pi_len, &flen); 

    (*len) = pi_len + flen; 
    return plain_text; 
} 

int main(int argc,char **argv) 
{ 
    if(argc != 2) 
    { 
     perror("\n Error:\nCorrect Usage: Enter Password to be used"); 
     exit(-1); 
    } 

    EVP_CIPHER_CTX en,de;     /* The EVP structure which keeps track of all crypt operations see evp.h for details */ 
    int in, out, fd, dec,i =0;     /* fd for input and output files and random dev*/ 
    unsigned int pwd_len = strlen((const char *)argv[1]);   /* Length of the pwd supplied by the user */ 
    unsigned char *pwd =(unsigned char*) argv[1];   /* Pointer to the pwd supplied by the user */ 
    unsigned int rd= 0; 
    unsigned char salt[8]; 
    unsigned char * encry = NULL, *decry = NULL; 
    i =0; 
    if((in = open("plain.txt",O_RDONLY)) == -1)   /* Opening a plain text file for encryption */ 
    { 
     perror("\n Error,Opening file for reading::"); 
     exit(-1); 
    } 

    if((fd = open("/dev/random", O_RDONLY)) == -1) 
    { 
     perror("\n Error,Opening /dev/random::"); 
     exit(-1); 
    } 
    else 
    { 
     if(read(fd,salt,8) == -1) 
     { 
     perror("\n Error,reading from /dev/random::"); 
     exit(-1); 
     } 
    } 

    if(aes_init(pwd,pwd_len,(unsigned char*) salt,&en,&de))  /* Generating Key and IV and initializing the EVP struct */ 
    { 
     perror("\n Error, Cant initialize key and IV:"); 
     return -1; 
    } 

    if((out = open("encrypt.txt",O_RDWR|O_CREAT,0400 | 0200)) == -1) 
    { 
     dbug_p("ENC%d",out); 
     perror("\n Error,Opening the file to be written::"); 
     exit(-1); 
    } 

    rd =0; 
    while((rd = read(in,buf,SIZE)) >0) 
    { 
     dbug_p("\nREAD::%s::%d*\n",buf,rd); 
     encry = aes_encrypt(&en,(unsigned char*) buf, &rd); 
     if((write(out,encry,rd)) != rd) 
     { 
     perror("\n Error,Required encrypted bytes not written::"); 
     exit(-1); 
     }  
     free(encry); 
    } 

    rd =0; 
    if((dec = open("dec22.txt",O_RDWR|O_CREAT,0400 | 0200)) == -1) 
    { 
     dbug_p("dec%d",dec); 
     perror("\n Error,Opening the decrypting o/p file::"); 
     exit(-1); 
    } 

    if((lseek(out,0,SEEK_SET)) != 0) perror("\n Error:setting lseek::"); 
    for(i=0;i<SIZE;i++) buf[i] =0; 
    while((rd = read(out,dbuf,SIZE)) >0) 
    { 
     decry = aes_decrypt(&de,(unsigned char*) dbuf, &rd); 
     if((write(dec,decry,rd)) != rd) 
     { 
     perror("\n Error,Required decrypted bytes not written::"); 
     exit(-1); 
     } 
     free(decry); 
    } 

    close(in); 
    close(fd); 
    EVP_CIPHER_CTX_cleanup(&en); 
    EVP_CIPHER_CTX_cleanup(&de); 
    return 0; 
} 

私の問題は、私は、暗号化ファイルを復号化するとき、私の私があるファイルを取得するということでした正しく復号化されない(例えば、正しい文字列ごみ正しい文字列ごみ ...)

[email protected]:~/mpro/EFF$ cat plain.txt 
Today is tuesday 
tomorrow is wednesday 
then thursday and friday and saturday 
finally sunday 

復号化されたファイル

cat dec22.txt 
Today is tuesdayw)Q������O-%�A�8���R��.�O���and saturday 
finally sunday 

これが原因である可能性があります。それはまた何か他のものを読んでいるのか、私はどこかの愚かな誤りを作り出しています。

EDIT:私はちょうどそれが正しく任意のゴミを印刷せずに暗号化および復号化(36charロングにしようとした)配列を暗号化する場合。

私はいくつかの* nixファイル構造の詳細が不足していると思います。 ファイルにこの暗号化を行うためのより良い方法がありますか?

多くのお礼ありがとうございます

+0

いくつかの内部コンポーネントで[OpenSSL 1.1.0cがダイジェストアルゴリズムを変更しました](http://stackoverflow.com/q/39637388/608639)。以前はMD5が使用され、1.1.0はSHA256に切り替えられました。変更が 'EVP_BytesToKey'と' openssl enc'のようなコマンドの両方に影響しないように注意してください。 – jww

答えて

4

あなたの分析は間違っていると思います。このループには問題がある:まず

while((rd = read(in,buf,SIZE)) >0) 
{ 
    dbug_p("\nREAD::%s::\n",buf); 
    encry = aes_encrypt(&en,(unsigned char*) buf, &rd); 
    dbug_p("\n EN::%s::\n",encry); 
    decry = aes_decrypt(&de,(unsigned char*) encry,&rd); 
    dbug_p("\n DE::%s::\n",decry); 

      free(encry); 
     free(decry); 
} 

あなたがゼロターミネータを期待%sを使用して印刷するので。ただし、暗号化/復号化されたデータはゼロ終了しません。代わりにfor (i = 0; i < rd; i++) printf("%02x ");のようなループを使用してrd文字を印刷する必要があります。これが問題の分析に欠陥がある理由です。

第2に、実際の問題では、一度にSIZEバイトを読み取り、別々にaes_decrypt()に送信しているとします。 EVP_DecryptFinal_ex()が(暗号化されたすべてのブロックが読み込まれる前に)あまりに早く呼び出されているため、これは失敗します。あなたには2つの選択肢があります。いずれかのループ反復でEVP_DecryptUpdate()を介して読み取りバイトを送信し、ループを完了した後(ループに先立ってinit)EVP_DecryptFinal()を呼び出すか、ファイル全体を最初にバッファに読み込んでから、aes_decrypt()を一度に送信します。

つまり、aes_encrypt()のデータブロック全体をaes_decrypt()に送信する必要があります。機能を分割し、別のチャンクでEVPの「更新」機能を使用しない限り、それらを異なるチャンクで送信することはできません。

+0

もう一度私の質問にお答えいただき、ありがとうございます。実際に私は実際のコードでaes_decrypt()を呼び出すのではない。まず、plain.txtをループ(毎回32バイト)で読み込み、aes_encrypt()に渡してencrypt.txtファイルに書き込むまでEOFを開いてからlseekを開いてファイルを開き、この暗号化されたファイルから32バイト/ループの繰り返しを読み込み、今度はaes_decrypt()を呼び出して、復号化されたコードを新しいtxtファイルに書き出します。私は完全なコードで上記の私のコードを更新してください多くを確認してください多くのおかげで – abhi

+0

あなたのコメントに何を言っていますか?今私は解読されたファイルの中にゴミを取得していませんが、いくつかの文字が解読されたファイルから欠落しています。多くのありがとう.. – abhi

+1

あなたの現在のコードがどのように見えるかわかりませんが、どうすればいいですか:init、{read、update、write}、final、write。暗号化と復号化の両方を行います。 –

3
while((rd = read(in,buf,SIZE)) >0) 
{ 
    dbug_p("\nREAD::%s::%d*\n",buf,rd); 
    encry = aes_encrypt(&en,(unsigned char*) buf, &rd); 

と、

unsigned char* aes_encrypt(EVP_CIPHER_CTX *e,unsigned char * plain_text, unsigned int * len) /* this function encryptes the file:fd is passed as parameter */ 
    { 
int ci_len = (*len) + AES_BLOCK_SIZE; 
int flen =0; 
unsigned char * cipher_text = malloc(ci_len); 

EVP_EncryptInit_ex(e, NULL, NULL, NULL, NULL);    /* allows reusing of e for multiple cipher cycles */ 
EVP_EncryptUpdate(e, cipher_text, &ci_len, plain_text, *len);  /* Update cipher text */ 
EVP_EncryptFinal_ex(e, cipher_text+ci_len, &flen);   /* updates the remaining bytes */ 

あなたはEVP_EncryptFinal_ex複数回呼んでいます。最後に一度だけ呼び出されるはずです。 復号化の方法は同じです。

ここでは、暗号化の方法に関するmanページの簡単な例を示します。 復号化にも同様の機能があり、動作するはずです。

int do_crypt(char *outfile) 
     { 
     unsigned char outbuf[1024]; 
     int outlen, tmplen; 
     /* Bogus key and IV: we'd normally set these from 
     * another source. 
     */ 
     unsigned char key[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; 
     unsigned char iv[] = {1,2,3,4,5,6,7,8}; 
     char intext[] = "Some Crypto Text"; 
     EVP_CIPHER_CTX ctx; 
     FILE *out; 
     EVP_CIPHER_CTX_init(&ctx); 
     EVP_EncryptInit_ex(&ctx, EVP_bf_cbc(), NULL, key, iv); 

     if(!EVP_EncryptUpdate(&ctx, outbuf, &outlen, intext, strlen(intext))) 
       { 
       /* Error */ 
       return 0; 
       } 
     /* Buffer passed to EVP_EncryptFinal() must be after data just 
     * encrypted to avoid overwriting it. 
     */ 
     if(!EVP_EncryptFinal_ex(&ctx, outbuf + outlen, &tmplen)) 
       { 
       /* Error */ 
       return 0; 
       } 
     outlen += tmplen; 
     EVP_CIPHER_CTX_cleanup(&ctx); 
     /* Need binary mode for fopen because encrypted data is 
     * binary data. Also cannot use strlen() on it because 
     * it wont be null terminated and may contain embedded 
     * nulls. 
     */ 
     out = fopen(outfile, "wb"); 
     fwrite(outbuf, 1, outlen, out); 
     fclose(out); 
     return 1; 
     } 

次の例ではファイルをあなたのケースとして読んでいます。どのようにUpdate(複数回呼び出される)とFinal(最後に1回)ルーチンが使用されるかを参照してください。

int do_crypt(FILE *in, FILE *out, int do_encrypt) 
     { 
     /* Allow enough space in output buffer for additional block */ 
     inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH]; 
     int inlen, outlen; 
     /* Bogus key and IV: we'd normally set these from 
     * another source. 
     */ 
     unsigned char key[] = ""; 
     unsigned char iv[] = "12345678"; 
     /* Don't set key or IV because we will modify the parameters */ 
     EVP_CIPHER_CTX_init(&ctx); 
     EVP_CipherInit_ex(&ctx, EVP_rc2(), NULL, NULL, NULL, do_encrypt); 
     EVP_CIPHER_CTX_set_key_length(&ctx, 10); 
     /* We finished modifying parameters so now we can set key and IV */ 
     EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, do_encrypt); 
     for(;;) 
       { 
       inlen = fread(inbuf, 1, 1024, in); 
       if(inlen <= 0) break; 
       if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen)) 
         { 
         /* Error */ 
         EVP_CIPHER_CTX_cleanup(&ctx); 
         return 0; 
         } 
       fwrite(outbuf, 1, outlen, out); 
       } 
     if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen)) 
       { 
       /* Error */ 
       EVP_CIPHER_CTX_cleanup(&ctx); 
       return 0; 
       } 
     fwrite(outbuf, 1, outlen, out); 
     EVP_CIPHER_CTX_cleanup(&ctx); 
     return 1; 
     } 
関連する問題