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

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

import org.bouncycastle.crypto.engines.RSABlindedEngine;
import java.io.ByteArrayOutputStream;
import java.security.spec.MGF1ParameterSpec;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import java.security.InvalidAlgorithmParameterException;
import java.security.ProviderException;
import java.security.spec.AlgorithmParameterSpec;
import org.bouncycastle.crypto.CryptoException;
import java.security.SignatureException;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.PrivateKey;
import org.bouncycastle.crypto.CipherParameters;
import java.security.InvalidKeyException;
import java.security.interfaces.RSAPublicKey;
import java.security.PublicKey;
import org.bouncycastle.jcajce.util.BCJcaJceHelper;
import org.bouncycastle.jcajce.provider.util.DigestFactory;
import org.bouncycastle.crypto.signers.PSSSigner;
import java.security.SecureRandom;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import java.security.spec.PSSParameterSpec;
import java.security.AlgorithmParameters;
import org.bouncycastle.jcajce.util.JcaJceHelper;
import java.security.SignatureSpi;

public class PSSSignatureSpi extends SignatureSpi
{
    private final JcaJceHelper helper;
    private AlgorithmParameters engineParams;
    private PSSParameterSpec paramSpec;
    private PSSParameterSpec originalSpec;
    private AsymmetricBlockCipher signer;
    private Digest contentDigest;
    private Digest mgfDigest;
    private int saltLength;
    private byte trailer;
    private boolean isRaw;
    private RSAKeyParameters key;
    private SecureRandom random;
    private PSSSigner pss;
    private boolean isInitState;
    
    private byte getTrailer(final int n) {
        if (n == 1) {
            return -68;
        }
        throw new IllegalArgumentException("unknown trailer field");
    }
    
    private void setupContentDigest() {
        this.contentDigest = DigestFactory.getDigest(this.paramSpec.getDigestAlgorithm());
        if (this.isRaw) {
            this.contentDigest = new NullPssDigest(this.contentDigest);
        }
    }
    
    protected PSSSignatureSpi(final AsymmetricBlockCipher asymmetricBlockCipher, final PSSParameterSpec pssParameterSpec) {
        this(asymmetricBlockCipher, pssParameterSpec, false);
    }
    
    protected PSSSignatureSpi(final AsymmetricBlockCipher signer, final PSSParameterSpec pssParameterSpec, final boolean isRaw) {
        this.helper = new BCJcaJceHelper();
        this.isInitState = true;
        this.signer = signer;
        this.originalSpec = pssParameterSpec;
        if (pssParameterSpec == null) {
            this.paramSpec = PSSParameterSpec.DEFAULT;
        }
        else {
            this.paramSpec = pssParameterSpec;
        }
        if ("MGF1".equals(this.paramSpec.getMGFAlgorithm())) {
            this.mgfDigest = DigestFactory.getDigest(this.paramSpec.getDigestAlgorithm());
        }
        else {
            this.mgfDigest = DigestFactory.getDigest(this.paramSpec.getMGFAlgorithm());
        }
        this.saltLength = this.paramSpec.getSaltLength();
        this.trailer = this.getTrailer(this.paramSpec.getTrailerField());
        this.isRaw = isRaw;
        this.setupContentDigest();
    }
    
