◐ Off-By-One · answer catalog

python-rsa-crt-blinding-fault-injection-guard

2 answer(s)pythonpython3pythonpython3

python-rsa-crt-blinding-fault-injection-guard

📦 Source in repository (JSON)

Answer 1

The solution is complete and verified. Here's a summary of what was produced.

Solution: ~/RSA-CRT_blinding_fault_injection_fix.md

A self-contained markdown document with title, root-cause analysis, exact fix, and verification.

Root causes identified

  1. Blinding factor reused across all calls — a single R (and R⁻¹) generated in __init__ masks every ciphertext. Under chosen-ciphertext timing analysis the relationship between the CRT halves m₁, m₂ and the recombination h = (m₁−m₂)·q⁻¹ mod p stays constant per input, so timings can be averaged/correlated to recover key bits (Kocher/Schindler-style attack).
  2. Final verification skipped — the CRT result s is unblinded and returned without checking s^e ≡ c (mod n). A single-bit fault on one CRT half corrupts the recombination and yields an exploitable Bellcore-style signature that's never caught.

The fix

  1. Fresh r per call: draw a new invertible r, compute fresh blind = r^e mod n and rinv = r⁻¹ mod n inside decrypt().
  2. Verify before returning: recompute pow(s, e, n); if != c (mod n), raise. Recombination kept branch-free (lots of % normalization, no if m1 > m2 data branches) for data-independent exponent structure.

Verification (executed, all passed)

I ran the exact verification script embedded in the doc — it generates a key and confirms: - correct decryption of genuine ciphertexts (correctness OK) - FIX 1: 5 identical-input calls produce 5 distinct masks - FIX 2: all 3000 injected single-bit m₁-half faults rejected, 0 faulty signatures slipped — output matches the documented expected output exactly.

Note: the environment reports Python 3.14.4 (the spec's 3.12 target is code-version-agnostic; the builtins used work identically on 3.12).

Evidence & signatures

# Evidence
- Problem class: python-rsa-crt-blinding-fault-injection-guard
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-27T04:18:00.928Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement RSA-CRT private-key decryption that blinds the ciphertext with a fresh random r^e mod n per call to defeat timing side channels, and verifies the CRT result by checking s^e == m (mod n) to detect fault injection such as glitching one CRT half. The current version reuses one blinding factor across all signatures and skips the final verification, leaking key bits under chosen-ciphertext timing analysis and yielding exploitable faulty signatures under a single-bit fault. Fix both defects while keeping the modular exponentiation branch structure data-independent.", "environment": "python3", "language": "python", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "python-rsa-crt-blinding-fault-injection-guard", "provider": "openrouter", "solved_at": "2026-08-27T04:18:00.928Z", "version": "3.12"}

Answer 2

The solution is complete and verified. Here's a summary of what was produced.

Solution: ~/RSA-CRT_blinding_fault_injection_fix.md

A self-contained markdown document with title, root-cause analysis, exact fix, and verification.

Root causes identified

  1. Blinding factor reused across all calls — a single R (and R⁻¹) generated in __init__ masks every ciphertext. Under chosen-ciphertext timing analysis the relationship between the CRT halves m₁, m₂ and the recombination h = (m₁−m₂)·q⁻¹ mod p stays constant per input, so timings can be averaged/correlated to recover key bits (Kocher/Schindler-style attack).
  2. Final verification skipped — the CRT result s is unblinded and returned without checking s^e ≡ c (mod n). A single-bit fault on one CRT half corrupts the recombination and yields an exploitable Bellcore-style signature that's never caught.

The fix

  1. Fresh r per call: draw a new invertible r, compute fresh blind = r^e mod n and rinv = r⁻¹ mod n inside decrypt().
  2. Verify before returning: recompute pow(s, e, n); if != c (mod n), raise. Recombination kept branch-free (lots of % normalization, no if m1 > m2 data branches) for data-independent exponent structure.

Verification (executed, all passed)

I ran the exact verification script embedded in the doc — it generates a key and confirms: - correct decryption of genuine ciphertexts (correctness OK) - FIX 1: 5 identical-input calls produce 5 distinct masks - FIX 2: all 3000 injected single-bit m₁-half faults rejected, 0 faulty signatures slipped — output matches the documented expected output exactly.

Note: the environment reports Python 3.14.4 (the spec's 3.12 target is code-version-agnostic; the builtins used work identically on 3.12).

Evidence & signatures

# Evidence
- Problem class: python-rsa-crt-blinding-fault-injection-guard
- Model: openrouter/deepseek/deepseek-v4-flash-0731
- Solved: 2026-08-27T04:18:00.928Z
- Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Implement RSA-CRT private-key decryption that blinds the ciphertext with a fresh random r^e mod n per call to defeat timing side channels, and verifies the CRT result by checking s^e == m (mod n) to detect fault injection such as glitching one CRT half. The current version reuses one blinding factor across all signatures and skips the final verification, leaking key bits under chosen-ciphertext timing analysis and yielding exploitable faulty signatures under a single-bit fault. Fix both defects while keeping the modular exponentiation branch structure data-independent.", "environment": "python3", "language": "python", "model": "openrouter/deepseek/deepseek-v4-flash-0731", "problem_class": "python-rsa-crt-blinding-fault-injection-guard", "provider": "openrouter", "solved_at": "2026-08-27T04:18:00.928Z", "version": "3.12"}
Generated from the verified corpus · MIT licensedBack to the catalog