2

この場合、ファイル (.txt) を読み取ろうとしており、openssl の EVP API を使用して AES256CBC で暗号化/復号化しています。(read(plain.txt)->create(encrypt.txt)->create(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

この理由は何でしょうか。それは何か他のものも読んでいますか、それとも私はどこかで愚かなエラーを犯しています.

編集:配列を暗号化するだけで(36文字の長さで試した場合)、ガベージを出力せずに正しく暗号化および復号化されます。

私はいくつかの* nixファイル構造の詳細が欠落している(処理していない)と思います..?? または、ファイルでこの暗号化を行うより良い方法はありますか?

どうもありがとう

4

2 に答える 2

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まず、ゼロターミネータを期待するを使用して印刷するためです。ただし、暗号化/復号化されたデータはゼロ終端されていません。代わりに、次rdのようなループを使用して文字を出力する必要for (i = 0; i < rd; i++) printf("%02x ");があります。これが、問題の分析に欠陥がある可能性が高い理由です。

第二に、実際の問題では、一度にバイトを読み取り、それらを別々SIZEに送信していると思います。の呼び出しが早すぎるため (暗号化されたすべてのブロックが読み取られる前に)、aes_decrypt()これは失敗します。EVP_DecryptFinal_ex()2 つのオプションがあります。EVP_DecryptUpdate()各ループ反復で読み取りバイトを送信しEVP_DecryptFinal()、ループの完了後に呼び出す (およびループの前にそれに応じて初期化する) か、最初にファイル全体をバッファーに読み取ってからaes_decrypt()、一度に送信します。

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

于 2012-04-30T23:14:24.680 に答える
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(複数回呼び出される) ルーチンと(最後に 1 回) ルーチンがどのようFinalに使用されるかを参照してください。

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;
        }
于 2012-05-01T01:38:31.477 に答える