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

package org.bouncycastle.crypto.tls;

import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Pack;
import org.bouncycastle.crypto.CryptoServiceProperties;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.constraints.DefaultServiceProperties;
import org.bouncycastle.crypto.CryptoServicePurpose;
import org.bouncycastle.crypto.constraints.ConstraintUtils;
import java.security.SecureRandom;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import java.math.BigInteger;

public abstract class TlsRsaKeyExchange
{
    public static final int PRE_MASTER_SECRET_LENGTH = 48;
    private static final BigInteger ONE;
    
    private TlsRsaKeyExchange() {
    }
    
    public static byte[] decryptPreMasterSecret(final byte[] array, final int n, final int n2, final RSAKeyParameters rsaKeyParameters, final int n3, SecureRandom secureRandom) {
        if (array == null || n2 < 1 || n2 > getInputLimit(rsaKeyParameters) || n < 0 || n > array.length - n2) {
            throw new IllegalArgumentException("input not a valid EncryptedPreMasterSecret");
        }
        if (!rsaKeyParameters.isPrivate()) {
            throw new IllegalArgumentException("'privateKey' must be an RSA private key");
        }
        final BigInteger modulus = rsaKeyParameters.getModulus();
        final int bitLength = modulus.bitLength();
        if (bitLength < 512) {
            throw new IllegalArgumentException("'privateKey' must be at least 512 bits");
        }
        CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties("RSA", ConstraintUtils.bitsOfSecurityFor(modulus), rsaKeyParameters, CryptoServicePurpose.DECRYPTION));
        if ((n3 & 0xFFFF) != n3) {
            throw new IllegalArgumentException("'protocolVersion' must be a 16 bit value");
        }
        secureRandom = CryptoServicesRegistrar.getSecureRandom(secureRandom);
        final byte[] bytes = new byte[48];
        secureRandom.nextBytes(bytes);
        try {
            final byte[] rsaBlinded = rsaBlinded(rsaKeyParameters, convertInput(modulus, array, n, n2), secureRandom);
            final int n4 = (bitLength - 1) / 8;
            final int n5 = rsaBlinded.length - 48;
            final int n6 = checkPkcs1Encoding2(rsaBlinded, n4, 48) | -((Pack.bigEndianToShort(rsaBlinded, n5) ^ n3) & 0xFFFF) >> 31;
            for (int i = 0; i < 48; ++i) {
                bytes[i] = (byte)((bytes[i] & n6) | (rsaBlinded[n5 + i] & ~n6));
            }
            Arrays.fill(rsaBlinded, (byte)0);
        }
        catch (final Exception ex) {}
        return bytes;
    }
    
    public static int getInputLimit(final RSAKeyParameters rsaKeyParameters) {
        return (rsaKeyParameters.getModulus().bitLength() + 7) / 8;
    }
    
    private static int caddTo(final int n, final int n2, final byte[] array, final byte[] array2) {
        final int n3 = n2 & 0xFF;
        int n4 = 0;
        for (int i = n - 1; i >= 0; --i) {
            final int n5 = n4 + ((array2[i] & 0xFF) + (array[i] & n3));
            array2[i] = (byte)n5;
            n4 = n5 >>> 8;
        }
        return n4;
    }
    
    private static int checkPkcs1Encoding2(final byte[] array, final int n, final int n2) {
        int n3 = n - n2 - 10;
        final int n4 = array.length - n;
        final int n5 = array.length - 1 - n2;
        for (int i = 0; i < n4; ++i) {
            n3 |= -(array[i] & 0xFF);
        }
        int n6 = n3 | -((array[n4] & 0xFF) ^ 0x2);
        for (int j = n4 + 1; j < n5; ++j) {
            n6 |= (array[j] & 0xFF) - 1;
        }
        return (n6 | -(array[n5] & 0xFF)) >> 31;
    }
    
    private static BigInteger convertInput(final BigInteger val, final byte[] array, final int n, final int n2) {
        final BigInteger fromUnsignedByteArray = BigIntegers.fromUnsignedByteArray(array, n, n2);
        if (fromUnsignedByteArray.compareTo(val) < 0) {
            return fromUnsignedByteArray;
        }
        throw new DataLengthException("input too large for RSA cipher.");
    }
    
    private static BigInteger rsa(final RSAKeyParameters rsaKeyParameters, final BigInteger bigInteger) {
        return bigInteger.modPow(rsaKeyParameters.getExponent(), rsaKeyParameters.getModulus());
    }
    
    private static byte[] rsaBlinded(final RSAKeyParameters rsaKeyParameters, final BigInteger val, final SecureRandom secureRandom) {
        final BigInteger modulus = rsaKeyParameters.getModulus();
        final int n = modulus.bitLength() / 8 + 1;
        if (rsaKeyParameters instanceof RSAPrivateCrtKeyParameters) {
            final RSAPrivateCrtKeyParameters rsaPrivateCrtKeyParameters = (RSAPrivateCrtKeyParameters)rsaKeyParameters;
            final BigInteger publicExponent = rsaPrivateCrtKeyParameters.getPublicExponent();
            if (publicExponent != null) {
                final BigInteger randomInRange = BigIntegers.createRandomInRange(TlsRsaKeyExchange.ONE, modulus.subtract(TlsRsaKeyExchange.ONE), secureRandom);
                final BigInteger modPow = randomInRange.modPow(publicExponent, modulus);
                final BigInteger modOddInverse = BigIntegers.modOddInverse(modulus, randomInRange);
                final BigInteger rsaCrt = rsaCrt(rsaPrivateCrtKeyParameters, modPow.multiply(val).mod(modulus));
                final BigInteger mod = modOddInverse.add(TlsRsaKeyExchange.ONE).multiply(rsaCrt).mod(modulus);
                final byte[] bytes = toBytes(rsaCrt, n);
                final byte[] bytes2 = toBytes(modulus, n);
                final byte[] bytes3 = toBytes(mod, n);
                caddTo(n, subFrom(n, bytes, bytes3), bytes2, bytes3);
                return bytes3;
            }
        }
        return toBytes(rsa(rsaKeyParameters, val), n);
    }
    
    private static BigInteger rsaCrt(final RSAPrivateCrtKeyParameters rsaPrivateCrtKeyParameters, final BigInteger x) {
        final BigInteger publicExponent = rsaPrivateCrtKeyParameters.getPublicExponent();
        final BigInteger p2 = rsaPrivateCrtKeyParameters.getP();
        final BigInteger q = rsaPrivateCrtKeyParameters.getQ();
        final BigInteger dp = rsaPrivateCrtKeyParameters.getDP();
        final BigInteger dq = rsaPrivateCrtKeyParameters.getDQ();
        final BigInteger qInv = rsaPrivateCrtKeyParameters.getQInv();
        final BigInteger modPow = x.remainder(p2).modPow(dp, p2);
        final BigInteger modPow2 = x.remainder(q).modPow(dq, q);
        final BigInteger add = modPow.subtract(modPow2).multiply(qInv).mod(p2).multiply(q).add(modPow2);
        if (!add.modPow(publicExponent, rsaPrivateCrtKeyParameters.getModulus()).equals(x)) {
            throw new IllegalStateException("RSA engine faulty decryption/signing detected");
        }
        return add;
    }
    
    private static int subFrom(final int n, final byte[] array, final byte[] array2) {
        int n2 = 0;
        for (int i = n - 1; i >= 0; --i) {
            final int n3 = n2 + ((array2[i] & 0xFF) - (array[i] & 0xFF));
            array2[i] = (byte)n3;
            n2 = n3 >> 8;
        }
        return n2;
    }
    
    private static byte[] toBytes(final BigInteger bigInteger, final int n) {
        final byte[] byteArray = bigInteger.toByteArray();
        final byte[] array = new byte[n];
        System.arraycopy(byteArray, 0, array, array.length - byteArray.length, byteArray.length);
        return array;
    }
    
    static {
        ONE = BigInteger.valueOf(1L);
    }
}
