RSA 加密方案的深入學習

RSA 是一種非常流行的非對稱加密算法,它是由 Ron Rivest、Adi Shamir、Leonard Adleman 在1977年一起提出的,RSA 就是他們三人姓氏開頭字母拼在一起組成的。相對于對稱加密算法使用相同的密鑰進行加解密,非對稱加密算法需要兩把不同的密鑰,一個是公鑰,一個是私鑰,公鑰可以公開提供給任何人,私鑰不可以公開。可以用公鑰加密、私鑰解密,也可以用私鑰加密、公鑰解密。

RSA 的密鑰生成過程

  1. 選擇兩個大的質數 p 和 q,計算兩個質數的乘積 N,素數是指在大于 1 的自然數中,除了 1 和自身外,無法被其他自然數整除的數。
  2. 對 p 和 q 使用歐拉函數運算得到各自的互質數的數量 Φ (p) = (p-1) , Φ (q) = (q-1) 并將各個結果進行相乘 R = Φ (p) * Φ (q),歐拉函數Φ (n)是小于等于 n 的正整數中與 n 互質的數的數目
  3. 在大于 1 小于 R 的區間中選擇一個整數 E,并且該整數與 R 互質。
  4. 求 E 關于 R 的模逆元 D,即 E * D ≡ 1 (mod R)。

通過上述的步驟可以得到公鑰 (N, E) 和私鑰 (N, D),用一個例子帶入說明就是:

  1. 選擇兩個質數 p (3) 和 q (11)
  2. 并兩只質數的乘積 N (33) = p (3) * q (11)
  3. 根據歐拉函數計算 R (20) = (3 - 1) * (11 - 1)
  4. 選擇一個與 20 互質的整數 E (3)
  5. 計算 E(3) * D % R(20) = 1 ,得到 D 的為 7

通過上述計算公鑰為(33, 3),私鑰為(33, 7)。

RSA 對明文加解密過程

  • 加密
    使用公鑰進行加密,將明文每個字符轉換為數字,可以轉換為 ASCII 值,每個明文數字做 E 次方運算,然后再計算和 N 的余數,得到的結果就是加密后的密文。例:現在有一個明文數字9,密文生成的過程就是先計算 9 的 3 次方等于 729,再計算和 33 的余數為 3,3 就是最終的密文。

  • 解密
    使用私鑰進行解密,將拿到的密文先求 D 次方運算,然后再計算和 N 的余數,得到的結果就是解密后的明文。例:根據上一步得到的密文 3,先計算 3 的 7 次方等于 2187,再計算和 33 的余數為 9,這樣就得到了明文。

RSA 加密標準

RSA 算法通常對輸入數據的長度有限制,一般不能超過模數 N 的長度,如果明文數據較長,需要將其分成若干塊進行加密。加密標準主要分為 PKCS1 和 OAEP。OAEP 目前更加安全,推薦使用 OAEP 的標準。

RSA 的安全性

RSA 的安全性非常依賴于密鑰生成第一步中兩個質數的范圍,當質數非常大時,因數分解會變得非常困難,這也是 RSA 算法之所以安全的核心點,隨著計算機硬件能力逐步提升,512 位和 768 位的質數已經被人分解了,目前常用的 1024 位質數在理論上已經不安全了,推薦以后使用 2048 位或者更高 4096 位質數來生成密鑰。在理論上來說,量子計算機被應用之前,RSA 算法都是安全的。

RSA 的應用場景

RSA 的加解密速度很慢,并且明文長度是不能超過公鑰 N 的長度的,所以無法加密數據量大的明文,實際中常常搭配 AES 加密方式做混合加解密。通過 RSA 將 AES 密鑰加密,傳遞密鑰后兩端利用 AES 進行數據加密傳輸。

代碼實現

  • php
// 公鑰加密數據
$pubFilepath = 'public_key.pem';
$fp = fopen($filepath,"rb");
$pubContent = fread($fp, filesize($filepath);
$publicKey = openssl_get_publickey($pubContent);
openssl_public_encrypt("hello", $data, $publicKey);

// 私鑰解密數據
$priFilepath = 'private_key.pem';
$pr = fopen($priFilepath, 'rb');
$priContent = fread($pr, filesize($priFilepath);
$privateKey = openssl_get_privatekey($priContent);
openssl_private_decrypt($data, $result, $privateKey);
  • go
// Demo 密鑰生成以及加解密示例
func Demo() string {
    rng := rand.Reader

    //生成密鑰,選擇2048位長度
    pri, err := rsa.GenerateKey(rng, 2048)
    if err != nil {
        panic(err)
    }

    //明文
    text := "hello world"
    cipherText := RsaEncrypt(&pri.PublicKey, text)
    result := RsaDecrypt(pri, cipherText)

    return result
}

// RsaEncrypt 加密
func RsaEncrypt(pub *rsa.PublicKey, text string) string {
    rng := rand.Reader

    result, err := rsa.EncryptOAEP(sha256.New(), rng, pub, []byte(text), []byte("test hello"))
    if err != nil {
        panic(err)
    }

    //將加密的密文字節轉為base64方便傳輸
    content := base64.StdEncoding.EncodeToString(result)

    return content
}

// RsaDecrypt 解密
func RsaDecrypt(pri *rsa.PrivateKey, cipherText string) string {
    //將base64轉為密文字節
    de, err := base64.StdEncoding.DecodeString(cipherText)
    if err != nil {
        panic(err)
    }

    rng := rand.Reader

    ra, err := rsa.DecryptOAEP(sha256.New(), rng, pri, de, []byte("test hello"))
    if err != nil {
        panic(err)
    }

    return string(ra)
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • RSA是第一個比較完善的公開密鑰算法,它既能用于加密,也能用于數字簽名。RSA以它的三個發明者Ron Rivest...
    暗物質閱讀 1,721評論 0 0
  • 原文 在此本來RSA跟區塊鏈并無聯系, 但是非對稱加密以及私鑰/公鑰的理解相似, 因此理解RSA對與理解ECC有相...
    mrzzcn閱讀 566評論 0 2
  • ??密碼學是指研究信息加密,破解密碼的技術科學。密碼學的起源可追溯到2000年前。而當今的密碼學是以數學為基礎的。...
    Hmilylpp閱讀 680評論 0 0
  • 本文結構: 一些基本的數學知識 RSA的具體過程 為什么RSA的私鑰解密一定能得到明文 RSA算法可靠嗎 RSA算...
    風再起時ME閱讀 3,392評論 2 2
  • 數據信息安全對我們每個人都有很重要的意義,特別是一些敏感信息,可能一些類似于收貨地址、手機號還沒引起大家的注意。但...
    metabolism閱讀 699評論 0 0