Hardcoded Cryptographic Key
ID |
swift.hardcoded_cryptographic_key |
Severity |
critical |
Resource |
Predictability |
Language |
Swift |
Tags |
CWE:321, MASWE:0013, NIST.SP.800-53, OWASP:2021:A2, PCI-DSS:3.6.3, crypto |
Description
Cryptographic keys that are hardcoded into source code can be easily extracted and exploited by malicious actors. This practice compromises the security of the application, as these keys are not changeable without altering the source code.
Rationale
Hardcoding cryptographic keys in source code is a risky practice as it exposes sensitive information that should remain secret. The concern arises because hardcoded keys are not modifiable without a code change, making them an attractive target for attackers who can access the source code or binaries.
Consider the following Swift example using CommonCrypto:
import Foundation
import CommonCrypto
class Encryptor {
// FLAW: Hardcoded cryptographic key
private static let key: [UInt8] = [
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF
]
// FLAW: Hardcoded IV (should also be random)
private static let iv: [UInt8] = [
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10
]
static func encrypt(_ data: Data) -> Data? {
var cryptData = Data(count: data.count + kCCBlockSizeAES128)
var numBytesEncrypted: size_t = 0
let cryptStatus = data.withUnsafeBytes { dataBytes in
cryptData.withUnsafeMutableBytes { cryptBytes in
key.withUnsafeBytes { keyBytes in
iv.withUnsafeBytes { ivBytes in
// FLAW: Using hardcoded key
CCCrypt(
CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES),
CCOptions(kCCOptionPKCS7Padding),
keyBytes.baseAddress, key.count, // HARDCODED KEY
ivBytes.baseAddress,
dataBytes.baseAddress, data.count,
cryptBytes.baseAddress, cryptData.count,
&numBytesEncrypted
)
}
}
}
}
guard cryptStatus == kCCSuccess else { return nil }
cryptData.count = numBytesEncrypted
return cryptData
}
}
Another common vulnerable pattern using CryptoKit:
import Foundation
import CryptoKit
class SecureStorage {
// FLAW: Hardcoded encryption key
private static let encryptionKey = "MySecretKey12345".data(using: .utf8)!
func encryptData(_ data: Data) throws -> (Data, AES.GCM.Nonce) {
// FLAW: Creating SymmetricKey from hardcoded data
let key = SymmetricKey(data: SecureStorage.encryptionKey)
let sealedBox = try AES.GCM.seal(data, using: key)
return (sealedBox.ciphertext, sealedBox.nonce)
}
}
In these examples, the cryptographic keys are hardcoded directly into the class. If this code is compiled and distributed, anyone with access to the binary can retrieve and misuse the keys, nullifying any intended cryptographic protection.
Remediation
To remediate this vulnerability, cryptographic keys should be managed securely, never hardcoding them in source code. Instead, use environmental variables, configuration files, or dedicated secrets management services that provide secure storage and retrieval of sensitive data.
An alternative is to perform cryptographic operations using an external, managed service. Known as Key Management Services (KMS), they provide different features including key generation and storage, key rotation and lifecycle management, encryption / decryption and other cryptographic operations like digital signatures, key wrapping, secure random number generation, etc.
For the previous hardcoded key, the fix retrieves the key material from a secure location such as environment variables or the Keychain. A Key Management Service (KMS) or secrets vault could be used alternatively.
import Foundation
import CryptoKit
import Security
class SecureEncryptor {
func encrypt(_ data: Data) throws -> (ciphertext: Data, nonce: AES.GCM.Nonce, tag: Data) {
// FIXED: Retrieve key from secure location
let key = try retrieveKeyFromKeychain()
// Encrypt using AES-GCM
let sealedBox = try AES.GCM.seal(data, using: key)
return (
ciphertext: sealedBox.ciphertext,
nonce: sealedBox.nonce,
tag: sealedBox.tag
)
}
private func retrieveKeyFromKeychain() throws -> SymmetricKey {
// Query the Keychain for the encryption key
let query: [String: Any] = [
kSecClass as String: kSecClassKey,
kSecAttrApplicationTag as String: "com.example.app.encryptionkey",
kSecAttrKeyType as String: kSecAttrKeyTypeAES,
kSecReturnData as String: true
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess,
let keyData = item as? Data else {
throw EncryptionError.keyNotFound
}
return SymmetricKey(data: keyData)
}
// Alternative: Retrieve from environment variable (less secure than Keychain)
private func retrieveKeyFromEnvironment() throws -> SymmetricKey {
guard let base64Key = ProcessInfo.processInfo.environment["ENCRYPTION_KEY"],
let keyData = Data(base64Encoded: base64Key) else {
throw EncryptionError.keyNotFound
}
return SymmetricKey(data: keyData)
}
}
enum EncryptionError: Error {
case keyNotFound
}
Best practice for key generation and storage:
import Foundation
import CryptoKit
import Security
class KeyManager {
// Generate a new random key and store it securely in Keychain
static func generateAndStoreKey() throws {
// Generate a secure random 256-bit key
let key = SymmetricKey(size: .bits256)
// Extract key data
let keyData = key.withUnsafeBytes { Data($0) }
// Store in Keychain
let query: [String: Any] = [
kSecClass as String: kSecClassKey,
kSecAttrApplicationTag as String: "com.example.app.encryptionkey",
kSecAttrKeyType as String: kSecAttrKeyTypeAES,
kSecValueData as String: keyData,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
let status = SecItemAdd(query as CFDictionary, nil)
guard status == errSecSuccess else {
throw KeyError.storageFailure
}
}
}
enum KeyError: Error {
case storageFailure
}
In the improved examples, keys are retrieved from secure storage mechanisms like the Keychain or environment variables. This approach enhances security by keeping cryptographic keys outside the source code, allowing them to be rotated and managed without altering the application code.
References
-
CWE-321 : Use of Hard-coded Cryptographic Key.
-
OWASP - Top 10 2021 Category A02 : Cryptographic Failures.
-
Cryptographic Storage Cheat Sheet, in OWASP Cheat Sheet Series.
-
MASWE-0013: Hardcoded Cryptographic Keys in Use.