Insufficient Key Size
ID |
swift.insufficient_key_size |
Severity |
high |
Resource |
Predictability |
Language |
Swift |
Tags |
CWE:326, MASWE:0020, NIST.SP.800-53, OWASP:2021:A2, PCI-DSS:6.5.3, crypto |
Rationale
In cryptography, the strength of an encryption scheme is significantly driven by the size of the key. Insufficient key sizes can lead to vulnerabilities that render encrypted data susceptible to exposure through brute-force attacks.
In Swift, a common mistake is using cryptographic keys with insufficient length in bits. For instance, RSA keys shorter than 2048 bits are generally considered weak for most usages, such as key wrapping and digital signature:
import Security
import Foundation
func generateWeakRSAKeyPair() throws -> (SecKey, SecKey) {
// VULNERABLE: Weak key size for RSA, 1024 bits
let attributes: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits as String: 1024 // FLAW: Too weak
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error),
let publicKey = SecKeyCopyPublicKey(privateKey) else {
throw error!.takeRetainedValue() as Error
}
return (privateKey, publicKey)
}
In this example, setting kSecAttrKeySizeInBits to 1024 generates an RSA keypair with a modulus length of 1024 bits, which is below the secure threshold for RSA keys.
Another vulnerable example using CommonCrypto for AES with insufficient key size:
import CommonCrypto
import Foundation
func encryptWithWeakAES(_ data: Data, key: Data) -> Data? {
// FLAW: Key is only 64 bits (8 bytes) - way too small for AES
let keyData = key.prefix(8) // FLAW: Only 64 bits
var encrypted = Data(count: data.count + kCCBlockSizeAES128)
var numBytesEncrypted: size_t = 0
let status = keyData.withUnsafeBytes { keyBytes in
data.withUnsafeBytes { dataBytes in
encrypted.withUnsafeMutableBytes { encryptedBytes in
CCCrypt(
CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES),
CCOptions(kCCOptionPKCS7Padding),
keyBytes.baseAddress, keyData.count, // FLAW: 64-bit key
nil,
dataBytes.baseAddress, data.count,
encryptedBytes.baseAddress, encrypted.count,
&numBytesEncrypted
)
}
}
}
guard status == kCCSuccess else { return nil }
encrypted.count = numBytesEncrypted
return encrypted
}
Remediation
To remedy insufficient key size vulnerabilities, developers should adhere to well-established cryptographic standards and ensure that cryptographic keys are of adequate length. Here are some practical steps for Java:
-
Update your cryptographic algorithms and libraries: Always use up-to-date and secure libraries. Java’s built-in cryptographic libraries, or well-known libraries like Bouncy Castle, should be considered.
-
Choose adequate key sizes: For example, with AES, opt for a minimum of 128 bits, ideally 256 bits, for symmetric encryption keys.
-
Review and Refactor: Legacy systems often contain outdated encryption; perform a security review to identify areas where cryptography needs strengthening.
-
Stay Informed: Cryptographic standards evolve. Regularly consult NIST and similar organizations’ guidelines to ensure compliance with current best practices.
Through comprehensive auditing and adherence to these guidelines, an organization can significantly reduce the risk posed by insufficient cryptographic key sizes.
For the RSA example, the following code should be used instead:
import Security
import Foundation
func generateSecureRSAKeyPair() throws -> (SecKey, SecKey) {
// FIXED: 2048 bit key, the minimum threshold for RSA key length
let attributes: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits as String: 2048 // FIXED: Secure key size
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error),
let publicKey = SecKeyCopyPublicKey(privateKey) else {
throw error!.takeRetainedValue() as Error
}
return (privateKey, publicKey)
}
For AES, always use proper key sizes (128, 192, or 256 bits):
import CryptoKit
import Foundation
func encryptWithSecureAES(_ data: Data) throws -> (ciphertext: Data, key: SymmetricKey) {
// FIXED: Generate proper 256-bit AES key
let key = SymmetricKey(size: .bits256)
let sealedBox = try AES.GCM.seal(data, using: key)
return (sealedBox.combined!, key)
}
For elliptic curve cryptography, use approved curves with adequate security levels:
import CryptoKit
func generateSecureECKeyPair() -> (privateKey: P256.Signing.PrivateKey, publicKey: P256.Signing.PublicKey) {
// FIXED: Use P-256 curve (256-bit key, provides ~128-bit security)
let privateKey = P256.Signing.PrivateKey()
let publicKey = privateKey.publicKey
return (privateKey, publicKey)
}
func generateHighSecurityECKeyPair() -> (privateKey: P384.Signing.PrivateKey, publicKey: P384.Signing.PublicKey) {
// Even better: Use P-384 curve (384-bit key, provides ~192-bit security)
let privateKey = P384.Signing.PrivateKey()
let publicKey = privateKey.publicKey
return (privateKey, publicKey)
}
import Security
import Foundation
func generateRSAKeyPairWithAttributes() throws -> (SecKey, SecKey) {
// FIXED: Use 2048-bit RSA (or 3072/4096 for higher security)
let keyAttributes: [String: Any] = [
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
kSecAttrKeySizeInBits as String: 2048, // FIXED
kSecPrivateKeyAttrs as String: [
kSecAttrIsPermanent as String: false
]
]
var error: Unmanaged<CFError>?
guard let privateKey = SecKeyCreateRandomKey(keyAttributes as CFDictionary, &error),
let publicKey = SecKeyCopyPublicKey(privateKey) else {
throw error!.takeRetainedValue() as Error
}
return (privateKey, publicKey)
}
Configuration
The rule has the following configurable parameters:
-
minKeySize, that indicates the minimum key size allowed for each algorithm. -
allowedEllipticCurves, that indicates the elliptic curves allowed for ECDH or ECDSA schemes.
properties:
minKeySize:
- AES/128 # Advanced Encryption Standard, block cipher
- CMAC/128 # Block Cipher Message Authentication Code
- DiffieHellman/2048 # Diffie-Hellman key agreement
- DSA/2048 # Digital Signature Standard (DSA)
- ECDH/256 # Elliptic Curve Diffie-Hellman key agreement
- ECDSA/256 # Elliptic Curve DSA
- HMAC/128 # Hash-based Message Authentication Code
- RSA/2048 # RSA
# Elliptic curves allowed for ECDH or ECDSA schemes
allowedEllipticCurves: [
Curve1174, Curve25519, Curve41417,
P-256, secp256r1, secp256k1,
P-384, secp384r1,
brainpoolP256t1, brainpoolP384t1
]
References
-
CWE-326 : Inadequate Encryption Strength.
-
MASWE-0020: Improper Encryption.
-
SafeCurves: choosing safe curves for elliptic-curve cryptography