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");
第二步 執行加解密操作
公鑰加密
呼叫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則不用,速度較快。