Coppersmith攻击

  1. 知道p的高位
  2. 知道m的高位
  3. 知道d的低位

大致学习下,收集佬们的脚本,帮助理解。

Coppersmith定理指出在一个e阶的mod n多项式f(x)中,如果有一个根小于$n^{\frac{1}{e}}$,就可以运用一个O(log n)的算法求出这些根。

或者,给定$\beta$,快速求出模某个b意义下较小的根,其中,$b \geq n^{\beta} (0 < \beta \leq 1)$。

Coppersmith在RSA中运用的比较多的是已知部分二进制位,通过Coppersmith来求得剩余的位数。遇到其它方面的再补充。

知道p的高位

知道p的高位位p的位数的约$\frac {1}{2}$即可。

#sage
n = ...
e = ...
p4 = ...#p的高位部分
pbits = ...#p的初始位数

kbits = pbits - p4.nbits()
print(p4.nbits())
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits, beta=0.4)
#经过以上一些函数处理后,n和p已经被转化为10进制
if roots:        
    p = p4+int(roots[0]) 
    print("n: "+str(n))
    print("p: "+str(p))
    print("q: "+str(n//p))

知道m的高位

设m的高位部分为$m_{0}$,低位部分为x,故$m = m_{0} + x$

#Sage
n = ...
e = ...
c = ...
mbar = ...#m的高位部分
kbits = ...#低位位数
#有mbar = (m >> kbits) << kbits
beta = 1
nbits = n.nbits()
print("upper {} bits of {} bits is given".format(nbits - kbits, nbits))
PR.<x> = PolynomialRing(Zmod(n))
f = (mbar + x)^e - c
#c = m^e = (mbar + x)^e
x0 = f.small_roots(X=2^kbits, beta=1)[0]  
# find root < 2^kbits with factor = n
print("m:", mbar + x0)

知道d的低位

知道的低位约为n的位数的$\frac{1}{4}(\frac{n.nbits()}{4})$就可以恢复d。

#Sage
def partial_p(p0, kbits, n):
    PR.<x> = PolynomialRing(Zmod(n))
    nbits = n.nbits()
    f = 2^kbits*x + p0
    f = f.monic()
    roots = f.small_roots(X=2^(nbits//2-kbits), beta=0.4)  # find root < 2^(nbits//2-kbits) with factor >= n^0.4
    if roots:
        x0 = roots[0]
        p = gcd(2^kbits*x0 + p0, n)
        return ZZ(p)
def find_p(d0, kbits, e, n):
    X = var('X')
    for k in range(1, e+1):
        results = solve_mod([e*d0*X - k*X*(n-X+1) + k*n == X], 2^kbits)
        for x in results:
            p0 = ZZ(x[0])
            p = partial_p(p0, kbits, n)
            if p and p != 1:
                return p
if __name__ == '__main__':
    n = 
    e = 
    c = 
    d0 = 
    beta = 0.5
    nbits = n.nbits()
    kbits = d0.nbits()
    print("lower %d bits (of %d bits) is given" % (kbits, nbits))
    p = int(find_p(d0, kbits, e, n))
    print("found p: %d" % p)
    q = n//int(p)
    print("d:", inverse_mod(e, (p-1)*(q-1)))

暂时先放这三种比较常用的。

方法解释:small_root(x = ,beta = )。

x表示解根的上限,过大会解不出来,需要调试,看题目环境确定。

beta的取值:当p,q位数相同时,一般只能取0.4。如果p,q位数不同,需要具体分析。

使用条件:未知位数 / 总位数 $\leq$ 0.44。

如当p、q位数为1024是,未知的位数不能超过454位过多,略微超过几位可以爆破出来。

参考:

https://lazzzaro.github.io/2020/05/06/crypto-RSA/


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1666739907@qq.com
github