跳转至

dp 泄露攻击

RSA 的 CRT 私钥参数定义为:

\[ d_p=d\bmod(p-1) \]

因为 \(ed\equiv1\pmod{p-1}\),所以:

\[ ed_p\equiv1\pmod{p-1} \]

存在整数 \(k\) 使:

\[ ed_p-1=k(p-1) \]

因此:

\[ p=\frac{ed_p-1}{k}+1 \]

又因为 \(0<d_p<p-1\),通常有 \(1\le k<e\)。当 \(e=65537\) 时,枚举 \(k\) 的成本很低。

识别条件

  • 已知 \(n,e,c\) 和 \(d_p\);
  • \(d_p\) 是 \(d\bmod(p-1)\),不是完整私钥 \(d\);
  • 公钥指数 \(e\) 较小或为常见值 \(65537\),可枚举 \(1\le k<e\)。

方法一:枚举 k

def factor_from_dp(n, e, dp):
    value = e * dp - 1
    for k in range(1, e):
        if value % k != 0:
            continue
        p = value // k + 1
        if p > 1 and n % p == 0:
            return p, n // p
    return None


result = factor_from_dp(n, e, dp)
if result:
    p, q = result
    phi = (p - 1) * (q - 1)
    d = pow(e, -1, phi)
    m = pow(c, d, n)

方法二:随机底数 GCD

由 \(ed_p-1\) 是 \(p-1\) 的倍数可知,对多数不被 \(p\) 整除的 \(a\):

\[ a^{ed_p-1}\equiv1\pmod p \]

因此可以计算:

\[ \gcd(a^{ed_p-1}-1,n) \]
from math import gcd


def factor_from_dp_gcd(n, e, dp):
    exponent = e * dp - 1
    for base in range(2, 100):
        factor = gcd(pow(base, exponent, n) - 1, n)
        if 1 < factor < n:
            return factor, n // factor
    return None

这种方法避免枚举全部 \(k\),但个别底数可能得到 \(1\) 或 \(n\),需要更换底数。

防护

  • 将 \(d_p,d_q,q^{-1}\bmod p\) 视为与完整私钥同等级的秘密;
  • 防止调试日志、故障注入、旁信道和内存泄露暴露 CRT 参数;
  • 使用具备 RSA blinding、常数时间实现和故障检测的密码库。