徹底理解RSA加密算法


RSA是非常典型的非對稱加密算法

 

 

它的算法是這樣的

 

加密是我們把明文M轉化成密文C 需要用到加密運算 而解密時我們要用解密運算將密文C轉化成M 從表達式中

可以看出 e和d使我們需要確定的參數 而N是兩者共有的 所以我們把參數e,d稱之為私鑰 N就是公鑰 兩者都屬於密鑰 

這里M比N小 我們不能狹義地去看待這些數 因為計算機本質上傳輸的都是二進制數據 計算機是用電信號 所以所謂圖片 影片 文本等等不都是二進制數據么 也就是數

看起來好像很簡單 

但是我們現在面臨幾個問題 首先 初始時e怎么確定 N怎么確定 

其次 由e和N如何確定d的值 從而進行解密操作

還有 為什么解密這個式子是成立的 為什么可以這么解密

 

 我們先保存這些問題 來看一下RSA密鑰的產生過程

首先 我們隨機選擇兩個大素數p,q

計算N=pq

此時

 

上式的證明如下:

如果m和n是互質的正整數。那么,ϕ(mn)=ϕ(m)ϕ(n)=(m-1)(n-1)

 

 

是N的歐拉函數  

 

 

 之后

 

 

 gcd就是我們的歐幾里得算法 c++代碼如下

int gcd(int a,int b)///輾轉相除法求最大公約數
{

    int t = a;
    while(a%b)
    {
        a=b;
        b=t%b;
        t=a;
    }
    return b;
}

這個還可以直接遞歸實現

int gcd(int a, int b)
{
    return b == 0 ? a : gcd(b, a%b);
}

 

也就是說 當gcd的兩個參數互質時 函數值才是1 所以e與N的歐拉函數互質(歐幾里得算法用來求最大公約數)

之后我們求解下列方程解出d

其實也就是ed mod φ(N)=1 解出d

 

 

 兩個-是= 三個-是同余的意思 也就是說 ed mod φ(N)=1 mod  φ(N) = 1

最后我們再保存公鑰和私鑰 算法結束 

 

 

現在我們來討論一下其中的問題

 

首先我們要知道歐拉定理:

數論中,歐拉定理,(也稱費馬-歐拉定理)是一個關於同余的性質。歐拉定理表明,若n,a為正整數,且n,a互質,則:

 

 

 也就是 a的φ(N)次方 對n取余 = 1

其證明如下:

 

 

 

 此時根據歐拉定理我們又可以又有一個推論:

 

 

 

 

 

 

 

 

 我們可以用這些推論來解決實際問題

比如用來簡化冪的模運算

問題如下:

計算7^{222}的個位數

實際是求7^{222}被10除的余數。7和10[[互素]],且φ(10)=4

 

 

 

 

 

 

 

 

 現在 我們回到RSA算法中 我們選擇e時 肯定是要小於φ(N) 之后我們要選擇d 而使得ed mod φ(N)=1

那么因為我們合適的d值 就會存在 ed = 1+ kφ(N)

所以我們開始的解密和加密公式

C^d =(M^e)^d=M^(1+kφ(N) )=M mod N 得證

而如何去選擇合適的d值

我們發現 ed mod φ(N) = 1

所以求d  就是求e對φ(N)的乘法逆元

 

求解乘法逆元 我們首先想到的是 簡單暴力的迭代算法:

int d;
 for (d = 1;; d++) ///求d d是e的乘法逆元 n1是φ(N)
    {
        if (d * e % n1 == 1)
            break;
    }

但是這樣又一個壞處 因為d是從1開始一直自增1去遍歷 所以n1不能太大 也就是說p和q不能太大 但是本身p,q需要是大質數 這樣才能保證加密的性能

於是我們

需要用到擴展歐幾里得算法求乘法逆元d

 

要了解擴展歐幾里得算法我們需要先知道貝祖定理:

若a,b是整數,且gcd(a,b)=d,那么對於任意的整數x,y,ax+by都一定是d的倍數,特別地,一定存在整數x,y,使ax+by=d成立。
它的一個重要推論是:a,b互質的充要條件是存在整數x,y使ax+by=1.
 
 

 所以 通常談到最大公約數時,我們都會提到一個非常基本的事實:給予二個整數a、b,必存在整數x、y使得ax + by = gcd(a,b)

 

有兩個數a,b,對它們進行輾轉相除法,可得它們的最大公約數——這是眾所周知的。然后,收集輾轉相除法中產生的式子,倒回去,可以得到ax+by=gcd(a,b)的整數解。

擴展歐幾里得算法可以用來計算模反元素(也叫模逆元),而模反元素在RSA加密算法中有舉足輕重的地位。

 

我們舉個例子:

用類似輾轉相除法,求二元一次不定方程47x+30y=1的整數解

 

 這個過程也可以用矩陣表示 q表示商,r表示余數

 

 

那么使用擴展歐幾里德算法的過程應該是這樣:

求exgcd(e, m)—>利用歐幾里得算法不斷遞歸直到x=1,y=0—>反向遞歸求出第一層的x和y,x即為e模m的逆元。

 

用代數表示一下 就是

我們要處理的是求出 a 和 b的最大公約數,並求出 x 和 y 使得 a*x + b*y= gcd ,而我們已經求出了下一個狀態:b 和 a%b 的最大公約數,並且求出了一組x1 和y1 使得: b*x1 + (a%b)*y1 = gcd , 這兩個相鄰的狀態之間應該存在一種關系

