Back to Cheat Sheets

🔐 Insufficient Cryptography

OWASP Mobile Top 10 - M10

HIGH RISK

📋 What Is It?

Insufficient Cryptography occurs when mobile applications use weak, broken, or improperly implemented cryptographic algorithms. This includes using deprecated algorithms (MD5, SHA1), weak key generation, hardcoded encryption keys, insecure random number generators, and improper initialization vectors. Strong cryptography is essential for protecting data in transit and at rest.

M10 OWASP Rank
61% Apps Affected
Varies Time to Crack

⚠️ Common Crypto Weaknesses

  • Weak Algorithms: Using DES, RC4, MD5, SHA1
  • Hardcoded Keys: Encryption keys in source code
  • ECB Mode: Using insecure block cipher modes
  • Weak RNG: Predictable random number generation
  • Fixed IV: Reusing initialization vectors
  • Custom Crypto: Rolling your own encryption

🔴 Attack Flow

1. Attacker extracts encrypted data

2. Identifies weak algorithm (DES, MD5)

3. Uses rainbow tables or brute force

4. Decrypts data with weak key

5. BREACH: Sensitive data exposed!

❌ Vulnerable Code

// Bad: Weak algorithm DES (Android) public String encryptData(String data) throws Exception { // VULNERABLE: DES is deprecated and weak SecretKeySpec key = new SecretKeySpec("12345678".getBytes(), "DES"); Cipher cipher = Cipher.getInstance("DES"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] encrypted = cipher.doFinal(data.getBytes()); return Base64.encodeToString(encrypted, Base64.DEFAULT); } // Bad: Hardcoded encryption key (Android) public class CryptoUtils { // VULNERABLE: Hardcoded key in source code private static final String SECRET_KEY = "MySecretKey12345"; public static String encrypt(String data) { // Anyone can decompile and extract this key SecretKeySpec key = new SecretKeySpec(SECRET_KEY.getBytes(), "AES"); // ... } } // Bad: ECB mode (Android) public String encryptWithECB(String data) throws Exception { // VULNERABLE: ECB mode doesn't hide patterns Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key); return Base64.encodeToString(cipher.doFinal(data.getBytes()), Base64.DEFAULT); } // Bad: Weak random number generator (Android) public String generateSessionId() { // VULNERABLE: Random() is predictable Random random = new Random(); return String.valueOf(random.nextLong()); } // Bad: MD5 for password hashing (iOS) func hashPassword(_ password: String) -> String { // VULNERABLE: MD5 is broken, use bcrypt/scrypt let data = password.data(using: .utf8)! var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH)) data.withUnsafeBytes { _ = CC_MD5($0.baseAddress, CC_LONG(data.count), &digest) } return digest.map { String(format: "%02x", $0) }.joined() } // Bad: Static IV (Android) public String encrypt(String data) throws Exception { // VULNERABLE: Same IV for every encryption byte[] iv = "1234567890123456".getBytes(); IvParameterSpec ivSpec = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); return Base64.encodeToString(cipher.doFinal(data.getBytes()), Base64.DEFAULT); } // Bad: Custom encryption algorithm public String customEncrypt(String data) { // VULNERABLE: Don't roll your own crypto! StringBuilder encrypted = new StringBuilder(); for (char c : data.toCharArray()) { encrypted.append((char)(c + 5)); // Caesar cipher! } return encrypted.toString(); }

✅ Secure Code

