Skip to content

Use non-random initialization vector (IV)

Use non-random initialization vector (IV)

Description

Use of a non-random initialization vector makes the application vulnerable to dictionary attacks.

The following example demonstrates improper settings of hardcoded static IV:

public; class InsecureExample {
    @Override
    public void; run() throws; Exception;{
        byte;[]; IV = "0123456789abcdef".getBytes();
        String; clearText = "Jan van Eyck was here 1434";
        String; key = "ThisIs128bitSize";
        SecretKeySpec; skeySpec = new SecretKeySpec(key.getBytes(), "AES");
        Cipher; cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher;.init(Cipher.ENCRYPT_MODE;, skeySpec;, new; IvParameterSpec(IV))
        byte;[]; encryptedMessage = cipher.doFinal(clearText.getBytes());
        Log;.i(TAG, String.format("Message: %s";, Base64;.encodeToString(encryptedMessage, Base64.DEFAULT;)))
    }
}

Recommendation

In order to mitigate IV related cryptographic flaws, consider the following recommendations:

  • Unique IV for each encryption: It's essential to use a unique IV for each encryption operation. Reusing the same IV with the same key can lead to security vulnerabilities, such as exposing patterns in the ciphertext or facilitating attacks like replay attacks.
  • Randomness: IVs should be generated using a cryptographically secure random number generator (SecureRandom for Java, SecRandomCopyBytes for Swift). This randomness ensures that attackers cannot predict the IV, which would weaken the security of the encryption.
  • IV length: The length of the IV depends on the encryption algorithm being used. For example, in AES, the IV length is typically 128 bits (16 bytes) for AES-128, 192 bits (24 bytes) for AES-192, and 256 bits (32 bytes) for AES-256. It's important to use IVs of the appropriate length for the encryption algorithm.
import java.security.SecureRandom
import javax.crypto.spec.IvParameterSpec

object IVGenerator {
        fun generateIV(length: Int): ByteArray {
                val iv = ByteArray(length)
                val secureRandom = SecureRandom()
                secureRandom.nextBytes(iv)
                return iv
        }
}

fun main() {
        val ivLength = 16 // Length of IV in bytes
        val iv = IVGenerator.generateIV(ivLength)
        println("Generated IV: ${bytesToHex(iv)}")
}

fun bytesToHex(bytes: ByteArray): String {
        return bytes.joinToString("") { "%02x".format(it) }
}
import CryptoKit

func generateIV(length: Int) -> Data {
        var iv = Data(count: length)
        _ = iv.withUnsafeMutableBytes { ivPtr in
                guard let ivBaseAddress = ivPtr.baseAddress else { return }
                _ = SecRandomCopyBytes(kSecRandomDefault, length, ivBaseAddress)
        }
        return iv
}

let ivLength = 16 // Length of IV in bytes
let iv = generateIV(length: ivLength)
print("Generated IV: \(iv.hexEncodedString())")

extension Data {
        func hexEncodedString() -> String {
                return map { String(format: "%02hhx", $0) }.joined()
        }
}
import 'dart:typed_data';
import 'dart:math';

Uint8List generateIV(int length) {
    final random = Random.secure();
    return Uint8List.fromList(List.generate(length, (index) => random.nextInt(256)));
}

void main() {
    final ivLength = 16; // Length of IV in bytes
    final iv = generateIV(ivLength);
    print('Generated IV: ${bytesToHex(iv)}');
}

String bytesToHex(Uint8List bytes) {
    return bytes.map((byte) => byte.toRadixString(16).padLeft(2, '0')).join();
}

Standards

  • OWASP_MASVS_L1:
    • MSTG_CRYPTO_2
    • MSTG_CRYPTO_3
    • MSTG_CRYPTO_4
  • OWASP_MASVS_L2:
    • MSTG_CRYPTO_2
    • MSTG_CRYPTO_3
    • MSTG_CRYPTO_4
  • PCI_STANDARDS:
    • REQ_2_2
    • REQ_3_6
    • REQ_3_7
    • REQ_4_2
    • REQ_6_2
  • OWASP_MASVS_v2_1:
    • MASVS_CRYPTO_1
    • MASVS_CRYPTO_2
  • SOC2_CONTROLS:
    • CC_2_1
    • CC_4_1
    • CC_6_7
    • CC_7_1
    • CC_7_2
    • CC_7_4
    • CC_7_5