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

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

import java.util.Arrays;
import java.security.PublicKey;
import java.security.Signature;
import com.google.crypto.tink.subtle.Validators;
import com.google.crypto.tink.AccessesPartialKey;
import java.security.spec.KeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.KeyFactory;
import java.security.NoSuchProviderException;
import com.google.crypto.tink.signature.RsaSsaPkcs1PublicKey;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.signature.RsaSsaPkcs1Parameters;
import javax.annotation.Nullable;
import com.google.crypto.tink.internal.ConscryptUtil;
import com.google.crypto.tink.internal.Util;
import java.security.Provider;
import java.security.interfaces.RSAPublicKey;
import com.google.crypto.tink.config.internal.TinkFipsUtil;
import com.google.errorprone.annotations.Immutable;
import com.google.crypto.tink.PublicKeyVerify;

@Immutable
public final class RsaSsaPkcs1VerifyConscrypt implements PublicKeyVerify
{
    public static final TinkFipsUtil.AlgorithmFipsCompatibility FIPS;
    private static final byte[] EMPTY;
    private static final byte[] legacyMessageSuffix;
    private final RSAPublicKey publicKey;
    private final String signatureAlgorithm;
    private final byte[] outputPrefix;
    private final byte[] messageSuffix;
    private final Provider conscrypt;
    
    @Nullable
    static Provider conscryptProviderOrNull() {
        if (Util.isAndroid() && Util.getAndroidApiLevel() <= 21) {
            return null;
        }
        return ConscryptUtil.providerOrNull();
    }
    
    public static String toRsaSsaPkcs1Algo(final RsaSsaPkcs1Parameters.HashType hashType) throws GeneralSecurityException {
        if (hashType == RsaSsaPkcs1Parameters.HashType.SHA256) {
            return "SHA256withRSA";
        }
        if (hashType == RsaSsaPkcs1Parameters.HashType.SHA384) {
            return "SHA384withRSA";
        }
        if (hashType == RsaSsaPkcs1Parameters.HashType.SHA512) {
            return "SHA512withRSA";
        }
        throw new GeneralSecurityException("unknown hash type");
    }
    
    public static PublicKeyVerify create(final RsaSsaPkcs1PublicKey key) throws GeneralSecurityException {
        final Provider conscrypt = conscryptProviderOrNull();
        if (conscrypt == null) {
            throw new NoSuchProviderException("RSA-PKCS1.5 using Conscrypt is not supported.");
        }
        return createWithProvider(key, conscrypt);
    }
    
    @AccessesPartialKey
    public static PublicKeyVerify createWithProvider(final RsaSsaPkcs1PublicKey key, final Provider conscrypt) throws GeneralSecurityException {
        final KeyFactory keyFactory = KeyFactory.getInstance("RSA", conscrypt);
        final RSAPublicKey publicKey = (RSAPublicKey)keyFactory.generatePublic(new RSAPublicKeySpec(key.getModulus(), key.getParameters().getPublicExponent()));
        return new RsaSsaPkcs1VerifyConscrypt(publicKey, key.getParameters().getHashType(), key.getOutputPrefix().toByteArray(), key.getParameters().getVariant().equals(RsaSsaPkcs1Parameters.Variant.LEGACY) ? RsaSsaPkcs1VerifyConscrypt.legacyMessageSuffix : RsaSsaPkcs1VerifyConscrypt.EMPTY, conscrypt);
    }
    
    private RsaSsaPkcs1VerifyConscrypt(final RSAPublicKey pubKey, final RsaSsaPkcs1Parameters.HashType hashType, final byte[] outputPrefix, final byte[] messageSuffix, final Provider conscrypt) throws GeneralSecurityException {
        if (!RsaSsaPkcs1VerifyConscrypt.FIPS.isCompatible()) {
            throw new GeneralSecurityException("Can not use RSA-PKCS1.5 in FIPS-mode, as BoringCrypto module is not available.");
        }
        Validators.validateRsaModulusSize(pubKey.getModulus().bitLength());
        Validators.validateRsaPublicExponent(pubKey.getPublicExponent());
        this.publicKey = pubKey;
        this.signatureAlgorithm = toRsaSsaPkcs1Algo(hashType);
        this.outputPrefix = outputPrefix;
        this.messageSuffix = messageSuffix;
        this.conscrypt = conscrypt;
    }
    
    @Override
    public void verify(final byte[] signature, final byte[] data) throws GeneralSecurityException {
        if (!Util.isPrefix(this.outputPrefix, signature)) {
            throw new GeneralSecurityException("Invalid signature (output prefix mismatch)");
        }
        final Signature verifier = Signature.getInstance(this.signatureAlgorithm, this.conscrypt);
        verifier.initVerify(this.publicKey);
        verifier.update(data);
        if (this.messageSuffix.length > 0) {
            verifier.update(this.messageSuffix);
        }
        boolean verified = false;
        try {
            final byte[] signatureNoPrefix = Arrays.copyOfRange(signature, this.outputPrefix.length, signature.length);
            verified = verifier.verify(signatureNoPrefix);
        }
        catch (final RuntimeException ex) {
            verified = false;
        }
        if (!verified) {
            throw new GeneralSecurityException("Invalid signature");
        }
    }
    
    static {
        FIPS = TinkFipsUtil.AlgorithmFipsCompatibility.ALGORITHM_REQUIRES_BORINGCRYPTO;
        EMPTY = new byte[0];
        legacyMessageSuffix = new byte[] { 0 };
    }
}
