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

package org.bouncycastle.jcajce.provider.asymmetric.ec;

import org.bouncycastle.crypto.digests.WhirlpoolDigest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.RIPEMD160Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.digests.Blake2sDigest;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.Blake2bDigest;
import org.bouncycastle.util.Arrays;
import java.io.ByteArrayOutputStream;
import javax.crypto.ShortBufferException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import org.bouncycastle.jcajce.provider.util.BadBlockException;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.InvalidKeyException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import javax.crypto.NoSuchPaddingException;
import java.security.NoSuchAlgorithmException;
import org.bouncycastle.util.Strings;
import java.security.AlgorithmParameters;
import org.bouncycastle.jce.interfaces.ECKey;
import java.security.Key;
import org.bouncycastle.jcajce.util.BCJcaJceHelper;
import java.security.SecureRandom;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.jcajce.util.JcaJceHelper;
import javax.crypto.CipherSpi;

public class GMCipherSpi extends CipherSpi
{
    private final JcaJceHelper helper;
    private SM2Engine engine;
    private int state;
    private ErasableOutputStream buffer;
    private AsymmetricKeyParameter key;
    private SecureRandom random;
    
    public GMCipherSpi(final SM2Engine engine) {
        this.helper = new BCJcaJceHelper();
        this.state = -1;
        this.buffer = new ErasableOutputStream();
        this.engine = engine;
    }
    
    public int engineGetBlockSize() {
        return 0;
    }
    
    public int engineGetKeySize(final Key key) {
        if (key instanceof ECKey) {
            return ((ECKey)key).getParameters().getCurve().getFieldSize();
        }
        throw new IllegalArgumentException("not an EC key");
    }
    
    public byte[] engineGetIV() {
        return null;
    }
    
    public AlgorithmParameters engineGetParameters() {
        return null;
    }
    
    public void engineSetMode(final String str) throws NoSuchAlgorithmException {
        if (!Strings.toUpperCase(str).equals("NONE")) {
            throw new IllegalArgumentException("can't support mode " + str);
        }
    }
    
    public int engineGetOutputSize(final int n) {
        if (this.state == 1 || this.state == 3) {
            return this.engine.getOutputSize(n);
        }
        if (this.state == 2 || this.state == 4) {
            return this.engine.getOutputSize(n);
        }
        throw new IllegalStateException("cipher not initialised");
    }
    
    public void engineSetPadding(final String s) throws NoSuchPaddingException {
        if (!Strings.toUpperCase(s).equals("NOPADDING")) {
            throw new NoSuchPaddingException("padding not available with IESCipher");
        }
    }
    
    public void engineInit(final int n, final Key key, final AlgorithmParameters algorithmParameters, final SecureRandom secureRandom) throws InvalidKeyException, InvalidAlgorithmParameterException {
        final AlgorithmParameterSpec algorithmParameterSpec = null;
        if (algorithmParameters != null) {
            throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + algorithmParameters.getClass().getName());
        }
        this.engineInit(n, key, algorithmParameterSpec, secureRandom);
    }
    
    public void engineInit(final int state, final Key key, final AlgorithmParameterSpec algorithmParameterSpec, final SecureRandom random) throws InvalidAlgorithmParameterException, InvalidKeyException {
        if (state == 1 || state == 3) {
            if (!(key instanceof PublicKey)) {
                throw new InvalidKeyException("must be passed public EC key for encryption");
            }
            this.key = ECUtils.generatePublicKeyParameter((PublicKey)key);
        }
        else {
            if (state != 2 && state != 4) {
                throw new InvalidKeyException("must be passed EC key");
            }
            if (!(key instanceof PrivateKey)) {
                throw new InvalidKeyException("must be passed private EC key for decryption");
            }
            this.key = ECUtil.generatePrivateKeyParameter((PrivateKey)key);
        }
        if (random != null) {
            this.random = random;
        }
        else {
            this.random = CryptoServicesRegistrar.getSecureRandom();
        }
        this.state = state;
        this.buffer.reset();
    }
    
    public 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 new IllegalArgumentException("cannot handle supplied parameter spec: " + ex.getMessage());
        }
    }
    
    public byte[] engineUpdate(final byte[] b, final int off, final int len) {
        this.buffer.write(b, off, len);
        return null;
    }
    
    public int engineUpdate(final byte[] b, final int off, final int len, final byte[] array, final int n) {
        this.buffer.write(b, off, len);
        return 0;
    }
    
    public byte[] engineDoFinal(final byte[] b, final int off, final int len) throws IllegalBlockSizeException, BadPaddingException {
        if (len != 0) {
            this.buffer.write(b, off, len);
        }
        try {
            Label_0101: {
                if (this.state != 1) {
                    if (this.state != 3) {
                        break Label_0101;
                    }
                }
                try {
                    this.engine.init(true, new ParametersWithRandom(this.key, this.random));
                    return this.engine.processBlock(this.buffer.getBuf(), 0, this.buffer.size());
                }
                catch (final Exception ex) {
                    throw new BadBlockException("unable to process block", ex);
                }
            }
            if (this.state != 2) {
                if (this.state != 4) {
                    throw new IllegalStateException("cipher not initialised");
                }
            }
            try {
                this.engine.init(false, this.key);
                return this.engine.processBlock(this.buffer.getBuf(), 0, this.buffer.size());
            }
            catch (final Exception ex2) {
                throw new BadBlockException("unable to process block", ex2);
            }
            throw new IllegalStateException("cipher not initialised");
        }
        finally {
            this.buffer.erase();
        }
    }
    
    public int engineDoFinal(final byte[] array, final int n, final int n2, final byte[] array2, final int n3) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
        final byte[] engineDoFinal = this.engineDoFinal(array, n, n2);
        System.arraycopy(engineDoFinal, 0, array2, n3, engineDoFinal.length);
        return engineDoFinal.length;
    }
    
    protected static final class ErasableOutputStream extends ByteArrayOutputStream
    {
        public ErasableOutputStream() {
        }
        
        public byte[] getBuf() {
            return this.buf;
        }
        
        public void erase() {
            Arrays.fill(this.buf, (byte)0);
            this.reset();
        }
    }
    
    public static class SM2 extends GMCipherSpi
    {
        public SM2() {
            super(new SM2Engine());
        }
    }
    
    public static class SM2withBlake2b extends GMCipherSpi
    {
        public SM2withBlake2b() {
            super(new SM2Engine(new Blake2bDigest(512)));
        }
    }
    
    public static class SM2withBlake2s extends GMCipherSpi
    {
        public SM2withBlake2s() {
            super(new SM2Engine(new Blake2sDigest(256)));
        }
    }
    
    public static class SM2withMD5 extends GMCipherSpi
    {
        public SM2withMD5() {
            super(new SM2Engine(new MD5Digest()));
        }
    }
    
    public static class SM2withRMD extends GMCipherSpi
    {
        public SM2withRMD() {
            super(new SM2Engine(new RIPEMD160Digest()));
        }
    }
    
    public static class SM2withSha1 extends GMCipherSpi
    {
        public SM2withSha1() {
            super(new SM2Engine(new SHA1Digest()));
        }
    }
    
    public static class SM2withSha224 extends GMCipherSpi
    {
        public SM2withSha224() {
            super(new SM2Engine(new SHA224Digest()));
        }
    }
    
    public static class SM2withSha256 extends GMCipherSpi
    {
        public SM2withSha256() {
            super(new SM2Engine(SHA256Digest.newInstance()));
        }
    }
    
    public static class SM2withSha384 extends GMCipherSpi
    {
        public SM2withSha384() {
            super(new SM2Engine(new SHA384Digest()));
        }
    }
    
    public static class SM2withSha512 extends GMCipherSpi
    {
        public SM2withSha512() {
            super(new SM2Engine(new SHA512Digest()));
        }
    }
    
    public static class SM2withWhirlpool extends GMCipherSpi
    {
        public SM2withWhirlpool() {
            super(new SM2Engine(new WhirlpoolDigest()));
        }
    }
}
