RSA共模攻击
利用场景
俩次加密使用了相同的N,有不同的e和c。即已知条件:e1,e2,c1,c2,n;
根据
gcd(e1, e2) = 1
m = c1^d1 mod n
m = c2^d2 mod n
求m。
推导过程
先引入 欧几里德扩展算法 :
扩展欧几里得算法用于求解两个整数的最大公约数(GCD)以及相应的贝祖等式(Bézout’s identity)。
对于俩个整数e1和e2,如果它们的最大公约数为1,即gcd(e1, e2) = 1
,那么存在整数s1和s2,使得
e1*s1 + e2*s2 = 1
这个等式表达了 e1 和 e2 的线性组合等于 1,其中 s1 和 s2 是整数。
所以根据欧几里德扩展算法,已知e1*s1 + e2*s2 = 1
。
因为
c1 = m^e1 mod n
c2 = m^e2 mod n
所以
(c1^s1*c2^s2) mod n = ((m^e1 mod n)^s1*(m^e2 mod n)^s2) mod n
即
(c1^s1*c2^s2) mod n = (m^(e1^s1 + e2^s2)) mod n
所以
(c1^s1*c2^s2) mod n = (m^(1)) mod n
即
c1^s1*c2^s2= m
可以得证 m
注意的点:
因为 e1*s1 + e2*s2 = 1
这里可知 s1和s2中有一个为负数,在计算时需要判断哪一个为负数并进行模反转。
利用公式:
gcd, s, t = gmpy2.gcdext(e1, e2)
这里使用了 gmpy2 库中的 gcdext
函数来计算两个整数 e1
和 e2
的最大公约数以及相应的 Bézout 系数。贝祖系数就是 s1和 s2;
例题分析
[SWPUCTF 2021 新生赛]crypto2
from gmpy2 import *
from Crypto.Util.number import *
flag = '***************'
p = getPrime(512)
q = getPrime(512)
m1 = bytes_to_long(bytes(flag.encode()))
n = p*q
e1 = getPrime(32)
e2 = getPrime(32)
print()
flag1 = pow(m1,e1,n)
flag2 = pow(m1,e2,n)
print('flag1= '+str(flag1))
print('flag2= '+str(flag2))
print('e1= ' +str(e1))
print('e2= '+str(e2))
print('n= '+str(n))
#flag1= 100156221476910922393504870369139942732039899485715044553913743347065883159136513788649486841774544271396690778274591792200052614669235485675534653358596366535073802301361391007325520975043321423979924560272762579823233787671688669418622502663507796640233829689484044539829008058686075845762979657345727814280
#flag2= 86203582128388484129915298832227259690596162850520078142152482846864345432564143608324463705492416009896246993950991615005717737886323630334871790740288140033046061512799892371429864110237909925611745163785768204802056985016447086450491884472899152778839120484475953828199840871689380584162839244393022471075
#e1= 3247473589
#e2= 3698409173
#n= 103606706829811720151309965777670519601112877713318435398103278099344725459597221064867089950867125892545997503531556048610968847926307322033117328614701432100084574953706259773711412853364463950703468142791390129671097834871371125741564434710151190962389213898270025272913761067078391308880995594218009110313
已知条件c1,c2,e1,e2,n,且e1和e2互素。
EXP:
from Crypto.Util.number import long_to_bytes
from gmpy2 import gmpy2, invert
c1 = 100156221476910922393504870369139942732039899485715044553913743347065883159136513788649486841774544271396690778274591792200052614669235485675534653358596366535073802301361391007325520975043321423979924560272762579823233787671688669418622502663507796640233829689484044539829008058686075845762979657345727814280
c2 = 86203582128388484129915298832227259690596162850520078142152482846864345432564143608324463705492416009896246993950991615005717737886323630334871790740288140033046061512799892371429864110237909925611745163785768204802056985016447086450491884472899152778839120484475953828199840871689380584162839244393022471075
e1 = 3247473589
e2 = 3698409173
n = 103606706829811720151309965777670519601112877713318435398103278099344725459597221064867089950867125892545997503531556048610968847926307322033117328614701432100084574953706259773711412853364463950703468142791390129671097834871371125741564434710151190962389213898270025272913761067078391308880995594218009110313
gcd, s, t = gmpy2.gcdext(e1, e2)
if s < 0:
s = -s
c1 = invert(c1, n)
elif t < 0:
t = -t
c2 = invert(c2, n)
m = pow(c1, s, n) * pow(c2, t, n) % n
print(long_to_bytes(m))
参考文章:https://1ablades.github.io/2017/08/09/RSA%E5%85%B1%E6%A8%A1%E6%94%BB%E5%87%BB/
https://ctf-wiki.org/crypto/asymmetric/rsa/rsa_module_attack/#_7
RSA共享素数
攻击原理
当存在两个公钥的 N 不互素时,我们显然可以直接对这两个数求最大公因数,然后直接获得 p,q,进而获得相应的私钥。
例题分析
[羊城杯 2021]Bigrsa
题目
from Crypto.Util.number import *
from flag import *
n1 = 103835296409081751860770535514746586815395898427260334325680313648369132661057840680823295512236948953370895568419721331170834557812541468309298819497267746892814583806423027167382825479157951365823085639078738847647634406841331307035593810712914545347201619004253602692127370265833092082543067153606828049061
n2 = 115383198584677147487556014336448310721853841168758012445634182814180314480501828927160071015197089456042472185850893847370481817325868824076245290735749717384769661698895000176441497242371873981353689607711146852891551491168528799814311992471449640014501858763495472267168224015665906627382490565507927272073
e = 65537
m = bytes_to_long(flag)
c = pow(m, e, n1)
c = pow(c, e, n2)
print("c = %d" % c)
# output
# c = 60406168302768860804211220055708551816238816061772464557956985699400782163597251861675967909246187833328847989530950308053492202064477410641014045601986036822451416365957817685047102703301347664879870026582087365822433436251615243854347490600004857861059245403674349457345319269266645006969222744554974358264
n1 和 n2 都不能直接分解,且n1和n2互质。
EXP:
from Crypto.Util.number import *
n1 = 103835296409081751860770535514746586815395898427260334325680313648369132661057840680823295512236948953370895568419721331170834557812541468309298819497267746892814583806423027167382825479157951365823085639078738847647634406841331307035593810712914545347201619004253602692127370265833092082543067153606828049061
n2 = 115383198584677147487556014336448310721853841168758012445634182814180314480501828927160071015197089456042472185850893847370481817325868824076245290735749717384769661698895000176441497242371873981353689607711146852891551491168528799814311992471449640014501858763495472267168224015665906627382490565507927272073
e = 65537
c = 60406168302768860804211220055708551816238816061772464557956985699400782163597251861675967909246187833328847989530950308053492202064477410641014045601986036822451416365957817685047102703301347664879870026582087365822433436251615243854347490600004857861059245403674349457345319269266645006969222744554974358264
q = GCD(n1,n2)
p1 = n1 // q
p2 = n2 // q
d1 = inverse(e, (q-1)*(p1-1))
d2 = inverse(e, (q-1)*(p2-1))
print(long_to_bytes(pow(pow(c, d2, n2), d1, n1)))