那么我們來驗證一下:

  我們給出這一條定理: a%b = a - (a/b)*b  //c系語言的除是取整數部分的除  因為歐拉定理我們清楚地知道 gcd(a,b)= gcd(b,a % b)

帶入化簡

 gcd = b*x1 + (a-(a/b)*b)*y1

            = b*x1 + a*y1 – (a/b)*b*y1

            = a*y1 + b*(x1 – a/b*y1)

 對比之前我們的狀態:求一組 x 和 y 使得:a*x + b*y = gcd 

根據恆等定理 系數是不是要相同啊:

沒錯

x = y1

 y = x1 – a/b*y1

這時候 我們就可以寫出擴展歐幾里得算法

int exgcd(int a2,int  b2,int &x,int &y)
{
    if(b2==0)
    {
        x=1;y=0;
        return a2;
    }

    int ans = exgcd(b2,a2%b2,x,y);
    double temp=x;
    x=y;
    y=temp-a2/b2*y;
    return ans;       ///返回的還是最大公約數 但是我們就方便求x和y

}

這時候 我們很方便地可以求x和y  也就可以求出乘法逆元

乘法逆元是: ed mod φ(N)=1

也就存在這個表達式 ed +kφ(N)= 1 根據前邊我們知道當gcd(ed φ(N)) != 1 的時候是沒有解

一般,根據不定方程等數論部分的知識 我們應該能夠找到無數組解滿足條件,但是誰會閑的無聊讓你寫一堆通解

一般是讓你求解出最小的那組解,怎么做?我們求解出來了一個特殊的解 x0 那么,我們用 x0 %  φ(N)其實就得到了最小的解了

因為啊 d的通解正是x0+kt

 也就是說  d對於 φ(N) 的逆元是一個關於 φ(N) 同余的

那么根據最小整數原理,一定存在一個最小的正整數,它是 d 關於φ(N) 的逆元,而最小的肯定是在(0 , φ(N))之間的,而且只有一個 這些都是純數學推導

不得不說數學真的很重要

這時候還有一點要注意 我們有時候得到的x0可能是負數 所以要用函數abs()取絕對值

至此 所有RSA加密的問題都迎刃而解了

現在我給出模擬RSA加密的總代碼

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b)///輾轉相除法求最大公約數
{

    int t = a;
    while(a%b!=0)
    {
        a=b;
        b=t%b;
        t=a;
    }
    return b;
}

int x,y,q;
int exgcd(int a2,int  b2,int &x,int &y)
{
    if(b2==0)
    {
        x=1;y=0;
        return a2;
    }

    int ans = exgcd(b2,a2%b2,x,y);
    double temp=x;
    x=y;
    y=temp-a2/b2*y;
    return ans;       ///返回的還是最大公約數 但是我們就方便求x和y

}
int tocal(int a3,int b3)
{
    int x0,y0;
    int gcd = exgcd(a3,b3,x0,y0);
    if(1%gcd!=0) return -1; ///gcd得等於1  ...
    x0*=1/gcd;
    b3=abs(b3);
    int ans = x0%b3;
    if (ans<=0) ans+=b3;
    return ans;


}
int main()
{
    int p, q;
    cout << "輸入p、q (p、q為質數)" << endl;
    cin >> p >> q;
    int n = p * q;
    int n1 = (p - 1) * (q - 1);///歐幾里得函數
    int e;
    cout << "輸入e (e是與" << n1 << "互質的) 且 1<e<" << n1 << endl;///按照定義來
    cin >> e;
    int d;
    /*其實也可以窮舉法求d 但是這樣 輸入的p和q不能過大 所以n1才不會太大
    for (d = 1;; d++) ///求d d是e的乘法逆元
    {
        if (d * e % n1 == 1)
            break;
    }
    */
    d = tocal(e,n1);

    cout << endl << endl;

    cout << "{ " << e << "," << n << " }" << "為公鑰" << endl;
    cout << "{ " << d << "," << n << " }" << "為私鑰" << endl;


    cout << endl << endl;

    int before;
    cout << "輸入明文,且明文小於"<<n << endl;
    cin >> before;

    cout << endl;
    int i;

    cout << "密文為" << endl;
    int after;
    after = before % n;
    for (i = 1; i < e; i++)
    {
        after = (after * before) % n;
    }
    cout << after << endl;

    cout << "明文為" << endl;
    int real;
    real = after % n;
    for (i = 1; i < d; i++)
    {
        real = (real * after) % n;
    }
    cout << real << endl;
    return 0;

}

 

運行結果:完全正確

 

 

 

 后話:最初的網絡安全都是基於對稱加密。沒有公鑰私鑰之分 一旦別人擁有密鑰 數據就會泄露;

后來地球上出現了迄今為止最重要的非對稱加密RSA算法。

公鑰對外公開 而私鑰自己保有

世界上很多事情,都是單向(或者反向問題難度大大增加)的。殺一個人比救一個人容易 摔碎一個餐具比拼好一個餐具容易 研究毒葯比研究毒葯的解葯容易

令兩個大素數相乘容易 把一個大數分解成兩個素數相乘就很難

解密確實用了私鑰,一個跟加密過程不一致的方式。即解密並不是我們常識理解的那種逆運算,比如1+1=2,反過來2-1=1。但是RSA卻不是這樣很顯然的方式

所以才叫非對稱加密 這樣對概念也就能深深的理解


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM