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

package org.bouncycastle.crypto.hpke;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.Bytes;
import org.bouncycastle.util.Pack;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.modes.ChaCha20Poly1305;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.AEADCipher;

public class AEAD
{
    private final short aeadId;
    private final byte[] key;
    private final byte[] baseNonce;
    private long seq;
    private AEADCipher cipher;
    
    public AEAD(final short aeadId, final byte[] key, final byte[] baseNonce) {
        this.seq = 0L;
        this.key = key;
        this.baseNonce = baseNonce;
        this.aeadId = aeadId;
        this.seq = 0L;
        switch (aeadId) {
            case 1:
            case 2: {
                this.cipher = GCMBlockCipher.newInstance(AESEngine.newInstance());
                break;
            }
            case 3: {
                this.cipher = new ChaCha20Poly1305();
                break;
            }
        }
    }
    
    public byte[] seal(final byte[] array, final byte[] array2) throws InvalidCipherTextException {
        return this.process(true, array, array2, 0, array2.length);
    }
    
    public byte[] seal(final byte[] array, final byte[] array2, final int n, final int n2) throws InvalidCipherTextException {
        Arrays.validateSegment(array2, n, n2);
        return this.process(true, array, array2, n, n2);
    }
    
    public byte[] open(final byte[] array, final byte[] array2) throws InvalidCipherTextException {
        return this.process(false, array, array2, 0, array2.length);
    }
    
    public byte[] open(final byte[] array, final byte[] array2, final int n, final int n2) throws InvalidCipherTextException {
        Arrays.validateSegment(array2, n, n2);
        return this.process(false, array, array2, n, n2);
    }
    
    private byte[] computeNonce() {
        final byte[] longToBigEndian = Pack.longToBigEndian(this.seq++);
        final byte[] clone = Arrays.clone(this.baseNonce);
        Bytes.xorTo(8, longToBigEndian, 0, clone, clone.length - 8);
        return clone;
    }
    
    private byte[] process(final boolean b, final byte[] array, final byte[] array2, final int n, final int n2) throws InvalidCipherTextException {
        switch (this.aeadId) {
            case 1:
            case 2:
            case 3: {
                this.cipher.init(b, new ParametersWithIV(new KeyParameter(this.key), this.computeNonce()));
                this.cipher.processAADBytes(array, 0, array.length);
                final byte[] array3 = new byte[this.cipher.getOutputSize(n2)];
                final int processBytes = this.cipher.processBytes(array2, n, n2, array3, 0);
                if (processBytes + this.cipher.doFinal(array3, processBytes) != array3.length) {
                    throw new IllegalStateException();
                }
                return array3;
            }
            default: {
                throw new IllegalStateException("Export only mode, cannot be used to seal/open");
            }
        }
    }
}
