Lessons From Two Years of Crypto Audits
Analysts investigate attack surfaces and defenses concerning Lessons From Two Years of Crypto Audits.
Summary
## Overview
Jean-Philippe Aumasson (Kudelski Security, Taurus digital asset custodian, author) presented patterns and lessons from two years of cryptographic security audits. Context: audit differs from compliance checklist—it's technical assessment of code against specifications, finding implementation bugs in cryptographic systems. Clients (primarily blockchain companies, some traditional enterprises) provide code and documentation; auditors identify bugs, assign severity (low/medium/high/informational), recommend fixes, verify patches post-remediation. Key observation: most bugs found are not purely cryptographic but software implementation bugs in crypto context (memory corruption, race conditions). Motivations: (1) show developers common classes of bugs to avoid, (2) demonstrate why writing secure crypto code is hard, (3) provide recommendations for developers and organizations commissioning audits. Pattern: ~90-95% of clients genuinely want to improve security posture; ~5-10% primarily seek audit as publicity/marketing claim.
## Common Cryptographic Implementation Bugs
**Hardcoded Nonce Reuse**: Authenticated cipher (ChaCha20-Poly1305 or AES-GCM) reuses same nonce across all encryption operations because nonce hardcoded in code (e.g., circle value fixed). Security requirement: nonce must be unique for each encrypted message; reuse completely defeats encryption even though cipher itself is theoretically secure. Real case: major cryptocurrency organization. Attack: attacker can decrypt ciphertext using XOR properties of stream ciphers.
**Password Key Derivation Using Fast Hash**: Using SHA-256 to derive encryption key from password fails because: (1) passwords have low entropy (dictionary-attackable) compared to 128+ bit encryption keys, (2) SHA-256 is optimized for speed—each password guess fast to compute. Solution: use slow key derivation functions (PBKDF2, scrypt, bcrypt) with salt (pseudo-random value that varies per password). Slow functions make dictionary attack computationally expensive; salt forces attacker to repeat full cracking effort for each unique password. Common across many blockchain/web applications.
**Short Address Hashes Enabling Collision Attacks**: Large cryptocurrency (top-20 market cap) used 64-bit addresses (derived by hashing public key). Attack: find collision (different private/public key pairs mapping to same address); average cost ~2^63 hash operations. Security threshold 128-bit; 2^63 falls far below (analogous to DES 56-bit security considered broken). Impact: attacker finds pre-image (private key generating victim's address), steals all victim funds, hijacks accounts, prevents victim access. Specific case: Lisk (not fixed at presentation time). Compare to cryptographically sound: 128-bit security requires 2^128 operations minimum.
**ECB Mode Block Cipher Usage**: AES used in ECB (Electronic Code Book) mode—encrypts each plaintext block independently with same key. Vulnerability: identical plaintext blocks produce identical ciphertext blocks, leaking patterns (famous penguin image example encrypts to visible penguin silhouette). Real case: anonymous cryptocurrency wallet. Solution: use CBC, CTR, GCM, or other modes that combine blocks with randomization (initialization vector) or counter-mode diffusion. Basic cryptography class covers ECB weakness in first 20 minutes; still appears in production code.
**Hardware Wallet NFC Protocol Issues**: NFC (Near Field Communication) secure element wallet found multiple flaws: (1) symmetric key sent in plaintext (symmetric keys should remain secret), (2) PIN transmitted only as hash of 3-5 digits (trivially brute-forced without GPU), (3) commands received without signature/authentication (no verification commands from trusted host). Impact: compromise of symmetric key and PIN. Organization fixed all issues post-audit.
**BIP32 Seed Truncation Silent Failure**: BIP32 derivation tool (key derivation from seed) accepts seed of any size, silently truncates to first 32 bytes without warning. Attack: attacker with truncated seed (first 32 bytes) derives same addresses as full seed (64 bytes), enabling account hijacking/fund theft. Tool design failure: should either reject wrong-sized inputs or explicitly warn truncation. Impact: high severity—users storing millions in cryptocurrency trusting fragile tools. Fortunately discovered and fixed; demonstrates API design anti-pattern.
## Rust Language Security Considerations
**Advantages**: Memory-safe system language (no garbage collector, uses reference counting). Compiler highly picky, forces clean code discipline; users typically more security-conscious than JavaScript developers. Fewer vulnerabilities from memory corruption compared to C/C++. Growing adoption in cryptography and blockchain projects (major cryptocurrency selected Rust for server-side code).
**Unsafe Blocks**: Rust memory-safe by default but allows unsafe blocks to work directly with pointers. Memory corruption bugs (out-of-bounds reads/writes) possible in unsafe code; C FFI calls (foreign function interface to C libraries) often require unsafe blocks. Audit strategy: grep for unsafe keyword; examine all unsafe blocks; look for null pointer dereferences, buffer overflows.
**Common Issues**: (1) Unwrap() panic—deserialize function returns Option/Result; unwrap() panics on None/error instead of error handling. Not exploitable for RCE but causes denial-of-service (crash without error message). (2) Sensitive data handling—difficult to reliably zero sensitive values (keys, seeds, plaintexts) from memory after use in garbage-collected languages; Rust middle ground allows better control on heap-allocated memory but stack allocation opaque. Zero-eyes crate claims to address this but tools limited.
**Audit Tools**: Cargo (build system) runs: (1) cargo test for unit tests, (2) cargo clippy for lint/code hygiene inspection (indicates developer care), (3) cargo audit for vulnerable dependencies (checks deprecation, CVE status). Static analyzers less useful than C/C++ (fewer tools, less mature). Security audits typically require manual code review, not automated tool output.
## Recommendations for Developers and Organizations
**Developer Guidance**: (1) Review common bug patterns (nonce handling, key derivation, mode selection, API design) before implementation, (2) Use tested libraries rather than implementing crypto primitives from scratch, (3) Avoid hardcoding secrets, (4) Use slow key derivation for passwords, (5) Select appropriate block cipher modes (not ECB), (6) Implement proper authentication/signatures, (7) Test edge cases (empty inputs, truncation).
**Organization Commissioning Audits**: (1) Provide both specification and code for auditors to verify consistency, (2) Expect mixture of cryptographic and software bugs—most issues are implementation, not theory, (3) Permit publication of audit reports as transparency signal and industry contribution, (4) Ask auditors about common patterns they find across multiple clients, (5) Budget time for fixes and re-audit of patches.
**Hard Reality**: Writing secure cryptographic code extremely difficult; even experienced cryptographers commit embarrassing bugs. Bugs persist in widely-used libraries and platforms despite best efforts. Continuous review, testing, and external audit critical for security-critical systems.
Related talks
Black Hat·46 min
Troy Hunt
Security researchers examine technical aspects of Lessons From 11 Billion Breached Records.
Black Hat·54 min
Presenters detail vulnerability discovery and exploitation in Lessons and Lulz: The 5th Annual Black Hat USA NOC Report.
Black Hat·36 min
Presenters detail vulnerability discovery and exploitation in Lessons and Lulz: The 4th Annual Black Hat USA NOC Report.


