AESGCM class uses hardcoded SecureRandom in key encryption

Issue #324 invalid
Marco Buzzanca created an issue

Problem

I tried to set a custom SecureRandom within RCAEncrypter's JCAContext and it is not getting used by the part of the algorithm that generates the encrypted key. I detected the issue by using a mock SecureRandom.

Description

The AESGCM class initializes ciphers during encryption and decryption with an hardcoded SecureRandom. Relevant snippet contains the definition of the AESGCM.encrypt() method:

public static AuthenticatedCipherText encrypt(final SecretKey secretKey,
                                              final Container<byte[]> ivContainer,
                                              final byte[] plainText,
                                              final byte[] authData,
                                              final Provider provider)
        throws JOSEException {

        // Key alg must be "AES"
        final SecretKey aesKey = KeyUtils.toAESKey(secretKey);

        Cipher cipher;

        byte[] iv = ivContainer.get();

        try {
                if (provider != null) {
                        cipher = Cipher.getInstance("AES/GCM/NoPadding", provider);
                } else {
                        cipher = Cipher.getInstance("AES/GCM/NoPadding");
                }

                GCMParameterSpec gcmSpec = new GCMParameterSpec(AUTH_TAG_BIT_LENGTH, iv);
                // this initialization uses hardcoded JceSecurity.RANDOM !!!
                cipher.init(Cipher.ENCRYPT_MODE, aesKey, gcmSpec);

        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {

                throw new JOSEException("Couldn't create AES/GCM/NoPadding cipher: " + e.getMessage(), e);

        } catch (NoClassDefFoundError e) {
                // We have Java 6, GCMParameterSpec not available,
                // switch to BouncyCastle API
                return LegacyAESGCM.encrypt(aesKey, iv, plainText, authData);
        }

        cipher.updateAAD(authData);

        byte[] cipherOutput;

        try {
                cipherOutput = cipher.doFinal(plainText);

        } catch (IllegalBlockSizeException | BadPaddingException e) {

                throw new JOSEException("Couldn't encrypt with AES/GCM/NoPadding: " + e.getMessage(), e);
        }

        final int tagPos = cipherOutput.length - ByteUtils.byteLength(AUTH_TAG_BIT_LENGTH);

        byte[] cipherText = ByteUtils.subArray(cipherOutput, 0, tagPos);
        byte[] authTag = ByteUtils.subArray(cipherOutput, tagPos, ByteUtils.byteLength(AUTH_TAG_BIT_LENGTH));

        // retrieve the actual IV used by the cipher -- it may be internally-generated.
        ivContainer.set(actualIVOf(cipher));

        return new AuthenticatedCipherText(cipherText, authTag);
}

Given that the JCAContext does allow usage of a custom implementation SecureRandom via its setSecureRandom() method, shouldn't this class make use of the custom SecureRandom as well?

Comments (2)

  1. Connect2id OSS

    The IV is generated from the JCA context, prior to calling the cited method:

    https://bitbucket.org/connect2id/nimbus-jose-jwt/src/dd19a712b2b8c0f7c64cb6678cbf96f97d81553e/src/main/java/com/nimbusds/jose/crypto/impl/ContentCryptoProvider.java#lines-190

    Container<byte[]> ivContainer = new Container<>(AESGCM.generateIV(jcaProvider.getSecureRandom()));
    authCipherText = AESGCM.encrypt(cek, ivContainer, plainText, aad, jcaProvider.getContentEncryptionProvider());
    

    Or perhaps you meant something else?

  2. Log in to comment