📋 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!
↓
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