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

package org.bouncycastle.pqc.jcajce.provider.cmce;

import org.bouncycastle.crypto.InvalidCipherTextException;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.pqc.crypto.cmce.CMCEKEMExtractor;
import org.bouncycastle.crypto.Wrapper;
import org.bouncycastle.crypto.SecretWithEncapsulation;
import javax.security.auth.DestroyFailedException;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.ShortBufferException;
import java.security.InvalidParameterException;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.jcajce.spec.KEMParameterSpec;
import java.security.InvalidKeyException;
import java.security.InvalidAlgorithmParameterException;
import java.security.SecureRandom;
import org.bouncycastle.util.Exceptions;
import java.security.spec.AlgorithmParameterSpec;
import java.security.Key;
import javax.crypto.NoSuchPaddingException;
import java.security.NoSuchAlgorithmException;
import org.bouncycastle.util.Strings;
import org.bouncycastle.pqc.crypto.cmce.CMCEParameters;
import java.security.AlgorithmParameters;
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
import org.bouncycastle.pqc.crypto.cmce.CMCEKEMGenerator;
import javax.crypto.CipherSpi;

class CMCECipherSpi extends CipherSpi
{
    private final String algorithmName;
    private CMCEKEMGenerator kemGen;
    private KTSParameterSpec kemParameterSpec;
    private BCCMCEPublicKey wrapKey;
    private BCCMCEPrivateKey unwrapKey;
    private AlgorithmParameters engineParams;
    private CMCEParameters cmceParameters;
    
    CMCECipherSpi(final String algorithmName) {
        this.algorithmName = algorithmName;
    }
    
    CMCECipherSpi(final CMCEParameters cmceParameters) {
        this.cmceParameters = cmceParameters;
        this.algorithmName = Strings.toUpperCase(cmceParameters.getName());
    }
    
    @Override
    protected void engineSetMode(final String str) throws NoSuchAlgorithmException {
        throw new NoSuchAlgorithmException("Cannot support mode " + str);
    }
    
    @Override
    protected void engineSetPadding(final String str) throws NoSuchPaddingException {
        throw new NoSuchPaddingException("Padding " + str + " unknown");
    }
    
    @Override
    protected int engineGetKeySize(final Key key) {
        return 2048;
    }
    
    @Override
    protected int engineGetBlockSize() {
        return 0;
    }
    
    @Override
    protected int engineGetOutputSize(final int n) {
        return -1;
    }
    
    @Override
    protected byte[] engineGetIV() {
        return null;
    }
    
    @Override
    protected AlgorithmParameters engineGetParameters() {
        if (this.engineParams == null) {
            try {
                (this.engineParams = AlgorithmParameters.getInstance(this.algorithmName, "BCPQC")).init(this.kemParameterSpec);
            }
            catch (final Exception ex) {
                throw Exceptions.illegalStateException(ex.toString(), ex);
            }
        }
        return this.engineParams;
    }
    
    @Override
    protected void engineInit(final int n, final Key key, final SecureRandom secureRandom) throws InvalidKeyException {
        try {
            this.engineInit(n, key, (AlgorithmParameterSpec)null, secureRandom);
        }
        catch (final InvalidAlgorithmParameterException ex) {
            throw Exceptions.illegalArgumentException(ex.getMessage(), ex);
        }
    }
    
    @Override
    protected void engineInit(final int n, final Key key, final AlgorithmParameterSpec algorithmParameterSpec, final SecureRandom secureRandom) throws InvalidKeyException, InvalidAlgorithmParameterException {
        if (algorithmParameterSpec == null) {
            this.kemParameterSpec = new KEMParameterSpec("AES-KWP");
        }
        else {
            if (!(algorithmParameterSpec instanceof KTSParameterSpec)) {
                throw new InvalidAlgorithmParameterException(this.algorithmName + " can only accept KTSParameterSpec");
            }
            this.kemParameterSpec = (KTSParameterSpec)algorithmParameterSpec;
        }
        if (n == 3) {
            if (!(key instanceof BCCMCEPublicKey)) {
                throw new InvalidKeyException("Only a " + this.algorithmName + " public key can be used for wrapping");
            }
            this.wrapKey = (BCCMCEPublicKey)key;
            this.kemGen = new CMCEKEMGenerator(CryptoServicesRegistrar.getSecureRandom(secureRandom));
        }
        else {
            if (n != 4) {
                throw new InvalidParameterException("Cipher only valid for wrapping/unwrapping");
            }
            if (!(key instanceof BCCMCEPrivateKey)) {
                throw new InvalidKeyException("Only a " + this.algorithmName + " private key can be used for unwrapping");
            }
            this.unwrapKey = (BCCMCEPrivateKey)key;
        }
        if (this.cmceParameters != null) {
            final String upperCase = Strings.toUpperCase(this.cmceParameters.getName());
            if (!upperCase.equals(key.getAlgorithm())) {
                throw new InvalidKeyException("cipher locked to " + upperCase);
            }
        }
    }
    
