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

package com.google.crypto.tink;

import com.google.errorprone.annotations.CanIgnoreReturnValue;
import java.security.spec.ECParameterSpec;
import com.google.crypto.tink.subtle.EllipticCurves;
import java.security.interfaces.ECKey;
import java.security.interfaces.RSAKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.KeySpec;
import java.security.spec.X509EncodedKeySpec;
import com.google.crypto.tink.subtle.EngineFactory;
import java.security.KeyFactory;
import javax.annotation.Nullable;
import java.io.IOException;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.subtle.Base64;
import java.security.Key;
import java.io.BufferedReader;
import com.google.crypto.tink.subtle.Enums;

public enum PemKeyType
{
    RSA_PSS_2048_SHA256("RSA", "RSASSA-PSS", 2048, Enums.HashType.SHA256), 
    RSA_PSS_3072_SHA256("RSA", "RSASSA-PSS", 3072, Enums.HashType.SHA256), 
    RSA_PSS_4096_SHA256("RSA", "RSASSA-PSS", 4096, Enums.HashType.SHA256), 
    RSA_PSS_4096_SHA512("RSA", "RSASSA-PSS", 4096, Enums.HashType.SHA512), 
    RSA_SIGN_PKCS1_2048_SHA256("RSA", "RSASSA-PKCS1-v1_5", 2048, Enums.HashType.SHA256), 
    RSA_SIGN_PKCS1_3072_SHA256("RSA", "RSASSA-PKCS1-v1_5", 3072, Enums.HashType.SHA256), 
    RSA_SIGN_PKCS1_4096_SHA256("RSA", "RSASSA-PKCS1-v1_5", 4096, Enums.HashType.SHA256), 
    RSA_SIGN_PKCS1_4096_SHA512("RSA", "RSASSA-PKCS1-v1_5", 4096, Enums.HashType.SHA512), 
    ECDSA_P256_SHA256("EC", "ECDSA", 256, Enums.HashType.SHA256), 
    ECDSA_P384_SHA384("EC", "ECDSA", 384, Enums.HashType.SHA384), 
    ECDSA_P521_SHA512("EC", "ECDSA", 521, Enums.HashType.SHA512);
    
    public final String keyType;
    public final String algorithm;
    public final int keySizeInBits;
    public final Enums.HashType hash;
    private static final String PUBLIC_KEY = "PUBLIC KEY";
    private static final String PRIVATE_KEY = "PRIVATE KEY";
    private static final String BEGIN = "-----BEGIN ";
    private static final String END = "-----END ";
    private static final String MARKER = "-----";
    
    private PemKeyType(final String keyType, final String algorithm, final int keySizeInBits, final Enums.HashType hash) {
        this.keyType = keyType;
        this.algorithm = algorithm;
        this.keySizeInBits = keySizeInBits;
        this.hash = hash;
    }
    
    @Nullable
    public Key readKey(final BufferedReader reader) throws IOException {
        String line;
        for (line = reader.readLine(); line != null && !line.startsWith("-----BEGIN "); line = reader.readLine()) {}
        if (line == null) {
            return null;
        }
        line = line.trim().substring("-----BEGIN ".length());
        final int index = line.indexOf("-----");
        if (index < 0) {
            return null;
        }
        final String type = line.substring(0, index);
        final String endMarker = "-----END " + type + "-----";
        final StringBuilder base64key = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            if (line.indexOf(":") > 0) {
                continue;
            }
            if (line.contains(endMarker)) {
                break;
            }
            base64key.append(line);
        }
        try {
            final byte[] key = Base64.decode(base64key.toString(), 0);
            if (type.contains("PUBLIC KEY")) {
                return this.getPublicKey(key);
            }
            if (type.contains("PRIVATE KEY")) {
                return this.getPrivateKey(key);
            }
        }
        catch (final GeneralSecurityException | IllegalArgumentException ex) {
            return null;
        }
        return null;
    }
    
    private Key getPublicKey(final byte[] key) throws GeneralSecurityException {
        final KeyFactory keyFactory = EngineFactory.KEY_FACTORY.getInstance(this.keyType);
        return this.validate(keyFactory.generatePublic(new X509EncodedKeySpec(key)));
    }
    
    private Key getPrivateKey(final byte[] key) throws GeneralSecurityException {
        final KeyFactory keyFactory = EngineFactory.KEY_FACTORY.getInstance(this.keyType);
        return this.validate(keyFactory.generatePrivate(new PKCS8EncodedKeySpec(key)));
    }
    
    @CanIgnoreReturnValue
    private Key validate(final Key key) throws GeneralSecurityException {
        if (this.keyType.equals("RSA")) {
            final RSAKey rsaKey = (RSAKey)key;
            final int foundKeySizeInBits = rsaKey.getModulus().bitLength();
            if (foundKeySizeInBits != this.keySizeInBits) {
                throw new GeneralSecurityException(String.format("invalid RSA key size, want %d got %d", this.keySizeInBits, foundKeySizeInBits));
            }
        }
        else {
            final ECKey ecKey = (ECKey)key;
            final ECParameterSpec ecParams = ecKey.getParams();
            if (!EllipticCurves.isNistEcParameterSpec(ecParams)) {
                throw new GeneralSecurityException("unsupport EC spec: " + ecParams.toString());
            }
            final int foundKeySizeInBits2 = EllipticCurves.fieldSizeInBits(ecParams.getCurve());
            if (foundKeySizeInBits2 != this.keySizeInBits) {
                throw new GeneralSecurityException(String.format("invalid EC key size, want %d got %d", this.keySizeInBits, foundKeySizeInBits2));
            }
        }
        return key;
    }
}
