RSA dp泄漏攻击
dp泄漏攻击
给 n, e, d p, c
import gmpy2 as gp
e =
n =
dp =
c =
for x in range(1, e):
if(e*dp%x==1):
p=(e*dp-1)//x+1
if(n%p!=0):
continue
q=n//p
phin=(p-1)*(q-1)
d=gp.invert(e, phin)
m=gp.powmod(c, d, n)
if(len(hex(m)[2:])%2==1):
continue
print('--------------')
print(m)
print(hex(m)[2:])
print(bytes.fromhex(hex(m)[2:]))
变种1
-
\(变种 1 : 给 p, e, d_{p}, c, b , 其中 n=p^{b} q_{\text {。 }}\)
Hensel lifting for Takagi's scheme (p.189) :
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))
变种2
- $变种 2 : 给 n, e, d p_{0}, c, k , 其中 d p_{0} 为 d p 高 (n bits -k) 位, 即 d p_{0}=d p>>k_{\text {。 }} $
(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
变种3
-
变种 3 : 给 n, e, d p, c , 其中 d p 很小, e 很大。
\(枚举 d p , 因 e \cdot d p \equiv 1(\bmod (p-1)) , 又由费马小定理, 对任意 r , 有 \\ m^{e \cdot d p} \equiv m(\bmod p) , 即 p \mid\left(m^{e \cdot d p}-m\right) ;\\ 又 p \mid n , 很大概率 p=\operatorname{gcd}\left(m^{e \cdot d p}-m, n\right) 。\)
变种4
- 变种4 : 给 N, e, c , 其中 d p 过小。
情形1: $q<N^{0.382} $
\(参数 \beta=\frac{q_{\text {bit }}}{N_{\text {bit }}}, \delta=\frac{d p_{\text {bit }}}{N_{\text {bit }}} ,满足 3 \beta<1+\beta^{2}+2 \delta , 可确定 \beta 和 \delta 的值。\\ 构造格子维度为 n , 格子中模数 N 的最大次幂为 m , 应满足关系\)
\(\frac{m(m+1)}{2}+\frac{n(n-1)(2 \delta+\beta)}{2}-(1-\beta) n m<0\)
确定 $ \beta $和 $\delta $之后,可枚举确定 n 和 m 的取值 (最小值) , $$ m=(1-\beta) n $$ 是 一个较优的取值。
beta =
delta =
n = round((1-2*beta-2*delta)/((1-beta)^2-2*delta-beta),6)
m = (1-beta)*n
print(m,n)
构造多项式,分解多项式为\((ax+by)\)的项,其中\(a=k\),\(b=dp\)。
# 脚本1
# Sage
def getC(Scale):
C = [[0 for __ in range(Scale)] for _ in range(Scale)]
for i in range(Scale):
for j in range(Scale):
if i == j or j == 0:
C[i][j] = 1
else:
C[i][j] = C[i-1][j-1] + C[i-1][j]
return C
def getMatrix(Scale, Mvalue, N, E, Del, Bet):
M = [[0 for __ in range(Scale)] for _ in range(Scale)]
C = getC(Scale)
X, Y = int(pow(N,Del)*(Scale+1)//2), int(pow(N,(Del+Bet))*(Scale+1)//2)
for i in range(Scale):
for j in range(Scale):
M[i][j] = N**max(Mvalue-i,0)*E**(max(i-j,0))*X**(Scale-1-j)*Y**j*C[i][j]*(-1)**j
return M
N =
E =
delta = 0.01
beta = 0.37
Scale = 35
Mvalue = 22
M = getMatrix(Scale,Mvalue,N,E,delta,beta)
M = matrix(ZZ,M)
A = M.LLL()[0]
p = []
X = int(pow(N,delta)*(Scale+1)//2)
Y = int(pow(N,(delta+beta))*(Scale+1)//2)
for i in range(Scale):
p.append(A[i]//(X**(Scale-1-i)*Y**i))
PR.<x,y> = PolynomialRing(ZZ)
f = 0
for i in range(Scale):
f += p[i]*x^(Scale-1-i)*y^i
print(f.factor())
# 脚本2
# Sage
N =
e =
n = 12
beta = 0.36
delta = 0.02
X = int(N ** delta*(n+1)/2)
Y = int(N ** (delta + beta)*(n+1)/2)
def C(a,b):
ret=1
for i in range(b):
ret *= (a-i)
ret /= (b-i)
return ret
def get_Matrix(n,m):
MM=[[0 for __ in range(n)] for _ in range(n)]
for j in range(n):
pN = max(0,m-j)
for i in range(j+1):
MM[j][i] = pow(N,pN)*pow(X,n-i-1)*pow(Y,i)*pow(e,j-i)*C(j,i)*pow(-1,i)
MM = Matrix(ZZ,MM)
return MM
M = get_Matrix(n,n//2+1)
L = M.LLL()[0]
x,y = var('x'),var('y')
f = 0
for i in range(n):
f += x**(n-i-1) * y**i * (L[i] // pow(X,n-i-1) // pow(Y,i))
print(f.factor())
参考:
Cryptanalysis of Unbalanced RSA with Small CRT-Exponent
https://hash-hash.github.io/2022/05/14/Unbalanced-RSA-with-Small-CRT-Exponent/#An-Approach-Modulo-e
NSSCTF Round#3 - Secure_in_N
情形2 : $q<N^{0.468} $
\(参数 \beta=\frac{q_{\text {bit }}}{N_{\text {bit }}}, \delta=\frac{d p_{\text {bit }}}{N_{\text {bit }}}, \alpha=\frac{e_{\text {bit }}}{N_{\text {bit }}} , \\变量上界 X=2 N^{\alpha+\beta+\delta-1}, Y=N^{\beta}, Z=2 N^{1-\beta} , 对于变量 m 需充分 大。\)
\(\tau=\frac{(1-\beta)^{2}-\delta}{2 \beta(1-\beta)}, \sigma=\frac{1-\beta-\delta}{2(1-\beta)}, t=\tau m, s=\sigma m\)
\(整数域上有根 (x, y, z)=\left(x_{0}, p, q\right) 。\)
from copy import deepcopy
# https://www.iacr.org/archive/pkc2006/39580001/39580001.pdf
# Author: ZM__________J, To1in
N =
e =
alpha = log(e, N)
beta =
delta =
P.<x,y,z>=PolynomialRing(ZZ)
X = ceil(2 * N^(alpha + beta + delta - 1))
Y = ceil(2 * N^beta)
Z = ceil(2 * N^(1 - beta))
def f(x,y):
return x*(N-y)+N
def trans(f):
my_tuples = f.exponents(as_ETuples=False)
g = 0
for my_tuple in my_tuples:
exponent = list(my_tuple)
mon = x ^ exponent[0] * y ^ exponent[1] * z ^ exponent[2]
tmp = f.monomial_coefficient(mon)
my_minus = min(exponent[1], exponent[2])
exponent[1] -= my_minus
exponent[2] -= my_minus
tmp *= N^my_minus
tmp *= x ^ exponent[0] * y ^ exponent[1] * z ^ exponent[2]
g += tmp
return g
m = 5 # need to be adjusted according to different situations
tau = ((1 - beta)^2 - delta) / (2 * beta * (1 - beta))
sigma = (1 - beta - delta) / (2 * (1 - beta))
print(sigma * m)
print(tau * m)
s = ceil(sigma * m)
t = ceil(tau * m)
my_polynomials = []
for i in range(m+1):
for j in range(m-i+1):
g_ij = trans(e^(m-i) * x^j * z^s * f(x, y)^i)
my_polynomials.append(g_ij)
for i in range(m+1):
for j in range(1, t+1):
h_ij = trans(e^(m-i) * y^j * z^s * f(x, y)^i)
my_polynomials.append(h_ij)
known_set = set()
new_polynomials = []
my_monomials = []
# construct partial order
while len(my_polynomials) > 0:
for i in range(len(my_polynomials)):
f = my_polynomials[i]
current_monomial_set = set(x^tx * y^ty * z^tz for tx, ty, tz in f.exponents(as_ETuples=False))
delta_set = current_monomial_set - known_set
if len(delta_set) == 1:
new_monomial = list(delta_set)[0]
my_monomials.append(new_monomial)
known_set |= current_monomial_set
new_polynomials.append(f)
my_polynomials.pop(i)
break
else:
raise Exception('GG')
my_polynomials = deepcopy(new_polynomials)
nrows = len(my_polynomials)
ncols = len(my_monomials)
L = [[0 for j in range(ncols)] for i in range(nrows)]
for i in range(nrows):
g_scale = my_polynomials[i](X * x, Y * y, Z * z)
for j in range(ncols):
L[i][j] = g_scale.monomial_coefficient(my_monomials[j])
# remove N^j
for i in range(nrows):
Lii = L[i][i]
N_Power = 1
while (Lii % N == 0):
N_Power *= N
Lii //= N
L[i][i] = Lii
for j in range(ncols):
if (j != i):
L[i][j] = (L[i][j] * inverse_mod(N_Power, e^m))
L = Matrix(ZZ, L)
nrows = L.nrows()
L = L.LLL()
# Recover poly
reduced_polynomials = []
for i in range(nrows):
g_l = 0
for j in range(ncols):
g_l += L[i][j] // my_monomials[j](X, Y, Z) * my_monomials[j]
reduced_polynomials.append(g_l)
# eliminate z
my_ideal_list = [y * z - N] + reduced_polynomials
# Variety
my_ideal_list = [Hi.change_ring(QQ) for Hi in my_ideal_list]
for i in range(len(my_ideal_list),3,-1):
print(i)
V = Ideal(my_ideal_list[:i]).variety(ring=ZZ)
print(V)
参考: