badkey1
RSA源码审计可用点
if Integer(n).gcd(d) != 1:
raise ValueError("RSA private exponent is not coprime to modulus")
写成表达式
后面使用while循环生成q的同时爆破a,对于a爆破(0,e)就好
exp
from Crypto.Util.number import *
from pwn import *
context.log_level='debug'
from hashlib import sha256
p=remote('47.94.206.10',39984)
from tqdm import *
print(string.ascii_letters)
def proof():
p.recvuntil(b'sha256(XXXX+')
temp=p.recvuntil(b') == ',drop=True)
h=p.recvuntil(b'\n',drop=True)
print(temp,h)
for i in tqdm(string.ascii_letters+string.digits):
for j in string.ascii_letters+string.digits:
for m in string.ascii_letters+string.digits:
for n in string.ascii_letters+string.digits:
temp1=(i+j+m+n).encode()+temp
# print(temp)
if sha256(temp1).hexdigest()==h.decode():
print('true')
p.sendline((i+j+m+n).encode())
return
proof()
pp=12510875347176235686997812103317869460948038516680558933190808704266569039260784999860406852809645040121612396013734331543157989801627761134198090682817857
qq=7333254708337403375133788300619379627444747520722960530311097998509786409312055064698519936360202960226160296457194092174813082331974217099658032007084301
p.recvuntil(b'p = ')
p.sendline(str(pp).encode())
p.recvuntil(b'q = ')
p.sendline(str(qq).encode())
p.interactive()
生成p,q的代码
e=65537
while 1:
p=getPrime(512)
a=p-1
for i in range(e):
if a*i%e==0:
continue
if gcd((a*i%e),a*i-1)==(a*i%e):
q=(a*i-1)//(a*i%e)
if isPrime(q) and q.bit_length()==512:
print(p,q)
n=p*q
d = inverse(e, (p-1)*(q-1))
RSA.construct([n,e,d,p,q])
break
badkey2
题目
e = 65537
p = getPrime(512)
while p % e == 1:
p = getPrime(512)
signal.alarm(10)
print("Give me 10 bad RSA keypairs that have the same prime factor:", p)
used_n = []
for i in range(10):
try:
n = int(input('n = '))
assert n % p == 0
assert n not in used_n
used_n.append(n)
q = n // p
assert q > 0
assert q != p
assert q.bit_length() == 512
assert isPrime(q)
assert q % e != 1
d = inverse(e, (p-1)*(q-1))
except:
print("Invalid n")
exit(2)
try:
key = RSA.construct([n,e,d])
print("This is not a bad RSA keypair,")
exit(3)
except KeyboardInterrupt:
print("Hacker detected.")
exit(4)
except ValueError:
print("Good job!")
print("How could this happen?")
from secret import flag
print(flag)
同样是源码审计,关键代码处
if not hasattr(input_comps, 'd'):
key = RsaKey(n=n, e=e)
else:
d = input_comps.d
if hasattr(input_comps, 'q'):
p = input_comps.p
q = input_comps.q
else:
# Compute factors p and q from the private exponent d.
# We assume that n has no more than two factors.
# See 8.2.2(i) in Handbook of Applied Cryptography.
ktot = d * e - 1
# The quantity d*e-1 is a multiple of phi(n), even,
# and can be represented as t*2^s.
t = ktot
while t % 2 == 0:
t //= 2
# print('t',t)
# Cycle through all multiplicative inverses in Zn.
# The algorithm is non-deterministic, but there is a 50% chance
# any candidate a leads to successful factoring.
# See "Digitalized Signatures and Public Key Functions as Intractable
# as Factorization", M. Rabin, 1979
spotted = False
a = Integer(2)
while not spotted and a < 100:
k = Integer(t)
# Cycle through all values a^{t*2^i}=a^k
while k < ktot:
cand = pow(a, k, n)
# print(pow(cand, 2, n) == 1)
# Check if a^k is a non-trivial root of unity (mod n)
if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1:
# We have found a number such that (cand-1)(cand+1)=0 (mod n).
# Either of the terms divides n.
p = Integer(n).gcd(cand + 1)
spotted = True
break
k *= 2
# This value was not any good... let's try another!
# print(a)
# print(a)
a += 2
if not spotted:
raise ValueError("Unable to compute factors p and q from exponent d.")
RSA.construct([n, e, d])
这里只有n,e,d,没有p,q所以会跳到下面的else。其他的报错点基本没用,gcd(n,d)!=1这个在第一题里面考过想必不会再考。
首先要了解已知e,d分解n的原理。
链接文章 rsa中已知 n,e,d 来分解n_rsa分解n_前方是否可导?的博客-CSDN博客](https://blog.csdn.net/weixin_44110537/article/details/107869682))
while not spotted and a < 100:
k = Integer(t)
# Cycle through all values a^{t*2^i}=a^k
while k < ktot:
cand = pow(a, k, n)
# print(pow(cand, 2, n) == 1)
# Check if a^k is a non-trivial root of unity (mod n)
if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1:
# We have found a number such that (cand-1)(cand+1)=0 (mod n).
# Either of the terms divides n.
p = Integer(n).gcd(cand + 1)
spotted = True
break
k *= 2
# This value was not any good... let's try another!
# print(a)
# print(a)
a += 2
上面这块自己多看看,网上原理解释的多着勒
下面是重点:
源码分解取的g是2到100间的偶数。要使他们在环n中满足
只需要
很显然只需要小于50的所有素数满足
我们可以计算一下任意一个数满足上面等式的概率
1/2 | 1/2 | |
---|---|---|
1/2 | $g^{(p-1)//2}=1\mod p$ (A) | $g^{(p-1)//2}=-1\mod p$ (B) |
1/2 | $g^{(q-1)//2}=1\mod q$ (C) | $g^{(q-1)//2}=-1\mod q$ (D) |
当AC或者BD出现时满足上面式子,AD,BC出现不满足。(自己可以写代码试一试)
即对每个数,有1/2的可能满足,所有2到50一共15个素数
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
满足上面情况的概率是
也就是生成33000个素数是有很大概率找到满足条件的q
生成3000个也有大概10%的概率找到一个q。
优化:
直接使用getPrime()函数生成512素数太慢了。使用gmpy2的next_prime代替。
p是给定的,使用可以先计算15个素数在p的是否二次剩余结果。
再对生成的q,依次每个素数继续判断是否等于上述由p生成的结果。
对pow函数,使用gmpy2.powmod()函数替代
10s内遍历3000个素数,进程多开,获取多组结果。可以求解。
exp
from Crypto.PublicKey import RSA
from Crypto.Util.number import *
from pwn import *
from sympy import nextprime
import gmpy2
e = 65537
y = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
def the_order(phi, n):
for i in y:
if pow(i, phi // 4, n) != 1 and pow(i, phi // 4, n) != n - 1:
return False
return True
def new_j(q):
for i,j in zip(y,qurd):
if gmpy2.powmod(i,(q-1)//2,q)!=j and (gmpy2.powmod(i,(q-1)//2,q)-q)!=j:
return False
return True
p = 10504439101028664660056785533759761989088172436818960343147332749877720113462493129457363760368927072119588571013756543758997202324469792864400112417216047
qurd=[]
for i in y:
if pow(i,(p-1)//2,p)==1:
qurd.append(1)
else:
qurd.append(-1)
q = [
12941445952388271518501756052187011501149499405168871440740910983587444166758145638747983510693930985198611865987273890258362827292141887844321565302715167,
13331340306630130632668295656287107871517200264928668178560258006455071414325214985671123108479969251649736161940966364680698677632149263463624078927408023,
7434749292102457006806028905956300543802343309461078048043254784168801223420316278052344606710502595254921038363421407101671516522244532611045003295946327,
11890409393719017428826746031529522511702108519519988991626127567700592749109448482192996138745563686861491040026308935700133966439960052967280078213491223,
12094689984134957547999803262855914414769454801965823112591686665694489791426019652663923493412725161510838415526513885922802598797054279454614070190610647,
8312683912123787445374745935954752950118979295974508463977560704132674342154607799632011674489957072006007963119710237246105506104613247726875195578361487,
12400983895223684533295037506453462964523981567289739456700770289624685689767428392042068167419707479466810080703087508448782504371547866119057602182365543,
9239611150884101380010270524076721469903671396858138633200589273674800677797448403758231467635502406504335152314887188454728232761046216225222069851991183,
10406762411752496134569102116243476673685791553223602413823061321535980066882136219630826271673775265409346346583771428390397397572542310484182406462859583,
8735423512925567382151910965101795971352363586798572095418396512045770841639141112337897020112899066136897666947156134330548105970258198099327792405157647,
9886818365906641873221553238917195355478636246811928665300629399133053405551992608688549378012227830243145920322961044585283900419548704642207044451904687]
for i in q:
n=p*i
try:
d = inverse(e, (p - 1) * (i - 1))
RSA.construct([n, e, d])
except:
print("TRUE")
st=time.time()
i=1
q=0b1<<511
print(q.bit_length())
while 1:
if random.random()>0.6:
q=q+2**random.randint(200,300)
if i%1000==0:
print(i)
i+=1
q=gmpy2.next_prime(q)
while (q-1)%4==0:
q=gmpy2.next_prime(q)
# print(q)
n=p*q
if new_j(q):
print('find')
print('p=',p)
print('q=',q)
d = inverse(e, (p-1)*(q-1))
try:
RSA.construct([n,e,d])
except:
print(time.time()-st)
break
output示例
512
1000
2000
find
p= 10504439101028664660056785533759761989088172436818960343147332749877720113462493129457363760368927072119588571013756543758997202324469792864400112417216047
q= 6703903964971298549787012499102923063739682910296196688861780773154167769700571554512674915212042448594411695416399727778548935735790753939350691161926863
8.528871774673462
8.5秒遍历3000个结果,找到一个解