GCM Cipher with reused initialization vector is detected. Using the same initialization vector and Key to encrypt numerous plaintext blocks allows an attacker to compare the ciphertexts and glean information about the encrypted data based on assumptions about its content.
1// Noncompliant: GCM Cipher with reused initialization vector `theInnerIV2` is detected.
2fun noncompliant(clearText: String): String {
3 val cipher1: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
4 val cipher2: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
5 val keySpec: SecretKeySpec = SecretKeySpec(theKey.getEncoded(), "AES")
6
7 private val theInnerIV2: Array<Byte>
8
9 val gcmParameterSpec: GCMParameterSpec = GCMParameterSpec(GCM_TAG_LENGTH * 8, theInnerIV2)
10 cipher1.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec)
11 val gcmParameterSpec: GCMParameterSpec = GCMParameterSpec(GCM_TAG_LENGTH * 8, theInnerIV2)
12 cipher2.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec)
13
14 val decoded: Array<Byte> = Base64.getDecoder().decode(cipherText)
15 val decryptedText: Array<Byte> = cipher.doFinal(decoded)
16 return String(decryptedText)
17}
1// Compliant: GCM Cipher with new initialization vector is used
2fun compliant(clearText: String): String {
3 val cipher: Cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
4
5 val keySpec: SecretKeySpec= SecretKeySpec(theKey.getEncoded(), "AES")
6
7 private val theInnerIV: Array<Byte>
8 val gcmParameterSpec: GCMParameterSpec = GCMParameterSpec(GCM_TAG_LENGTH * 8, theInnerIV)
9 cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec)
10
11 val cipherText: Array<Byte> = cipher.doFinal(clearText.getBytes())
12
13 val encoded = base64.getEncoder().encodeToString(cipherText)
14 return encoded
15}