Inadequate Padding
ID |
swift.inadequate_padding |
Severity |
high |
Resource |
Predictability |
Language |
Swift |
Tags |
CWE:325, MASWE:0023, NIST.SP.800-53, OWASP:2021:A2, PCI-DSS:6.5.3, crypto |
Description
Inadequate encryption strength due to inadequate padding.
Padding is a crucial process in block cipher encryption, where data is modified to fit the required block size of the encryption algorithm. Inadequate or incorrect padding can lead to vulnerabilities such as padding oracle attacks, where attackers exploit the padding errors to decrypt data without knowing the encryption key.
Rationale
Certain padding schemes are known to have specific attacks, such as padding oracle attacks. For example, with RSA, the PKCS#1 v1.5 padding scheme is vulnerable to chosen ciphertext attack (discovered by D. Bleichenbacher). The Optimal Asymmetric Encryption Padding (OAEP, aka. PKCS#1 v2) padding scheme was designed to be resistant to such attack.
The zero padding scheme sometimes seen with symmetric block ciphers is also known to have vulnerabilities.
Some authenticated cipher modes of operation (e.g., GCM) often run in counter mode, and do not require padding. Other modes require padding with block ciphers.
The following is a summary of the most common padding schemes and their vulnerabilities:
| Official Name | Standard/RFC | Aliases | Use Case | Known Weaknesses |
|---|---|---|---|---|
PKCS#7 |
RFC 5652 |
PKCS5 (64-bit blocks) |
Symmetric Encryption |
Padding oracle attacks if decrypted before MAC validation |
PKCS#1 v1.5 |
PKCS#1, RFC 2313/8017 |
– |
Asymmetric Encryption (RSA) |
Padding oracle and Bleichenbacher attacks |
OAEP |
PKCS#1 v2, RFC 2437/8017 |
RSA-OAEP |
Asymmetric Encryption (RSA) |
Original OAEP had IND-CCA1 security; fixed in RSA-OAEP |
PSS |
PKCS#1 v2.1, RFC 8017 |
RSA-PSS |
Digital Signature (RSA) |
Secure if implemented correctly |
X9.23 |
ANSI X9.23 |
– |
Symmetric Encryption |
Padding oracle attacks (similar to PKCS#7) |
TBC |
(No standardized doc) |
Trailing Bit Complement |
Symmetric Encryption (rare) |
Not widely analyzed; possible predictability |
ISO-10126 |
ISO/IEC 10126 |
– |
Symmetric Encryption |
Padding oracle attacks (similar to PKCS#7) |
ISO-7816 |
ISO/IEC 7816-4 |
– |
Smart Card Protocols |
Not typically used as general padding; context-specific |
ISO-9797-1 Method 1 |
ISO/IEC 9797-1 |
Zero padding |
MAC |
Predictable padding risks if not combined with authentication |
ISO-9797-1 Method 2 |
ISO/IEC 9797-1 |
Bit padding (1 + 0s) |
MAC |
More secure than Method 1 but still padding-dependent |
ISO-9797-1 Method 3 |
ISO/IEC 9797-1 |
Length-prepended padding |
MAC |
Secure if length data is authenticated |
AES-KW |
RFC 3394 |
AES Key Wrap |
Key Wrapping/Encryption |
No padding; requires data length multiple of 64 bits; secure if implemented correctly |
AES-KWP |
RFC 5649 |
AES Key Wrap with Padding |
Key Wrapping/Encryption |
Allows any data length; uses padding; secure if implemented correctly |
PSEP |
DFJW04 paper |
– |
Signcryption |
No major weaknesses reported in the framework |
In Swift, inadequate padding can occur with both symmetric and asymmetric encryption:
import Security
import Foundation
func encryptRSAPKCS1_Vulnerable(_ plaintext: Data, publicKey: SecKey) throws -> Data {
// FLAW: PKCS#1 v1.5 padding vulnerable to Bleichenbacher attack
var error: Unmanaged<CFError>?
guard let encrypted = SecKeyCreateEncryptedData(
publicKey,
.rsaEncryptionPKCS1, // FLAW: Vulnerable padding
plaintext as CFData,
&error
) else {
throw error!.takeRetainedValue() as Error
}
return encrypted as Data
}
import CryptoSwift
func encryptNoPadding_Vulnerable(_ plaintext: String, key: [UInt8], iv: [UInt8]) throws -> [UInt8] {
// FLAW: No padding specified for block cipher
let aes = try AES(key: key, blockMode: CBC(iv: iv), padding: .noPadding) // FLAW
return try aes.encrypt(Array(plaintext.utf8))
}
import CryptoSwift
func encryptZeroPadding_Vulnerable(_ plaintext: String, key: [UInt8], iv: [UInt8]) throws -> [UInt8] {
// FLAW: Zero padding has ambiguity issues
let aes = try AES(key: key, blockMode: CBC(iv: iv), padding: .zeroPadding) // FLAW
return try aes.encrypt(Array(plaintext.utf8))
}
Remediation
To remediate inadequate padding vulnerabilities, follow these best practices:
-
Specify Proper Padding Schemes: Always use encryption algorithms with a specified padding scheme. Prefer standard padding such as PKCS#7 when using block ciphers.
-
Employ Secure Modes of Encryption: Use secure modes of operation such as CBC (Cipher Block Chaining) along with padding, rather than ECB (Electronic Codebook), which is more predictable and less secure. In particular, authenticated encryption modes eliminate the need for separate padding validation.
-
Stay Updated with Cryptographic Best Practices: Continuously monitor and adapt to industry best practices for cryptography to ensure encryption implementations remain secure.
-
Conduct Comprehensive Security Testing: Perform regular cryptographic security assessments and penetration testing to identify and address potential vulnerabilities in encryption processes.
By following these guidelines, developers can ensure that their encryption implementations effectively protect data against padding-related vulnerabilities and other cryptographic threats.
For Swift, use secure padding schemes:
import Security
import Foundation
func encryptRSAOAEP_Fixed(_ plaintext: Data, publicKey: SecKey) throws -> Data {
// FIXED: OAEP padding (PKCS#1 v2.0) is secure
var error: Unmanaged<CFError>?
guard let encrypted = SecKeyCreateEncryptedData(
publicKey,
.rsaEncryptionOAEPSHA256, // FIXED: Secure padding
plaintext as CFData,
&error
) else {
throw error!.takeRetainedValue() as Error
}
return encrypted as Data
}
func decryptRSAOAEP_Fixed(_ ciphertext: Data, privateKey: SecKey) throws -> Data {
var error: Unmanaged<CFError>?
guard let decrypted = SecKeyCreateDecryptedData(
privateKey,
.rsaEncryptionOAEPSHA256, // FIXED
ciphertext as CFData,
&error
) else {
throw error!.takeRetainedValue() as Error
}
return decrypted as Data
}
import CryptoSwift
struct EncryptedData {
let ciphertext: [UInt8]
let iv: [UInt8]
}
func encryptWithPKCS7_Fixed(_ plaintext: String, key: [UInt8]) throws -> EncryptedData {
// FIXED: PKCS#7 padding for block cipher
let iv = (0..<AES.blockSize).map { _ in UInt8.random(in: 0...UInt8.max) }
let aes = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) // FIXED
let ciphertext = try aes.encrypt(Array(plaintext.utf8))
return EncryptedData(ciphertext: ciphertext, iv: iv)
}
func decryptWithPKCS7_Fixed(_ encrypted: EncryptedData, key: [UInt8]) throws -> String {
let aes = try AES(key: key, blockMode: CBC(iv: encrypted.iv), padding: .pkcs7)
let decrypted = try aes.decrypt(encrypted.ciphertext)
return String(bytes: decrypted, encoding: .utf8) ?? ""
}
import CryptoKit
import Foundation
func encryptWithAESGCM_Fixed(_ plaintext: Data, key: SymmetricKey) throws -> Data {
// FIXED: AES-GCM is AEAD mode, doesn't require padding
let sealedBox = try AES.GCM.seal(plaintext, using: key)
// Combined data includes nonce, ciphertext, and authentication tag
return sealedBox.combined!
}
func decryptWithAESGCM_Fixed(_ combined: Data, key: SymmetricKey) throws -> Data {
let sealedBox = try AES.GCM.SealedBox(combined: combined)
return try AES.GCM.open(sealedBox, using: key)
}
import Security
import CryptoKit
import Foundation
func signWithRSAPSS_Fixed(_ message: Data, privateKey: SecKey) throws -> Data {
// FIXED: PSS padding for RSA signatures
let hash = SHA256.hash(data: message)
var error: Unmanaged<CFError>?
guard let signature = SecKeyCreateSignature(
privateKey,
.rsaSignatureMessagePSSSHA256, // FIXED: PSS padding
Data(hash) as CFData,
&error
) else {
throw error!.takeRetainedValue() as Error
}
return signature as Data
}
func verifyRSAPSS_Fixed(_ message: Data, signature: Data, publicKey: SecKey) throws -> Bool {
let hash = SHA256.hash(data: message)
var error: Unmanaged<CFError>?
let result = SecKeyVerifySignature(
publicKey,
.rsaSignatureMessagePSSSHA256, // FIXED
Data(hash) as CFData,
signature as CFData,
&error
)
if let error = error {
throw error.takeRetainedValue() as Error
}
return result
}
Configuration
The rule has the following configurable parameters:
-
allowedPaddings, that indicates the list of allowed paddings. -
forbiddenPaddings, that indicates the list of forbidden paddings.
If the normalized padding scheme is in the allowedPaddings list, the detector considers the padding as acceptable. If the normalized padding scheme is in the forbiddenPaddings list, the detector considers the padding as insecure and emits a vulnerability. If it does not match any of the lists, the detector logs a warning but does not emit a vulnerability.
References
-
CWE-325 : Missing Cryptographic Step.
-
CWE-780 : Use of RSA Algorithm without OAEP.
-
MASWE-0023: Risky Padding.
-
https://developer.apple.com/documentation/security/seckeycreateencrypteddata(::_:_:)[SecKeyCreateEncryptedData]: RSA encryption with padding