1. 程式人生 > >RSA加密與解密簡單實現

RSA加密與解密簡單實現

非對稱金鑰加密概述

使用對稱金鑰加密體制進行保密通訊時,任意不同的兩個使用者之間都應該使用互不相同的金鑰。這樣,如果一個網路中有n個使用者,他們之間彼此都可能進行祕密通訊,這時網路中將需要n(n-1)/2個金鑰(其中,每個使用者都需要儲存n-1個金鑰),這樣巨大的金鑰量給金鑰分配和管理帶來了極大的困難。另外,隨著計算機網路,特別是因特網的發展,網路上互不相識的使用者可能需要進行保密的會話(例如,如果使用者在進行電子商務活動時,需要保密的連線,這時的客戶物件可能根本不是固定的物件)。最後,對稱金鑰加密機制難以解決簽名驗證問題。
非對稱金鑰加密也稱為公開金鑰加密,或者叫做公鑰加密演算法。使用公開金鑰密碼的每一個使用者都分別擁有兩個金鑰:加密金鑰和解密金鑰,它們兩者並不相同,並且由加密金鑰得到解密金鑰在計算機上是不可行的。每一個使用者的加密金鑰都是公開的。因此,加密金鑰也稱為公開金鑰。所有使用者的公開金鑰都將記錄在作用類似於電話號碼薄的金鑰本上,而它可以被所有使用者訪問,這樣每一個使用者都可以得到其他所有使用者的公開金鑰。同時,每一個使用者的解密金鑰將由使用者儲存並嚴格保密。因此,解密金鑰也稱為私有金鑰。
非對稱密碼演算法解決了對稱密碼體制中金鑰管理的難題,並提供了對資訊傳送人的身份進行驗證的手段,是現代密碼學最重要的發明。公鑰加密演算法一般是將對金鑰的求解轉化為對數學上的困難問題的求解,例如RSA演算法的安全性是建立在“大數分解和素性檢測”這個數論難題的基礎上,已知兩個大素數a、b,求出a*b是容易計算的,而已知a*b,想知道其是哪兩個大素數的乘積目前還沒有好的計算方法,另外也有一些非對稱加密演算法(如ELGamal演算法)的安全性是基於求“離散對數”這個數學難題上的。
在公鑰密碼系統中每個實體都有自己的公鑰和相應的私鑰。公鑰密碼系統的加密變換和解密變換分別用E和D表示。任何實體B要向實體A傳送資訊m的步驟如下:實體B首先獲得實體A的真實公鑰的拷貝(eA),實體B使用eA計算密文c=E(m)併發送給實體A,實體A使用自己的私鑰dA,計算m=D(c)解密密文,恢復出明文m。這裡公鑰不需要保密,但要保證它的真實性,即eA確實是實體A掌握的私鑰dA所對應的公鑰。提供真實的公鑰比安全地分配金鑰實現起來要容易得多。這也是公鑰密碼系統的主要優點之一。
公鑰密碼系統的主要目的是提供保密性,它不能提供資料來源認證(data origin authentication)和資料完整性(data integrity)。資料來源認證是指:指定的資料是在以前的某個時間確實是由真正的源建立的。資料完整性是指:真正的源建立該資料後經過傳輸後儲存沒有發生改變。資料來源認證和資料完整性要由其他技術來提供(如訊息認證碼技術、數字簽名技術等)。
從本質上來看,公鑰密碼比對稱金鑰密碼加密的速度要慢,粗略的說,公鑰加密演算法RSA硬體實現比分組加密演算法DES硬體實現的速度慢1500倍,而軟體實現的速度要慢100倍。
公鑰解密也可以提供認證保證(如:在實體認證協議、帶認證的金鑰建立協議等)。公鑰加密中必須有頒發讓傳送訊息的人得到想要傳送到的那個人的公鑰的真實拷貝,否則就會受到偽裝攻擊。在實踐中有很多方法分發真實的公鑰,如:使用可信的公共檔案,使用線上可信伺服器,使用離線伺服器和認證。

公鑰加密的優點:

● 大型網路中的每個使用者需要的金鑰數量少。
● 對管理公鑰的可信第三方的信任程度要求不高而且是離線的。
● 只有私鑰是保密的,而公鑰只要保證它的真實性。

缺點:

● 多數公鑰加密比對稱金鑰加密的速度要慢幾個數量級。
● 公鑰加密方案的金鑰長度比對稱加密的金鑰要長。
● 公鑰加密方案沒有被證明是安全的。

公鑰密碼的概念本身就被公認為是密碼學上的一塊里程碑。二十多年來的研究表明,公鑰密碼成功地解決了計算機網路安全中的金鑰管理,身份認證和數字簽名等問題,已經成為資訊保安技術中的重大核心技術。

RSA演算法概述

