kotlin.lang.security.gcm-detection.gcm-detection

profile photo of semgrepsemgrep
Author
unknown
Download Count*

GCM detected, please check that IV/nonce is not reused, an Initialization Vector (IV) is a nonce used to randomize the encryption, so that even if multiple messages with identical plaintext are encrypted, the generated corresponding ciphertexts are different.Unlike the Key, the IV usually does not need to be secret, rather it is important that it is random and unique. Certain encryption schemes the IV is exchanged in public as part of the ciphertext. Reusing same Initialization Vector with the same Key to encrypt multiple plaintext blocks allows an attacker to compare the ciphertexts and then, with some assumptions on the content of the messages, to gain important information about the data being encrypted.

Run Locally

Run in CI

Defintion

rules:
  - id: gcm-detection
    metadata:
      category: security
      cwe:
        - "CWE-323: Reusing a Nonce, Key Pair in Encryption"
      references:
        - https://cwe.mitre.org/data/definitions/323.html
      technology:
        - kotlin
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      owasp:
        - A02:2021 - Cryptographic Failures
      subcategory:
        - audit
      likelihood: LOW
      impact: LOW
      confidence: LOW
      vulnerability_class:
        - Cryptographic Issues
    languages:
      - kt
    message: GCM detected, please check that IV/nonce is not reused, an
      Initialization Vector (IV) is a nonce used to randomize the encryption, so
      that even if multiple messages with identical plaintext are encrypted, the
      generated corresponding ciphertexts are different.Unlike the Key, the IV
      usually does not need to be secret, rather it is important that it is
      random and unique. Certain encryption schemes the IV is exchanged in
      public as part of the ciphertext. Reusing same Initialization Vector with
      the same Key to encrypt multiple plaintext blocks allows an attacker to
      compare the ciphertexts and then, with some assumptions on the content of
      the messages, to gain important information about the data being
      encrypted.
    patterns:
      - pattern-either:
          - pattern: $METHOD.getInstance("AES/GCM/NoPadding",...)
          - pattern: GCMParameterSpec(...)
    severity: INFO

Examples

gcm-detection.kt

import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
import java.util.Base64

public class GcmHardcodedIV
{
    fun byteArrayOfInts(vararg ints: Int) = Array<Byte>(ints.size) { pos -> ints[pos].toByte() }
    public final val GCM_TAG_LENGTH: Int = 16
    public final val BAD_IV: String = "ab0123456789"
    public final val BAD_IV2 = byteArrayOfInts(0,1,2,3,4,5,6,7,8,9,10,11)

    private val theIV: Array<Byte>
    private val theKey: SecretKey

    public fun main(args: Array<String>) : Void
    {
        val clearText: String = args[0]
        System.out.println(clearText)

        try {
            setKeys()

            val cipherText: String = encrypt(clearText)
            System.out.println(cipherText)

            val decrypted: String = decrypt(cipherText)
            System.out.println(decrypted)
        } catch(e: Exception) {
            System.out.println(e.getMessage())
        }
    }

    public fun encrypt(clearText: String): String {
        // ruleid:gcm-detection
        val cipher: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
        val keySpec: SecretKeySpec= SecretKeySpec(theKey.getEncoded(), "AES")
        val theBadIV: Array<Byte> = BAD_IV.getBytes()

        // ruleid:gcm-detection
        val gcmParameterSpec: GCMParameterSpec = GCMParameterSpec(GCM_TAG_LENGTH * 8, theBadIV)
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmParameterSpec)

        val cipherText: Array<Byte> = cipher.doFinal(clearText.getBytes())

        val encoded = base64.getEncoder().encodeToString(cipherText)
        return encoded
    }

    public fun decrypt(cipherText: String): String {
        // ruleid:gcm-detection
        val cipher: Cipher = Cipher.getInstance("AES/GCM/NoPadding")
        val keySpec: SecretKeySpec = SecretKeySpec(theKey.getEncoded(), "AES")

        // ruleid:gcm-detection
        val gcmParameterSpec: GCMParameterSpec = GCMParameterSpec(GCM_TAG_LENGTH * 8, theIV)
        cipher.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec)

        val decoded: Array<Byte> = Base64.getDecoder().decode(cipherText)
        val decryptedText: Array<Byte> = cipher.doFinal(decoded)

        return String(decryptedText)
    }

    public fun setKeys(): Void {
        val keyGenerator: KeyGenerator = KeyGenerator.getInstance("AES")
        keyGenerator.init(256)

        theIV = BAD_IV.getBytes()
    }

}