nkeys-cpp is a cryptographic library that handles sensitive key material. This document outlines security considerations, best practices, and the library's security design.
If you discover a security vulnerability, please report it privately:
- Do not open a public GitHub issue
- Email the maintainer with details about the vulnerability
- Include steps to reproduce, potential impact, and suggested fixes if available
- Allow reasonable time for a fix before public disclosure
Ed25519 Signatures
- Implementation: Monocypher 4.x
- Algorithm: Ed25519 (Curve25519 + SHA-512)
- Key size: 256-bit (32 bytes)
- Signature size: 512-bit (64 bytes)
- Security level: 128-bit (equivalent to AES-128)
Random Number Generation
- macOS/BSD:
arc4random_buf()- cryptographically secure CSPRNG - Linux:
/dev/urandomwith complete read validation - Windows: Not currently supported (contributions welcome)
- Fallback: None - throws exception if secure RNG unavailable
Sensitive Data Handling
The library implements multiple layers of protection for sensitive key material:
- Automatic Wiping: RAII guards ensure keys are wiped even on exceptions
- Explicit Wiping:
wipe()method zeros all sensitive data - Volatile Pointers: Prevents compiler optimization from removing wipe operations
- No Swap: Sensitive data kept in process memory (not swapped to disk)
Memory Zeroing Implementation
static void secureZero(std::span<std::uint8_t> data) {
if (data.empty()) return;
volatile std::uint8_t* p = data.data();
for (size_t i = 0; i < data.size(); ++i) {
p[i] = 0;
}
}The volatile qualifier ensures the compiler cannot optimize away the zeroing loop.
CRC Validation
- Uses lookup table to ensure constant-time execution
- Prevents timing attacks on checksum validation
- No conditional branches based on data values
All public APIs perform strict validation:
- Key lengths: Verified against Ed25519 requirements
- Prefix types: Validated against known key types
- CRC checksums: Verified on all decoded keys
- Base32 encoding: Validated character set
- Signature lengths: Must be exactly 64 bytes
Invalid input results in exceptions, never undefined behavior.
DO:
- ✅ Store seeds in secure locations (encrypted files, key management systems)
- ✅ Use appropriate file permissions (600 for seed files)
- ✅ Call
wipe()on key pairs when done using them - ✅ Generate keys on secure systems with good entropy
- ✅ Use key types appropriately (User keys for users, Server keys for servers)
DON'T:
- ❌ Store seeds in version control or logs
- ❌ Transmit seeds over insecure channels
- ❌ Reuse seeds across different security contexts
- ❌ Share seeds between multiple identities
- ❌ Log or print seed material
Critical Checks:
// Always verify the signature before trusting the message
auto pub = nkeys::FromPublicKey(trustedPublicKey);
if (!pub->verify(message, signature)) {
throw std::runtime_error("Signature verification failed");
}
// Only now is it safe to use 'message'Never:
- Skip signature verification
- Use unverified messages as trusted input
- Verify signatures with wrong key type
- Trust message content before successful verification
All key generation functions use exception-safe patterns:
auto kp = nkeys::CreateUser();
// Even if an exception is thrown here, the key material
// has been wiped from the stack by RAII guardsWhen built with NKEYS_ENABLE_HARDENING=ON (default), the following protections are enabled:
Stack Protection
-fstack-protector-strong: Guards stack against buffer overflows- Protects functions with vulnerable characteristics
Fortified Sources
-D_FORTIFY_SOURCE=2: Compile-time and runtime buffer overflow checks- Applied automatically in Release builds
Position Independent Execution (Linux)
-Wl,-z,relro,-z,now: Read-only relocations, immediate binding- Prevents GOT overwrites
Development builds can enable:
AddressSanitizer (-DNKEYS_ENABLE_ASAN=ON)
- Detects memory errors (use-after-free, buffer overflows)
- ~2x slowdown, use in testing
UndefinedBehaviorSanitizer (-DNKEYS_ENABLE_UBSAN=ON)
- Detects undefined behavior at runtime
- Minimal performance impact
- Windows: Secure random number generation not implemented
- Windows users should contribute
BCryptGenRandom()support
- Windows users should contribute
- Exotic Platforms: Only tested on macOS, Linux (Ubuntu/Debian)
- Timing: CRC uses constant-time lookup tables
- Power Analysis: Not protected (not applicable for software-only implementation)
- Cache Timing: Monocypher provides some cache-timing resistance
- Speculative Execution: No specific mitigations (Spectre, Meltdown)
The library does not protect against:
- Excessive memory allocation (caller's responsibility)
- CPU exhaustion from signature verification
- File size limits (enforced at 100MB in CLI tool)
The library protects against:
- ✅ Memory disclosure attacks (key material wiping)
- ✅ Timing attacks on CRC validation
- ✅ Signature forgery (Ed25519 security guarantees)
- ✅ Key confusion (prefix validation)
- ✅ Corrupt/tampered keys (CRC validation)
The library does NOT protect against:
- ❌ Physical access to running process (memory dumps)
- ❌ Root/admin level attackers
- ❌ Compromised compilers or build tools
- ❌ Side-channel attacks requiring special equipment
- ❌ Attacks on key storage (filesystem, OS)
Ed25519 is considered secure against all known attacks:
- No known practical attacks against Curve25519
- Conservative security margin
- Immune to many side-channel attacks
- Widely peer-reviewed and deployed
Not Quantum-Resistant: Like all current asymmetric cryptography, Ed25519 is vulnerable to quantum computers with Shor's algorithm.
- Uses Monocypher, an audited cryptographic library
- Monocypher is designed for side-channel resistance
- No custom cryptographic code (principle of "don't roll your own crypto")
This library is suitable for:
- General-purpose authentication
- Internal service-to-service authentication
- Developer tooling and automation
This library is NOT certified for:
- FIPS 140-2/140-3 compliance
- Medical device software
- Payments (PCI-DSS)
- Government classified systems
Always consult security/compliance experts for regulated environments.
Before deploying nkeys-cpp in production:
- Seeds stored in secure location with appropriate access controls
- Build includes hardening flags (
NKEYS_ENABLE_HARDENING=ON) - All key pairs explicitly wiped after use
- Exception handling reviewed for memory safety
- Signature verification errors handled appropriately
- No seeds in logs, version control, or unsecured storage
- Tested with sanitizers during development
- Platform has secure random number generation support
- Security incident response plan in place
- Regular dependency updates (Monocypher, compiler)
- Monitor this repository for security updates
- Subscribe to GitHub releases for notifications
- Review Monocypher releases for cryptographic updates
- Keep compiler and standard library updated