2022年 HSC-1th中CRYPTO的BABY-RSA
照例下载附件,是 py 文件:
from Crypto.Util.number import *
def lfsr(status,mask):
out = (status << 1) & 0xffffffff
i=(status&mask)&0xffffffff
lastbit=0
while i!=0:
lastbit^=(i&1)
i=i>>1
out^=lastbit
return (out,lastbit)
status= 1
mask = 0b10110001110010011100100010110101
num = bytes_to_long(m)
p = getPrime(1024)
q = getPrime(1024)
n = p*q
e = 65537
hp = bin(p)[2:]
c = pow(num, e, n)
print("n=",n)
print("c=",c)
f=open("key","w+",encoding='utf-8')
for i in range(568):
curnum = int(hp[i])
(status,out)=lfsr(status,mask)
f.write(str(curnum ^ out))
f.close()
'''
n= 9363543374665338283861145656340115756598328744870620756798779080826725774691364161648335378062705433999048117564356637094421930886166369832353405527855104576202658647651524758179962855692461154859961903531990172279764099199157181167775307950690492969859829926808950964120678082460448847927074487568619536568740301649988555476490206693181162301088156855926656544441682939839165455244630182978802660669255401576213941067679888164237586879364615664942234247896214195262510935345922512831632385741735810122730130366521612834556565838623708828780093323310348242654778247293430853566054703991781432542625271396246500576703
c= 3641304537029815746727163894554557322382012539953948183406308231174259571263608621970973671202001456955622458371303424750815017578104069924877881162707673935496925529412748663209884628320657034190702348924814794263041483260377960569530869386619921425415323912964305979776909598200202236912823968867485696101691879580799000240715778010424877093758489309380968229017074542588151574195295436881889313935734282141447498134543053106463951864974512375314091440713165047188590693431938599822340588934591712592995622334522799914563528630705687647950894928965913199772209825508001274120556508220248069647851360567609656517789
'''
. . 一看 lfsr 我开心了一下,我研究过这个:
https://blog.csdn.net/xiao__1bai/article/details/120392307
后来又哭了,果然还是研究得不透彻,稍微变一下式就卡住了,就那里怎么求出原来的 out 就想了很久~
后来在不断尝试后逐渐有了思路 lfsr 加密函数中传入的两个参数 status ,mask 都是固定 的,那么 return (out,lastbit) 不也是固定的吗?这样就可以求出原来的 out 了啊!
from Crypto.Util.number import *
m = open("flag.txt","rb").read()
def lfsr(status,mask):
out = (status << 1) & 0xffffffff
i=(status&mask)&0xffffffff
lastbit=0
while i!=0:
lastbit^=(i&1)
i=i>>1
out^=lastbit
return (out,lastbit)
status= 1
mask = 0b10110001110010011100100010110101
num = bytes_to_long(m)
p = getPrime(1024)
q = getPrime(1024)
n = p*q
e = 65537
hp = bin(p)[2:]
c = pow(num, e, n)
f=open("key","w+",encoding='utf-8')
for i in range(568):
curnum = int(hp[i])
(status,out)=lfsr(status,mask)
print(out,end='')
f.write(str(curnum ^ out))
f.close()
'''
out=
1101110101011011011111100001101100111111101100000010011101001110101101011110000100001110111110010000000010111110011001011000110010100101100001001111011110010000011011001010110001100000111110001111110001010101001101011110011110000100110100110000110011001101010100111000100000100110010010011001110000010110010110100101101100100111000011010100001000101010000111001000010110101110000000010101011000011111110001001111110010100011000100111010000010010110001000101111001000000100100011001010111110110100001001001000000100100101111111101000000011000100001001100001011010010010
'''
. . 用上面的结果再异或回结果 key ,就能得出 568 位的 curnum ,这就是 RSA 关键参数 P 的一部分啊:
out=list("1101110101011011011111100001101100111111101100000010011101001110101101011110000100001110111110010000000010111110011001011000110010100101100001001111011110010000011011001010110001100000111110001111110001010101001101011110011110000100110100110000110011001101010100111000100000100110010010011001110000010110010110100101101100100111000011010100001000101010000111001000010110101110000000010101011000011111110001001111110010100011000100111010000010010110001000101111001000000100100011001010111110110100001001001000000100100101111111101000000011000100001001100001011010010010")
key=list("0101110100100111011011011000111010000111101000101010100100100011010111011000010010100101110110011101110110010100010111001110010011101010111011001100011011010110001010011111111110100110101010101110100110011010110101110110000110010101010000010110100110110110001110101011000011110100011011100101101101001000110010100111000111001111010101011011111110010111100101111001010000100010100001000111010011011111010011101100011101011010011010110001101110110110000110010011001101100000110000110100101010010010110101100101111101110000010011101110010101110100011101100110111111001010")
for i in range(568):
print(int(out[i])^int(key[i]),end='')
. . 然后继续用关键字查资料,发现 568 位可以实现 RSA 高位攻击,恢复 P :
相关的脚本一大堆:https://www.jianshu.com/p/e407be39a22b?from=singlemessage
由于没下sage,用在线网址:https://sagecell.sagemath.org/
. . 一开始直接用别人的脚本发现很多错,后来发现是sage 语法变了,print 要加括号了:
from sage.all import *
n = 0x4a2c6dd9af83d8cc06b4e721475e9d8a9bce1de6ddd43be7658f13bb5c5b452e9f42d9d77b8c5c3e50ef64e0edc524903e8ee759d805a63cfe613ec022115d54e73724ced3bfff73e1872b7b35b040537f8ac89523d9e2860199d6d0b1c4d7830ee5b468bd7406990ffa29caa2d8fad285b3dba209b34b427d749d7e2aebded78f49e5017bfeec1cb9f72e63506d82af561a4858f652d3fb152526c10c7e4c5e15c84803efac675fb9297d915bd1e2eda5a5de3d48bbf68380303e0d8de81704fff8c9f07ae4d15212b9066227583345425ba7a04e06fd0c16ec6bfdd764318587d1bfe76a9834043b16392018e192456cb3ea994d2a187cabfa706efbee8dbfL
e = 0x10001
pbits = 1024
for i in range(0,256):
p4 =0x807c1395b8128e6de865ab20dd2a39684f6831464553c65215cfe2861192657b6938d227c75e902ae858fdbd8b118c8522c08a3bf978bb203bc1644fe526f2de55b065b050795800
p4=p4+int(hex(i),16)
kbits = pbits - p4.nbits()
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits, beta=0.4)
if roots:
p = p4+int(roots[0])
print ("n: ", n)
print ("p: ", p)
print ("q: ", n/p)
break
. . 得出 n、p、q 后直接常规解密即可:
import libnum
from Crypto.Util.number import long_to_bytes
p = 90225006288627020933267024425797647042965554486273674145474629022335483579168020321334177600624475358419458781387021577078957978886555066264514364951229871833611713144617155837023313756741716041993159155093522769416742461683810041045361926334946115547487234272520914249496954864904467634471167509689549908477
q = 103779913793651074214263503010594071424969073353841622604658974812940029980624584116398305918269283126971163279620945190907582597922068185151061264528002313474791985042185827606404465614715082278876591600452809285354307582767265999134237277732506671463834101956213961309366951706106789005830772784151863039339
n = p * q
e = 65537
c=3641304537029815746727163894554557322382012539953948183406308231174259571263608621970973671202001456955622458371303424750815017578104069924877881162707673935496925529412748663209884628320657034190702348924814794263041483260377960569530869386619921425415323912964305979776909598200202236912823968867485696101691879580799000240715778010424877093758489309380968229017074542588151574195295436881889313935734282141447498134543053106463951864974512375314091440713165047188590693431938599822340588934591712592995622334522799914563528630705687647950894928965913199772209825508001274120556508220248069647851360567609656517789
d = libnum.invmod(e, (p - 1) * (q - 1))
m = pow(c, d, n)
string = long_to_bytes(m)
print(string.decode())
. . 解毕! 敬礼!
|