已知d低位攻击
题目:
n=92896523979616431783569762645945918751162321185159790302085768095763248357146198882641160678623069857011832929179987623492267852304178894461486295864091871341339490870689110279720283415976342208476126414933914026436666789270209690168581379143120688241413470569887426810705898518783625903350928784794371176183
e=3
m=random.getrandbits(512)
c=pow(m,e,n)=56164378185049402404287763972280630295410174183649054805947329504892979921131852321281317326306506444145699012788547718091371389698969718830761120076359634262880912417797038049510647237337251037070369278596191506725812511682495575589039521646062521091457438869068866365907962691742604895495670783101319608530
d&((1<<512)-1)=787673996295376297668171075170955852109814939442242049800811601753001897317556022653997651874897208487913321031340711138331360350633965420642045383644955
解题思路:
-
1<<512-1
=512
个1
组合在一起
d&(1<<512-1)
=d_low
(d的最后512位字节) -
根据RSA相关参数我们可以知道
e*d=kф(n)+1
-
我们设
s=p+q
得到e*d=k(n-s+1)+1
-
再设
d
的低位为d<sub>0</sub>
,与n<sup>1/2</sup>
约为一个bit
长度级别,设n
的bit
长度为L
-
然后得到
e*d<sub>0</sub> ≡ k(n-s+1)+1 (mod 2<sup>L/2</sup>)
① -
又有
p<sup>2</sup>-sp+n=p<sup>2</sup>-p<sup>2</sup>-pq+n=0
② -
则p①-k②
=ed0p ≡ kpn-kps+kp+p-kp2+kps-kn ≡ kpn+kp+p-kp2-kn (mod 2L/2)
-
由于
d<<ф(n)
,且e=3
,所以k
肯定<e
,遍历一下就行了 -
消掉
s
后就只剩下p
这个未知数了 -
即解同余式方程
ed<sub>0</sub>x ≡ knx+kx+x-kx<sup>2</sup>-kn (mod 2<sup>L/2</sup>)
-
然后得到
p
的低位p<sub>0</sub>
解答:
def get_full_p(p_low, n,d_low):
PR.<x> = PolynomialRing(Zmod(n))
d_lowbits = d_low.nbits()
nbits = n.nbits()
p_lowbits = p_low.nbits()
f = 2^p_lowbits*x + p_low
f = f.monic()
roots = f.small_roots(X=2^(nbits//2-p_lowbits), beta=0.4)
if roots:
x0 = roots[0]
p = gcd(2^d_lowbits*x0 + p_low, n)
return ZZ(p)
def find_p_low(d_low, e, n):
X = var('X')
for k in range(1, e+1):
results = solve_mod([e*d_low*X == k*n*X + k*X + X-k*X**2 - k*n], 2^d_low.nbits())
for x in results:
p_low = ZZ(x[0])
p = get_full_p(p_low, n,d_low)
if p and p != 1:
return p
n = 92896523979616431783569762645945918751162321185159790302085768095763248357146198882641160678623069857011832929179987623492267852304178894461486295864091871341339490870689110279720283415976342208476126414933914026436666789270209690168581379143120688241413470569887426810705898518783625903350928784794371176183
c = 56164378185049402404287763972280630295410174183649054805947329504892979921131852321281317326306506444145699012788547718091371389698969718830761120076359634262880912417797038049510647237337251037070369278596191506725812511682495575589039521646062521091457438869068866365907962691742604895495670783101319608530
d_low = 787673996295376297668171075170955852109814939442242049800811601753001897317556022653997651874897208487913321031340711138331360350633965420642045383644955
e = 3
find_p_low(d_low, e, n)
#9188765830170326258642510026168563497927415242471400727621853319326260905122407669621339984215654143516262932956971178004512056542245685884515054294531083
import gmpy2
from Crypto.Util.number import *
p = 9188765830170326258642510026168563497927415242471400727621853319326260905122407669621339984215654143516262932956971178004512056542245685884515054294531083
n = 92896523979616431783569762645945918751162321185159790302085768095763248357146198882641160678623069857011832929179987623492267852304178894461486295864091871341339490870689110279720283415976342208476126414933914026436666789270209690168581379143120688241413470569887426810705898518783625903350928784794371176183
c = 56164378185049402404287763972280630295410174183649054805947329504892979921131852321281317326306506444145699012788547718091371389698969718830761120076359634262880912417797038049510647237337251037070369278596191506725812511682495575589039521646062521091457438869068866365907962691742604895495670783101319608530
q = n // p
phi = (p-1)*(q-1)
e = 3
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
#FLAG{2^8rsa5ab086745f6ec745619a8b65fe4ec560}