// 
// Decompiled by Procyon v0.6.0
// 

package com.google.crypto.tink.aead.internal;

import java.security.spec.AlgorithmParameterSpec;
import java.security.Key;
import javax.crypto.spec.IvParameterSpec;
import com.google.crypto.tink.AccessesPartialKey;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.GeneralSecurityException;
import java.security.Provider;
import javax.crypto.SecretKey;
import com.google.crypto.tink.config.internal.TinkFipsUtil;
import com.google.errorprone.annotations.Immutable;

@Immutable
public final class InsecureNonceChaCha20Poly1305Jce
{
    private static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS;
    private static final int NONCE_SIZE_IN_BYTES = 12;
    private static final int TAG_SIZE_IN_BYTES = 16;
    private static final int KEY_SIZE_IN_BYTES = 32;
    private static final String KEY_NAME = "ChaCha20";
    private final SecretKey keySpec;
    private final Provider provider;
    
    private InsecureNonceChaCha20Poly1305Jce(final byte[] key, final Provider provider) throws GeneralSecurityException {
        if (!InsecureNonceChaCha20Poly1305Jce.FIPS.isCompatible()) {
            throw new GeneralSecurityException("Can not use ChaCha20Poly1305 in FIPS-mode.");
        }
        if (key.length != 32) {
            throw new InvalidKeyException("The key length in bytes must be 32.");
        }
        this.keySpec = new SecretKeySpec(key, "ChaCha20");
        this.provider = provider;
    }
    
    @AccessesPartialKey
    public static InsecureNonceChaCha20Poly1305Jce create(final byte[] key) throws GeneralSecurityException {
        final Cipher cipher = ChaCha20Poly1305Jce.getValidCipherInstance();
        return new InsecureNonceChaCha20Poly1305Jce(key, cipher.getProvider());
    }
    
    public static boolean isSupported() {
        return ChaCha20Poly1305Jce.isSupported();
    }
    
    public byte[] encrypt(final byte[] nonce, final byte[] plaintext, final byte[] associatedData) throws GeneralSecurityException {
        return this.encrypt(nonce, plaintext, 0, associatedData);
    }
    
    public byte[] encrypt(final byte[] nonce, final byte[] plaintext, final int ciphertextOffset, final byte[] associatedData) throws GeneralSecurityException {
        if (plaintext == null) {
            throw new NullPointerException("plaintext is null");
        }
        if (nonce.length != 12) {
            throw new GeneralSecurityException("nonce length must be 12 bytes.");
        }
        final AlgorithmParameterSpec params = new IvParameterSpec(nonce);
        final Cipher cipher = ChaCha20Poly1305Jce.getCipherInstance(this.provider);
        cipher.init(1, this.keySpec, params);
        if (associatedData != null && associatedData.length != 0) {
            cipher.updateAAD(associatedData);
        }
        final int ciphertextSize = cipher.getOutputSize(plaintext.length);
        if (ciphertextSize > Integer.MAX_VALUE - ciphertextOffset) {
            throw new GeneralSecurityException("plaintext too long");
        }
        final int outputSize = ciphertextOffset + ciphertextSize;
        final byte[] output = new byte[outputSize];
        final int written = cipher.doFinal(plaintext, 0, plaintext.length, output, ciphertextOffset);
        if (written != ciphertextSize) {
            throw new GeneralSecurityException("not enough data written");
        }
        return output;
    }
    
    public byte[] decrypt(final byte[] nonce, final byte[] ciphertext, final byte[] associatedData) throws GeneralSecurityException {
        return this.decrypt(nonce, ciphertext, 0, associatedData);
    }
    
    public byte[] decrypt(final byte[] nonce, final byte[] ciphertextWithPrefix, final int ciphertextOffset, final byte[] associatedData) throws GeneralSecurityException {
        if (ciphertextWithPrefix == null) {
            throw new NullPointerException("ciphertext is null");
        }
        if (nonce.length != 12) {
            throw new GeneralSecurityException("nonce length must be 12 bytes.");
        }
        if (ciphertextWithPrefix.length < ciphertextOffset + 16) {
            throw new GeneralSecurityException("ciphertext too short");
        }
        final AlgorithmParameterSpec params = new IvParameterSpec(nonce);
        final Cipher cipher = ChaCha20Poly1305Jce.getCipherInstance(this.provider);
        cipher.init(2, this.keySpec, params);
        if (associatedData != null && associatedData.length != 0) {
            cipher.updateAAD(associatedData);
        }
        return cipher.doFinal(ciphertextWithPrefix, ciphertextOffset, ciphertextWithPrefix.length - ciphertextOffset);
    }
    
    static {
        FIPS = TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_NOT_FIPS;
    }
}
