2016-04-10 118 views
-1

解密和加密代碼(下面包含)可能是錯誤的。他們正在編譯錯誤,但解密後的文件與純文本文件不同。它是亂碼。(C語言)在基於AES-CTR的加密解密工具中出現亂碼解密

我試圖找出它爲什麼是亂碼。我懷疑我的代碼沒問題。

我做了一堆事情可能可以解決問題,但沒有工作。我有一種使用AES-CTR的特定方式,即我不直接包含OpenSSL。我取決於隨機性(IV,等等)的/dev/urandom/dev/random

這些東西包括我處理我的加密和解密函數的方式(如:使用*(ptr)而不是ptr[]和其他幾個通常不需要的等效替換),我傳遞什麼參數並檢查某些驗證最後保存加密或解密的文本。

我不會遞增(或改變)初始化的IV。 IV是16個字節。

早些時候,我這樣做是爲了增加的IV的最後一個字節:

size_t blocksize = CCA_STRENGTH; /* CCA_STRENGTH is "#define CCA_STRENGTH 16" */ 
char *iv = (char *) malloc(16 * sizeof(char)); 
ri(); /* PRNG initialized.*/ 
prng_getbytes(iv, blocksize); 
* 
* 
* 
* 
size_t iv_counter = 0; 
while loop starts here... 
* 
* 
*(iv +(block_size - 1)) += iv_counter; 
* 
* 
while loop ends here... 

這個while循環,其中加密和解密的情況是下面存在(這部分被臨時拆除,因爲它是一個安全要求而不是編碼標準或加密或解密功能的要求)。

這是我的解密代碼:

#include "pv.h" 

void decrypt_file (const char *ptxt_fname, void *raw_sk, size_t raw_len, int fin) 
{ 
    int fd; 
    if((fd = open(ptxt_fname, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) 
     { 
      /*fd will become -1 on failure.*/ 
      perror("plaintext file permission error\n"); 
      exit(EXIT_FAILURE); 
      } 

    size_t block_size = CCA_STRENGTH; 

    const char *aes_key; 
    aes_key = (const char *) raw_sk; 
    aes_ctx aes; 

    aes_setkey(&aes, aes_key, block_size); 
    char *iv; 
    iv = (char *) malloc(block_size * sizeof(char)); 
    size_t bytes_read; 
    bytes_read = read(fin, iv, block_size); 

    char *buf = (char *) malloc(block_size * sizeof(char)); /*ctxt-file read buffer*/ 
    char *ptxt = (char *) malloc(block_size * sizeof(char)); /*p-text buffer*/ 
    memset(ptxt, 0, block_size); 

    bytes_read = read(fin, buf, block_size); 

     while(bytes_read >= 1) 
    { 

     aes_encrypt(&aes, ptxt, iv); /* earlier it was "aes_decrypt(&aes, ptxt, iv);" which was not the correct reverse transformation function */ 
     for(loop_variable = 0; loop_variable < bytes_read; loop_variable++) 
     { 
      *(ptxt + loop_variable) = *(ptxt + loop_variable)^*(buf + loop_variable); 
     } 

     if((result = write_chunk(fd, ptxt, bytes_read)) == -1) 
     { 
      perror("Problem when writing to ptxt file... \n"); 
      close(fd); 
      unlink(ptxt_fname); /*for file deletion*/ 
      aes_clrkey(&aes); 
      free(ptxt); 
      free(iv); 
      free(buf); 
      exit(EXIT_FAILURE); 
     } 
     if((bytes_read = read(fin, buf, block_size)) < 1) 
     { 
      close(fd); 
      aes_clrkey(&aes); 
      free(ptxt); 
      free(iv); 
      free(buf); 
      break; 
     } 
    } 

} 

void 
usage (const char *pname) 
{ 
    printf ("Simple File Decryption Utility\n"); 
    printf ("Usage: %s SK-FILE CTEXT-FILE PTEXT-FILE\n", pname); 
    printf ("  Exits if either SK-FILE or CTEXT-FILE don't exist, or\n"); 
    printf ("  if a symmetric key sk cannot be found in SK-FILE.\n"); 
    printf ("  Otherwise, tries to use sk to decrypt the content of\n"); 
    printf ("  CTEXT-FILE: upon success, places the resulting plaintext\n"); 
    printf ("  in PTEXT-FILE; if a decryption problem is encountered\n"); 
    printf ("  after the processing started, PTEXT-FILE is truncated\n"); 
    printf ("  to zero-length and its previous content is lost.\n"); 

    exit (1); 
} 

int main (int argc, char **argv) 
{ 
    int fdsk, fdctxt; 
    char *sk = NULL; 
    size_t sk_len = 0; 

    if (argc != 4) { 
    usage (argv[0]); 
    } 
    else if (((fdsk = open (argv[1], O_RDONLY)) == -1) 
     || ((fdctxt = open (argv[2], O_RDONLY)) == -1)) { 
    if (errno == ENOENT) { 
     usage (argv[0]); 
    } 
    else { 
     perror (argv[0]); 

     exit (-1); 
    } 
    } 
    else { 
    setprogname (argv[0]); 

    if (!(sk = import_sk_from_file (&sk, &sk_len, fdsk))) { 
     printf ("%s: no symmetric key found in %s\n", argv[0], argv[1]); 

     close (fdsk); 
     exit (2); 
    } 
    close (fdsk); 

    decrypt_file (argv[3], sk, sk_len, fdctxt);  
    bzero(sk, sk_len); 
    free(sk); 


    close (fdctxt); 
    } 

    return 0; 
} 

這是我的加密代碼:

#include "pv.h" 

void encrypt_file (const char *ctxt_fname, void *raw_sk, size_t raw_len, int fin) 
{ 

    size_t block_size = CCA_STRENGTH; 
    int fd; /* ctxt fd */ 
    if((fd = open(ctxt_fname,O_WRONLY|O_TRUNC|O_CREAT,0600)) < 0) 
    { 
     perror("Ciphertext file permission error\n"); 
     exit(EXIT_FAILURE); 
    } 

    char *iv; 
    iv = (char *) malloc(block_size * sizeof(char)); 

    ri(); /*IV initialized*/ 
    prng_getbytes(iv, block_size); 

    struct aes_ctx aes; 
    const char *aes_key = aes_key = (const char *) raw_sk; 

    aes_setkey(&aes, aes_key, block_size); /*sets the encryption key.*/ 

    char *buf = buf = (char *) malloc(block_size * sizeof(char)); /*file read buffer*/ 
    char *ctxt = ctxt = (char *) malloc(block_size * sizeof(char)); /*ciphertext buffer*/ 
    int result; 
    size_t looper = 0; 
    size_t bytes_read; 
    result = write_chunk(fd, iv, block_size); 

    if(result == -1) 
    { 
     exit(-1); 
    } 

    bytes_read = read(fin, buf, block_size); /*returns how many bytes read*/ 
    while(bytes_read >= 1) 
    { 
     aes_encrypt(&aes, ctxt, iv); 
     for(looper = 0; looper < bytes_read; looper++) 
     { 

      *(ctxt + looper) = *(ctxt + looper)^*(buf + looper); 
     } 

     result = write_chunk(fd, ctxt, bytes_read); 
     if(result == -1) 
     { 
      perror("Problem when writing to ctxt file... \n"); 
      close(fd); 
      unlink(ctxt_fname); /*for file deletion*/ 
      aes_clrkey(&aes); 
      free(ctxt); 
      free(iv); 
      free(buf); 
      exit(EXIT_FAILURE); 
     }  
     printf("crossed written to file\n"); 

     if((bytes_read = read(fin, buf, block_size)) < 1) 
     { 
      close(fd); 
      aes_clrkey(&aes); 
      free(ctxt); 
      free(iv); 
      free(buf); 
      break; 
     } 

    } 
} 

void usage (const char *pname) 
{ 
    printf ("Personal Vault: Encryption \n"); 
    printf ("Usage: %s SK-FILE PTEXT-FILE CTEXT-FILE\n", pname); 
    printf ("  Exits if either SK-FILE or PTEXT-FILE don't exist.\n"); 
    printf ("  Otherwise, encrpyts the content of PTEXT-FILE under\n"); 
    printf ("  sk, and place the resulting ciphertext in CTEXT-FILE.\n"); 
    printf ("  If CTEXT-FILE existed, any previous content is lost.\n"); 

    exit (1); 
} 

int main (int argc, char **argv) 
{ 
    int fdsk, fdptxt; 
    char *raw_sk; 
    size_t raw_len; 



    if (argc != 4) 
    { 
     usage (argv[0]); 
    } 
    else if (((fdsk = open (argv[1], O_RDONLY)) == -1) || ((fdptxt = open (argv[2], O_RDONLY)) == -1)) 
    { 
     if (errno == ENOENT) 
     { 
      usage (argv[0]); 
     } 
     else 
     { 
      perror (argv[0]); 

      exit (-1); 
     } 
    } 
    else 
    { 
     setprogname (argv[0]); 

     if (!(import_sk_from_file (&raw_sk, &raw_len, fdsk))) 
     { 
      printf ("%s: no symmetric key found in %s\n", argv[0], argv[1]); 

      close (fdsk); 
      exit (2); 
     } 
     close (fdsk); 


     bzero(raw_sk, raw_len); 
     free(raw_sk); 


     close (fdptxt); 
    } 

    return 0; 
} 

的加密代碼首先被前面加上16個字節IV的向加密文件(因爲它應該是我猜;我們從解密過程中的ctxt文件中讀取這16個字節),然後實際加密發生(將其視爲黑盒子)w這裏我們發送IV和密鑰;返回16個字節。返回的這16個字節必須與明文文件緩衝區異或(如果一個文件大於16個字節,則每個循環最多16個字節)。

發佈XORed字節(最多16字節)寫入文件。這件事發生在最後一輪,最後一輪試圖讀取沒有更多內容可讀的文件時,循環終止。 讀取函數在每次調用時嘗試讀取下一個可用字節(最多可指定的字節數)。

這不是一個完美的實現,因爲我放寬了安全性方面(隨機化每個週期的IV),但是,它必須首先像這樣工作。

在數學上,我所要做的應該是這個概念的翻版:

ciphertext_block = message_block^[AES(IV, Key)]

message_block = ciphertext_block^[AES(IV, Key)]

這裏,密文/ message_block指字符塊對於第1輪到第n輪,這將是16個字節,但在上一輪中可以或不可以是16個字節。在任何情況下,XORing將在16個字節字符(AES-CTR的輸出)和另一個塊(用於加密的密文塊,用於解密的密文塊)之間完成,無論如何,它可以高達16個字節,因此它們是異或約束,即它們將是XOR輸出長度的決定因素)。由於它們是決策者,只要XORing操作覆蓋它們的長度,XORing循環就會停止,並且我們將向文件(用於加密的ctxt文件,用於解密的ptxt文件)寫入該循環。

不應有任何填充要求。

我不確定我是否應該在任何地方使用realloc函數。

如果任何讀者在理解我想要做的事情時遇到問題,我會很樂意提供額外的文檔。

該程序有幾個庫依賴項,但是,代碼編譯無錯誤。

這是我的編譯命令:

gcc -g -O2 -ansi -Wall -Wsign-compare -Wchar-subscripts -Werror -I. -I/usr/include/ -I/home/devel/libdcrypt/include/ -c pv_keygen.c pv_misc.c 
gcc -g -O2 -ansi -Wall -Wsign-compare -Wchar-subscripts -Werror -o pv_keygen pv_keygen.o pv_misc.o -L. -L/usr/lib/ -L/home/devel/libdcrypt/lib/ -ldcrypt -lgmp 

這僅僅是我的加密文件的彙編。幾乎相等(同樣嚴格)的命令是用於我的keygen和解密文件的。 Keygen代碼似乎工作正常(我還沒有在這裏包括);我能夠生成一個密鑰並將其序列化爲一個文件。該密鑰文件實際上包含兩個密鑰,而我只讀取AES-CTR的前半部分。下一半將用於MACing目的(使用AES-CBC)。

文件大小細節

明文文件:X字節

加密文件:(X + 16)字節

破譯文本文件:X字節

統計數據是正確的,內容不是。解密後的文本文件和純文本文件必須相同。

我想:diff plaintext_file decrypted_file在RedHat上進行文件比較。

密鑰文件實際上是32個字節,其中前16個字節用於加密,後16個字節將用於MACing後加密完成。

密鑰文件(其是序列化到基座-64)(十六進制):

0000000 4662 6e4b 6631 7268 4876 676c 772f 664e 
0000010 4d5a 6f32 384e 5141 7139 6635 3442 7245 
0000020 646c 4a77 5553 4c30 4f63 3d6f 000a  
000002d 

輸入明文文件(十六進制):

0000000 6161 6161 6161 6161 6161 6161 610a 6161 
0000010 000a         
0000011 

加密文件(十六進制):

0000000 540e 0e30 d74d 5000 78c1 13e3 0476 d4a2 
0000010 61c9 76ac e717 cd6d 013e e872 8e16 4827 
0000020 00a2         
0000021 

解密文件(十六進制):

0000000 8bea 616a 1f1b d6b0 fd13 da46 5824 ec00 
0000010 0081         
0000011 

(我修剪下來的東西到哪裏可以存在錯誤)外部引用:

1)http://www.scs.stanford.edu/nyu/05sp/lab/lab1.html

2)http://www.scs.stanford.edu/nyu/05sp/lab/install-libs.html

+0

方:「做了一堆隨機的東西」 - 飛鏢和眼罩甚至在看起來很簡單的任務上也很少工作,而且幾乎從不在密碼學等事情上。所以這個結果有點自我預言。 – WhozCraig

+0

@WhozCraig隨機性不會有幫助。讓我再說一遍。這些嘗試使它發揮作用是一個相當深思熟慮的嘗試。看起來似乎有些問題很嚴重(僅在加密和/或解密時)。表面處理,這是我所期待的。 – Avineshwar

+2

這對於* review *或* debug *來說相當複雜。發佈之前,請確保您首先撰寫您的應用程序的權利。因此,從加密代碼中刪除文件處理,並圍繞它編寫單元測試。很高興看到你嘗試去除例如IV創造,但你需要進一步採取這一步。 –

回答

-1

這裏是修復:

問題的存在,我想做到這一點,我做這件事的方式。由於沒有與實施相關的問題,因此我的解密代碼中存在此問題。

在我的解密代碼,沒有包括AES_DECRYPT功能時我其實在尋找的東西是一種精確逆變換反之相同的密鑰(正確的技術在解密WRT AES項)的點正被用來解密相同的文件。

作爲一個解決方法,AES_DECRYPT應該只是AES_ENCRYPT,它會工作了。

現在,我可以進行額外的增加(安全加強和數據完整性考慮)。

0

爲什麼不直接在CTR模式下使用AES,無需要爲每16個字節進行一次AES調用,然後將輸出與數據異或。

CTR模式接受純文本,密鑰和IV,併產生AES CTR模式加密數據。 IOW CTR模式執行所有XOR和計數器遞增操作。

小心CTR模式,相同的鍵/ IV對只能使用一次。

支持AES和其他分組密碼的大多數庫都具有較低級別的塊加密,並使用該加密實現CBC,CFB,CTR,OFB等更高級模式以及諸如PKCS#7néePKCS #5填充。