在一次RSA密钥对生成中,假设p= 473398607161 ,q= 4511491 ,e= 17 ,求解出d作为flag提交.
import gmpy2
p = 473398607161
q = 4511491
e = 17
d = int(gmpy2.invert(e,(p-1)*(q-1)))
print(d)
import gmpy2
p = 9648423029010515676590551740010426534945737639235739800643989352039852507298491399561035009163427050370107570733633350911691280297777160200625281665378483
q = 11874843837980297032092405848653656852760910154543380907650040190704283358909208578251063047732443992230647903887510065547947313543299303261986053486569407
e = 65537
c = 83208298995174604174773590298203639360540024871256126892889661345742403314929861939100492666605647316646576486526217457006376842280869728581726746401583705899941768214138742259689334840735633553053887641847651173776251820293087212885670180367406807406765923638973161375817392737747832762751690104423869019034
n = p*q
f = (p-1)*(q-1)
d = int(gmpy2.invert(e,f))
m = pow(c,d,n) #pow(c,d,n)的内部运算
print('明文:',m)
pow(c,d,n)的底层实现原理
已知p,q,dp,dq,c求明文:
首先有如下公式:
dp≡d mod (p-1) ,dq≡d mod (q-1) , m≡c^d(mod n) , n=pq
因为m ≡ c^d (mod n),推出 m = c^d +kn = c^d + kpq,分别取余p和q,得m1 ≡ c^d (mod p),m2 ≡ c^d (mod q),即c^d = m1 + tp(或c^d = m2 + tq),代入m2 ≡ c^d (mod q)得m2 ≡ (m1+tp)(mod q) ==> m2 - m1 ≡ t*p (mod q) ==>(m2-m1) * p^(-1) = t mod q ,(p^(-1) 为p的逆元),从而 t = (m2 - m1)p^(-1) mod q,有因为c^d = m1 + tp,所以c^d = m1 + ((m2 - m1)*p^(-1) mod q)*p,又m ≡ c^d (mod n) ==> m = (m1+((m2-m1)p^(-1) mod q)p) mod n。而m1 ≡ c^d (mod p),m2 ≡ c^d(mod q),dp ≡ d mod (p-1),dq ≡ d mod (q-1),从而m1 ≡ c^(dp+k1(p-1)) mod p,m2=c^(dq+k2(q-1)) mod q,由费马小定理可知c^(p-1)≡1 mod p,c^(q-1) ≡ 1 mod q,所以m1 ≡ c^dp mod p,m2 ≡ c^dq mod q .
因为(p,q)=1, 则存在s,t,使得sp+tq=1,即sp≡1 mod q,又p^(-1) * p%(?) = 1,即p^(-1) * p ≡ 1 mod (?) ,所以s=p^(-1),可以用扩展欧几里得算法求解
import libnum
p = 8637633767257008567099653486541091171320491509433615447539162437911244175885667806398411790524083553445158113502227745206205327690939504032994699902053229
q = 12640674973996472769176047937170883420927050821480010581593137135372473880595613737337630629752577346147039284030082593490776630572584959954205336880228469
dp = 6500795702216834621109042351193261530650043841056252930930949663358625016881832840728066026150264693076109354874099841380454881716097778307268116910582929
dq = 783472263673553449019532580386470672380574033551303889137911760438881683674556098098256795673512201963002175438762767516968043599582527539160811120550041
c = 24722305403887382073567316467649080662631552905960229399079107995602154418176056335800638887527614164073530437657085079676157350205351945222989351316076486573599576041978339872265925062764318536089007310270278526159678937431903862892400747915525118983959970607934142974736675784325993445942031372107342103852
n = p*q
def ext_euclid(a, b):
if b == 0:
return 1, 0, a
else:
x, y, q = ext_euclid(b, a % b) # q = gcd(a, b) = gcd(b, a%b)
x, y = y, (x - (a // b) * y)
return x, y, q
def mod_inv(a, b):
return ext_euclid(a, b)[0] % b
pn = mod_inv(p,q)
m1 = pow(c,dp,p)
m2 = pow(c,dq,q)
m = (((m1-m2)*pn%q)*p+m1)%n
print(libnum.n2s(m)) #数字转字符串
已知e,n,dp/(dq),c求明文:
首先有如下公式:
dp ≡ d mod (p-1) ,ed ≡ 1 mod φ(n) ,n=pq ,φ(n)=(p-1)(q-1)
import libnum
e = 65537
n=248254007851526241177721526698901802985832766176221609612258877371620580060433101538328030305219918697643619814200930679612109885533801335348445023751670478437073055544724280684733298051599167660303645183146161497485358633681492129668802402065797789905550489547645118787266601929429724133167768465309665906113
dp=905074498052346904643025132879518330691925174573054004621877253318682675055421970943552016695528560364834446303196939207056642927148093290374440210503657
c=140423670976252696807533673586209400575664282100684119784203527124521188996403826597436883766041879067494280957410201958935737360380801845453829293997433414188838725751796261702622028587211560353362847191060306578510511380965162133472698713063592621028959167072781482562673683090590521214218071160287665180751
pd = e*dp-1
def ext_euclid(a, b):
if b == 0:
return 1, 0, a
else:
x, y, q = ext_euclid(b, a % b)
x, y = y, (x - (a // b) * y)
return x, y, q
def mod_inv(a, b):
return ext_euclid(a, b)[0] % b #函数返回的第一个数%b
for i in range(1,e):
if pd%i == 0:
if n%(pd//i+1) == 0:
p = pd//i+1
q = n//p
fn = (p-1)*(q-1)
d = mod_inv(e,fn)
m = pow(c,d,n)
print(libnum.n2s(m))
共模攻击
前提:有两组及以上的RSA加密过程,而且其中两次的m和n都是相同的,那么就可以在不计算出d而直接计算出m的值。
设模数为n,两个用户的公钥分别为e1和e2,且e1和e2互素,明文为m,密文分别为c1和c2。在已知e1,e2,n,c1,c2的情况下,推理过程如下:
c1 ≡ m^e1 (mod n) ,c2 ≡ m^e2 (mod n)
从而c1 * c2 ≡ m^(e1+e2)(mod n),这里求出的m需要开根号,并不好。注意到e1和e2互素,即(e1,e2)=1,所以存在整数s,t,使得s * e1+t * e2=1,这样就可以把m的次方化为1,利用扩展欧几里得算法求出s,t,由此可得c1^s * c2^t ≡ m^(s * e1+t * e2)(mod n) ≡ m (mod n),推出m ≡ c1^s * c2^t (mod n)
#共模攻击
import libnum
e1 = 11187289
c1=22322035275663237041646893770451933509324701913484303338076210603542612758956262869640822486470121149424485571361007421293675516338822195280313794991136048140918842471219840263536338886250492682739436410013436651161720725855484866690084788721349555662019879081501113222996123305533009325964377798892703161521852805956811219563883312896330156298621674684353919547558127920925706842808914762199011054955816534977675267395009575347820387073483928425066536361482774892370969520740304287456555508933372782327506569010772537497541764311429052216291198932092617792645253901478910801592878203564861118912045464959832566051361
e2 = 9647291
c2=18702010045187015556548691642394982835669262147230212731309938675226458555210425972429418449273410535387985931036711854265623905066805665751803269106880746769003478900791099590239513925449748814075904017471585572848473556490565450062664706449128415834787961947266259789785962922238701134079720414228414066193071495304612341052987455615930023536823801499269773357186087452747500840640419365011554421183037505653461286732740983702740822671148045619497667184586123657285604061875653909567822328914065337797733444640351518775487649819978262363617265797982843179630888729407238496650987720428708217115257989007867331698397
n=22708078815885011462462049064339185898712439277226831073457888403129378547350292420267016551819052430779004755846649044001024141485283286483130702616057274698473611149508798869706347501931583117632710700787228016480127677393649929530416598686027354216422565934459015161927613607902831542857977859612596282353679327773303727004407262197231586324599181983572622404590354084541788062262164510140605868122410388090174420147752408554129789760902300898046273909007852818474030770699647647363015102118956737673941354217692696044969695308506436573142565573487583507037356944848039864382339216266670673567488871508925311154801
def ext_euclid(a, b):
if b == 0:
return 1, 0, a
else:
x, y, q = ext_euclid(b, a % b) # q = gcd(a, b) = gcd(b, a%b)
x, y = y, (x - (a // b) * y)
return x, y, q
r,s,q = ext_euclid(e1,e2)
m = (pow(c1,r,n)*pow(c2,s,n))%n
print(libnum.n2s(m))
证书公钥解析
RSA公钥文件解密密文的原理分析
首先得到两个文件,将pub.key文件的内容进行公钥解析
公钥解析网站
得到e和n,对n进行分解因数求p,q,使用yafu工具或网站factordb
代码:
import rsa
import gmpy2
c = 1854183526100811878807183372982532818560316522978821358738967769534081571682
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463
e = 65537
n = 86934482296048119190666062003494800588905656017203025617216654058378322103517
fn = (p-1)*(q-1)
d = int(gmpy2.invert(e,fn))
key = rsa.PrivateKey(n,e,d,q,p)
with open(r'c:\111\flag.enc','rb') as f: #文件路径
f = f.read()
print(rsa.decrypt(f,key))
给出两个文件,data.txt文件中第一行的数据的形式有没有像公钥(e,n)的形式,猜测两个数据为e和n。下面的数据应该是密文。
但我在写的过程中把下面的数据整合到一块了,结果解出个b’\x05E\xba!’
. . . . . .猜错了!根据每个数据的位数(8位或9位)和n的位数(9位)几乎一样,可能是每一行数据进行解密最后整合到一块。第一、二、三行数据分别解出:
b’f‘ , b’l’ ,b’a’
说明猜想是对的。
代码:
import libnum,gmpy2
e = 19
n = 920139713
p = 18443
q = 49891
d = int(gmpy2.invert(e,(p-1)*(q-1)))
f = open(r'c:\111\data.txt','rb')
next(f) #跳过文件中的第一行
next(f) #跳过文件中的第二行
for i in f: #行读取
m = pow(int(i),d,n)
print(libnum.n2s(m).decode(),end = '') #libnum解出的是bytes类型,转换成字符串类型用.decode('utf-8')
将文件中的16进制数据转成10进制数据(n的16进制数后面有个‘L’是数据类型标识),这里的e = 3, len( c ) = 274 ,len(n) = 617,e和c都很小,n很大,应该属于小指数明文爆破攻击。
小指数明文爆破攻击:
当e和m都很小,而n很大时,会出现两种情况。
1.m^e < n,此时c = m^e,直接开e次根号即可得到m。
2.m^e > n但并没有超过n太多,且k是可以爆破的大小时,根据 c ≡ m^e (mod n ),有m^e = c +k * n,通过列举k,对c+k * n开e次根,找到满足条件的m。
import libnum
import gmpy2
n = 10456335904838169914349646852830082932152130624533179855437700729986430916359910968035371355128152016750075271161129744979254605922991030753616570849211931989112941277121682363790710646503345520505931418350219098036569932546893477983585713668853372819392130314661542626399462820378837771792293945490048339575869129479058678981790418112887403292721775644533540769467889512773382494878291574262142755186374570245813695390664702262226281601456889176191920270658811753696081082528539263191477192236336112147705564796435800152614366113854349615104191052807647128834113146535639155857819697492608839941056356828288393881491
e = 3
c = 2217344750798296091193230394221582894657909643174934416842588335871298152598368701484028832407289746218387783855373449002121088413603751014125921242419602155087438902181522441026460003722677539409576093794862185483713606547386172606576925933695952279401957552813065318376293
k = 0
while True:
pd = gmpy2.iroot(c + k*n,e) #大整数开根
if pd[1] == True:
m = int(pd[0])
print(libnum.n2s(m))
break
else:
k+=1
代码里已经给出了e,n,p,q,c,没什么好说的,直接上代码:
import gmpy2
import libnum
p = 262248800182277040650192055439906580479
q = 262854994239322828547925595487519915551
e = 65533
n = p*q
f = (p-1)*(q-1)
c = 27565231154623519221597938803435789010285480123476977081867877272451638645710
d = int(gmpy2.invert(e,f))
m = pow(c,d,n)
print(libnum.n2s(m))
文件中给出了 p+q和(p+1) * (q+1),根据
φ(n) = (p-1) * (q-1) = (p+1) * (q+1) - 2*(p+q)
n = p*q = (p+1) * (q+1) - (p+q) -1
求出φ(n),n后,直接上代码
import libnum
import gmpy2
e = int('0xe6b1bee47bd63f615c7d0a43c529d219',16)
#a = p+q b = (p+1)*(q+1)
a = int('0x1232fecb92adead91613e7d9ae5e36fe6bb765317d6ed38ad890b4073539a6231a6620584cea5730b5af83a3e80cf30141282c97be4400e33307573af6b25e2ea',16)
b = int('0x5248becef1d925d45705a7302700d6a0ffe5877fddf9451a9c1181c4d82365806085fd86fbaab08b6fc66a967b2566d743c626547203b34ea3fdb1bc06dd3bb765fd8b919e3bd2cb15bc175c9498f9d9a0e216c2dde64d81255fa4c05a1ee619fc1fc505285a239e7bc655ec6605d9693078b800ee80931a7a0c84f33c851740',16)
n = b-a-1
f = b-2*a
d = int('0x2dde7fbaed477f6d62838d55b0d0964868cf6efb2c282a5f13e6008ce7317a24cb57aec49ef0d738919f47cdcd9677cd52ac2293ec5938aa198f962678b5cd0da344453f521a69b2ac03647cdd8339f4e38cec452d54e60698833d67f9315c02ddaa4c79ebaa902c605d7bda32ce970541b2d9a17d62b52df813b2fb0c5ab1a5',16)
c = int('0x50ae00623211ba6089ddfae21e204ab616f6c9d294e913550af3d66e85d0c0693ed53ed55c46d8cca1d7c2ad44839030df26b70f22a8567171a759b76fe5f07b3c5a6ec89117ed0a36c0950956b9cde880c575737f779143f921d745ac3bb0e379c05d9a3cc6bf0bea8aa91e4d5e752c7eb46b2e023edbc07d24a7c460a34a9a',16)
m = pow(c,d,n)
print(libnum.n2s(m))