1. 程式人生 > >openssl中aes、rsa演算法的使用

openssl中aes、rsa演算法的使用

一、RSA

1.  演算法原理

RSA演算法是一個廣泛使用的公鑰演算法。其金鑰包括公鑰和私鑰。它能用於數字簽名、身份認證以及金鑰交換。RSA金鑰長度一般使用1024位或者更高。RSA金鑰資訊主要包括[1]:

Ø         n:模數

Ø         e:公鑰指數

Ø         d:私鑰指數

Ø         p:最初的大素數

Ø         q:最初的大素數

Ø         dmp1:e*dmp1 = 1 (mod (p-1))

Ø         dmq1:e*dmq1 = 1 (mod (q-1))

Ø         iqmp:q*iqmp = 1 (mod p )

其中,公鑰為n和e;私鑰為n和d。在實際應用中,公鑰加密一般用來協商金鑰;私鑰加密一般用來簽名。

RSA簡潔幽雅,但計算速度比較慢,通常加密中並不是直接使用RSA 來對所有的資訊進行加密,最常見的情況是隨機產生一個對稱加密的金鑰,然後使用對稱加密演算法對資訊加密,之後用RSA對剛才的加密金鑰進行加密。

使用RSA演算法需要注意兩個問題:

1. 加密位數。這個是在生成key時需要指定的,在呼叫加解密函式時會用到。

2. 填充模式。有三種

1) RSA_PKCS1_PADDING 填充模式,最常用的模式
要求:
  輸入 必須 比 RSA 鑰模長(modulus) 短至少11個位元組, 也就是 RSA_size(rsa) – 11
    如果輸入的明文過長,必須切割, 然後填充
        輸出 和modulus一樣長
根據這個要求,對於512bit的金鑰, block length = 512/8 – 11 = 53 位元組


2) RSA_PKCS1_OAEP_PADDING 

RSA_size(rsa) – 41 

3) RSA_NO_PADDING  不填充
RSA_size(rsa)

2.  使用方法

(1) 公鑰和私鑰儲存到檔案中

第一步 生成公鑰、私鑰檔案


   生成KEY時,需要提供key的位數以及e變數因子。   

通過PEM_write_RSAPublicKey,PEM_write_RSAPrivateKey這兩個方法,把公鑰和私鑰以PEM格式寫入檔案。

這裡有個問題,那就是記憶體釋放問題。RSA_new與RSA_free,BN_new與BN_free配對,但即使這樣還是會產生記憶體洩露,需要在整個程式結束的時候呼叫CRYPTO_cleanup_all_ex_data(); 

需要注意的是,CRYPTO_cleanup_all_ex_data()不能在potential race-conditions條件在呼叫(我理解的意思是當函式外部存在RSA結構體的時候,在函式內部執行CRYPTO_cleanup_all_ex_data()將導致函式外的RSA結構體也被清理掉),因此最好在程式結束的時候才呼叫。

第二步 執行加解密操作


公鑰加密,首先呼叫PEM_read_RSAPublicKey方法,從PEM檔案中把key讀取到RSA的結構中,然後呼叫RSA_public_encrypt對資料分塊加密,需要指定填充模式。

RSA_public_encrypt每次最多加密RSA_size(rsa)長度的資料,所以需要重複執行。

私鑰解密,一樣的道理,只不過呼叫的方法換成PEM_read_RSAPrivateKey和RSA_private_decrypt。

(2) 公鑰和私鑰儲存到記憶體中

第一步 加密key

已經格式化的key,直接讀取;如果沒格式化,則需要做一些處理。

(1)公鑰字串開頭要加上“-----BEGIN PUBLIC KEY-----\n”,結尾加上“\n-----END PUBLIC KEY-----\n”。否則會出現error:0906D06C:PEM routines:PEM_read_bio:no start line

(2)公鑰字串每隔64個字元要加一個換行,否則會報祕鑰格式錯誤。

c++程式碼實現舉例:

int nPublicKeyLen = strPublicKey.size();      //strPublicKey為base64編碼的公鑰字串
for(int i = 64; i < nPublicKeyLen; i+=64)
{
if(strPublicKey[i] != '\n')
{
strPublicKey.insert(i, "\n");
}
i++;
}
strPublicKey.insert(0, "-----BEGIN PUBLIC KEY-----\n");
strPublicKey.append("\n-----END PUBLIC KEY-----\n");

openssl提供了bio介面以支援各種形式的祕鑰讀取

第二步 執行加解密操作

公鑰加密



呼叫PEM_read_bio_RSA_PUBKEY從記憶體中讀取公鑰到RSA中,私鑰則呼叫PEM_read_bio_RSAPrivateKey方法。

二、AES

1.  演算法原理

AES加密資料塊分組長度必須為128位元,金鑰長度可以是128位元、192位元、256位元中的任意一個(如果資料塊及金鑰長度不足時,會補齊)。AES加密有很多輪的重複和變換。大致步驟如下:

1、金鑰擴充套件(KeyExpansion)

2、初始輪(Initial Round)

3、重複輪(Rounds),每一輪又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey

4、最終輪(Final Round),最終輪沒有MixColumns。

AES中有幾個引數需要注意:

1. 分塊長度,固定128位元。編碼時填寫這個引數即可

2. 金鑰長度,使用者自己選擇,一般使用128位元

3.  ECB、CBC、CFB、OFB)

2.  使用方法

常用的模式是ECB和CBC

(1) ECB(Electronic Codebook,電碼本)模式是分組密碼的一種最基本的工作模式。在該模式下,待處理資訊被分為大小合適的分組,然後分別對每一分組獨立進行加密或解密處理

(a)for迴圈使用:


(b)下面我們看下openssl中的原始碼實現:


(2) CBC:是一種迴圈模式,前一個分組的密文和當前分組的明文異或操作後再加密,這樣做的目的是增強破解難度。

openssl中提供的加密介面,是對整個輸入資料加密,然後返回整個的加密結果,不需要for迴圈去分塊加密,因為他們的前後塊有關聯。

(a)使用:


(b)原始碼:




//從上面的原始碼可以看出,cbc本質上和ecb差別不大,唯一區別是將前一次加密結果,與要加密的內容異或。因此,cbc的並行性較差,因為每次都要等待前一次的結果,而ecb則不用,速度較快。