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

package org.bouncycastle.cms.bc;

import org.bouncycastle.operator.GenericKey;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.util.CipherFactory;
import org.bouncycastle.operator.MacCaptureStream;
import org.bouncycastle.operator.OutputAEADEncryptor;
import java.io.IOException;
import org.bouncycastle.crypto.modes.AEADBlockCipher;
import java.io.OutputStream;
import org.bouncycastle.operator.DefaultSecretKeySizeProvider;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.operator.OutputEncryptor;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import java.security.SecureRandom;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.operator.SecretKeySizeProvider;

public class BcCMSContentEncryptorBuilder
{
    private static final SecretKeySizeProvider KEY_SIZE_PROVIDER;
    private final ASN1ObjectIdentifier encryptionOID;
    private final int keySize;
    private EnvelopedDataHelper helper;
    private SecureRandom random;
    
    public BcCMSContentEncryptorBuilder(final ASN1ObjectIdentifier asn1ObjectIdentifier) {
        this(asn1ObjectIdentifier, BcCMSContentEncryptorBuilder.KEY_SIZE_PROVIDER.getKeySize(asn1ObjectIdentifier));
    }
    
    public BcCMSContentEncryptorBuilder(final ASN1ObjectIdentifier encryptionOID, final int keySize) {
        this.helper = new EnvelopedDataHelper();
        this.encryptionOID = encryptionOID;
        final int keySize2 = BcCMSContentEncryptorBuilder.KEY_SIZE_PROVIDER.getKeySize(encryptionOID);
        if (encryptionOID.equals(PKCSObjectIdentifiers.des_EDE3_CBC)) {
            if (keySize != 168 && keySize != keySize2) {
                throw new IllegalArgumentException("incorrect keySize for encryptionOID passed to builder.");
            }
            this.keySize = 168;
        }
        else if (encryptionOID.equals(OIWObjectIdentifiers.desCBC)) {
            if (keySize != 56 && keySize != keySize2) {
                throw new IllegalArgumentException("incorrect keySize for encryptionOID passed to builder.");
            }
            this.keySize = 56;
        }
        else {
            if (keySize2 > 0 && keySize2 != keySize) {
                throw new IllegalArgumentException("incorrect keySize for encryptionOID passed to builder.");
            }
            this.keySize = keySize;
        }
    }
    
    public BcCMSContentEncryptorBuilder setSecureRandom(final SecureRandom random) {
        this.random = random;
        return this;
    }
    
    public OutputEncryptor build() throws CMSException {
        if (this.random == null) {
            this.random = new SecureRandom();
        }
        return this.build(this.helper.createKeyGenerator(this.encryptionOID, this.keySize, this.random).generateKey());
    }
    
    public OutputEncryptor build(final byte[] array) throws CMSException {
        if (this.random == null) {
            this.random = new SecureRandom();
        }
        if (this.keySize > 0 && (this.keySize + 7) / 8 != array.length && this.keySize != 56 && array.length != 8 && this.keySize != 168 && array.length != 24) {
            throw new IllegalArgumentException("attempt to create encryptor with the wrong sized key");
        }
        if (this.helper.isAuthEnveloped(this.encryptionOID)) {
            return new CMSAuthOutputEncryptor(this.encryptionOID, new KeyParameter(array), this.random);
        }
        return new CMSOutputEncryptor(this.encryptionOID, new KeyParameter(array), this.random);
    }
    
    static {
        KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE;
    }
    
    private static class AADStream extends OutputStream
    {
        private AEADBlockCipher cipher;
        
        public AADStream(final AEADBlockCipher cipher) {
            this.cipher = cipher;
        }
        
        @Override
        public void write(final byte[] array, final int n, final int n2) throws IOException {
            this.cipher.processAADBytes(array, n, n2);
        }
        
        @Override
        public void write(final int n) throws IOException {
            this.cipher.processAADByte((byte)n);
        }
    }
    
    private class CMSAuthOutputEncryptor extends CMSOutputEncryptor implements OutputAEADEncryptor
    {
        private AEADBlockCipher aeadCipher;
        private MacCaptureStream macOut;
        
        CMSAuthOutputEncryptor(final ASN1ObjectIdentifier asn1ObjectIdentifier, final KeyParameter keyParameter, final SecureRandom secureRandom) throws CMSException {
            super(asn1ObjectIdentifier, keyParameter, secureRandom);
            this.aeadCipher = this.getCipher();
        }
        
        private AEADBlockCipher getCipher() {
            if (!(this.cipher instanceof AEADBlockCipher)) {
                throw new IllegalArgumentException("Unable to create Authenticated Output Encryptor without Authenticaed Data cipher!");
            }
            return (AEADBlockCipher)this.cipher;
        }
        
        @Override
        public OutputStream getOutputStream(final OutputStream outputStream) {
            this.macOut = new MacCaptureStream(outputStream, this.aeadCipher.getMac().length);
            return CipherFactory.createOutputStream(this.macOut, this.cipher);
        }
        
        @Override
        public OutputStream getAADStream() {
            return new AADStream(this.aeadCipher);
        }
        
        @Override
        public byte[] getMAC() {
            return this.macOut.getMac();
        }
    }
    
    private class CMSOutputEncryptor implements OutputEncryptor
    {
        private KeyParameter encKey;
        private AlgorithmIdentifier algorithmIdentifier;
        protected Object cipher;
        
        CMSOutputEncryptor(final ASN1ObjectIdentifier asn1ObjectIdentifier, final KeyParameter encKey, final SecureRandom secureRandom) throws CMSException {
            this.algorithmIdentifier = BcCMSContentEncryptorBuilder.this.helper.generateEncryptionAlgID(asn1ObjectIdentifier, encKey, secureRandom);
            this.encKey = encKey;
            this.cipher = EnvelopedDataHelper.createContentCipher(true, encKey, this.algorithmIdentifier);
        }
        
        @Override
        public AlgorithmIdentifier getAlgorithmIdentifier() {
            return this.algorithmIdentifier;
        }
        
        @Override
        public OutputStream getOutputStream(final OutputStream outputStream) {
            return CipherFactory.createOutputStream(outputStream, this.cipher);
        }
        
        @Override
        public GenericKey getKey() {
            return new GenericKey(this.algorithmIdentifier, this.encKey.getKey());
        }
    }
}
