protected synchronized void engineInit()

in src/com/amazon/corretto/crypto/provider/AesGcmSpi.java [294:384]


    protected synchronized void engineInit(
        int jceOpMode, Key key, AlgorithmParameterSpec algorithmParameterSpec, SecureRandom secureRandom
    ) throws InvalidKeyException, InvalidAlgorithmParameterException {
        if (key == null) {
            throw new InvalidKeyException("Key can't be null");
        }

        final GCMParameterSpec spec;
        if (algorithmParameterSpec instanceof GCMParameterSpec) {
            spec = (GCMParameterSpec) algorithmParameterSpec;
        } else if (algorithmParameterSpec instanceof IvParameterSpec) {
            spec = new GCMParameterSpec(DEFAULT_TAG_LENGTH,
                    ((IvParameterSpec) algorithmParameterSpec).getIV());
        } else {
            throw new InvalidAlgorithmParameterException("I don't know how to handle a " + algorithmParameterSpec.getClass());
        }

        byte[] encodedKey = null;
        if (jceKey != key) {
            if (!(key instanceof  SecretKey)) {
                throw new InvalidKeyException("Need a SecretKey");
            }
            String keyAlgorithm = key.getAlgorithm();
            if (!"RAW".equalsIgnoreCase(key.getFormat())) {
                throw new InvalidKeyException("Need a raw format key");
            }
            if (!keyAlgorithm.equalsIgnoreCase("AES")) {
                throw new InvalidKeyException("Expected an AES key");
            }
            encodedKey = key.getEncoded();
            if (encodedKey == null) {
                throw new InvalidKeyException("Key doesn't support encoding");
            }

            if (!MessageDigest.isEqual(encodedKey, this.key)) {
                if (encodedKey.length != 128 / 8 && encodedKey.length != 192 / 8 && encodedKey.length != 256 / 8) {
                    throw new InvalidKeyException("Bad key length of " + (encodedKey.length * 8) + " bits; expected 128, 192, or 256 bits");
                }

                keyUsageCount = 0;
                if (context != null) {
                    context.release();
                }

                context = null;
            } else {
                encodedKey = null;
            }
        }

        byte[] iv = spec.getIV();

        if ((spec.getTLen() % 8 != 0) || spec.getTLen() > 128 || spec.getTLen() < 96) {
            throw new InvalidAlgorithmParameterException("Unsupported TLen value; must be one of {128, 120, 112, 104, 96}");
        }


        if (this.iv != null && this.key != null && (jceOpMode == Cipher.ENCRYPT_MODE || jceOpMode == Cipher.WRAP_MODE)) {
            if (Arrays.equals(this.iv, iv) && (encodedKey == null || MessageDigest.isEqual(this.key, encodedKey))) {
                throw new InvalidAlgorithmParameterException("Cannot reuse same iv and key for GCM encryption");
            }
        }

        if (iv == null || iv.length == 0) {
            throw new InvalidAlgorithmParameterException("IV must be at least one byte long");
        }

        switch (jceOpMode) {
            case Cipher.ENCRYPT_MODE:
            case Cipher.WRAP_MODE:
                this.opMode = NATIVE_MODE_ENCRYPT;
                break;
            case Cipher.DECRYPT_MODE:
            case Cipher.UNWRAP_MODE:
                this.opMode = NATIVE_MODE_DECRYPT;
                break;
            default:
                throw new InvalidAlgorithmParameterException("Unsupported cipher mode " + jceOpMode);
        }


        this.iv = iv;
        this.tagLength = spec.getTLen() / 8;
        if (encodedKey != null) {
            this.key = encodedKey;
            this.jceKey = (SecretKey) key;
        }
        this.needReset = false;

        stateReset();
    }