RSA算法的数学原理

欧拉函数及其重要性质

n是任意正整数,欧拉函数以\phi(n)表示,\phi(n)等于所有小于等于n的正整数中与n互质的个数。比如在1~8里,与8互质的数字是1、3、5、7,因此\phi(8)=4。我们探讨一些欧拉函数的特殊性质吧:

性质 1 \phi(1)=1,因为1与其自身互质,这是显而易见的。

性质 2 如果n是质数,那么\phi(n)=n-1,因为质数与每个小于其自身的正整数都互质。

性质 3 如果p是质数,k是正整数,那么:
\phi(p^k)=p^k-p^{k-1}=p^k\left(1-\frac{1}{p}\right)
这是因为所有小于等于p^k的正整数有p^k个这么多,其中只有不是p的倍数才能与p^k互质。而p的倍数有:1\times p, 2\times p, \dots,p^{k-1}\times p这些,共有p^{k-1}个。自然地就有\phi(p^k)=p^k-p^{k-1}

性质 4 如果p_1p_2是两个互质的整数,那么:
\phi(p_1\times p_2)=\phi(p_1)\times\phi(p_2)

性质 5 欧拉定理 首先阐述一下x\equiv y(mod\space n)表示x除以n的余数是y。用代码表示为x % n == y。欧拉定理是指:如果an互质,那么下面等式成立:
a^{\phi(n)}\equiv1(mod\space n)
或者说,a^{\phi(n)}除以n余数为1。比如说3与7互质,依据性质2有\phi(7)=6,那么3^6\div7等于104余1。欧拉定理是RSA算法的核心,其证明比较复杂就不阐述了(我也弄不懂)。

性质 6 模反元素 如果两个正整数a与n互质,那么一定可以找到一个整数b,使得a*b除以n余1,或者说:
ab\equiv1(mod\space n)
这个时候我们把b称为a的模反元素。欧拉定理可以证明模反元素必然存在,a^{\phi(n)-1}就是a的模反元素:a\times a^{\phi(n)-1}\equiv1(mod\space n)。事实上模反元素不止一个,也可能是负数。

扩展欧几里得算法

在RSA算法中,对于以下方程
e\cdot d - k\cdot\phi(n)=1
已知e\phi(n),需要求解dk。我们需要用扩展欧几里得算法进行求解。假设函数gcd(a,b)ab的最大公约数,这里引出裴属定理:

Th 7 裴属定理 对于整数ab,一定存在整数xy使得ax+by=gcd(a,b)。如果ax+by=m有解,那么m一定是gcd(a,b)的倍数。

要证明上述定理,当b=0时,此时gcd(a,b)=a,令x=1,y=0即可解。

a\cdot b\neq0时,设x_1y_1满足ax_1+by_1=gcd(a,b)。我们重新赋值,将b替换为a\%b,将a替换为b;设x_2y_2满足:
b\cdot x_2+a\%b\cdot y_2=gcd(b,a\%b)=gcd(a,b)
于是有:
b\cdot x_2+a\%b\cdot y_2=a\cdot x_1+b\cdot y_1
我们假设b\cdot k+t=a,即a除以b等于kt,那么a\%b=a-b\cdot k,于是有:
a\cdot x_1+b\cdot y_1=b\cdot x_2+(a-k\cdot b)\cdot y_2
解得:
x_1=y_2,\space y_1=x_2-ky_2
于是用扩展欧几里得算法求解原方程的代码就呼之欲出了:

int ext_gcd(int a, int b, int &x, int &y) {
    // 求解a*x+b*y=1的解(x, y)
    if (b == 0) {
        // 递归出口 给x与y赋值
        x = 1;
        y = 0;
        return a;
    }
    // 递归求解x2, y2
    int gcd = ext_gcd(b, a % b, x, y);
    // 通过x2, y2求解x1, y1
    int x2 = x, y2 = y;
    int k = a / b;  // a除以b向下取整
    x = y2;
    y = x2 - k * y;
    return gcd;
}

快速幂算法求模

在RSA算法的加密过程里我们将会计算a的b次方对n的余数,其中a与b可能都是超大整数,直接暴力计算不可行。我们需要用快速幂算法快速算出(a^b)%n,这个算法又叫蒙哥马利算法。

首先我们需要将b拆分为二进制之写法。设b=13,其二进制表示为1101,我们将二进制写法拆分成如下形式:
13=1\times2^3+1\times2^2+0\times2^1+1\times2^0
更一般地,假设十进制数字b的二进制共有K位,我们用b_k01表示其二进制的第k位,那么有:
b=b_K\cdot2^K+b_{K-1}\cdot2^{K-1}+\dots+b_0\cdot2^0
那么:
a^b=a^{b_K\cdot2^K}\times a^{b_{K-1}\cdot2^{K-1}}\times\dots\times a^{b_1\cdot2}\times a^{b_0}
举个例子,我们要用快速幂算法计算3^{13},13表示为二进制是1101,那么就有:
3^{13}=3^8\cdot3^4\cdot3^1
这里描述一下快速幂算法计算3^{13}

