近段時間一直在RSA,PKI, CA,Certificate裏混,恰恰RSA牽扯到了數論的一些知識,想一想是否能用代碼來完整的實現一下,也算作一個總結php
整除: a整除b, 表示爲 a|b => b = ka => b%a=0html
質數:除1和自身外,不被其它數整除python
分析:判斷一個質數只有該數與小於它的數取餘都不爲0, 則能夠判斷此數爲質數算法
1 #!/usr/bin/env python 2 import math 3 def prime(number): 4 for i in range(2,number): 5 if number%i == 0: 6 break 7 if i == number-1: 8 return True 9 else: 10 return False 11 number = int (raw_input('please input a number:')) 12 13 print prime(number) 14 print prime_fast(number)
分析:若是一個數是合數,n = p*q, 若是 p<=sqrt(n),那麼q>=sqrt(n), 若是sqrt(n)+1之內沒有數能夠整除n,能夠判定大於(sqrt(n),n)也不會有數能夠整除n安全
15 def prime_fast(number): 16 N = int(math.sqrt(number)+1) 17 for i in range(2,N): 18 if number % i == 0: 19 break 20 if i == N-1: 21 return True 22 else: 23 return False
最大公約數:能同時整除a和b的最大值,表示爲gcd(a,b)函數
即 a % gcd(a,b) = 0 && b % gcd(a,b)=0 && 最大的公約數ui
分析: 歐幾里德定理 gcd(a,b) = gcd(b, a mod b)加密
證實: 設 a = q * b + r q爲整數, r爲餘數 設 d 爲 a, b 的公約數 則 d|a=m, d|b= n, (m,n爲整數) 由於 r = a - q*b 因此 d|r = d|a -q*d|b = m - q*n =k 仍爲整數 由於 d|b, d|r都爲整數 因此 d是(r,b)的公約數 因爲d是任意假設的,而d便是(a,b)的公約數,又是(b,r)的公約數,可得(a,b)與(b,r)的公約數相同 因此最大公約數也相同表示爲 gcd(a,b)=gcd(b,r)=gcd(b,a mod b)
經過這個定理,算gcd(a,b)只須要計算gcd(b, a %b)就能夠,那麼數學的表示:.net
r_0=a, r_1=b r_0 = q_1 * r_1 + r_2 r_1 = q_2 * r_2 + r_3 r_2 = q_3 * r_3 + r_4 ... r_i = q_(i+1) * r_(i+1) + r_(i+2) ... r_(n-2) = q_(n-1) * r_(n-1) + r_n (r_n爲最大公約數) r_(n-1) = q_n * r_n + 0
證實1: r_n爲a, b的公約數unix
由於 r_(n-1) = q_n * r_n 因此 r_n | r_(n-1) ........q_n 由於 r_(n-2) = q_(n-1) * r_(n-1) + r_n 因此 r_n | r_(n-2) ........q_(n-1)*q_n+1 能夠推斷 r_n | r_1, r_n | r_0 => r_n | a, r_n | b r_n 爲 a, b 的公約數
證實2: r_n 爲a, b的最大公約數
設a, b的最大公約數g(a,b) = g 則 g | a, g | b => g | r_0, g | r_1 由於 r_0 = q_1 * r_1 + r_2 因此 g | r2 ..............r_0/g-q_1*r_1/g爲整數 因此 g | r_n 因此 r_n >= g 由於g 是最大公約數,因此r_n是最大公約數
證實3: r_(n+1)=0
r_0 = q_1 * r_1 + r_2 r_1 = q_2 * r_2 + r_3 ... r_i = q_(i+1)*r_(i+1)+r_(i+2) ... r_(n-2) = q_(n-1) * r_(n-1) + r_n r_2是r_1的餘數,因此r_2<r_1 r_3是r_2的餘數,因此r_3<r_2 ... r_0>r_1>r_2>r_i...>r_(n-1) 因爲都是整數,所以確定存一個r_(n+1)=0,算法終止
歐幾里德算法
def gcd(a,b): 「a = q * b + r」 if a<b: a,b = b,a while (a%b!=0): #餘數最終會等於0 a,b = b,a%b #b = (a%b)*r + r_1 return b
擴展歐幾里德算法
分析: a * x + b * y = gcd(a,b)
def exgcd(a,b): "ax+by=gcd(a,b)" if b==0: return (1,0) #a*x1 + b*y1 = a x1=1 y1=0 #a*x2 + b*y2 = b x2=0 y2=1 while b!=0: q = a/b #gcd(a,b)=gcd(b,a%b) a,b = b, a%b #x_i = x_(i-2) - a/b*x_(i-1) x1,x2 = x2, x1-q*x2 #此時的x1是x2, x2實際上是x3 下一次的賦值 x3=x1-q*x2 #y_i = y_(i-2)- a/b*y_(i-1) y1,y2 = y2,y1-q*y2 #因爲y的值取決於前兩次的值,而初值又給定,所以y值確定能算出,b是循環終止,因此能夠算出一對(x,y) return (x1,y1,a)
歐拉函數:
def oula(number): counter = 0 for i in range(1,number): if gcd(i,number)==1: #gcd(a,b)=1, a and b relatively prime counter+=1 return counter
RSA加解密的數學表示
加密 m ^ e mod n = c 解密 c ^ d mod n = m 代入 (m ^ e) ^ d mod n = m 得 m ^ (e*d) mod n = m => m ^ (e*d-1) mod n = 1 歐拉定理: m ^ φ(n) mod n = 1 所以 e*d-1 = k*φ(n) e * d - k*φ(n) = 1 a * x + b * y = 1
例子:
Alice發一個信息給Bob, 該信息的數數爲 m = 89
Bob首先要生成公鑰(n,e)和私鑰(n,d)
Bob 選取 p=53, q=59 做爲 n = p * q = 3127 Bob 任意選取 e=3 此時能夠計算出 φ(n)=(p-1)(q-1)=52*58=3016, 由於p,q是質數,一樣也能夠經過代碼計算oula(3127)=3016 計算私鑰:e * d - k * φ(n) = 1 3 * d + 3016*k = 1 由於並不在意k的值,但代入代碼中的(a,b)爲正數 經過代碼計算得出 exgcd(3,3016) d,k = -1005,1 d=-1005是個負數因此須要尋找另外一個解 3 *(3016-1005) + 3016*1 - 3*3016 d,k = 2011,-2 d = 2011 只要給出3016的整數倍,k就是整數,就是另外一個解 Bob給Alice (n=3127,e=3) Bob本身保存私鑰 (n=3127,d=2011)
Alice對信息進行加密
m ^ e mod n = c 89 ^ 3 mod 3127 = 1394 把 c=1394傳給Bob,這個是用(n,e)加密過的信息c,原始信息爲m
Bob用私鑰解密
c ^ d mod n = 1394 ^ 2011 mod 3127 = 89L 獲得原信息 m
RSA的安全性
知道 n, e, 能否算得出d,其中最重要的就是一個參數 φ(n),雖然我有代碼計算 oula(number),可是這並非那麼容易的事,運行程序隨着當number的位數增長,時間成倍的增長,暴力的破解是能夠破解,但若是要你花一萬年的時間呢,得不嘗失了,目前最多也就破了768位,當咱們的n是1024位時基本就是安全的,爲何選p,q爲質數呢,也在於當p,q爲質數時,算φ(n)=(p-1)(q-1),但若是你不知道p,q,由n來因式分解的話,就等死吧
參考:
http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=26403844&id=5065983 http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html http://www.wikiwand.com/zh/碾轉相除法