RSA加密演算法於1977年由美國麻省理工學院的Ronal Rivest,Adi Shamir和Len Adleman三位年輕教授提出,並以三人的姓氏Rivest,Shamir和Adleman命名為RSA演算法。這三位科學家榮獲2002年度圖靈獎,以表彰他們在演算法方面的突出貢獻。該演算法利用了數論領域的一個事實,那就是雖然把兩個大質數相乘生成一個合數是件十分容易的事情,但要把一個合數分解為兩個質數的乘積卻十分困難。合數分解問題目前仍然是數學領域尚未解決的一大難題,至今沒有任何高效的分解方法。它無須收發雙方同時參與加密過程,既可以用於保密也可以用於簽名,因而非常適合於電子郵件系統的加密,互連網和信用卡安全系統。

RSA演算法的加密和解密過程

在RSA演算法中,每個實體有自己的公鑰(e,n)及私鑰(d,n),其中n = pq(p、q是兩個大素數),ф(n) = (p-1)(q-1),ed = 1 mod ф(n),顯然e應該滿足gcd(e,ф(n)) = 1。實體B加密訊息m,將密文在公開通道上傳送給實體A。實體A接到密文後對其解密。具體演算法如下。

1. 公私鑰的生成演算法

RSA的公私鑰生成演算法十分簡單,可以分為五步:
(1) 隨機地選擇兩個大素數p和q,而且保密;
(2) 計算n=pq,將n公開;
(3) 計算ф(n) = (p-1)(q-1),對ф(n)保密;
(4) 隨機地選擇一個正整數e,1

2.加密演算法

實體B的操作如下:
(1) 得到實體A的真實公鑰(e,n);
(2) 把訊息表示成整數m,0<m≤n-1;
(3) 使用平方-乘積演算法,計算C = Ek(m) = me mod n;
(4) 將密文C傳送給實體A。

3.解密演算法

實體A接收到密文C,使用自己的私鑰d計算m = Dk(C)= Cd mod n。
我們選擇p=3,q=11,得到n=33,ф(n)= (p-1)(q-1)=2×10=20。由於7和20互質,故設e=7。對於所選的e=7,解方程7×d=1 mod 20,可以得到d=3。因此公鑰為(7,33),私鑰為(3,33)。
在我們的例子中,由於所選的p和q太小,破譯當然很容易,我們的例子只是用來說明此演算法的原理。對於明文SUZANNE,RSA的加密和解密過程如表所示。

這裡寫圖片描述

加密程式

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long

using namespace std;

const int p = 3;
const int q = 11;
const int e = 7;

int exgcd(int a,int b,int &x,int &y)
{
    int t,gcd;
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    gcd=exgcd(b,a%b,x,y);
    t=x,x=y,y=t-a/b*y;
    return gcd;
}
int inv(int a,int b)
{
    int x,y;
    exgcd(a,b,x,y);
    x%=b;
    x=(x+b)%b;
    return x;
}
int fastpow(int a,int b,int c){
        int res=1;
        while(b){
                if(b&1) res=(res*a)%c;
                a=(a*a)%c;
                b>>=1;
        }
        return (res+c)%c;
}

int main(){
    int n = p * q;
    printf("傳送方公鑰(e,n)為:(%d,%d)\n",e,n);
    freopen("RSA1.txt","r",stdin);
    freopen("RSA2.txt","w",stdout);
    char ch;
    while(scanf("%c",&ch)==1){
        int t = fastpow(ch-'A',e,n);
        printf("%c",t+'A');
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

解密程式

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long

using namespace std;

const int p = 3;
const int q = 11;
const int e = 7;

int exgcd(int a,int b,int &x,int &y)
{
    int t,gcd;
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    gcd=exgcd(b,a%b,x,y);
    t=x,x=y,y=t-a/b*y;
    return gcd;
}
int inv(int a,int b)
{
    int x,y;
    exgcd(a,b,x,y);
    x%=b;
    x=(x+b)%b;
    return x;
}
int fastpow(int a,int b,int c){
        int res=1;
        while(b){
                if(b&1) res=(res*a)%c;
                a=(a*a)%c;
                b>>=1;
        }
        return (res+c)%c;
}

int main(){
    int n = p * q;
    int Fai_n = (p-1) * (q-1);
    int x,y;//x和y不需要進行初始化
    exgcd(e,Fai_n,x,y);
    int d = (x + Fai_n) % Fai_n;
    printf("接收方祕鑰(d,n)為:(%d,%d)\n",d,n);
    freopen("RSA2.txt","r",stdin);
    freopen("RSA3.txt","w",stdout);
    char ch;
    while(scanf("%c",&ch)==1){
        int t = fastpow(ch-'A',d,n);
        printf("%c",t+'A');
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

RSA1.txt中存放IHAVEADREAM
RSA2.txt中加密文字為C]AVQAJIQAM
RSA3.txt中解密後文本為IHAVEADREAM