openssl AES 加密/解密

AES算法

AES進行加/解密須要考慮下面三個設置。html

密鑰

使用的密鑰長度爲128/192/256位,這裏以128位爲例算法

初始向量

初始向量位128位函數

填充

AES以128位,即16字節爲單位進行操做,若是明文長度不是16的整數倍就須要進行填充,openssl默認以PKCS#7方式進行填充。PKCS#7填充時將明文長度擴充爲16的整數倍,每個填充的字節值爲填充的長度。加密

例如:spa

  • 如明文長度爲8,填充8個字節,每一個字節均爲0x8。DD表示明文,08爲填充。

| DD DD DD DD DD DD DD DD 08 08 08 08 08 08 08 08 |命令行

  • 如明文長度爲16,額外填充16個字節。DD表示明文,10爲填充。

| DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD | 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 |code

openssl命令進行加/解密

1 指定密鑰和初始向量orm

$ openssl enc -aes-128-cbc -in in.txt -out out.txt -K 12345678901234567890 -iv 12345678

將in.txt文件的內容進行加密後輸出到out.txt中。這裏經過-K指定密鑰,-iv指定初始向量。注意AES算法的密鑰和初始向量都是128位的,這裏-K和-iv後的參數都是16進製表示的,最大長度爲32。 即-iv 1234567812345678指定的初始向量在內存中爲 | 12 34 56 78 12 34 56 78 00 00 00 00 00 00 00 00 |。htm

經過-d參數表示進行解密 以下ip

$ openssl enc -aes-128-cbc -in in.txt -out out.txt -K 12345678901234567890 -iv 12345678 -d

表示將加密的in.txt解密後輸出到out.txt中

2 經過字符串密碼加/解密

$ openssl enc -aes-128-cbc -in in.txt -out out.txt -pass pass:helloworld

這時程序會根據字符串"helloworld"和隨機生成的salt生成密鑰和初始向量,也能夠用-nosalt不加鹽。

C中調用openssl庫

下面這個是C語言調用openssl的例子,來自openssl官方文檔

int do_crypt(FILE *in, FILE *out, int do_encrypt)
 {
     /* Allow enough space in output buffer for additional block */
     unsigned char inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
     int inlen, outlen;
     EVP_CIPHER_CTX *ctx;
     /*
      * Bogus key and IV: we'd normally set these from
      * another source.
      */
     unsigned char key[] = "0123456789abcdeF";
     unsigned char iv[] = "1234567887654321";

     /* Don't set key or IV right away; we want to check lengths */
     ctx = EVP_CIPHER_CTX_new();
     EVP_CipherInit_ex(&ctx, EVP_aes_128_cbc(), NULL, NULL, NULL,
                       do_encrypt);
     OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
     OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);

     /* 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_free(ctx);
             return 0;
         }
         fwrite(outbuf, 1, outlen, out);
     }
     if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen)) {
         /* Error */
         EVP_CIPHER_CTX_free(ctx);
         return 0;
     }
     fwrite(outbuf, 1, outlen, out);

     EVP_CIPHER_CTX_free(ctx);
     return 1;
 }

do_encrypt爲1時加密,爲0時解密。

須要注意的在調用EVP_CipherUpdate時,EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)這裏outbuf的長度必需要超過inlen + EVP_MAX_BLOCK_LENGTH。 這是填充的影響,AES-128-CBC加密時末尾會有1~16字節的填充。解密時,有時候在調用EVP_CipherFinal_ex以前沒法肯定是否密文已經結束。如這裏每次從文件中讀入1024個字節,調用EVP_CipherUpdate解密時,對最後的16個字節,可能有部分是填充,解密時須要去掉,爲此這裏只返回1008個字節,outlen爲1008,剩餘16個字節的數據保存下來。再讀入1024個字節進行解密時,即可能返回1024+16個字節,若是outbuf的長度不夠,便會發生內存越界。 因此函數聲明變量時,unsigned char inbuf[1024]; unsigned char outbuf[1024+EVP_MAX_BLOCK_LENGTH];的緣由(這這裏數據塊長度爲16個字節)。

另外,這裏使用密鑰01234567890abcdeF,對應的openssl命令行操做時-K 30313233343536373839616263646546。由於字符0的ASCII碼爲0x30,以此類推,一樣 初始向量1234567887654321,對應openssl命令的參數-iv 31323334353637383837363534333231。下面的命令與上面的函數效果相同。

$ #加密
$ openssl enc aes-128-cbc -in in.txt -out out.txt -K 30313233343536373839616263646546 -iv 31323334353637383837363534333 -e
$ #解密
$ openssl enc aes-128-cbc -in in.txt -out out.txt -K 30313233343536373839616263646546 -iv 31323334353637383837363534333 -d

若是是用openssl命令加密文件,在其餘程序中讀取解密的話,這裏就須要額外注意。

也能夠經過int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *x, int padding);取消填充,這時明文長度必需要16的整數倍。

相關文章
相關標籤/搜索