java.lang.security.audit.crypto.gcm-detection.gcm-detection

profile photo of semgrepsemgrep
Author
221
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
      functional-categories:
        - crypto::search::randomness::javax.crypto
      cwe:
        - "CWE-323: Reusing a Nonce, Key Pair in Encryption"
      references:
        - https://cwe.mitre.org/data/definitions/323.html
      technology:
        - java
      owasp:
        - A02:2021 - Cryptographic Failures
      subcategory:
        - audit
      likelihood: MEDIUM
      impact: MEDIUM
      confidence: LOW
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      vulnerability_class:
        - Cryptographic Issues
    languages:
      - java
    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: new GCMParameterSpec(...);
    severity: INFO

Examples

gcm-detection.java

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
{
    public static final int GCM_TAG_LENGTH = 16;
    public static final String BAD_IV = "ab0123456789";
    public static final byte[] BAD_IV2 = new byte[]{0,1,2,3,4,5,6,7,8,9,10,11};

    private static byte[] theIV;
    private static SecretKey theKey;

    public static void main( String[] args )
    {
        String clearText = args[0];
        System.out.println(clearText);

        try {
            setKeys();

            String cipherText = encrypt(clearText);
            System.out.println(cipherText);

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

    public static String encrypt(String clearText) throws Exception {
        // ruleid:gcm-detection
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        SecretKeySpec keySpec = new SecretKeySpec(theKey.getEncoded(), "AES");
        byte[] theBadIV = BAD_IV.getBytes();

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

        byte[] cipherText = cipher.doFinal(clearText.getBytes());

        return Base64.getEncoder().encodeToString(cipherText);
    }

    public static String decrypt(String cipherText) throws Exception {
        // ruleid:gcm-detection
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        SecretKeySpec keySpec = new SecretKeySpec(theKey.getEncoded(), "AES");

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

        byte[] decoded = Base64.getDecoder().decode(cipherText);
        byte[] decryptedText = cipher.doFinal(decoded);

        return new String(decryptedText);
    }

    public static void setKeys() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(256);

        theIV = BAD_IV.getBytes();
    }

}