// Good: AES-256 with GCM mode (Android) public String encryptDataSecurely(String data) throws Exception { // Use AES-256 with GCM mode (authenticated encryption) KeyGenerator keyGen = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore" ); KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder( "MyKeyAlias", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) .build(); keyGen.init(spec); SecretKey key = keyGen.generateKey(); // Generate random IV for each encryption Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] iv = cipher.getIV(); // Random IV byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); // Prepend IV to ciphertext byte[] combined = new byte[iv.length + encrypted.length]; System.arraycopy(iv, 0, combined, 0, iv.length); System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length); return Base64.encodeToString(combined, Base64.NO_WRAP); } // Good: Key from Android Keystore (Android) private SecretKey getOrCreateKey() throws Exception { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); if (!keyStore.containsAlias("MyKeyAlias")) { // Generate new key in Keystore (hardware-backed if available) KeyGenerator keyGen = KeyGenerator.getInstance( KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore" ); keyGen.init(new KeyGenParameterSpec.Builder( "MyKeyAlias", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT ) .setBlockModes(KeyProperties.BLOCK_MODE_GCM) .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) .setKeySize(256) .setUserAuthenticationRequired(false) .build()); return keyGen.generateKey(); } return ((KeyStore.SecretKeyEntry) keyStore.getEntry( "MyKeyAlias", null )).getSecretKey(); } // Good: Secure random number generation (Android) public String generateSecureSessionId() { // Use SecureRandom for cryptographic operations SecureRandom random = new SecureRandom(); byte[] bytes = new byte[32]; random.nextBytes(bytes); return Base64.encodeToString(bytes, Base64.NO_WRAP); } // Good: Password hashing with PBKDF2 (Android) public String hashPassword(String password, byte[] salt) throws Exception { // Use PBKDF2 with high iteration count int iterations = 100000; // Adjust based on performance int keyLength = 256; PBEKeySpec spec = new PBEKeySpec( password.toCharArray(), salt, iterations, keyLength ); SecretKeyFactory factory = SecretKeyFactory.getInstance( "PBKDF2WithHmacSHA256" ); byte[] hash = factory.generateSecret(spec).getEncoded(); return Base64.encodeToString(hash, Base64.NO_WRAP); } // Good: iOS Keychain with encryption (iOS) func encryptAndStore(_ data: Data) -> Bool { // Generate symmetric key in Secure Enclave (if available) let tag = "com.example.key".data(using: .utf8)! let attributes: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeySizeInBits as String: 256, kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave, kSecPrivateKeyAttrs as String: [ kSecAttrIsPermanent as String: true, kSecAttrApplicationTag as String: tag ] ] var error: Unmanaged<CFError>? guard let privateKey = SecKeyCreateRandomKey( attributes as CFDictionary, &error ) else { return false } // Use CryptoKit for modern cryptography let symmetricKey = SymmetricKey(size: .bits256) let sealedBox = try? AES.GCM.seal(data, using: symmetricKey) // Store in Keychain return storeInKeychain(sealedBox?.combined) } // Good: Modern Swift crypto with CryptoKit (iOS) import CryptoKit func encryptData(_ data: Data) throws -> Data { // Generate or retrieve symmetric key let key = SymmetricKey(size: .bits256) // AES-GCM authenticated encryption let sealedBox = try AES.GCM.seal(data, using: key) // Returns combined: nonce + ciphertext + tag return sealedBox.combined! } // Good: Secure hashing with SHA-256 (iOS) func hashData(_ data: Data) -> String { // Use SHA-256 for hashing (not MD5/SHA1) let hash = SHA256.hash(data: data) return hash.compactMap { String(format: "%02x", $0) }.joined() } // Good: HMAC for message authentication (iOS) func generateHMAC(_ message: Data, key: SymmetricKey) -> String { let hmac = HMAC<SHA256>.authenticationCode(for: message, using: key) return Data(hmac).base64EncodedString() }

✓ Prevention Checklist

  • Use AES-256 with GCM mode for encryption
  • Store keys in Android Keystore or iOS Keychain
  • Never hardcode encryption keys in source code
  • Use SecureRandom for cryptographic operations
  • Generate unique IV/nonce for each encryption
  • Use PBKDF2, bcrypt, or scrypt for password hashing
  • Avoid deprecated algorithms (DES, RC4, MD5, SHA1)
  • Never implement custom cryptographic algorithms
  • Use authenticated encryption (GCM, CCM)
  • Regular cryptographic library updates

🔍 Detection & Tools

Analysis Tools:

MobSF Qark Androbugs Cryptography Linter Find Security Bugs

Crypto Libraries:

CryptoKit (iOS) Tink (Google) Libsodium Bouncy Castle Conscrypt

How to Test:

  • Static analysis: grep for "DES", "MD5", "ECB", "RC4"
  • Check for hardcoded keys in decompiled code
  • Analyze cipher initialization for weak parameters
  • Test random number generator predictability
  • Verify IV uniqueness across encryptions
  • Check password hashing algorithm strength

🌍 Real-World Breaches

  • Adobe (2013): Weak ECB encryption exposed 150M user passwords
  • LinkedIn (2012): Unsalted SHA1 hashes cracked in hours
  • Ashley Madison (2015): Weak bcrypt implementation compromised
  • Mobile Apps (2019): Hardcoded AES keys found in 100+ apps
  • IoT Devices (2020): Static encryption keys allowed mass decryption

📌 Quick Tips

  • DO NOT use DES, RC4, MD5, or SHA1
  • DO NOT hardcode encryption keys
  • DO NOT use ECB mode or static IVs
  • DO use AES-256-GCM or ChaCha20-Poly1305
  • DO store keys in Keystore/Keychain
  • DO use established crypto libraries

📜 Compliance

Related Standards:

  • PCI-DSS Requirement 3.5, 3.6, 4.1
  • FIPS 140-2/3 Cryptographic Standards
  • NIST 800-57, 800-131A
  • OWASP MASVS MSTG-CRYPTO-1 to 6
  • ISO 27001 A.10.1.1, A.10.1.2
  • GDPR Art. 32 - State of the Art Encryption