RSA

RSA

RSA簡介

RSA定義

相信只要對密碼學瞭解的同窗確定據說過RSA,它是三個發明者名詞的縮寫(Rivest-Shamir-Adleman),也是最先的公鑰密碼學系統之一,也是多是應用最普遍的公鑰密碼學系統。[1]這裏給它兩個定義html

  • 廣義的說,RSA密碼系統(RSA cryptosystem)是基於RSA問題的公鑰密碼學系統
  • 狹義的說,RSA假設(RSA assumption)是一個能夠構造單向陷門函數(One-way trapdoor functions)的假設。

RSA原理

咱們經過定義能夠看出若是一個密碼學方案使用了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是一個單向陷門置換

涉及到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方案是一個單向陷門函數。因爲RSA自己的數學性質是\(Z_n^*\)到自身的置換。因此RSA方案是一個單向陷門置換。

RSA假設基於什麼

保研夏令營的時候老師問我RSA假設基於啥?我其實不知道當時上課的時候說的啥,忽然腦子中想起就說是基於大整數分解。老師說不對。現在仔細翻書才明白。RSA假設啥都不基於,它就是一個假設。 大整數分解若是能被解決,那麼RSA必定能被解決。可是RSA被解決卻不必定須要大整數分解。大整數分解是更難的問題,沒法規約到RSA。[4]

RSA應用

RSA密碼系統,或者說全部的公鑰密碼學系統通常都有兩個應用,公鑰加密和簽名。值得注意的是,相同的密鑰對在不一樣的RSA應用中也不該該被屢次使用,這是極其危險的。這部分首先研究下參數選擇問題,下面咱們分別來講它們的應用。而後嘗試幾個開源實現。另外這節要參考PKCS #1 v2.1的標準[6] (最新的版本已經到v2.2了),這也是大多數實現參考的標準。(由於水平有限,省略了素數生成的部分)

e的選擇

選擇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更近乎行業標準

n的選擇

若是你想要保護你的密鑰20年,使用RSA2048bit。若是你能夠不計開銷,那麼就使用RSA4096bit。隨着計算機愈來愈快,將來你可能須要使用RSA8196bit。使用一個大RSA是好的,由於能夠省去將來更換的麻煩。[7]

RSA padding

直接用作加密和簽名的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方案。

  • 對於RSA加密,標準中給出了pkcs v1.5和OAEP。使用OAEP,pkcsv1.5是不安全的。
  • 對於RSA簽名,標準給出了pkcs v1.5和PSS。儘量使用PSS,雖然簽名中的pkcs v1.5沒有相應的攻擊,可是應該以保守的原則使用PSS。

PKCS #1 v2.1說了兩遍RSA,一個是帶CRT的一個不帶,被吐槽了:標準和實現摻在一塊兒

RSA加密

通常來說,RSA不會直接用於加密。須要使用對稱加密方案\(E\)來加密消息\(m\),最後傳遞消息\(RSAE(key,e),E(m,key)\)。相應的,使用\(key = RSAD(RSAE(key,e),d),m = D(E(m,key),key)\)。進行解密。

RSA簽名

對於簽名,首先使用hash函數對簽名進行去結構化\(H(m)\)。而後經過PRNG來將\(H(m)\)來映射到\(0,...,2^k-1\),其中\(k\)是知足\(2^k<n\)的最大的\(k\)。而後再進行樸素的簽名便可。

使用填充方案\(PSS\)是更好的選擇。

RSA開源實現和使用

OpenSSL

  • openssl命令

openssl命令行關於rsa的有三個命令模塊genrsarsarsautl。其中genrsa主要用於生成rsa密鑰。rsa主要用於轉換rsa密鑰格式。rsautl用於對數據的加密或者解密。具體使用方法能夠參考openssl的手冊。

值得注意的是,對於rsa模塊的命令有兩組選項分別是-pubin,-pubout-RSAPublickey_in,-RSAPublicKey_out。這是兩種不一樣的格式,我在網上搜索到了滿意的答案。(爲啥沒有privatekey的格式,由於PKCS#8只規定了公鑰的格式,私鑰由於不用分發因此不須要格式。)

  • openssl接口

生成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性能

提高RSA性能主要考慮兩個方面,一個是CRT,一個時模n乘法。對於CRT,PKCS #1中專門給出了相應的CRT標準。對於模n乘法也是選擇e的因素。

CRT

待更新。。。

模n乘法

RSA攻擊[5]

數學攻擊

實現攻擊(側信道)

相關的名詞

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.

相關文章
相關標籤/搜索