- 前言:这篇博客学习自lazzaro佬的博客
- RSA||Lazzaro
普通dp泄露
from Crypto.Util.number import bytes_to_long
m=bytes_to_long(flag)
n= 12308543373374311860115195114269947739026255098864232126071500623399852788903738569949462616714391748269539072128882946132686996592089735285396762634029371785959865779256901123369306119124563405765293657606975290441243965513640680841871955014230301486214824204887945375140818283280272607903500556306646445508386218951500563603482945071727344737690804338144982687000734071274618240408238519378280819162796749148066754028700125846348589164721591354555019608871411236973606149388257533629388508942271702742078883636357856776193846813894734271905070538713351614750057245897158615891962167410053552739441195871000310777649
e= 65537
dp= 28196759050232165736649945458463681080421101473761579424309687746007021074159564720195299959516638110870101025657932732247788828322476803386736345945717104030991724584628153257976163663460034720811420324255626233108130037584679035250792445830510130682783638394418531763109219293027733347554816808577799709553
c= 1855798257044238280327042455832785889763141234883180404158555071443088630113034033050409259513632343742665544043437830959750873431928980910236398026670945184328950692568113819821699696418438157336263799808404698795433243968536256780396910914692949484556950491722527661706255009863481905590371725089587377065000354109396062360440021447607401687082247775453369117424848927386857425051097931983703966253652921113920387008048024308793686643944404541941182997963873579988680965558581885273185721576668001462817150245955628293258512024323515581063235248627223179117549540541642185815489978089367061102920114395871329023208
先复习一下dp的推理过程
from Crypto.Util.number import *
from sympy import *
from tqdm import tqdm
from libnum import *
from string import *
from hashlib import *
import os
from gmpy2 import *
from hashlib import *
from random import *
n= 12308543373374311860115195114269947739026255098864232126071500623399852788903738569949462616714391748269539072128882946132686996592089735285396762634029371785959865779256901123369306119124563405765293657606975290441243965513640680841871955014230301486214824204887945375140818283280272607903500556306646445508386218951500563603482945071727344737690804338144982687000734071274618240408238519378280819162796749148066754028700125846348589164721591354555019608871411236973606149388257533629388508942271702742078883636357856776193846813894734271905070538713351614750057245897158615891962167410053552739441195871000310777649
e= 65537
dp= 28196759050232165736649945458463681080421101473761579424309687746007021074159564720195299959516638110870101025657932732247788828322476803386736345945717104030991724584628153257976163663460034720811420324255626233108130037584679035250792445830510130682783638394418531763109219293027733347554816808577799709553
c= 1855798257044238280327042455832785889763141234883180404158555071443088630113034033050409259513632343742665544043437830959750873431928980910236398026670945184328950692568113819821699696418438157336263799808404698795433243968536256780396910914692949484556950491722527661706255009863481905590371725089587377065000354109396062360440021447607401687082247775453369117424848927386857425051097931983703966253652921113920387008048024308793686643944404541941182997963873579988680965558581885273185721576668001462817150245955628293258512024323515581063235248627223179117549540541642185815489978089367061102920114395871329023208
for i in range(2,e):
if (e*dp-1)%i==0:
p=(e*dp-1)//i+1
q=n//p
d=inverse(e,(p-1)*(q-1))
print(long_to_bytes(pow(c,d,n)))
变式一 n = p b ∗ q n=p^b*q n=pb∗q
给定
n
,
c
,
p
,
d
p
,
b
n,c,p,dp,b
n,c,p,dp,b
from Crypto.Util.number import *
import gmpy2
p =
dp =
c =
b =
e =
mp1 = pow(c, dp, p)
mp = pow(c, dp - 1, p)
for i in range(1, b - 2):
x = pow(c - pow(mp1, e), 1, p**(i + 1))
y = pow(x * mp * (gmpy2.invert(e, p)), 1, p**(i + 1))
mp1 = mp1 + y
print(long_to_bytes(mp1))
变式二 已知dp高位
已知
d
p
0
,
n
,
c
,
k
,
p
dp_0,n,c,k,p
dp0,n,c,k,p
关于dp可以做一个模p的coppersmith,而n是p的倍数,所以可以对dp已知位和n做一个coppersmith得到dp
#Sage
dp0 =
e =
n =
F.<x> = PolynomialRing(Zmod(n))
d = inverse_mod(e, n)
for k in range(1, e):
f = (secret << 200) + x + (k - 1) * d
x0 = f.small_roots(X=2 ** (200 + 1), beta=0.44, epsilon=1/32)
if len(x0) != 0:
dp = x0[0] + (secret << 200)
for i in range(2, e):
p = (e * Integer(dp) - 1 + i) // i
if n % p == 0:
break
if p < 0:
continue
else:
print('k = ',k)
print('p = ',p)
print('dp = ',dp)
break
变式三 dp很小而e很大
- 在普通的dp泄露里我们通过爆破k来求解,然而如果e足够大,那么爆破的策略也就失效
- 继续做一个推导
e ∗ d p ≡ 1 m o d p − 1 → e ∗ d p − 1 = k ∗ ( p − 1 ) e*dp\equiv1\mod{p-1}\\ \rightarrow e*dp-1=k*(p-1) e∗dp≡1modp−1→e∗dp−1=k∗(p−1)
由欧拉定理,如果m与p不互素,则直接求 g c d ( m , n ) gcd(m,n) gcd(m,n)大概率得到p,如果m与p互素
m p − 1 ≡ 1 m o d p m e ∗ d p − 1 ≡ 1 m o d p m^{p-1} \equiv 1 \mod p\\ m^{e*dp-1} \equiv 1 \mod p mp−1≡1modpme∗dp−1≡1modp
所以求 g c d ( m e ∗ d p − 1 − 1 , n ) gcd(m^{e*dp-1}-1,n) gcd(me∗dp−1−1,n)大概率得到p
变式四 dp过小用变式三求解不了
这一部分用到一些构造格的知识,不太懂,直接去看la佬的博客吧
变式五 给出dp和dq
import gmpy2 as gp
p =
q =
dp =
dq =
c =
n = p*q
phin = (p-1)*(q-1)
dd = gp.gcd(p-1, q-1)
d=(dp-dq)//dd * gp.invert((q-1)//dd, (p-1)//dd) * (q-1) +dq
print(d)
m = gp.powmod(c, d, n)
print('-------------------')
print(m)
print(hex(m)[2:])
print(bytes.fromhex(hex(m)[2:]))