Common Cryptographic Pitfalls
← Back to Cryptography I: Blockchain Security and Cryptographic Foundations
Introduction
Cryptography is unforgiving. A single mistake—using weak randomness, accepting non-canonical signatures, or mishandling keys—can compromise the entire system. This chapter catalogs the most common cryptographic pitfalls, explains why they're dangerous, and shows you how to avoid them.
Pitfall 1: Weak Random Number Generation
The Mistake
// ❌ WRONG - Predictable randomness
void generateWeakKey() {
std::srand(std::time(nullptr)); // Seed with current time
std::uint8_t secretKey[32];
for (auto& byte : secretKey) {
byte = std::rand() % 256; // NOT cryptographically secure
}
return SecretKey{Slice{secretKey, 32}};
}Why It's Dangerous
Predictability:
Real-world example:
The Fix
Detection
Pitfall 2: Memory Leakage
The Mistake
Why It's Dangerous
Attack vectors:
Core dumps: Process crashes, core dump contains secrets
Swap files: Memory paged to disk, secrets written to swap
Hibernation: All memory written to hibernation file
Memory inspection: Debugger or malware reads process memory
Cold boot: RAM retains data briefly after power off
The Fix
Detection
Pitfall 3: Accepting Non-Canonical Signatures
The Mistake
Why It's Dangerous
Signature malleability allows attacks:
The Fix
Detection
Pitfall 4: Key Reuse Across Contexts
The Mistake
Why It's Dangerous
Cross-protocol attacks:
Key compromise amplification:
The Fix
Additional Protection: Hash Prefixes
Pitfall 5: Timing Attacks on Comparisons
The Mistake
Why It's Dangerous
Timing side-channel:
The Fix
Detection
Pitfall 6: Insufficient Key Length
The Mistake
Why It's Dangerous
The Fix
Guideline
Pitfall 7: Rolling Your Own Crypto
The Mistake
Why It's Dangerous
Expertise required:
Cryptography is subtle and unforgiving
Experts spend years studying attack techniques
Small mistakes lead to complete breaks
Standard algorithms battle-tested by thousands of experts
Common mistakes in custom crypto:
Weak key scheduling
Poor mode of operation
No authentication
Padding oracle vulnerabilities
Timing side-channels
Implementation bugs
The Fix
Rule
NEVER implement your own:
Encryption algorithms
Hash functions
Signature schemes
Random number generators
Key derivation functions
ALWAYS use:
OpenSSL
libsodium
Other well-vetted libraries
Standard algorithms (AES, SHA, etc.)
Pitfall 8: Ignoring Error Returns
The Mistake
Why It's Dangerous
The Fix
Guideline
Pitfall 9: Hardcoded Secrets
The Mistake
Why It's Dangerous
Exposure:
Source code in version control (git history)
Binary contains strings (recoverable)
Code reviews expose secrets
Logs may print secrets
Hard to rotate if compromised
The Fix
Best Practices
Pitfall 10: Insufficient Validation
The Mistake
Why It's Dangerous
Consequences:
Using invalid keys → signature verification fails
Using malformed data → undefined behavior
Skipping validation → security bypasses
Accepting bad input → system corruption
The Fix
Validation Checklist
Summary
Common cryptographic pitfalls and how to avoid them:
Weak RNG: Use
crypto_prng(), neverstd::rand()Memory leaks: Use RAII, call
secure_erase()Non-canonical sigs: Always enforce canonicality
Key reuse: Separate keys for separate purposes
Timing attacks: Use constant-time comparisons
Short keys: Use 256 bits minimum
Custom crypto: Never - use standard libraries
Ignored errors: Always check return values
Hardcoded secrets: Load from secure storage
Missing validation: Validate all inputs
Golden rules:
Trust no input
Check all returns
Erase all secrets
Use standard crypto
Fail loudly on errors
Last updated

