Skip to main content

Insecure generation of random numbers - Static IV

Need

Secure generation of random numbers and dynamic initialization vectors

Context

  • Usage of Swift for iOS and macOS app development
  • Usage of Foundation for building responsive and accessible web interfaces
  • Usage of CommonCrypto for cryptographic operations

Description

Non compliant code

import Foundation
import CommonCrypto

let key = "1234567890123456" // 16 bytes for AES128
let iv = "abcdefghijklmnop" // 16 bytes for AES128

func encryptAES(data: Data) -> Data {
let cryptLength = size_t(kCCBlockSizeAES128 + data.count + kCCKeySizeAES128)
var cryptData = Data(count:cryptLength)

let keyLength = size_t(kCCKeySizeAES128)
let options = CCOptions(kCCOptionPKCS7Padding)

var numBytesEncrypted :size_t = 0

let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
CCCrypt(CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES),
options,
key, keyLength,
iv,
dataBytes, data.count,
cryptBytes, cryptLength,
&numBytesEncrypted)
}
}

if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.removeSubrange(numBytesEncrypted..<cryptData.count)
} else {
print("Error: \\(cryptStatus)")
}

return cryptData
}

In this Swift code, the function encryptAES(data: Data) -> Data is used to encrypt data using AES encryption. The encryption key and initialization vector (IV) are hardcoded as key and iv respectively. This is a security vulnerability as the IV should be random and unique for each encryption process.

By using a static, hardcoded IV, it becomes possible for an attacker to predict the output of the encryption. If they have access to both the encrypted data and the IV, they can perform a reverse engineering attack to predict the random values that should remain secret.

The vulnerability lies in this line of code: let iv = "abcdefghijklmnop". This is where the IV is hardcoded instead of being randomly generated. This could allow an attacker to predict the random values that should remain secret, compromising the security of the encryption.

To fix this vulnerability, the IV should be randomly generated for each encryption process, ensuring that even if an attacker has access to the encrypted data, they cannot predict the random values used in the encryption.

Steps

  • Step 1: Replace the static, hardcoded values for the initialization vector (IV) with a dynamically generated random value.
  • Step 2: Use a secure random number generator to generate the random value for the IV.
  • Step 3: Ensure that the generated IV is unique for each encryption operation.
  • Step 4: Store the generated IV securely, as it will be needed for decryption.
  • Step 5: Update the encryption function to use the dynamically generated IV instead of the static value.

Compliant code

import Foundation
import CommonCrypto

let key = "1234567890123456" // 16 bytes for AES128

func generateRandomIV(for length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return String((0..<length).map{ _ in letters.randomElement()! })
}

func encryptAES(data: Data) -> Data {
let cryptLength = size_t(kCCBlockSizeAES128 + data.count + kCCKeySizeAES128)
var cryptData = Data(count:cryptLength)

let keyLength = size_t(kCCKeySizeAES128)
let options = CCOptions(kCCOptionPKCS7Padding)

var numBytesEncrypted :size_t = 0

let iv = generateRandomIV(for: 16) // 16 bytes for AES128

let cryptStatus = cryptData.withUnsafeMutableBytes {cryptBytes in
data.withUnsafeBytes {dataBytes in
CCCrypt(CCOperation(kCCEncrypt),
CCAlgorithm(kCCAlgorithmAES),
options,
key, keyLength,
iv,
dataBytes, data.count,
cryptBytes, cryptLength,
&numBytesEncrypted)
}
}

if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.removeSubrange(numBytesEncrypted..<cryptData.count)
} else {
print("Error: \\(cryptStatus)")
}

return cryptData
}

The updated code now includes a function generateRandomIV(for length: Int) -> String that generates a random initialization vector (IV) for AES encryption. This function uses a secure random number generator to generate a random string of the specified length. The generated string is composed of alphanumeric characters (both lowercase and uppercase) and digits.

The encryptAES(data: Data) -> Data function has been updated to use this dynamically generated IV instead of a static, hardcoded value. The IV is generated for each encryption operation, ensuring its uniqueness.

The IV is generated with a length of 16 bytes, which is the block size for AES128 encryption. The generated IV is passed to the CCCrypt function as the IV parameter.

This approach mitigates the risk of an attacker being able to predict the IV and perform a reverse engineering attack. The IV is unique for each encryption operation and is not hardcoded, making it unpredictable.

Please note that the generated IV needs to be stored securely as it will be needed for the decryption process. The storage method is not shown in this code and should be implemented according to the security requirements of your application.

References