    @Override
    protected void engineInit(final int n, final Key key, final AlgorithmParameters algorithmParameters, final SecureRandom secureRandom) throws InvalidKeyException, InvalidAlgorithmParameterException {
        AlgorithmParameterSpec parameterSpec = null;
        if (algorithmParameters != null) {
            try {
                parameterSpec = algorithmParameters.getParameterSpec(KEMParameterSpec.class);
            }
            catch (final Exception ex) {
                throw new InvalidAlgorithmParameterException("can't handle parameter " + algorithmParameters.toString());
            }
        }
        this.engineInit(n, key, parameterSpec, secureRandom);
    }
    
    @Override
    protected byte[] engineUpdate(final byte[] array, final int n, final int n2) {
        throw new IllegalStateException("Not supported in a wrapping mode");
    }
    
    @Override
    protected int engineUpdate(final byte[] array, final int n, final int n2, final byte[] array2, final int n3) throws ShortBufferException {
        throw new IllegalStateException("Not supported in a wrapping mode");
    }
    
    @Override
    protected byte[] engineDoFinal(final byte[] array, final int n, final int n2) throws IllegalBlockSizeException, BadPaddingException {
        throw new IllegalStateException("Not supported in a wrapping mode");
    }
    
    @Override
    protected int engineDoFinal(final byte[] array, final int n, final int n2, final byte[] array2, final int n3) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
        throw new IllegalStateException("Not supported in a wrapping mode");
    }
    
    @Override
    protected byte[] engineWrap(final Key key) throws IllegalBlockSizeException, InvalidKeyException {
        if (key.getEncoded() == null) {
            throw new InvalidKeyException("Cannot wrap key, null encoding.");
        }
        try {
            final SecretWithEncapsulation generateEncapsulated = this.kemGen.generateEncapsulated(this.wrapKey.getKeyParams());
            final Wrapper wrapper = WrapUtil.getWrapper(this.kemParameterSpec.getKeyAlgorithmName());
            wrapper.init(true, new KeyParameter(generateEncapsulated.getSecret()));
            final byte[] encapsulation = generateEncapsulated.getEncapsulation();
            generateEncapsulated.destroy();
            final byte[] encoded = key.getEncoded();
            final byte[] concatenate = Arrays.concatenate(encapsulation, wrapper.wrap(encoded, 0, encoded.length));
            Arrays.clear(encoded);
            return concatenate;
        }
        catch (final IllegalArgumentException ex) {
            throw new IllegalBlockSizeException("unable to generate KTS secret: " + ex.getMessage());
        }
        catch (final DestroyFailedException ex2) {
            throw new IllegalBlockSizeException("unable to destroy interim values: " + ex2.getMessage());
        }
    }
    
    @Override
    protected Key engineUnwrap(final byte[] array, final String algorithm, final int n) throws InvalidKeyException, NoSuchAlgorithmException {
        if (n != 3) {
            throw new InvalidKeyException("only SECRET_KEY supported");
        }
        try {
            final CMCEKEMExtractor cmcekemExtractor = new CMCEKEMExtractor(this.unwrapKey.getKeyParams());
            final byte[] secret = cmcekemExtractor.extractSecret(Arrays.copyOfRange(array, 0, cmcekemExtractor.getEncapsulationLength()));
            final Wrapper wrapper = WrapUtil.getWrapper(this.kemParameterSpec.getKeyAlgorithmName());
            final KeyParameter keyParameter = new KeyParameter(secret);
            Arrays.clear(secret);
            wrapper.init(false, keyParameter);
            final byte[] copyOfRange = Arrays.copyOfRange(array, cmcekemExtractor.getEncapsulationLength(), array.length);
            final SecretKeySpec secretKeySpec = new SecretKeySpec(wrapper.unwrap(copyOfRange, 0, copyOfRange.length), algorithm);
            Arrays.clear(keyParameter.getKey());
            return secretKeySpec;
        }
        catch (final IllegalArgumentException ex) {
            throw new NoSuchAlgorithmException("unable to extract KTS secret: " + ex.getMessage());
        }
        catch (final InvalidCipherTextException ex2) {
            throw new InvalidKeyException("unable to extract KTS secret: " + ex2.getMessage());
        }
    }
    
    public static class Base extends CMCECipherSpi
    {
        public Base() throws NoSuchAlgorithmException {
            super("CMCE");
        }
    }
    
    public static class MCE348864 extends CMCECipherSpi
    {
        public MCE348864() throws NoSuchAlgorithmException {
            super(CMCEParameters.mceliece348864r3);
        }
    }
    
    public static class MCE460896 extends CMCECipherSpi
    {
        public MCE460896() throws NoSuchAlgorithmException {
            super(CMCEParameters.mceliece460896r3);
        }
    }
    
    public static class MCE6688128 extends CMCECipherSpi
    {
        public MCE6688128() throws NoSuchAlgorithmException {
            super(CMCEParameters.mceliece6688128r3);
        }
    }
    
    public static class MCE6960119 extends CMCECipherSpi
    {
        public MCE6960119() throws NoSuchAlgorithmException {
            super(CMCEParameters.mceliece6960119r3);
        }
    }
    
    public static class MCE8192128 extends CMCECipherSpi
    {
        public MCE8192128() throws NoSuchAlgorithmException {
            super(CMCEParameters.mceliece8192128r3);
        }
    }
}
