#!/usr/bin/env python3 from Crypto.Cipher import AES from Crypto.Util.Padding import pad, unpad from ecdsa import SECP256k1 from ecdsa.ecdsa import Public_key, Private_key from flag import flag import hashlib import random g = SECP256k1.generator order = int(SECP256k1.order) secret = random.randrange(2, order - 1) pubkey = Public_key(g, g * secret) privkey = Private_key(pubkey, secret) arr = [] for i in range(30): h = random.randrange(2, order - 1) k = random.randrange(2, order - 1) sig = privkey.sign(h, k) lea_k = int("0x" + "{:064x}".format(k)[10:-10], 16) arr.append((h, lea_k, int(sig.r), int(sig.s))) print(arr) sha256 = hashlib.sha256() sha256.update(str(secret).encode()) key = sha256.digest() aes = AES.new(key, mode=AES.MODE_ECB) print(aes.encrypt(pad(flag, 16)).hex())
ECDSAで、nonceの前後40bitずつがちぎられて中央の176bitが 30個与えられる
ECDSAでは なので
とおく(が lea_k
)
すると
さらに変形して
これを2インスタンス作って
差を取ると4変数のMultivariate Polynomialができるので multivariate coppersmith
は適当に大きくしていく
import itertools from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence # https://github.com/defund/coppersmith def small_roots(f, bounds, m=1, d=None): if not d: d = f.degree() R = f.base_ring() N = R.cardinality() f /= f.coefficients().pop(0) f = f.change_ring(ZZ) G = PolynomialSequence([], f.parent()) for i in range(m+1): power = N^(m-i) * f^i for shifts in itertools.product(range(d), repeat=f.nvariables()): g = power for variable, shift in zip(f.variables(), shifts): g *= variable^shift G.append(g) B, monomials = G.coefficient_matrix() monomials = vector(monomials) factors = [monomial(*bounds) for monomial in monomials] for i, factor in enumerate(factors): B.rescale_col(i, factor) B = B.dense_matrix().LLL() B = B.change_ring(QQ) for i, factor in enumerate(factors): B.rescale_col(i, 1/factor) B = B.change_ring(ZZ) H = Sequence([], f.parent().change_ring(QQ)) for h in B*monomials: if h.is_zero(): continue H.append(h.change_ring(QQ)) I = H.ideal() if I.dimension() == -1: H.pop() elif I.dimension() == 0: V = I.variety(ring=ZZ) if V: roots = [] for root in V: root = map(R, map(root.__getitem__, f.variables())) roots.append(tuple(root)) return roots return [] # --- from ecdsa import SECP256k1 from Crypto.Cipher import AES from Crypto.Util.number import long_to_bytes import hashlib n = int(SECP256k1.order) params, ciphertext = open("output").read().strip().split("\n") params = eval(params) ciphertext = long_to_bytes(int(ciphertext, 16)) h1, b1, r1, s1 = params[0] h2, b2, r2, s2 = params[1] r1inv = int(inverse_mod(r1, n)) r2inv = int(inverse_mod(r2, n)) PR.<a1,c1,a2,c2> = PolynomialRing(Zmod(n)) f = r1inv*((2^216*a1 + 2^40*b1 + c1)*s1 - h1) - r2inv*((2^216*a2 + 2^40*b2 + c2)*s2 - h2) a1,c1,a2,c2 = small_roots(f, [2^40, 2^40, 2^40, 2^40], m=2, d=2)[0] k = 2^216*a1 + 2^40*b1 + c1 d = int(s1 * k - h1) * r1inv % n sha256 = hashlib.sha256() sha256.update(str(d).encode()) key = sha256.digest() aes = AES.new(key, mode=AES.MODE_ECB) print(aes.decrypt(ciphertext))