
# ecdsa_nonce_reuse_sim.py - Signing firmware with repeated nonce (k)
import ecdsa, hashlib
sk = ecdsa.SigningKey.generate(curve=ecdsa.NIST256p)
vk = sk.get_verifying_key()
# Sign two different firmware images with same nonce due to bad RNG
# In reality, this can happen with deterministic k if seed is constant.
# We'll simulate by using the same k manually (not possible with ecdsa library, so fake it)
def sign_with_fixed_k(sk, msg_hash, k):
# Simplified: return signature (r,s) using fixed k (for educational purposes)
# Not actual ECDSA, but shows concept.
r = (k * ecdsa.NIST256p.generator).x()
k_inv = pow(k, -1, ecdsa.NIST256p.order)
s = k_inv * (int.from_bytes(msg_hash, 'big') + r * sk.privkey.secret_multiplier) % ecdsa.NIST256p.order
return ecdsa.ecdsa.Signature(r, s)
msg1 = b"Firmware v1.0"
msg2 = b"Firmware v2.0"
h1 = hashlib.sha256(msg1).digest()
h2 = hashlib.sha256(msg2).digest()
# Use same k
k = 123456789
sig1 = sign_with_fixed_k(sk, h1, k)
sig2 = sign_with_fixed_k(sk, h2, k)
print("Two signatures with same k. Attacker can recover private key from (r,s1) and (r,s2).")
IoTデバイスがECDSAを使用してファームウェアアップデートに署名していますが、乱数生成器が脆弱なため、同じナンス(k)が2つの署名で再利用されています。両方の署名を観測した攻撃者は、秘密鍵を計算し、悪意のあるファームウェアに署名することができます。
kを持つ2つの署名が与えられた場合、秘密鍵は代数的に導出できます。シミュレーションを実行:
pip install ecdsa
python ecdsa_nonce_reuse_sim.py
このスクリプトは、同じkを持つ2つの署名の生成を示しています。実際の攻撃者は、式 k = (h1 - h2) / (s1 - s2) を使用して鍵を復元し、次に d = (s1*k - h1) / r で秘密鍵を導出します。