密钥的产生
(1)选两个保密的大素数p和q;
(2)计算,
,其中
是n的欧拉函数值,欧拉函数:小于n的正整数中与n互质的数的个数
当n=6,=2;当n=7,
=6;即当n为质数,欧拉函数值=n-1;
(3)选一整数,满足1<e<,且
(互质);
(4)计算e对于的模反元素d
一.共模攻击
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
在 RSA 加密算法里,假设使用两个不同的公钥指数 e1和 e2 对同一明文 m 进行加密,模数均为 n,那么会得到两个密文 c1 和 c2,
共模攻击是在 RSA 加密中,当两个不同的公钥指数 e1
和 e2
对同一明文 m
进行加密,且使用相同的模数 n
时,可以利用数学方法恢复出明文 m
。
扩展欧几里得算法(Extended Euclidean algorithm)是欧几里得算法(辗转相除法)的扩展,用于计算两个整数a和b的最大公约数d,同时还能找到整数x和y,使得ax+by=d。
在 RSA 共模攻击等场景中,计算两个公钥指数e1和e2的扩展欧几里得系数是很重要的步骤。扩展欧几里得算法可以帮助我们找到整数s1和s2,使得s1*e1+s2*e2=gcd(e1,e2)。当e1和e2互质时gcd(e1,e2)=1即s1*e1+s2*e2=1。
from Crypto.Util.number import *
import gmpy2
# 共模攻击函数
def attack(n, e1, e2, c1, c2):
# 计算 e1 和 e2 的扩展欧几里得系数
g, s1, s2 = gmpy2.gcdext(e1, e2)
if g != 1:
raise ValueError("e1 和 e2 不互质,无法进行共模攻击")
if s1 < 0:
s1 = -s1
c1 = gmpy2.invert(c1, n)
if s2 < 0:
s2 = -s2
c2 = gmpy2.invert(c2, n)
# 计算明文 m
m = pow(c1, s1, n) * pow(c2, s2, n) % n #幂取模运算:c1的s1次幂对n取余
return int(m)
flag1 = 100156221476910922393504870369139942732039899485715044553913743347065883159136513788649486841774544271396690778274591792200052614669235485675534653358596366535073802301361391007325520975043321423979924560272762579823233787671688669418622502663507796640233829689484044539829008058686075845762979657345727814280
flag2 = 86203582128388484129915298832227259690596162850520078142152482846864345432564143608324463705492416009896246993950991615005717737886323630334871790740288140033046061512799892371429864110237909925611745163785768204802056985016447086450491884472899152778839120484475953828199840871689380584162839244393022471075
e1 = 3247473589
e2 = 3698409173
n = 103606706829811720151309965777670519601112877713318435398103278099344725459597221064867089950867125892545997503531556048610968847926307322033117328614701432100084574953706259773711412853364463950703468142791390129671097834871371125741564434710151190962389213898270025272913761067078391308880995594218009110313
# 调用共模攻击函数
m = attack(n, e1, e2, flag1, flag2)
print(long_to_bytes(m))
二.
from Cryptodome.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
主要思路是利用两个 RSA 模数 n1
和 n2
存在相同素因子 p
的特点,通过计算最大公约数 GCD(n1, n2)
得到公因子 p
,进而计算出各自的私钥指数 d1
和 d2
,最后完成解密
from Crypto.Util.number import long_to_bytes, bytes_to_long, GCD
# 给定的密文和模数
c = 60406168302768860804211220055708551816238816061772464557956985699400782163597251861675967909246187833328847989530950308053492202064477410641014045601986036822451416365957817685047102703301347664879870026582087365822433436251615243854347490600004857861059245403674349457345319269266645006969222744554974358264
n1 = 103835296409081751860770535514746586815395898427260334325680313648369132661057840680823295512236948953370895568419721331170834557812541468309298819497267746892814583806423027167382825479157951365823085639078738847647634406841331307035593810712914545347201619004253602692127370265833092082543067153606828049061
n2 = 115383198584677147487556014336448310721853841168758012445634182814180314480501828927160071015197089456042472185850893847370481817325868824076245290735749717384769661698895000176441497242371873981353689607711146852891551491168528799814311992471449640014501858763495472267168224015665906627382490565507927272073
e = 65537
# 计算两个模数的最大公约数,得到共享的素因子 p
p = GCD(n1, n2)
# 计算 n1 对应的另一个素因子 q1
q1 = n1 // p
# 计算 n2 对应的另一个素因子 q2
q2 = n2 // p
# 验证 p 和 q1 的乘积是否等于 n1
assert p * q1 == n1
# 验证 p 和 q2 的乘积是否等于 n2
assert p * q2 == n2
# 计算 n1 的欧拉函数值 phi1
phi1 = (p - 1) * (q1 - 1)
# 计算 e 模 phi1 的乘法逆元 d1
d1 = pow(e, -1, phi1)
# 使用私钥指数 d1 对密文 c 进行解密,得到明文 m
m = pow(c, d1, n1)
# 将解密得到的整数明文转换为字节串并打印
print(long_to_bytes(m))
三.认识RSA
from Crypto.Util.number import *
from secret import flag
m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
e = 65537
n = p*q
c = pow(m,e,n)
print(f'p = {p}')
print(f'q = {q}')
print(f'c = {c}')
'''
p = 12567387145159119014524309071236701639759988903138784984758783651292440613056150667165602473478042486784826835732833001151645545259394365039352263846276073
q = 12716692565364681652614824033831497167911028027478195947187437474380470205859949692107216740030921664273595734808349540612759651241456765149114895216695451
c = 108691165922055382844520116328228845767222921196922506468663428855093343772017986225285637996980678749662049989519029385165514816621011058462841314243727826941569954125384522233795629521155389745713798246071907492365062512521474965012924607857440577856404307124237116387085337087671914959900909379028727767057
'''
import gmpy2
from Crypto.Util.number import long_to_bytes
e=65537
p = 12567387145159119014524309071236701639759988903138784984758783651292440613056150667165602473478042486784826835732833001151645545259394365039352263846276073
q = 12716692565364681652614824033831497167911028027478195947187437474380470205859949692107216740030921664273595734808349540612759651241456765149114895216695451
c = 108691165922055382844520116328228845767222921196922506468663428855093343772017986225285637996980678749662049989519029385165514816621011058462841314243727826941569954125384522233795629521155389745713798246071907492365062512521474965012924607857440577856404307124237116387085337087671914959900909379028727767057
n=p*q
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
四.变相求解p,q
('c=', '0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9eL')
('e=', '0x872a335')
#q + q*p^3 =1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586
#qp + q *p^2 = 1109691832903289208389283296592510864729403914873734836011311325874120780079555500202475594
from Crypto.Util.number import *
c=0x7a7e031f14f6b6c3292d11a41161d2491ce8bcdc67ef1baa9e
e=0x872a335
#q + qp^3=q(1p^3)=q(1+p)(p^2-q+1)=hint1
hint1=1285367317452089980789441829580397855321901891350429414413655782431779727560841427444135440068248152908241981758331600586
#qp + qp^2 =qp(1+p)=hint2
hint2=1109691832903289208389283296592510864729403914873734836011311325874120780079555500202475594
t=GCD(hint1,hint2)//最大公约数
p=hint2//t
q=t//(p+1)
n=p*q
phi=(p-1)*(q-1)
d=inverse(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
1. 提示信息的数学表达式
在 RSA 加密算法的这个特殊情境下,我们已知两个提示信息:
hint1 = q + q * p^3 = q(1 + p)(p^2 - p + 1)
hint2 = qp + q * p^2 = q * p*(p + 1)
可以看到,hint1
和 hint2
这两个表达式存在公因式 q(p + 1)
。
2. 最大公约数的作用
t = GCD(hint1, hint2)
通过计算 hint1
和 hint2
的最大公约数,我们能够提取出它们的公因式。因为最大公约数的定义就是能同时整除两个数的最大正整数,在这种情况下,GCD(hint1, hint2)
会得到 q(p + 1)
,也就是 t = q(p + 1)
。
3. 基于最大公约数求解素数
求解素数 p
p = hint2 // t
由于 hint2 = q * p*(p + 1)
,而 t = q(p + 1)
,那么 hint2
除以 t
时,公因式 q(p + 1)
会被消去,从而得到素数 p
。即 hint2 // t = (q * p*(p + 1)) // (q(p + 1)) = p
。
求解素数 q
q = t // (p + 1)
已经得到 t = q(p + 1)
,那么 t
除以 (p + 1)
就可以得到素数 q
,即 t // (p + 1) = q(p + 1) // (p + 1) = q
。
五.认识rsa
p=0x928fb6aa9d813b6c3270131818a7c54edb18e3806942b88670106c1821e0326364194a8c49392849432b37632f0abe3f3c52e909b939c91c50e41a7b8cd00c67d6743b4f q=0xec301417ccdffa679a8dcc4027dd0d75baf9d441625ed8930472165717f4732884c33f25d4ee6a6c9ae6c44aedad039b0b72cf42cab7f80d32b74061 e=0x10001 c=0x70c9133e1647e95c3cb99bd998a9028b5bf492929725a9e8e6d2e277fa0f37205580b196e5f121a2e83bc80a8204c99f5036a07c8cf6f96c420369b4161d2654a7eccbdaf583204b645e137b3bd15c5ce865298416fd5831cba0d947113ed5be5426b708b89451934d11f9aed9085b48b729449e461ff0863552149b965ax
将p,q,e转换成十进制的数字
from Crypto.Util.number import *
from gmpy2 import *
p = 0x928fb6aa9d813b6c3270131818a7c54edb18e3806942b88670106c1821e0326364194a8c49392849432b37632f0abe3f3c52e909b939c91c50e41a7b8cd00c67d6743b4f
q = 0xec301417ccdffa679a8dcc4027dd0d75baf9d441625ed8930472165717f4732884c33f25d4ee6a6c9ae6c44aedad039b0b72cf42cab7f80d32b74061
e = 0x10001
p = int(p)
q = int(q)
e = int(e)
n = p * q
c = 0x70c9133e1647e95c3cb99bd998a9028b5bf492929725a9e8e6d2e277fa0f37205580b196e5f121a2e83bc80a8204c99f5036a07c8cf6f96c420369b4161d2654a7eccbdaf583204b645e137b3bd15c5ce865298416fd5831cba0d947113ed5be5426b708b89451934d11f9aed9085b48b729449e461ff0863552149b965e22b6
c = int(c)
#计算欧拉函数值
phi = (p - 1) * (q - 1)
#计算私钥指数 d:使用 invert 函数计算 e 模 phi 的乘法逆元 d。
d = invert(e, phi)
m = powmod(c, d, n)
print(long_to_bytes(m))
六.小明文加密
flag= 25166751653530941364839663846806543387720865339263370907985655775152187319464715737116599171477207047430065345882626259880756839094179627032623895330242655333 n= 134109481482703713214838023035418052567000870587160796935708584694132507394211363652420160931185332280406437290210512090663977634730864032370977407179731940068634536079284528020739988665713200815021342700369922518406968356455736393738946128013973643235228327971170711979683931964854563904980669850660628561419
题目只有flag和n,试试低加密指数,小明文e的范围只有1-3,不断递增 e
的值,直至 flag
能够被 e
次开方得到一个整数结果,最后将开方结果转换为字节串并输出。
from Crypto.Util.number import *
from gmpy2 import *
flag= 25166751653530941364839663846806543387720865339263370907985655775152187319464715737116599171477207047430065345882626259880756839094179627032623895330242655333
n= 134109481482703713214838023035418052567000870587160796935708584694132507394211363652420160931185332280406437290210512090663977634730864032370977407179731940068634536079284528020739988665713200815021342700369922518406968356455736393738946128013973643235228327971170711979683931964854563904980669850660628561419
e=2
while iroot(flag,e)[1]==0:
e=e+1
print(long_to_bytes(iroot(flag,e)[0]))
#小明文爆破出e的值
七.factordb素数分解
from Crypto.Util.number import * flag = b'NSSCTF{******}' p = getPrime(256) q = getPrime(256) n = p*q e = 65537 phi = (p-1)*(q-1) m = bytes_to_long(flag) c = pow(m, e, n) print(f'n = {n}') print(f'e = {e}') print(f'c = {c}') ''' n = 7382582015733895208810490097582153009797420348201515356767397357174775587237553842395468027650317457503579404097373070312978350435795210286224491315941881 e = 65537 c = 6511001389892474870028836129813814173158254564777610289284056550272120510686249909340499673868720839756059423749304765055919251717618117507007046973023557 '''
已知n,求解p,q,可以使用yafu进行分解,一种是使用在线网站factordb进行分解,后者更快一些,factordb网址:factordb.com
import gmpy2
from Crypto.Util.number import long_to_bytes
e = 65537
p = 104660876276442216612517835199819767034152013287345576481899196023866133215633
q = 70538125404512947763739093348083497980212021962975762144416432920656660487657
c = 6511001389892474870028836129813814173158254564777610289284056550272120510686249909340499673868720839756059423749304765055919251717618117507007046973023557
n=p*q
phi=(p-1)*(q-1)#计算欧拉函数值
d=gmpy2.invert(e,phi)#该语句的主要功能是计算整数 e 在模 phi 意义下的乘法逆元,并将结果赋值给变量 d。在数论中,对于整数 e 和正整数 phi,如果存在整数 d 使得 (e * d) % phi == 1,那么就称 d 是 e 模 phi 的乘法逆元。
m=pow(c,d,n)#计算 c 的 d 次幂对 n 取模的结果
print(long_to_bytes(m))
八.相邻素数分解
from Crypto.Util.number import * import gmpy2 flag = b'NSSCTF{******}' p = getPrime(512) q = gmpy2.next_prime(p) n = p*q e = 65537 phi = (p-1)*(q-1) m = bytes_to_long(flag) c = pow(m, e, n) print(f'n = {n}') print(f'e = {e}') print(f'c = {c}') ''' n = 115637000420176820831322601039129424406844427046456738651883381559357542765613732363445112111006849040385859313572091386802534464534403117787314180179562651607533039692795522388596550968316951090748054495960090527479954143448774136390568881020918710834542819900918984139672802889774720153267841255456602500057 e = 65537 c = 98161406745910866780822530171878255235776133393411573803496865047700715941955255328757920065032397556905095591171977170479344602512244671081108703687450560269408412671849929423399172588599903975793985819498354819305128607934552101433664794909855378636055525016664559476808490723554481335856183927702549281730 '''
1.素数分解范围确定
由于 p
和 q
是相邻的素数且 n = p * q
,那么 p
和 q
应该比较接近。所以可以从
附近开始寻找可能的素数。
2.素数判断
需要一个函数来判断一个数是否为素数。
3.寻找相邻素数对
从 附近开始,分别向两边寻找素数,然后检查它们的乘积是否等于
n
。
import gmpy2
import sympy
from Crypto.Util.number import *
import binascii
n = 115637000420176820831322601039129424406844427046456738651883381559357542765613732363445112111006849040385859313572091386802534464534403117787314180179562651607533039692795522388596550968316951090748054495960090527479954143448774136390568881020918710834542819900918984139672802889774720153267841255456602500057
x = gmpy2.iroot(n, 2)[0] # 取第0个元素,也就是第一个元素
p = sympy.nextprime(x)
q = n // p
e = 65537
d = gmpy2.invert(e, (p - 1) * (q - 1))//e对于phi(n)的模反元素d
print(p)
print(q)
print(d)
c = 98161406745910866780822530171878255235776133393411573803496865047700715941955255328757920065032397556905095591171977170479344602512244671081108703687450560269408412671849929423399172588599903975793985819498354819305128607934552101433664794909855378636055525016664559476808490723554481335856183927702549281730
m = pow(c, d, n)
print(m)
print(long_to_bytes(m))
4.解释代码:x = gmpy2.iroot(n, 2)[0]
1.gmpy2.iroot
函数用于计算一个数的整数根。它的语法如下:
gmpy2.iroot(x, n)
- 参数:
x
:要计算根的数,通常为一个大整数。n
:要计算的根的次数,是一个正整数。
2. gmpy2.iroot
函数的返回值
gmpy2.iroot(x, n)
函数会返回一个包含两个元素的元组,格式如下:
(root, is_exact)
root
:是计算所得的整数根(向下取整)。也就是说,它是小于等于x
的n
次根的最大整数。is_exact
:是一个布尔类型的值,用来表明计算出的根是否精确。若root
的n
次幂恰好等于x
,则is_exact
为True
;反之则为False。
3. [0]
的作用
在 Python 中,元组和列表等序列类型的数据,可以通过方括号 []
加索引值来访问其中的元素,索引是从 0 开始计数的。所以 [0]
表示取元组里的第一个元素。
在代码 x = gmpy2.iroot(n, 2)[0]
中,使用 [0]
就是要从 gmpy2.iroot(n, 2)
返回的元组里提取出整数根 root
,并将其赋值给变量 x
。而返回元组里的第二个元素 is_exact
则被忽略了。
九、多/非素数
from Crypto.Util.number import *
flag = b'NSSCTF{******}' + b'1'*100
p = getPrime(256)
q = getPrime(256)
n = (p**3) * q
e = 65537
phi = (p-1)*(q-1)
m = bytes_to_long(flag)
c = pow(m, e, n)
print(f'p = {p}')
print(f'q = {q}')
print(f'e = {e}')
print(f'c = {c}')
'''
p = 80505091208742938705306670241621545375764148093711243653439069254008824979403
q = 67599990875658931406915486208971556223245451500927259766683936131876689508521
e = 65537
c = 7958690969908064264211283192959937430539613460471121984649054121171267262097603091410178042319139582772142226087020110084551158367679146616732446561228522673699836019156243452069036383047309578614662564794584927846163157472211089368697387945469398750955336949678910159585015004994620777231073804301249774041
'''
观察题目发现素数p实际为p**3,不是素数
根据欧拉函数的性质
当p是素数时,φ(p)=p-1。
当且只当n可以分解成两个互质的整数之积,n = p1 × p2,则φ(n) = φ(p1p2) = φ(p1)φ(p2)
特别的,对于两个素数p,q, φ(pq)=(p-1)(q-1)。(RSA算法应用)
若n是质数p的k次幂,
from Crypto.Util.number import *
import gmpy2
flag = (b'NSSCTF{******}'+ b'1'*100)
p = 80505091208742938705306670241621545375764148093711243653439069254008824979403
q = 67599990875658931406915486208971556223245451500927259766683936131876689508521
n = (p**3) * q
e = 65537
c = 7958690969908064264211283192959937430539613460471121984649054121171267262097603091410178042319139582772142226087020110084551158367679146616732446561228522673699836019156243452069036383047309578614662564794584927846163157472211089368697387945469398750955336949678910159585015004994620777231073804301249774041
phi = (p**3-p**2)*(q-1)
d=gmpy2.invert(e,phi)
m = pow(c, d, n)
print( long_to_bytes(m))
十、逆元不存在/不止p,q
from Crypto.Util.number import *
flag = b'NSSCTF{******}'
p = getPrime(512)
q = getPrime(512)
e = 65537
while True:
r = 2*getPrime(100)*e+1
if isPrime(r):
break
n = p*q*r
m = bytes_to_long(flag)
c = pow(m, e, n)
print(f'p = {p}')
print(f'q = {q}')
print(f'r = {r}')
print(f'e = {e}')
print(f'c = {c}')
'''
p = 7478755670255767435237487693415479182290330775502792675052667363676831056436638619069277770540533350723045234676443621124912287506103439704868369839725279
q = 9232828888049557325429111621080998490274442347556398052322580869768941301413255711626092627273543579067597113958627672298942570149816938335701615759283713
r = 102909133680612532601801231903654039
e = 65537
c = 142893174944324070830219394465469685943669308818639857030565389839224452373848570577201378981080333784852764502832587008270072323948511579823852437852643609820245476634896477031076952735298279618952398460203032125853063235638358942643559551563899381032067185778629120272032518475352761100115057449043142848203976076694124978394099839339406197
'''
这道题多了个素数r,但是不需要用直接解码
from Crypto.Util.number import *
import gmpy2
flag = b'NSSCTF{******}'
p = getPrime(512)
q = getPrime(512)
e = 65537
while True:
r = 2*getPrime(100)*e+1
if isPrime(r):
break
p = 7478755670255767435237487693415479182290330775502792675052667363676831056436638619069277770540533350723045234676443621124912287506103439704868369839725279
q = 9232828888049557325429111621080998490274442347556398052322580869768941301413255711626092627273543579067597113958627672298942570149816938335701615759283713
r = 102909133680612532601801231903654039
e = 65537
c = 142893174944324070830219394465469685943669308818639857030565389839224452373848570577201378981080333784852764502832587008270072323948511579823852437852643609820245476634896477031076952735298279618952398460203032125853063235638358942643559551563899381032067185778629120272032518475352761100115057449043142848203976076694124978394099839339406197
n = p*q
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
十一、yafu素数分解
from Crypto.Util.number import *
flag = b'NSSCTF{******}'
p = getPrime(128)
q = getPrime(128)
n = p*q
e = 65537
phi = (p-1)*(q-1)
m = bytes_to_long(flag)
c = pow(m, e, n)
print(f'n = {n}')
print(f'e = {e}')
print(f'c = {c}')
'''
n = 53690629441472827148854210396580805205350972614395425306316047967905824330731
e = 65537
c = 22130296334673852790451396673112575082637108306697684532954477845025885087040
'''
拿到之后只有n,如果还用factordb分解速度太慢,这时候就要引入一个新的分解工具yafu,这是安装教程:基于RSA解题时yafu的使用-优快云博客
from Crypto.Util.number import *
import gmpy2
p= 277349599849597463956171076348973750041
q= 193584665240506752994134779660255197091
c = 22130296334673852790451396673112575082637108306697684532954477845025885087040
n = 53690629441472827148854210396580805205350972614395425306316047967905824330731
phi = (p-1)*(q-1)
e = 65537
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
十二、费马分解
from Crypto.Util.number import *
import gmpy2
flag = b'NSSCTF{******}'
p = getPrime(512)
q = gmpy2.next_prime(p - getPrime(256))
n = p*q
e = 65537
phi = (p-1)*(q-1)
m = bytes_to_long(flag)
c = pow(m, e, n)
print(f'n = {n}')
print(f'e = {e}')
print(f'c = {c}')
'''
n = 148841588941490812589697505975986386226158446072049530534135525236572105309550985274214825612079495930267744452266230141871521931612761645600600201983605957650711248808703757693378777706453580124982526368706977258199152469200838211055230241296139605912607613807871432800586045262879581100319519318390454452117
e = 65537
c = 69038543593219231496623016705860610154255535760819426453485115089535439537440188692852514795648297200067103841434646958466720891016026061658602312900242658759575613625726750416539176437174502082858413122020981274672260498423684555063381678387696096811975800995242962853092582362805345713900308205654744774932
'''
费马小定理是数论中的一个重要定理,它表述为:如果 p 是一个质数,a 是一个整数且 1≤a≤p,那么
。另外一种等价的表述是对于任意整数 a,都有
。
from sympy.ntheory import factorint
from Crypto.Util.number import *
import gmpy2
def factorize_large_n(n):
factors = factorint(n)
if len(factors) == 2 and all(exp == 1 for exp in factors.values()):
p, q = factors.keys()
return p, q
return None, None
n = 148841588941490812589697505975986386226158446072049530534135525236572105309550985274214825612079495930267744452266230141871521931612761645600600201983605957650711248808703757693378777706453580124982526368706977258199152469200838211055230241296139605912607613807871432800586045262879581100319519318390454452117
p, q = factorize_large_n(n)
if p and q:
print(f"p = {p}, q = {q}")
else:
print("未找到合适的 p 和 q 或 n 不符合要求")
e = 65537
c = 69038543593219231496623016705860610154255535760819426453485115089535439537440188692852514795648297200067103841434646958466720891016026061658602312900242658759575613625726750416539176437174502082858413122020981274672260498423684555063381678387696096811975800995242962853092582362805345713900308205654744774932
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
十三、dp泄露
from Crypto.Util.number import *
e=65537
m=bytes_to_long(b'xxxx')
p=getPrime(512)
q=getPrime(512)
n=p*q
phi=(p-1)*(q-1)
d=inverse(e,phi)
dp=d%(p-1)
c=pow(m,e,n)
print("dp=",dp)
print("n=",n)
print("c=",c)
#dp= 5892502924236878675675338970704766304539618343869489297045857272605067962848952532606770917225218534430490745895652561015493032055636004130931491316020329
#n= 50612159190225619689404794427464916374543237300894011803225784470008992781409447214236779975896311093686413491163221778479739252804271270231391599602217675895446538524670610623369953168412236472302812808639218392319634397138871387898452935081756580084070333246950840091192420542761507705395568904875746222477
#c= 39257649468514605476432946851710016346016992413796229928386230062780829495844059368939749930876895443279723032641876662714088329296631207594999580050131450251288839714711436117326769029649419789323982613380617840218087161435260837263996287628129307328857086987521821533565738409794866606381789730458247531619
- 明确已知条件:已知公钥中的加密指数e、模数n,密文c以及泄露的dp。其中
。
- 推导计算p的式子:由
,两边同乘e有
。又因为
,所以
,其中k为某个整数。由于
,所以k<e。
- 计算p的值:
- 遍历法(e较小时):可以遍历k的取值,范围是1到(e-1)。对于每个k,计算
,并检查p是否能整除n。如果能整除,则找到了正确的p,然后通过
得到q。
- 遍历法(e较小时):可以遍历k的取值,范围是1到(e-1)。对于每个k,计算
- 恢复私钥d:计算出p和q后,根据
,再利用扩展欧几里得算法计算d,使得
。
- 解密消息:有了私钥d,就可以对密文c进行解密,得到明文
。
import gmpy2
from Crypto.Util.number import *
e=65537
'''
m=bytes_to_long(b'xxxx')
p=getPrime(512)
q=getPrime(512)
n=p*q
phi=(p-1)*(q-1)
d=inverse(e,phi)
dp=d%(p-1)
c=pow(m,e,n)
print("dp=",dp)
print("n=",n)
print("c=",c)
'''
dp= 5892502924236878675675338970704766304539618343869489297045857272605067962848952532606770917225218534430490745895652561015493032055636004130931491316020329
n= 50612159190225619689404794427464916374543237300894011803225784470008992781409447214236779975896311093686413491163221778479739252804271270231391599602217675895446538524670610623369953168412236472302812808639218392319634397138871387898452935081756580084070333246950840091192420542761507705395568904875746222477
c= 39257649468514605476432946851710016346016992413796229928386230062780829495844059368939749930876895443279723032641876662714088329296631207594999580050131450251288839714711436117326769029649419789323982613380617840218087161435260837263996287628129307328857086987521821533565738409794866606381789730458247531619
for i in range(1,65538):
if (dp*e-1)%i == 0:
if n%(((dp*e-1)//i)+1)==0:
p=((dp*e-1)//i)+1
q=n//(((dp*e-1)//i)+1)
phi = (p-1)*(q-1)
break
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))