res=1
底数=3
从右到左依次观察(1101)2每一位的值:
    第1位是1:
        res=res*底数=3
        底数=底数的平方=9
    第2位是0: 
        底数=底数的平方=81
    第3位是1:
        res=res*底数=3*81
        底数=底数的平方=6561
    第4位是1
        res=res*底数=3*81*6561
输出3*81*6561

一般地,快速幂算法可以写成:

long fast_pow(long a, long b) {
    // 快速幂算法求 a^b
    long res = 1;
    while (b) {
        if (b & 1) res = res * a;
        a = a * a;
        b = b >> 1;
    }
    return res;
}

取模运算不会干预乘法运算,于是我们马上就能写出快速幂算法求模的代码:

long fast_mode(long a, long b, long n) {
    // 快速幂算法求 a^b%n
    long res = 1;
    while (b) {
        if (b & 1) res = res * a % n;
        a = a * a % n;
        b = b >> 1;
    }
    return res;
}

RSA算法流程

理论讲完了,可以开始RSA算法的流程了。以下是RSA算法的流程:

生成密钥

  1. 选择pq两个超大质数,通常其二进制为1024或2048位。
  2. 计算n=p\times q,计算与n互质的整数的个数\phi(n)=(p-1)\times(q-1)
  3. 取正整数e,需要满足e\in{2, 3, ..., \phi(n)}e\phi(n)互质。实际中通常取65537。
  4. 计算e对于\phi(n)的模反元素d,即寻找整数d以满足e\cdot d\equiv1(mod\space n),或者说对于以下方程:e\cdot d - k\cdot\phi(n)=1,已知e\phi(n),求解dk,用扩展欧几里得算法可以求出来。
  5. 销毁pq,输出公钥(n,e),输出私钥(n,d)

加密与解密

  1. 输入明文m
  2. 计算密文c=m^e\%n,这里用上述的快速幂算法加速计算;
  3. 解密过程为m=c^d\%n,这里用上述的快速幂算法加速计算。

于是一份C++版本RSA算法代码就呼之欲出了。可惜的是cpp里long long类型只支持到64位,要在生产环境实现一份RSA加密算法,其数字至少需要1024位才足够安全。代码如下:

#include <iostream>
#include <math.h>
#include <vector>
using namespace std;
typedef long long ll;


ll ext_gcd(ll a, ll b, ll &x, ll &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    ll res = ext_gcd(b, a % b, x, y);
    ll t = y;
    y = x - (a / b) * y;
    x = t;
    return res;
}


ll fast_mode(ll a, ll b, ll n) {
    ll res = 1;
    while (b > 0) {
        if (b & 1) res = res * a % n;
        a = a * a % n;
        b >>= 1;
    }
    return res;
}


void gen_key(ll p, ll q, ll &n, ll &e, ll &d) {
    n = p * q;
    ll phi = (p - 1) * (q - 1);
    e = 65537;
    ll y;
    // 求解e*d-k*phi=1
    ext_gcd(e, phi, d, y);
    if (d < 0) d += phi;
}


int main() {
    ll p = 61;
    ll q = 53;
    ll msg;
    cout << "Please input message: ";
    cin >> msg;
    ll n, e, d;
    gen_key(p, q, n, e, d);
    ll cipher = fast_mode(msg, e, n);
    ll msg_decrypted = fast_mode(cipher, d, n);
    cout << n << endl;
    cout << e << endl;
    cout << d << endl;
    cout << msg << endl;
    cout << cipher << endl;
    cout << msg_decrypted << endl;
    return 0;
}

附录

证明-1 关于(x\cdot y)\%n=\left(x\cdot y\%n\right)\%n=\left(x\%n\cdot y\%n\right)\%n的证明:

假设n\cdot k_1+m_1=x,即m_1是余数,x\%n=m_1

假设n\cdot k_2+m_2=y,即m_2是余数,y\%n=m_y

于是:
(x\cdot y)\%n=\left[(n\cdot k_1+m_1)(n\cdot k_2+m_2)\right]\%n\\=(n^2k_1k_2+nk_1m_2+nk_2m_1+m_1m_2)\%n\\=(m_1m_2)\%n\\=\left(x\%n\cdot y\%n\right)\%n

同样地,我们有:
(x\cdot y\%n)\%n=\left[(nk_1+m_1)m_2\right]\%n\\=(nk_1m_2+m_1m_2)\%n\\=(m_1m_2)\%n

证明-2 证明解密过程的正确性,即证明m=c^d\%n。首先我们从密文的计算式c=m^e\%n得到c=m^e-nh,代入解密式得到:
m=\left(m^e-nh\right)^d\%n
这里略去一些二项式展开的过程,证明上式等价于证明:
m=m^{ed}\%n
由于在生成密钥过程中有ed=k\phi(n)+1,所以只需证:
m=m^{k\phi(n)+1}\%n

假如m与n互质,根据欧拉定理我们有m^{\phi(n)}\equiv1(mod\space n),或者说:
nt_0+1=m^{\phi(n)}
两边同时取n次方,进行二项式展开:
m^{k\phi(n)}=(nt_0+1)^k=nt_1+1
两边同时乘以m:
m^{k\phi(n)+1}=mnt_1+m
由此m=m^{k\phi(n)+1}\%n得证。

假如m与n并不互质,略。

引用

[1] 快速幂算法

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容