相信只要對密碼學瞭解的同窗確定據說過RSA,它是三個發明者名詞的縮寫(Rivest-Shamir-Adleman),也是最先的公鑰密碼學系統之一,也是多是應用最普遍的公鑰密碼學系統。[1]這裏給它兩個定義html
咱們經過定義能夠看出若是一個密碼學方案使用了RSA假設,那麼這個密碼學方案至少能夠說使用了RSA密碼系統。下面闡述RSA的具體原理。既然是具體的原理,咱們採起狹義的定義,即RSA是一個假設,這種假設是一種單向陷門函數。安全
咱們先介紹單向陷門函數,而後給出了RSA基本形式。接着闡述RSA的基本假設,最後經過它構造RSA單向陷門函數(也是單向陷門置換方案)。函數
Despite many years of study, RSA is essentially the only known reasonable candidate trapdoor permutation scheme.性能
[2]單向函數(One-way function)是一類這樣的函數\(F:x \rightarrow y\)正向計算很容易,可是反向計算,即經過\(y\)計算\(x\)很難的函數。單向陷門函數就一類特殊的單向函數。特殊之處在於存在陷門(trapdoor),經過陷門能夠反向計算單向函數。即若是使用陷門,咱們很容易逆向計算單向函數,可是若是沒有陷門,咱們仍然很難計算單向函數。加密
另外若是\(x\)和\(y\)所在域相同,即一一對應,那麼就說這個單向陷門函數就一個單向陷門置換。正式的定義請參考[2]。spa
涉及到RSA的基本形式,我不得不這裏寫出正式的定義,該定義來自於[3]。命令行
RSA主要由三個函數構成\(RSAGen\),\(F\),\(I\)。code
\(RSAGen(l,e)\)生成一個\(l\)位的素數\(p\)知足\(gcd(e,p-1) = 1\)htm
\(RSAGen(l,e)\)生成一個\(l\)位的素數\(q\)知足\(gcd(e,q-1) = 1\)且\(p \neq q\)接口
\(n \leftarrow pq\)
\(d \leftarrow e^{-1} \mod (p-1)(q-1)\)
輸出\((n,d)\)
對於給定的公鑰\(pk = (n,e),x \in Z_n\),咱們定義\(F(pk,x) := x^e \in Z_n\)。
對於給定的私鑰\(sk = (n,d),y \in Z_n\),咱們定義\(I(sk,y) := y^d \in Z_n\)。
注意這裏要求gcd(e,p-1) = 1且gcd(e,q-1) = 1是在保證能夠計算出d不然e不在羣\(Z_n\)即\(Z_{pq}\)中存在乘法逆。
一句話,RSA假設就是說假設上面的RSA方案是一個單向陷門函數。因爲RSA自己的數學性質是\(Z_n^*\)到自身的置換。因此RSA方案是一個單向陷門置換。
保研夏令營的時候老師問我RSA假設基於啥?我其實不知道當時上課的時候說的啥,忽然腦子中想起就說是基於大整數分解。老師說不對。現在仔細翻書才明白。RSA假設啥都不基於,它就是一個假設。 大整數分解若是能被解決,那麼RSA必定能被解決。可是RSA被解決卻不必定須要大整數分解。大整數分解是更難的問題,沒法規約到RSA。[4]
RSA密碼系統,或者說全部的公鑰密碼學系統通常都有兩個應用,公鑰加密和簽名。值得注意的是,相同的密鑰對在不一樣的RSA應用中也不該該被屢次使用,這是極其危險的。這部分首先研究下參數選擇問題,下面咱們分別來講它們的應用。而後嘗試幾個開源實現。另外這節要參考PKCS #1 v2.1的標準[6] (最新的版本已經到v2.2了),這也是大多數實現參考的標準。(由於水平有限,省略了素數生成的部分)
選擇e = 65537。
理論上任何知足上述條件的e都行,素數方便咱們知足gcd(p-1,e)=1。可是處於效率的考慮,咱們選擇一些費馬素數(即形式知足\(2^n+1\)的素數)。集合是{3,5,17,257,65537}。更高的費馬素數是沒法想象的大。
傾向於選擇小的e能夠加快速度。可是考慮到兼容性(不少標準都歸入65537,可能源於歷史上人們對e的誤解)和不少方案沒有使用正確的填充,咱們一般選擇65537做爲折中。(並非說選擇小的e不安全。)
通常來說咱們選擇e = 65537。
openssl提供了兩個選項e = 65537和e = 3來選擇。默認是e = 65537。
咱們總據說有什麼小指數攻擊,那是彷佛是由於不正確的填充(padding)或者其它緣由致使的。不是說e小致使的,對於正確的使用方案,e=3一樣跟e=65537安全。e=65537更近乎行業標準。
若是你想要保護你的密鑰20年,使用RSA2048bit。若是你能夠不計開銷,那麼就使用RSA4096bit。隨着計算機愈來愈快,將來你可能須要使用RSA8196bit。使用一個大RSA是好的,由於能夠省去將來更換的麻煩。[7]
直接用作加密和簽名的RSA都是不安全的!現存的攻擊包括小指數攻擊,共模攻擊,乘法攻擊等等更高級的多項式時間攻擊。[5]因此這裏有一個原則:
it is very bad to have any kind of structure in the
numbers that RSA operates on.
例如咱們使用2048bitRSA操做256bit的AES密鑰時,咱們選擇e=5,那麼\(2^{256*5} = 2^{1280}\),咱們直接使用開五次方就能夠得出結果。因此咱們須要打破原來數據的結構。這就是RSApadding,或者說公鑰密碼系統的padding。
For example, for encryption you might
use RSA-OAEP, and for signatures you might use RSA-PSS.
RSApadding在PKCS #1 v2.2中有標準。包括RSA-OAEP,RSA-PSS等padding方案。
PKCS #1 v2.1說了兩遍RSA,一個是帶CRT的一個不帶,被吐槽了:標準和實現摻在一塊兒。
通常來說,RSA不會直接用於加密。須要使用對稱加密方案\(E\)來加密消息\(m\),最後傳遞消息\(RSAE(key,e),E(m,key)\)。相應的,使用\(key = RSAD(RSAE(key,e),d),m = D(E(m,key),key)\)。進行解密。
對於簽名,首先使用hash函數對簽名進行去結構化\(H(m)\)。而後經過PRNG來將\(H(m)\)來映射到\(0,...,2^k-1\),其中\(k\)是知足\(2^k<n\)的最大的\(k\)。而後再進行樸素的簽名便可。
使用填充方案\(PSS\)是更好的選擇。
openssl命令行關於rsa的有三個命令模塊genrsa
,rsa
,rsautl
。其中genrsa主要用於生成rsa密鑰。rsa主要用於轉換rsa密鑰格式。rsautl用於對數據的加密或者解密。具體使用方法能夠參考openssl的手冊。
值得注意的是,對於rsa模塊的命令有兩組選項分別是-pubin
,-pubout
和-RSAPublickey_in
,-RSAPublicKey_out
。這是兩種不一樣的格式,我在網上搜索到了滿意的答案。(爲啥沒有privatekey的格式,由於PKCS#8只規定了公鑰的格式,私鑰由於不用分發因此不須要格式。)
生成RSA密鑰的函數
RSA * RSA_generate_key(int bits, unsigned long e, void (*callback) (int,int,void *),void *cb_arg);
從文件中讀取RSA函數
EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u);
RSA加密解密函數
int RSA_public_encrypt(int flen, const unsigned char *from,unsigned char *to, RSA *rsa,int padding);
int RSA_private_decrypt(int flen, const unsigned char *from,unsigned char *to, RSA *rsa,int padding);
RSA簽名驗證函數
int RSA_sign(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigret, unsigned int *siglen, RSA *rsa);
int RSA_verify(int type, const unsigned char *m, unsigned int m_length, unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
提高RSA性能主要考慮兩個方面,一個是CRT,一個時模n乘法。對於CRT,PKCS #1中專門給出了相應的CRT標準。對於模n乘法也是選擇e的因素。
待更新。。。
OAEP PSS DSA ECC PKCS
RSA是現在使用最普遍的公鑰密碼學系統,相關選擇要麼是紙上的標準,要麼是行業默認的標準。但願能用此文闡述RSA相關的內容,供他人和本身參考。文中有錯誤或者不詳盡之處,請發郵件給我或者在下方評論。
[1] https://en.wikipedia.org/wiki/RSA_(cryptosystem).
[2] A Graduate Course in Applied Cryptography by Dan Boneh and Victor Shoup, Version 0.4, September 2017, Chapter 10.2, P395-398.
[3] A Graduate Course in Applied Cryptography by Dan Boneh and Victor Shoup, Version 0.4, September 2017, Chapter 10.3, P398-401.
[4] Introduction to modern cryptography by Jonathan Katz and Yehuda Lindell, Second edition, Chaper 8.2.5, P314-316.
[5] https://crypto.stanford.edu/~dabo/pubs/papers/RSA-survey.pdf
[6] https://tools.ietf.org/html/rfc8017
[7] Cryptography Engineering by Niels Ferguson, Bruce Schneier and Tadayoshi kohno, the 1st Edition, Chapter 12.4.4, P203.