RSA大礼包
虚假的本科教学奖项:👍👍👍
真实的本科教学奖项:https://www.tr0y.wang/2017/11/06/CTFRSA/
关于RSA
先看了博客最后附的知乎链接,跟着思路走了一下
咱们要做的只是分解模数n
但是将两个足够大的素数的乘积再次分解成为了问题
如果 n 比较小,那么可以通过工具进行直接 n 分解,从而得到私钥。如果 n 的大小小于 256bit,那么我们通过本地工具即可爆破成功。例如采用 windows 平台的 RSATool 2v17,可以在几分钟内完成 256bit 的 n 的分解。
素数分解问题是困难的,但是可以通过计算机进行暴力分解。通常意义上来说,一般认为 2048bit 以上的 n 是安全的。现在一般的公钥证书都是 4096bit 的证书
如果两个n直接使用了相同的素数
gcd(n1,n2)
import gmpy2
# import math
import time
n1 = 9051013965404084482870087864821455535159008696042953021965631089095795348830954383127323853272528967729311045179605407693592665683311660581204886571146327720288455874927281128121117323579691204792399913106627543274457036172455814805715668293705603675386878220947722186914112990452722174363713630297685159669328951520891938403452797650685849523658191947411429068829734053745180460758604283051344339641429819373112365211739216160420494167071996438506850526168389386850499796102003625404245645796271690310748804327
n2 = 13225948396179603816062046418717214792668512413625091569997524364243995991961018894150059207824093837420451375240550310050209398964506318518991620142575926623780411532257230701985821629425722030608722035570690474171259238153947095310303522831971664666067542649034461621725656234869005501293423975184701929729170077280251436216167293058560030089006140224375425679571181787206982712477261432579537981278055755344573767076951793312062480275004564657590263719816033564139497109942073701755011873153205366238585665743
# t1=time.time()
p = gmpy2.gcd(n1, n2)
print ('gcd(n1, n2):\n', p)
q1 = n1 / p
q2 = n2 / p
print ('q1 is:\n', q1)
print ('q2 is:\n', q2)
# t2=time.time()
# print(t2-t1)
gmpy2的gcd要快很多。。
大数分解
https://zhuanlan.zhihu.com/p/267884783
https://blog.csdn.net/weixin_42251364/article/details/95462358
Pollard-Rho算法
rho算法其实是一种概率上的算法,虽然是靠概率,但是其准确率非常高(99.9%),更重要的是,该算法效率极高。其主要基于密码学当中的一个“生日悖论“来进行算法的设计。简单来讲就是,我们将N的两个因子x和y(就假设它有两个)从一大堆数里挑出来的概率非常小,但是如果我们挑满足x-y等于某个数的话,概率就要大很多。更进一步,如果我们找gcd(|x-y| ,N)呢?那么概率就会更大,就是这么个道理。
关于Rho算法,要注意有可能会进入死循环,也就是说我们要在算法中对其进行判圈,具体的做法是,每次a=f(a),再找一个b=f(f(b)),如果有一个时刻a=b那么就退出循环,因为b是以两倍的速度走得,当b追上了a,那么b至少已经走完一圈了。
原文链接:https://blog.csdn.net/The__Apollo/article/details/80279716
令p为n的最小素因子,存在x,x',x=x'(mod p),使得|x-x'|整除于n(),gcd(|x-x'|,n)
xi形成一个序列,而序列的优化则是Rho名字的来源
import math
from random import randint
from gmpy2 import *
n = 0x4333AF6B43F36028D8D9650EC3EED3238541EE5C15E626C58C9EC33674A6D08D5B1F2580A1A0B07E9D853536CD994E197889D122701A62BB2A9E79559F3D5281014535F6C54F83CA8D9700EEB67D99AF318D20A5150AD46D622A6A12DE0A758EE7DF75F5D10F2FE2585F2348537787063321FFDAC91BB3C3D1D88CBD04A824ED
x2 = 1
c = 7
while 1:
x1 = randint(1, n)
x2 = pow(x2, 2, n) + c % n
fac = gcd(abs(x1 - x2), n)
if fac > 1 and is_prime(fac):
print (fac)
break
print(n / fac)
Poland's p-1
需要分解n,则思想是需要n的因数。如果不能直接求因数则需要找一个不和n互质的数字num(暂定)从而通过gcd(n,num)求得n的因数之一
通过费马定理我们可以得知2^p-1=1(mod p)
,可以写作(2^p-1)-1=p*s
,那么num=gcd(n,p)
=gcd(n,p*s)
但是p的值未知,p-1的值未知,我们可以分析p-1可能有的最大素因数B(开方之后筛选最大素数?),则B!
是p-1的倍数,2B!是2p-1的倍数(指数幂)
from gmpy2 import *
def PollardRho_p_1(Q,N):
a = i = 2
while 1:
a = pow(a, i, N)//a^i(mod N)
d = gcd(a - 1, N)
if d != 1:
return d
i += 1
低加密指数攻击
低加密指数攻击:
假设e=3, 公钥中的加密指数e很小,但是模数n很大
有RSA加密公式: C=M^e % n (C密文,M明文)
则:
当M^e < n 时,
C = M^e ,所以对C开方就能得到M
当M^e > n 时,此时用爆破的方法
假设我们 M^e / n 的商为 k 余数为C,
则M^e = kn + C,对K进行爆破,只要k满足 kn + C能够开e次方就可以得明文
# -*- coding: cp936 -*-
import gmpy2
e = 3
# 读入 n, 密文
n= 22885480907469109159947272333565375109310485067211461543881386718201442106967914852474989176175269612229966461160065872310916096148216253429849921988412342732706875998100337754561586600637594798877898552625378551427864501926224989873772743227733285336042475675299391051376624685754547818835551263597996620383338263448888107691240136257201191331617560711786674975909597833383395574686942099700631002290836152972352041024137872983284691831292216787307841877839674258086005814225532597955826353796634417780156185485054141684249037538570742860026295194559710972266059844824388916869414355952432189722465103299013237588737
c= 15685364647213619014219110070569189770745535885901269792039052046431067708991036961644224230125219358149236447900927116989931929305133870392430610563331490276096858863490412102016758082433435355613099047001069687409209484751075897343335693872741
print ('n=', n)
print ('c=', c)
print '[+]Detecting m...'
result = gmpy2.iroot(c, 3)
print ' [-]The c has cubic root?', result[1]
if result[1]: print ' [-]The m is:', '{:x}'.format(result[0]).decode('hex')
print '[!]All Done!'
M^e足够小即可以直接爆破
低加密指数广播攻击
所谓广播
,就是发送方将一份明文进行多份加密,但是每份使用不同的密钥,即密钥中的模数n不同,但是指数e相同且很小,因此我们只要得到多份密文和对应的模数n就可以利用中国剩余定理进行解密。
CRT
# 信安数基CRT代码
import sys
def Get_Mi(m_list, M): # 获取所有的Mi
M_list = []
for mi in m_list:
M_list.append(M // mi)
return M_list
def Get_ei_list(M_list, m_list): # 取所有的Mi的逆元
ei_list = []
for i in range(len(M_list)):
ei_list.append(Get_ei(M_list[i], m_list[i])[0])
return ei_list
def Get_ei(a, b):
# 计算ei
if 0 == b:
x = 1;
y = 0;
q = a
return x, y, q
xyq = Get_ei(b, a % b)
x = xyq[0];
y = xyq[1];
q = xyq[2]
temp = x;
x = y;
y = temp - a // b * y
return x, y, q
def crt(a_list, m_list):
# 计算中国剩余定理,返回计算结果
M = 1 # M是所有mi的乘积
for mi in m_list:
M *= mi
Mi_list = Get_Mi(m_list, M)
Mi_inverse = Get_ei_list(Mi_list, m_list)
x = 0
for i in range(len(a_list)): # 开始计算x
x += Mi_list[i] * Mi_inverse[i] * a_list[i]
x %= M
return x
if __name__ == '__main__':
filename = input()
f = open(filename)
lines = f.readlines()
num = []
a_list = []
m_list = []
i = 0
for line in lines:
num.append(line.strip())
a_list = num[:3]
m_list = num[3:6]
m_list = [i for i in m_list if(len(str(i))!=0)]
a_list = list(map(int,a_list))
print(a_list)
m_list = list(map(int,m_list))
print(m_list)
print(crt(a_list, m_list))
import gmpy2
from functools import reduce
from Crypto.Util.number import long_to_bytes
# 中国剩余定理
def CRT(cipher, n):
N = reduce(lambda x, y: x * y, (i for i in n))
result = 0
data = zip(cipher, n)
for ci, ni in data:
Ni = N // ni
di = gmpy2.invert(Ni, ni)
result += ci * Ni * di
return result % N, N
x, N = CRT(c, n)
m = gmpy2.iroot(gmpy2.mpz(x), e)[0]
print(m)
print(long_to_bytes(m))
m,e相同,e和模数n已知,通过CRT求得m^e
iroot(m^e,e)
得到m
Coppersmith’s Method
格基规约算法
coppersmith 定理指出在一个 e 阶的 mod n 多项式 f(x)中,如果有一个根小于 n^(1/e),就可以运用一个 O(log n)的算法求出这些根。
共模攻击(使用相同的n)
如果在 RSA 的使用中使用了相同的模 n 对相同的明文 m 进行了加密,那么就可以在不分解 n 的情况下还原出明文 m 的值。即:
c1≡m^e1 mod n
c2≡m^e2 mod n
gcd(e1,e2)=1,存在s1e1+s2e2=1
https://zhuanlan.zhihu.com/p/451050633
对于不都为零的整数 a 和 b,gcd(a,b) 表示 a 和 b 的最大公约数。那么一定存在整数 x,y使得以下等式成立:
Gcd(a,b)=ax+by
则c1=m^e1 mod n,c2=m^e2 mod n
c1s1*c2s2=m^(s1e1+s2e2)=m (mod n)
n = 158052722013789461456896900244510199169216575693048895162538548356466884311543740968048825149608833390255268602486435690724338965409521812963337715301197225841194835534751041470231293288252951274190599189716955573428884560130364021535005115652592074445852835422027406556727605302404510264249211145063332337043
e = [665213, 368273]
c = [16698617641888248664694980135332125531792692516788088682722832061393117609508765284473236240256421599515450690670639565968165473479697383505401285976148490839526672808730165847471005704945978274496508928460578173068717106075169723401049489389383596761956301440156581021583368058047939083755488885694261340425L, 59192887933967939708054321952273893559113509451228797382728687616356609407020086787061368452871936378934964292805289941535766263083244529814852043063188312786173717046316177403357053871483983775362121186037776932260378728059531236711960979620603784044468207000654149190295060179235411429700710154759043236436L]
求 m
# -*- coding: cp936 -*-
import time
import gmpy2
n = 158052722013789461456896900244510199169216575693048895162538548356466884311543740968048825149608833390255268602486435690724338965409521812963337715301197225841194835534751041470231293288252951274190599189716955573428884560130364021535005115652592074445852835422027406556727605302404510264249211145063332337043
e = [665213, 368273]
c = [16698617641888248664694980135332125531792692516788088682722832061393117609508765284473236240256421599515450690670639565968165473479697383505401285976148490839526672808730165847471005704945978274496508928460578173068717106075169723401049489389383596761956301440156581021583368058047939083755488885694261340425L, 59192887933967939708054321952273893559113509451228797382728687616356609407020086787061368452871936378934964292805289941535766263083244529814852043063188312786173717046316177403357053871483983775362121186037776932260378728059531236711960979620603784044468207000654149190295060179235411429700710154759043236436L]
print '[+]Detecting m...'
time.clock()
c1 = c[0]
c2 = c[1]
e1 = e[0]
e2 = e[1]
s = gmpy2.gcdext(e1, e2)
s1 = s[1]
s2 = s[2]
# 求模反元素
if s1 < 0:
s1 = -s1
c1 = gmpy2.invert(c1, n)
elif s2 < 0:
s2 = -s2
c2 = gmpy2.invert(c2, n)
m = pow(c1, s1, n) * pow(c2, s2, n) % n
print ' [-]m is:' + '{:x}'.format(int(m)).decode('hex')
print '\n[!]Timer:', round(time.clock(),2), 's'
print '[!]All Done!'
低解密指数攻击
# 展开为连分数
def continuedFra(x, y):
cF = []
while y:
cF += [x / y]
x, y = y, x % y
return cF
def Simplify(ctnf):
numerator = 0
denominator = 1
for x in ctnf[::-1]:
numerator, denominator = denominator, x * denominator + numerator
return (numerator, denominator)
# 连分数化简
def calculateFrac(x, y):
cF = continuedFra(x, y)
cF = map(Simplify, (cF[0:i] for i in xrange(1, len(cF))))
return cF
# 连分数求解和化简
最终实现wiener‘s attack的部分为
def wienerAttack(e, n):
for (d, k) in calculateFrac(e, n):
if k == 0: continue
if (e * d - 1) % k != 0: continue
phi = (e * d - 1) / k
p, q = solve_pq(1, n - phi + 1, n) #根据韦达定理求解出来的p,q值
if p * q == n:
return abs(int(p)), abs(int(q))
print 'not find!'
关于赛题
赛题 https://blog.csdn.net/xiewenbonb/article/details/122396997
实现(直系白毛学姐博客) https://blog.csdn.net/m0_63571390/article/details/122375466