簡體   English   中英

使用openssl evp api(aes256cbc)加密文件的問題

[英]Issues with encrypting a file using openssl evp api(aes256cbc)

我試圖在這種情況下讀取文件(.txt),並使用openssl的EVP API使用AES256CBC對其進行加密/解密。 (讀(plain.txt) - >創建(encrypt.txt) - >創建(decrypt.txt))

# 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;
}

我的問題是,當我解密加密文件時,我得到的文件沒有正確解密(例如,正確的字符串垃圾,正確的字符串垃圾 ...)

abhi@ubuntu:~/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

這可能是什么原因。 它是否還在讀取其他內容,或者我在某處犯了任何愚蠢的錯誤。

編輯 :如果我只是加密一個數組(嘗試用36char長),它正確加密和解​​密,而不會打印任何垃圾。

我想我正在丟失(不處理)一些* nix文件結構的詳細信息.. ?? 還是有更好的方法對文件進行加密?

非常感謝

我認為您的分析是錯誤的。 這個循環是有問題的:

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字符for (i = 0; i < rd; i++) printf("%02x "); -這就是為什么您對問題的分析可能存在缺陷的原因。

其次,我認為在您的實際問題中,您一次讀取SIZE個字節,並將其分別發送到aes_decrypt() 這將失敗,因為EVP_DecryptFinal_ex()時間過早(在讀取所有加密塊之前)。 你有兩個選擇。 您可以在每次循環迭代中通過EVP_DecryptUpdate()發送讀取的字節,並在完成循環后調用EVP_DecryptFinal() (並在循環之前進行相應的初始化),或者先將整個文件讀入緩沖區,然后再通過aes_decrypt()發送aes_decrypt()一口氣。

或者換句話說,你需要發送從導致整個數據塊aes_encrypt()以后aes_decrypt() 您不能以不同的塊形式發送它們,除非將功能分開並在單獨的塊上使用EVP“更新”功能。

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 最后應該只調用一次。 您進行解密的方式也是如此。

這是手冊頁中有關如何進行加密的簡單示例。 具有類似的解密功能,它應該可以工作。

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 (多次調用)和FinalFinal一次)例程。

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[] = "0123456789";
        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;
        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM