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

package com.google.crypto.tink.signature.internal;

import com.google.crypto.tink.subtle.Bytes;
import java.security.PrivateKey;
import java.security.Signature;
import com.google.crypto.tink.AccessesPartialKey;
import com.google.crypto.tink.subtle.RsaSsaPkcs1VerifyJce;
import java.security.spec.KeySpec;
import java.security.spec.RSAPrivateCrtKeySpec;
import com.google.crypto.tink.InsecureSecretKeyAccess;
import com.google.crypto.tink.subtle.EngineFactory;
import java.security.KeyFactory;
import com.google.crypto.tink.signature.RsaSsaPkcs1PrivateKey;
import com.google.crypto.tink.subtle.Validators;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.signature.RsaSsaPkcs1Parameters;
import javax.annotation.Nullable;
import java.security.Provider;
import com.google.crypto.tink.PublicKeyVerify;
import java.security.interfaces.RSAPrivateCrtKey;
import com.google.crypto.tink.config.internal.TinkFipsUtil;
import com.google.errorprone.annotations.Immutable;
import com.google.crypto.tink.PublicKeySign;

@Immutable
public final class RsaSsaPkcs1SignJce implements PublicKeySign
{
    public static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS;
    private static final byte[] EMPTY;
    private static final byte[] legacyMessageSuffix;
    private static final byte[] testData;
    private final RSAPrivateCrtKey privateKey;
    private final String signatureAlgorithm;
    private final byte[] outputPrefix;
    private final byte[] messageSuffix;
    private final PublicKeyVerify verifier;
    @Nullable
    Provider conscryptOrNull;
    
    private static void validateHash(final RsaSsaPkcs1Parameters.HashType hash) throws GeneralSecurityException {
        if (hash == RsaSsaPkcs1Parameters.HashType.SHA256 || hash == RsaSsaPkcs1Parameters.HashType.SHA384 || hash == RsaSsaPkcs1Parameters.HashType.SHA512) {
            return;
        }
        throw new GeneralSecurityException("Unsupported hash: " + hash);
    }
    
    private RsaSsaPkcs1SignJce(final RSAPrivateCrtKey privateKey, final RsaSsaPkcs1Parameters.HashType hash, final byte[] outputPrefix, final byte[] messageSuffix, final PublicKeyVerify verifier, @Nullable final Provider conscryptOrNull) throws GeneralSecurityException {
        if (!RsaSsaPkcs1SignJce.FIPS.isCompatible()) {
            throw new GeneralSecurityException("Can not use RSA PKCS1.5 in FIPS-mode, as BoringCrypto module is not available.");
        }
        validateHash(hash);
        Validators.validateRsaModulusSize(privateKey.getModulus().bitLength());
        Validators.validateRsaPublicExponent(privateKey.getPublicExponent());
        this.privateKey = privateKey;
        this.signatureAlgorithm = RsaSsaPkcs1VerifyConscrypt.toRsaSsaPkcs1Algo(hash);
        this.outputPrefix = outputPrefix;
        this.messageSuffix = messageSuffix;
        this.verifier = verifier;
        this.conscryptOrNull = conscryptOrNull;
    }
    
    public static PublicKeySign create(final RsaSsaPkcs1PrivateKey key) throws GeneralSecurityException {
        final Provider conscryptOrNull = RsaSsaPkcs1VerifyConscrypt.conscryptProviderOrNull();
        return createWithProviderOrNull(key, conscryptOrNull);
    }
    
    public static PublicKeySign createWithProvider(final RsaSsaPkcs1PrivateKey key, final Provider provider) throws GeneralSecurityException {
        if (provider == null) {
            throw new NullPointerException("provider must not be null");
        }
        return createWithProviderOrNull(key, provider);
    }
    
    @AccessesPartialKey
    private static PublicKeySign createWithProviderOrNull(final RsaSsaPkcs1PrivateKey key, @Nullable final Provider providerOrNull) throws GeneralSecurityException {
        KeyFactory keyFactory;
        if (providerOrNull != null) {
            keyFactory = KeyFactory.getInstance("RSA", providerOrNull);
        }
        else {
            keyFactory = EngineFactory.KEY_FACTORY.getInstance("RSA");
        }
        final RSAPrivateCrtKey privateKey = (RSAPrivateCrtKey)keyFactory.generatePrivate(new RSAPrivateCrtKeySpec(key.getPublicKey().getModulus(), key.getParameters().getPublicExponent(), key.getPrivateExponent().getBigInteger(InsecureSecretKeyAccess.get()), key.getPrimeP().getBigInteger(InsecureSecretKeyAccess.get()), key.getPrimeQ().getBigInteger(InsecureSecretKeyAccess.get()), key.getPrimeExponentP().getBigInteger(InsecureSecretKeyAccess.get()), key.getPrimeExponentQ().getBigInteger(InsecureSecretKeyAccess.get()), key.getCrtCoefficient().getBigInteger(InsecureSecretKeyAccess.get())));
        PublicKeyVerify verifier;
        if (providerOrNull != null) {
            verifier = RsaSsaPkcs1VerifyConscrypt.createWithProvider(key.getPublicKey(), providerOrNull);
        }
        else {
            verifier = RsaSsaPkcs1VerifyJce.create(key.getPublicKey());
        }
        final PublicKeySign signer = new RsaSsaPkcs1SignJce(privateKey, key.getParameters().getHashType(), key.getOutputPrefix().toByteArray(), key.getParameters().getVariant().equals(RsaSsaPkcs1Parameters.Variant.LEGACY) ? RsaSsaPkcs1SignJce.legacyMessageSuffix : RsaSsaPkcs1SignJce.EMPTY, verifier, providerOrNull);
        final byte[] unused = signer.sign(RsaSsaPkcs1SignJce.testData);
        return signer;
    }
    
    private Signature getSignature() throws GeneralSecurityException {
        if (this.conscryptOrNull != null) {
            return Signature.getInstance(this.signatureAlgorithm, this.conscryptOrNull);
        }
        return EngineFactory.SIGNATURE.getInstance(this.signatureAlgorithm);
    }
    
    @Override
    public byte[] sign(final byte[] data) throws GeneralSecurityException {
        final Signature signer = this.getSignature();
        signer.initSign(this.privateKey);
        signer.update(data);
        if (this.messageSuffix.length > 0) {
            signer.update(this.messageSuffix);
        }
        byte[] signature = signer.sign();
        if (this.outputPrefix.length > 0) {
            signature = Bytes.concat(new byte[][] { this.outputPrefix, signature });
        }
        try {
            this.verifier.verify(signature, data);
        }
        catch (final GeneralSecurityException e) {
            throw new IllegalStateException("RSA signature computation error", e);
        }
        return signature;
    }
    
    static {
        FIPS = TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_REQUIRES_BORINGCRYPTO;
        EMPTY = new byte[0];
        legacyMessageSuffix = new byte[] { 0 };
        testData = new byte[] { 1, 2, 3 };
    }
}
