What Is Cryptography in Software Development
Cryptography is the practice of securing data through mathematical algorithms that make information unreadable without the correct key. In modern software development, cryptography protects data at rest (encrypted databases, files), data in transit (HTTPS, TLS), and user credentials (password hashing).
Developers use cryptography for three core purposes:
- Encryption: Transform plaintext into ciphertext using algorithms like AES (Advanced Encryption Standard). Only those with the decryption key can read the data.
- Hashing: Convert data into a fixed-size string (hash) that cannot be reversed. Used for password storage (bcrypt, Argon2) and data integrity verification (SHA-256).
- Signing: Create a digital signature using asymmetric cryptography (RSA, ECDSA) to verify data authenticity and integrity.
When implemented incorrectly, cryptography becomes security theater—it appears secure but provides no real protection. Weak algorithms (DES, MD5, SHA-1), hardcoded keys, and improper key storage make encrypted data as vulnerable as plaintext.
Common Cryptographic Vulnerabilities
1. Weak or Broken Algorithms
Algorithms like MD5, SHA-1, DES, and 3DES are cryptographically broken and should never be used:
// INSECURE: MD5 is broken (collision attacks since 2004)
const hash = crypto.createHash('md5').update(password).digest('hex');
// INSECURE: SHA-1 is deprecated (collision attacks since 2017)
const signature = crypto.createHash('sha1').update(data).digest('hex');
// SECURE: Use SHA-256 or SHA-3 for hashing
const hash = crypto.createHash('sha256').update(data).digest('hex');
// SECURE: Use bcrypt with salt for passwords (10+ rounds)
const hash = await bcrypt.hash(password, 12);
2. Hardcoded Cryptographic Keys
Embedding encryption keys or API secrets directly in source code exposes them in version control, binary files, and logs:
// INSECURE: Hardcoded AES key (CVSS 9.8 CRITICAL)
const key = Buffer.from('1234567890abcdef1234567890abcdef', 'hex');
const cipher = crypto.createCipher('aes-256-cbc', key);
// SECURE: Load keys from environment variables
const key = Buffer.from(process.env.ENCRYPTION_KEY, 'hex');
const cipher = crypto.createCipher('aes-256-gcm', key);
Real-world incident: Uber's 2016 breach exposed 57 million records because AWS keys were hardcoded in a GitHub repository. Attackers discovered the keys through a simple GitHub search.
3. ECB Mode (Electronic Codebook)
ECB mode encrypts identical plaintext blocks into identical ciphertext blocks, revealing patterns:
// INSECURE: ECB mode exposes patterns in encrypted data
const cipher = crypto.createCipheriv('aes-256-ecb', key, null);
// SECURE: Use GCM mode with authenticated encryption
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
4. Insecure Random Number Generation
Using Math.random() for cryptographic operations (tokens, keys, IVs) is predictable and exploitable:
// INSECURE: Math.random() is NOT cryptographically secure
const token = Math.random().toString(36).substring(2);
// SECURE: Use crypto.randomBytes() for cryptographic randomness
const token = crypto.randomBytes(32).toString('hex');
5. Password Storage Without Salting
Hashing passwords without unique salts allows rainbow table attacks:
// INSECURE: No salt (rainbow table attack)
const hash = crypto.createHash('sha256').update(password).digest('hex');
// SECURE: bcrypt automatically generates unique salts
const hash = await bcrypt.hash(password, 12);Cryptography Best Practices for Developers
1. Use Modern Algorithms (2025 Standards)
- Encryption: AES-256-GCM (authenticated encryption), ChaCha20-Poly1305
- Password Hashing: bcrypt (12+ rounds), Argon2id (memory-hard), scrypt
- Hashing: SHA-256, SHA-3, BLAKE3 (avoid MD5, SHA-1, SHA-0)
- Asymmetric Crypto: RSA-4096, Ed25519, ECDSA with P-256+
2. Never Roll Your Own Crypto
Custom cryptographic implementations are nearly always insecure. Use battle-tested libraries:
- JavaScript/Node.js:
crypto(built-in),libsodium-wrappers,bcrypt - Python:
cryptography,bcrypt,argon2-cffi - Java:
javax.crypto, Bouncy Castle, Google Tink - Go:
cryptostandard library,golang.org/x/crypto
3. Key Management Strategy
Store keys in environment variables (development), secret management systems (production):
- Cloud: AWS Secrets Manager, Azure Key Vault, Google Secret Manager
- Self-hosted: HashiCorp Vault, CyberArk, 1Password Secrets Automation
- CI/CD: GitHub Secrets, GitLab CI Variables, CircleCI Contexts
Rotate keys regularly (90 days for high-security, 1 year minimum for standard environments).
4. Always Use Initialization Vectors (IVs)
Never reuse IVs for the same key. Generate random IVs with crypto.randomBytes():
// Generate unique IV for each encryption operation
const iv = crypto.randomBytes(16); // 128-bit IV for AES
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
// Store IV alongside ciphertext (IV does not need to be secret)
const encrypted = Buffer.concat([iv, cipher.update(plaintext), cipher.final()]);
5. Prefer Authenticated Encryption
Use GCM mode (Galois/Counter Mode) for encryption that also verifies integrity:
// AES-256-GCM provides encryption + authentication
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
const encrypted = cipher.update(plaintext, 'utf8', 'hex');
cipher.final('hex');
const authTag = cipher.getAuthTag(); // Integrity verification tag
6. Avoid Crypto Assumptions
- Do not assume hashing is encryption (hashes cannot be decrypted)
- Do not assume encryption is authentication (use HMAC or GCM)
- Do not assume Base64 encoding is encryption (it is just encoding)
Real-World Cryptography Failures
Adobe (2013) - 153 Million Records
Adobe encrypted user passwords with AES-128-ECB mode without proper salting. Because ECB mode produces identical ciphertexts for identical plaintexts, attackers decrypted passwords through pattern analysis. The breach exposed 153 million accounts.
Lesson: Never use ECB mode. Use password-specific hashing (bcrypt, Argon2) instead of encryption.
LinkedIn (2012) - 117 Million Passwords
LinkedIn stored passwords using unsalted SHA-1 hashes. Attackers cracked 90% of passwords within days using rainbow tables and GPUs.
Lesson: Always use salted, adaptive hashing algorithms (bcrypt with 12+ rounds).
Zoom (2020) - Weak Encryption Claims
Zoom advertised "end-to-end encryption" but actually used TLS (transport encryption) with AES-128-ECB mode. Security researchers revealed the weakness, forcing Zoom to implement proper E2E encryption with AES-256-GCM.
Lesson: Use authenticated encryption (GCM) and be transparent about cryptographic implementations.
Equifax (2017) - 147 Million Records
While primarily an Apache Struts vulnerability, Equifax also stored unencrypted sensitive data and used weak key management. Attackers accessed plaintext Social Security numbers and financial records.
Lesson: Encrypt data at rest with proper key rotation and access controls.
How CodeSlick Detects Cryptographic Issues
CodeSlick's 294 security checks include cryptography-specific detections across 5 languages:
- Hardcoded secrets: 38 patterns detecting API keys, passwords, private keys, and encryption keys in source code
- Weak algorithms: Flags usage of MD5, SHA-1, DES, 3DES, ECB mode, and other deprecated crypto
- Insecure random: Detects
Math.random(),random.seed(), and non-cryptographic RNGs used for security - Plaintext passwords: Identifies password fields stored without hashing (JavaScript, Python, Java, Go)
- Missing salts: Detects password hashing without bcrypt/Argon2 adaptive algorithms
Each issue includes CVSS severity (8.0-9.8 for crypto issues), CWE mapping (CWE-327, CWE-328, CWE-759), and remediation guidance.
Example Detection
// CodeSlick flags this as CRITICAL (CVSS 9.8)
const key = "my-secret-encryption-key-123"; // Hardcoded key
const cipher = crypto.createHash('md5'); // Weak algorithm
// CodeSlick recommends:
// 1. Store keys in environment variables or key management systems
// 2. Use SHA-256+ for hashing, AES-256-GCM for encryption
// 3. Use bcrypt (12+ rounds) for password hashingDetect hardcoded keys, weak crypto algorithms, and insecure random number generation across JavaScript, Python, Java, and Go in under 3 seconds.
Cryptography Compliance Requirements
NIST Guidelines (FIPS 140-2/140-3)
US federal agencies require FIPS 140-2 validated cryptographic modules. Key requirements:
- AES with 128-bit or greater keys
- RSA with 2048-bit or greater keys (4096-bit recommended)
- SHA-256 or SHA-3 for hashing (SHA-1 deprecated since 2015)
- Hardware security modules (HSMs) for key storage
PCI DSS 4.0 (Payment Card Industry)
Requirements for applications handling payment card data:
- Strong cryptography must protect cardholder data at rest and in transit
- Encryption keys must be stored securely (not in application code or databases)
- Key rotation every 12 months minimum
- TLS 1.2+ for transmission (TLS 1.0/1.1 prohibited)
GDPR/CCPA (Data Privacy)
Encryption is considered a "technical safeguard" that reduces breach notification requirements if encryption keys remain secure. Organizations handling EU/California resident data should encrypt:
- Personally identifiable information (PII) at rest
- Database backups and archives
- Application logs containing sensitive data
HIPAA (Healthcare)
HIPAA requires encryption for electronic Protected Health Information (ePHI). While not mandated, encryption creates a "safe harbor" from breach notifications if the encrypted device/data is lost.