正是基於這種理論,1978年出現了著名的RSA算法,它通常是先生成壹對RSA密鑰,其中之壹是保密密鑰,由用戶保存;另壹個為公開密鑰,可對外公開,甚至可在網絡服務器中註冊。為提高保密強度,RSA密鑰至少為500位長,壹般推薦使用1024位。這就使加密的計算量很大。為減少計算量,在傳送信息時,常采用傳統加密方法與公開密鑰加密方法相結合的方式,即信息采用改進的DES或IDEA對話密鑰加密,然後使用RSA密鑰加密對話密鑰和信息摘要。對方收到信息後,用不同的密鑰解密並可核對信息摘要 。
RSA算法是壹個廣泛使用的公鑰算法。其密鑰包括公鑰和私鑰。它能用於數字簽名、身份認證以及密鑰交換。RSA密鑰長度壹般使用1024位或者更高。RSA密鑰信息主要包括:
n:模數
e:公鑰指數
d:私鑰指數
p:最初的大素數
q:最初的大素數
其中,公鑰為n和e;私鑰為n和d。
本文假設妳已經安裝好了OpenSSL,並且持有壹份1.1.1的源碼。
RSA相關的頭文件在rsa.h中、源文件在crypto/rsa目錄中。
這個結構定義了RSA內部數據信息。主要字段含義:
version —— 版本。
meth —— RSA運算抽象方法集合。
n,e,d,p,q,dmp1,dmq1,iqmp —— 密鑰相關的大數。
這個結構定義了RSA內部各種運算抽象方法集合。主要字段含義:
name —— 名稱描述。
rsa_pub_enc —— 公鑰加密方法。
rsa_pub_dec —— 公鑰解密方法。
rsa_priv_enc —— 私鑰加密方法。
rsa_priv_dec —— 公鑰解密方法。
rsa_sign —— 簽名方法。
rsa_verify —— 驗簽方法。
rsa_keygen —— 生成密鑰對方法。
在1.1.1中,大多數的數據結構已經不再向使用者開放,從封裝的角度來看,這是更合理的。如果妳在頭文件中找不到結構定義,不妨去源碼中搜壹搜。
RSA *RSA_new(void);
生成壹個RSA密鑰結構,采用默認的rsa_pkcs1_ossl_meth方法。
void RSA_free(RSA *r);
釋放RSA結構。
RSA *RSA_generate_key(int bits, unsigned long e, void (*callback) (int, int, void *), void *cb_arg);
生成RSA密鑰(舊版本)。
bits為密鑰位數,e為公鑰指數。
callback為密鑰生成過程中的幹預回調函數,通常傳入NULL。cb_arg為回調參數。
成功返回RSA指針,失敗返回NULL。
int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
生成RSA密鑰(新版本)。
rsa為RSA對象指針。bits為密鑰位置,e為公鑰指數的大數形式指針。cb為幹預回調函數,通常傳入NULL。
成功返回1,失敗返回0。
關於公鑰指數e,主要有兩個取值:
# define RSA_3 0x3L
# define RSA_F4 0x10001L
RSA *RSAPublicKey_dup(RSA *rsa);
復制RSA公鑰部分。
成功返回RSA指針,失敗返回NULL。
RSA *RSAPrivateKey_dup(RSA *rsa);
復制RSA私鑰部分。
成功返回RSA指針,失敗返回NULL。
int RSA_bits(const RSA *rsa);
獲取RSA密鑰位數。
int RSA_size(const RSA *rsa);
獲取RSA密鑰長度。
int RSA_check_key(const RSA *);
int RSA_check_key_ex(const RSA *, BN_GENCB *cb);
檢查RSA的有效性,必須為完整的密鑰對。
成功返回1,失敗返回0。
int RSA_print(BIO *bp, const RSA *r, int offset);
int RSA_print_fp(FILE *fp, const RSA *r, int offset);
將RSA信息輸出到bp/fp中,off為輸出信息在bp/fp中的偏移量,比如是屏幕bp/fp,則表示打印信息的位置離左邊屏幕邊緣的距離。
int RSA_public_encrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
RSA公鑰加密。
成功返回密文的長度,失敗返回-1。
int RSA_public_decrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
RSA公鑰解密。
成功返回明文的長度,失敗返回-1。
int RSA_private_encrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
RSA私鑰加密。
成功返回密文的長度,失敗返回-1。
int RSA_private_decrypt(int flen, const unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
RSA私鑰解密。
成功返回明文的長度,失敗返回-1。
關於padding填充方式,取值:
其中PKCS1填充大小為11字節,所以加密明文長度必須不大於(密鑰大小-11字節)。
# define RSA_PKCS1_PADDING_SIZE 11
int RSA_sign(int type, const unsigned char *m, unsigned int m_length,
unsigned char *sigret, unsigned int *siglen, RSA *rsa);
對數據m生成RSA簽名,生成的簽名長度與key的長度相同,如512位密鑰生成64字節簽名。
type指定摘要算法的NID,如NID_sha1。
成功返回1,失敗返回0。
int RSA_verify(int type, const unsigned char *m, unsigned int m_length,
const unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
對數據m驗證RSA簽名。
type指定摘要算法的NID,如NID_sha1。
成功返回1,失敗返回0。
以下函數在x509.h中定義:
int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa)
{
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa);
}
將RSA公鑰轉換為DER編碼,並寫入到bp抽象IO中。
成功返回1,失敗返回0。
RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa)
{
return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPrivateKey), bp, rsa);
}
從bp抽象IO中讀取DER編碼,並轉換為rsa結構私鑰。
成功返回有效指定,失敗返回NULL。
int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa)
{
return ASN1_item_i2d_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa);
}
將RSA公鑰轉換為DER編碼,並寫入到bp抽象IO中。
成功返回1,失敗返回0。
RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa)
{
return ASN1_item_d2i_bio(ASN1_ITEM_rptr(RSAPublicKey), bp, rsa);
}
從bp抽象IO中讀取DER編碼,並轉換為rsa結構公鑰。
成功返回有效指定,失敗返回NULL。
下面這個例子演示了RSA密鑰對的生成、公私鑰的復制、公鑰加密和私鑰解密的用法。
輸出:
下面這個例子演示了公私鑰的分開保存、讀取,以及使用公私鑰加解密。
輸出:
RSA_generate_key_ex() ret:1
i2d_RSAPrivateKey_bio() ret:1
i2d_RSAPublicKey_bio() ret:1
copy' private key size:64
copy' public key size:64
RSA_public_encrypt() ret:64
RSA_private_decrypt() ret:10
text:[1234567890]
下面這個例子演示了簽名的生成和驗證操作。
輸出:
ret:1
RSA_sign() ret:1
sign 64
4ec0af099c49646b72fda88a4fb11e8deb3898da9c3f611a5f25f05d9d005631858239bbb732cd5060dbc975363fc1b9cdfdc5a04554115a916f06f98163189f
RSA_verify() ret:1