蓝帽杯corrupted_key

一道综合的rsa.

题目如下

from Crypto.Util.number import *
key = RSA.generate(1024) open("flag.enc",'wb').write(PKCS1_OAEP.new(key.publickey()).encrypt(flag))
open('priv.pem','wb').write(key.exportKey('PEM'))

 

先是私钥分析。查了查资料,一个私钥文件包含标签头,n,e,d,p,q,dp,dq,inv_q%p. 将这些数据转化成16进制在经过base64加密,得到的就是pem私钥文件。

通过题目给出的文件  私钥解析可以详细看这篇

 -----BEGIN RSA PRIVATE KEY-----
 MIICXgIBAAKBgQDXFSUGqpzsBeUzXWtG9UkUB8MZn9UQkfH2Aw03YrngP0nJ3NwH
UFTgzBSLl0tBhUvZO07haiqHbuYgBegO+Aa3qjtksb+bH6dz41PQzbn/l4Pd1fXm
dJmtEPNh6TjQC4KmpMQqBTXF52cheY6GtFzUuNA7DX51wr6HZqHoQ73GQQIDAQAB


yQvOzxy6szWFheigQdGxAkEA4wFss2CcHWQ8FnQ5w7k4uIH0I38khg07HLhaYm1c
zUcmlk4PgnDWxN+ev+vMU45O5eGntzaO3lHsaukX9461mA==
-----END RSA PRIVATE KEY-----

 

我们可以得到 n,e,dq的低位,inv_q%p   ,通过这些元素解方程,求出其他元素。

 

 已知dq的低120位

 原理同dp泄露。知道了dq,可以把q的低位求出。

 dq = k ( dq-1 ) +1    --->  dq+k-1 = kp ----> 两边同时乘k在模2^120 的逆元 得到
k^-1 *(dq+k-1) = p (mod 2^120)

已知dq低位
那么可以枚举(1,e) 里的元素,求出k,从而求出q的低120位

通过sagemath 爆破 恢复q的高位,
q_low = []
for i in tqdm(range(e)):
    try:
        q0 = invert(i, 2 ** 120) * (e * dq_low + i - 1) % 2 ^ 120
        q_low.append(q0)
    except:
        continue

PR.<x> = Zmod(n)[]
roots = []
q_low=q_low[29500:]
for i in tqdm(range(len(q_low))):
    f = cf * (2^120*x + int(q_low[i])) ^ 2 - (2^120*x + int(q_low[i]))
    root = f.monic().small_roots(X = 2^(512-120))

这里取29500 是因为已经跑过一遍具体知道k的值,缩短遍历范围。得到了q就可以知道其他所有需要元素,找个常规脚本写就行。附上代码

#sagemath
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Util.number import *
from gmpy2 import *
from tqdm import tqdm

n = 0xd7152506aa9cec05e5335d6b46f5491407c3199fd51091f1f6030d3762b9e03f49c9dcdc075054e0cc148b974b41854bd93b4ee16a2a876ee62005e80ef806b7aa3b64b1bf9b1fa773e353d0cdb9ff9783ddd5f5e67499ad10f361e938d00b82a6a4c42a0535c5e76721798e86b45cd4b8d03b0d7e75c2be8766a1e843bdc641
e = 0x10001
cf = 0xe3016cb3609c1d643c167439c3b938b881f4237f24860d3b1cb85a626d5ccd4726964e0f8270d6c4df9ebfebcc538e4ee5e1a7b7368ede51ec6ae917f78eb598
dq_low = 0xc90bcecf1cbab3358585e8a041d1b1

q_low = []
for i in tqdm(range(e)):
    try:
        q0 = invert(i, 2 ** 120) * (e * dq_low + i - 1) % 2 ^ 120
        q_low.append(q0)
    except:
        continue

PR.<x> = Zmod(n)[]
roots = []
q_low=q_low[29500:]
for i in tqdm(range(len(q_low))):
    f = cf * (2^120*x + int(q_low[i])) ^ 2 - (2^120*x + int(q_low[i]))
    root = f.monic().small_roots(X = 2^(512-120))
    if root:
        q = 2^120*int(root[0]) + int(q_low[i])
        p = n // q
        assert p * q == n
        d = inverse(e, (p - 1) * (q - 1))
        rsa = RSA.construct((int(n), int(e), int(d), int(p), int(q)))
        # c = bytes_to_long(open('flag.enc', 'rb').read())
        c = 96458723724899437870554342796876171017896652413964521193266438981853945238446913579867464909353925601873532290626111170073532116639383463734148270579305067733147411306325252107181823453497914478588342362177625026365513002442585949837516090367171824895036711246039928723021679235071368954348296729327873680822
        c = long_to_bytes(c)
        print(PKCS1_OAEP.new(rsa).decrypt(c))

把q求出来在python里跑也一样

 

posted @ 2022-07-12 14:16  顶真珍珠  阅读(171)  评论(0编辑  收藏  举报