This implementation uses AES-256-GCM with scrypt key derivation for encrypting private keys. Here's why this is secure and recommendations for production use.
-
AES-256-GCM Encryption
- Industry standard symmetric encryption
- 256-bit key length (virtually unbreakable)
- Built-in authentication (prevents tampering)
- Galois/Counter Mode for performance
-
Scrypt Key Derivation
- Memory-hard function (resistant to ASICs)
- Configurable cost parameters
- Better than PBKDF2 for password-based keys
- Standard in cryptocurrency applications
-
Cryptographically Secure Randomness
crypto.randomBytes()for salts and IVs- Each encryption uses unique salt and IV
- No predictable patterns
-
Multiple Security Layers
- User password + User ID for master password
- Additional ENCRYPTION_SECRET from environment
- Separate encryption for each user
# Use strong, unique secrets
ENCRYPTION_SECRET=$(openssl rand -base64 32)
JWT_SECRET=$(openssl rand -base64 64)
# Separate secrets per environment
ENCRYPTION_SECRET_DEV=xxx
ENCRYPTION_SECRET_STAGING=yyy
ENCRYPTION_SECRET_PROD=zzzclass KeyRotationService {
static async rotateEncryptionKeys() {
// 1. Generate new encryption secret
// 2. Re-encrypt all private keys with new secret
// 3. Update environment variables
// 4. Invalidate old keys after grace period
}
}import rateLimit from 'express-rate-limit';
const walletExportLimit = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 3, // Only 3 private key exports per 15 minutes
message: 'Too many private key export attempts'
});class SecurityLogger {
static logPrivateKeyAccess(userId, action, success, ipAddress) {
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
userId,
action, // 'export', 'import', 'encrypt', 'decrypt'
success,
ipAddress,
severity: 'HIGH'
}));
}
}class MFAService {
static async requireMFAForPrivateKey(userId) {
// Require 2FA before allowing private key operations
const user = await User.findByPk(userId);
if (!user.mfaEnabled) {
throw new Error('MFA required for private key operations');
}
// Verify TOTP/SMS code
return await this.verifyMFAToken(user.mfaSecret, mfaToken);
}
}| Method | Security Level | Performance | Complexity | Cost |
|---|---|---|---|---|
| Current (AES-256-GCM + scrypt) | ββββ | ββββ | βββ | Free |
| HSM/KMS | βββββ | βββ | ββ | $$$ |
| Argon2 + AES-256-GCM | βββββ | βββ | βββ | Free |
| Web Crypto API | ββββ | βββββ | ββ | Free |
- Use strong, unique
ENCRYPTION_SECRET(min 32 bytes) - Implement proper key rotation strategy
- Add rate limiting on private key operations
- Enable comprehensive audit logging
- Use HTTPS everywhere
- Implement MFA for sensitive operations
- Regular security audits and penetration testing
- Secure environment variable management
- Database encryption at rest
- Proper backup and disaster recovery
- Never log private keys or encryption secrets
- Use separate encryption keys per environment
- Implement proper session management
- Regular dependency updates and security scanning
- Input validation and sanitization everywhere
- Implement proper CORS policies
- Use security headers (helmet.js)
- Regular security training for development team
class SecurityMonitoring {
static monitorSuspiciousActivity() {
// Alert on:
// - Multiple failed private key decryption attempts
// - Private key exports from unusual locations
// - Bulk wallet operations
// - Unusual API usage patterns
}
}For Production Use:
- Keep current implementation - it's already very secure
- Add HSM/KMS for enterprise-level security
- Implement MFA for private key operations
- Add comprehensive monitoring and alerting
- Regular security audits and penetration testing
The current implementation with AES-256-GCM and scrypt is production-ready and follows industry best practices. The additional recommendations are for enhanced security in high-value applications.