    @Override
    protected void engineInitVerify(final PublicKey publicKey) throws InvalidKeyException {
        if (!(publicKey instanceof RSAPublicKey)) {
            throw new InvalidKeyException("Supplied key is not a RSAPublicKey instance");
        }
        this.key = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey);
        (this.pss = new PSSSigner(this.signer, this.contentDigest, this.mgfDigest, this.saltLength, this.trailer)).init(false, this.key);
        this.isInitState = true;
    }
    
    @Override
    protected void engineInitSign(final PrivateKey privateKey, final SecureRandom random) throws InvalidKeyException {
        this.random = random;
        this.engineInitSign(privateKey);
    }
    
    @Override
    protected void engineInitSign(final PrivateKey privateKey) throws InvalidKeyException {
        if (!(privateKey instanceof RSAPrivateKey)) {
            throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance");
        }
        this.key = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey);
        this.pss = new PSSSigner(this.signer, this.contentDigest, this.mgfDigest, this.saltLength, this.trailer);
        if (this.random != null) {
            this.pss.init(true, new ParametersWithRandom(this.key, this.random));
        }
        else {
            this.pss.init(true, this.key);
        }
        this.isInitState = true;
    }
    
    @Override
    protected void engineUpdate(final byte b) throws SignatureException {
        this.pss.update(b);
        this.isInitState = false;
    }
    
    @Override
    protected void engineUpdate(final byte[] array, final int n, final int n2) throws SignatureException {
        this.pss.update(array, n, n2);
        this.isInitState = false;
    }
    
    @Override
    protected byte[] engineSign() throws SignatureException {
        this.isInitState = true;
        try {
            return this.pss.generateSignature();
        }
        catch (final CryptoException ex) {
            throw new SignatureException(ex.getMessage());
        }
    }
    
    @Override
    protected boolean engineVerify(final byte[] array) throws SignatureException {
        this.isInitState = true;
        return this.pss.verifySignature(array);
    }
    
    @Override
    protected void engineSetParameter(AlgorithmParameterSpec originalSpec) throws InvalidAlgorithmParameterException {
        if (originalSpec == null) {
            if (this.originalSpec == null) {
                return;
            }
            originalSpec = this.originalSpec;
        }
        if (!this.isInitState) {
            throw new ProviderException("cannot call setParameter in the middle of update");
        }
        if (!(originalSpec instanceof PSSParameterSpec)) {
            throw new InvalidAlgorithmParameterException("Only PSSParameterSpec supported");
        }
        final PSSParameterSpec paramSpec = (PSSParameterSpec)originalSpec;
        if (this.originalSpec != null && !DigestFactory.isSameDigest(this.originalSpec.getDigestAlgorithm(), paramSpec.getDigestAlgorithm())) {
            throw new InvalidAlgorithmParameterException("parameter must be using " + this.originalSpec.getDigestAlgorithm());
        }
        Digest mgfDigest;
        if (paramSpec.getMGFAlgorithm().equalsIgnoreCase("MGF1") || paramSpec.getMGFAlgorithm().equals(PKCSObjectIdentifiers.id_mgf1.getId())) {
            if (!(paramSpec.getMGFParameters() instanceof MGF1ParameterSpec)) {
                throw new InvalidAlgorithmParameterException("unknown MGF parameters");
            }
            final MGF1ParameterSpec mgf1ParameterSpec = (MGF1ParameterSpec)paramSpec.getMGFParameters();
            if (!DigestFactory.isSameDigest(mgf1ParameterSpec.getDigestAlgorithm(), paramSpec.getDigestAlgorithm())) {
                throw new InvalidAlgorithmParameterException("digest algorithm for MGF should be the same as for PSS parameters.");
            }
            mgfDigest = DigestFactory.getDigest(mgf1ParameterSpec.getDigestAlgorithm());
        }
        else {
            if (!paramSpec.getMGFAlgorithm().equals("SHAKE128") && !paramSpec.getMGFAlgorithm().equals("SHAKE256")) {
                throw new InvalidAlgorithmParameterException("unknown mask generation function specified");
            }
            mgfDigest = DigestFactory.getDigest(paramSpec.getMGFAlgorithm());
        }
        if (mgfDigest == null) {
            throw new InvalidAlgorithmParameterException("no match on MGF algorithm: " + paramSpec.getMGFAlgorithm());
        }
        this.engineParams = null;
        this.paramSpec = paramSpec;
        this.mgfDigest = mgfDigest;
        this.saltLength = this.paramSpec.getSaltLength();
        this.trailer = this.getTrailer(this.paramSpec.getTrailerField());
        this.setupContentDigest();
        if (this.key != null) {
            this.pss = new PSSSigner(this.signer, this.contentDigest, mgfDigest, this.saltLength, this.trailer);
            if (this.key.isPrivate()) {
                this.pss.init(true, this.key);
            }
            else {
                this.pss.init(false, this.key);
            }
        }
    }
    
    @Override
    protected AlgorithmParameters engineGetParameters() {
        if (this.engineParams == null && this.paramSpec != null) {
            try {
                (this.engineParams = this.helper.createAlgorithmParameters("PSS")).init(this.paramSpec);
            }
            catch (final Exception ex) {
                throw new RuntimeException(ex.toString());
            }
        }
        return this.engineParams;
    }
    
    @Override
    @Deprecated
    protected void engineSetParameter(final String s, final Object o) {
        throw new UnsupportedOperationException("engineSetParameter unsupported");
    }
    
    @Override
    protected Object engineGetParameter(final String s) {
        throw new UnsupportedOperationException("engineGetParameter unsupported");
    }
    
    private static class NullPssDigest implements Digest
    {
        private ByteArrayOutputStream bOut;
        private Digest baseDigest;
        private boolean oddTime;
        
        public NullPssDigest(final Digest baseDigest) {
            this.bOut = new ByteArrayOutputStream();
            this.oddTime = true;
            this.baseDigest = baseDigest;
        }
        
        @Override
        public String getAlgorithmName() {
            return "NULL";
        }
        
        @Override
        public int getDigestSize() {
            return this.baseDigest.getDigestSize();
        }
        
        @Override
        public void update(final byte b) {
            this.bOut.write(b);
        }
        
        @Override
        public void update(final byte[] b, final int off, final int len) {
            this.bOut.write(b, off, len);
        }
        
        @Override
        public int doFinal(final byte[] array, final int n) {
            final byte[] byteArray = this.bOut.toByteArray();
            if (this.oddTime) {
                System.arraycopy(byteArray, 0, array, n, byteArray.length);
            }
            else {
                this.baseDigest.update(byteArray, 0, byteArray.length);
                this.baseDigest.doFinal(array, n);
            }
            this.reset();
            this.oddTime = !this.oddTime;
            return byteArray.length;
        }
        
        @Override
        public void reset() {
            this.bOut.reset();
            this.baseDigest.reset();
        }
        
        public int getByteLength() {
            return 0;
        }
    }
    
    public static class PSSwithRSA extends PSSSignatureSpi
    {
        public PSSwithRSA() {
            super(new RSABlindedEngine(), null);
        }
    }
    
    public static class SHA1withRSA extends PSSSignatureSpi
    {
        public SHA1withRSA() {
            super(new RSABlindedEngine(), PSSParameterSpec.DEFAULT);
        }
    }
    
    public static class SHA1withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA1withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA1", "SHAKE128", null, 20, 1));
        }
    }
    
    public static class SHA1withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA1withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA1", "SHAKE256", null, 20, 1));
        }
    }
    
    public static class SHA224withRSA extends PSSSignatureSpi
    {
        public SHA224withRSA() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-224", "MGF1", new MGF1ParameterSpec("SHA-224"), 28, 1));
        }
    }
    
    public static class SHA224withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA224withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-224", "SHAKE128", null, 28, 1));
        }
    }
    
    public static class SHA224withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA224withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-224", "SHAKE256", null, 28, 1));
        }
    }
    
    public static class SHA256withRSA extends PSSSignatureSpi
    {
        public SHA256withRSA() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), 32, 1));
        }
    }
    
    public static class SHA256withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA256withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-256", "SHAKE128", null, 32, 1));
        }
    }
    
    public static class SHA256withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA256withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-256", "SHAKE256", null, 32, 1));
        }
    }
    
    public static class SHA384withRSA extends PSSSignatureSpi
    {
        public SHA384withRSA() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-384", "MGF1", new MGF1ParameterSpec("SHA-384"), 48, 1));
        }
    }
    
    public static class SHA384withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA384withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-384", "SHAKE128", null, 48, 1));
        }
    }
    
    public static class SHA384withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA384withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-384", "SHAKE256", null, 48, 1));
        }
    }
    
    public static class SHA3_224withRSA extends PSSSignatureSpi
    {
        public SHA3_224withRSA() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-224", "MGF1", new MGF1ParameterSpec("SHA3-224"), 28, 1));
        }
    }
    
    public static class SHA3_224withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA3_224withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-224", "SHAKE128", null, 28, 1));
        }
    }
    
    public static class SHA3_224withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA3_224withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-224", "SHAKE256", null, 28, 1));
        }
    }
    
    public static class SHA3_256withRSA extends PSSSignatureSpi
    {
        public SHA3_256withRSA() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-256", "MGF1", new MGF1ParameterSpec("SHA3-256"), 32, 1));
        }
    }
    
    public static class SHA3_256withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA3_256withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-256", "SHAKE128", null, 32, 1));
        }
    }
    
    public static class SHA3_256withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA3_256withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-256", "SHAKE256", null, 32, 1));
        }
    }
    
    public static class SHA3_384withRSA extends PSSSignatureSpi
    {
        public SHA3_384withRSA() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-384", "MGF1", new MGF1ParameterSpec("SHA3-384"), 48, 1));
        }
    }
    
    public static class SHA3_384withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA3_384withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-384", "SHAKE128", null, 48, 1));
        }
    }
    
    public static class SHA3_384withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA3_384withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-384", "SHAKE256", null, 48, 1));
        }
    }
    
    public static class SHA3_512withRSA extends PSSSignatureSpi
    {
        public SHA3_512withRSA() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-512", "MGF1", new MGF1ParameterSpec("SHA3-512"), 64, 1));
        }
    }
    
    public static class SHA3_512withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA3_512withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-512", "SHAKE128", null, 64, 1));
        }
    }
    
    public static class SHA3_512withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA3_512withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA3-512", "SHAKE256", null, 64, 1));
        }
    }
    
    public static class SHA512_224withRSA extends PSSSignatureSpi
    {
        public SHA512_224withRSA() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512(224)", "MGF1", new MGF1ParameterSpec("SHA-512(224)"), 28, 1));
        }
    }
    
    public static class SHA512_224withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA512_224withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512(224)", "SHAKE128", null, 28, 1));
        }
    }
    
    public static class SHA512_224withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA512_224withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512(224)", "SHAKE256", null, 28, 1));
        }
    }
    
    public static class SHA512_256withRSA extends PSSSignatureSpi
    {
        public SHA512_256withRSA() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512(256)", "MGF1", new MGF1ParameterSpec("SHA-512(256)"), 32, 1));
        }
    }
    
    public static class SHA512_256withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA512_256withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512(256)", "SHAKE128", null, 32, 1));
        }
    }
    
    public static class SHA512_256withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA512_256withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512(256)", "SHAKE256", null, 32, 1));
        }
    }
    
    public static class SHA512withRSA extends PSSSignatureSpi
    {
        public SHA512withRSA() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512", "MGF1", new MGF1ParameterSpec("SHA-512"), 64, 1));
        }
    }
    
    public static class SHA512withRSAandSHAKE128 extends PSSSignatureSpi
    {
        public SHA512withRSAandSHAKE128() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512", "SHAKE128", null, 64, 1));
        }
    }
    
    public static class SHA512withRSAandSHAKE256 extends PSSSignatureSpi
    {
        public SHA512withRSAandSHAKE256() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-512", "SHAKE256", null, 64, 1));
        }
    }
    
    public static class SHAKE128WithRSAPSS extends PSSSignatureSpi
    {
        public SHAKE128WithRSAPSS() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHAKE128", "SHAKE128", null, 32, 1));
        }
    }
    
    public static class SHAKE256WithRSAPSS extends PSSSignatureSpi
    {
        public SHAKE256WithRSAPSS() {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHAKE256", "SHAKE256", null, 64, 1));
        }
    }
    
    public static class nonePSS extends PSSSignatureSpi
    {
        public nonePSS() {
            super(new RSABlindedEngine(), null, true);
        }
    }
}
