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

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

import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.spec.KeySpec;
import java.security.Key;
import java.security.spec.X509EncodedKeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import com.google.crypto.tink.subtle.Bytes;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.util.Arrays;
import com.google.crypto.tink.internal.Util;
import java.security.KeyPairGenerator;
import javax.crypto.KeyAgreement;
import java.security.KeyFactory;
import java.security.GeneralSecurityException;
import com.google.crypto.tink.internal.ConscryptUtil;
import java.security.Provider;
import com.google.errorprone.annotations.Immutable;

@Immutable
public final class X25519Conscrypt implements X25519
{
    private static final int PRIVATE_KEY_LEN = 32;
    private static final int PUBLIC_KEY_LEN = 32;
    private static final byte[] x25519Pkcs8Prefix;
    private static final byte[] x25519X509Prefix;
    final Provider provider;
    
    private X25519Conscrypt(final Provider provider) {
        this.provider = provider;
    }
    
    public static X25519 create() throws GeneralSecurityException {
        final Provider provider = ConscryptUtil.providerOrNull();
        if (provider == null) {
            throw new GeneralSecurityException("Conscrypt is not available.");
        }
        final KeyFactory unusedKeyFactory = KeyFactory.getInstance("XDH", provider);
        final KeyAgreement unusedKeyAgreement = KeyAgreement.getInstance("XDH", provider);
        final X25519 output = new X25519Conscrypt(provider);
        final KeyPair unused = output.generateKeyPair();
        return output;
    }
    
    @Override
    public KeyPair generateKeyPair() throws GeneralSecurityException {
        final KeyPairGenerator keyGen = KeyPairGenerator.getInstance("XDH", this.provider);
        keyGen.initialize(255);
        final java.security.KeyPair keyPair = keyGen.generateKeyPair();
        final byte[] pkcs8EncodedPrivateKey = keyPair.getPrivate().getEncoded();
        if (pkcs8EncodedPrivateKey.length != 32 + X25519Conscrypt.x25519Pkcs8Prefix.length) {
            throw new GeneralSecurityException("Invalid encoded private key length");
        }
        if (!Util.isPrefix(X25519Conscrypt.x25519Pkcs8Prefix, pkcs8EncodedPrivateKey)) {
            throw new GeneralSecurityException("Invalid encoded private key prefix");
        }
        final byte[] privateKey = Arrays.copyOfRange(pkcs8EncodedPrivateKey, X25519Conscrypt.x25519Pkcs8Prefix.length, pkcs8EncodedPrivateKey.length);
        final byte[] x509EncodedPublicKey = keyPair.getPublic().getEncoded();
        if (x509EncodedPublicKey.length != 32 + X25519Conscrypt.x25519X509Prefix.length) {
            throw new GeneralSecurityException("Invalid encoded public key length");
        }
        if (!Util.isPrefix(X25519Conscrypt.x25519X509Prefix, x509EncodedPublicKey)) {
            throw new GeneralSecurityException("Invalid encoded public key prefix");
        }
        final byte[] publicKey = Arrays.copyOfRange(x509EncodedPublicKey, X25519Conscrypt.x25519X509Prefix.length, x509EncodedPublicKey.length);
        return new KeyPair(privateKey, publicKey);
    }
    
    @Override
    public byte[] computeSharedSecret(final byte[] privateValue, final byte[] peersPublicValue) throws GeneralSecurityException {
        final KeyFactory keyFactory = KeyFactory.getInstance("XDH", this.provider);
        if (privateValue.length != 32) {
            throw new InvalidKeyException("Invalid X25519 private key");
        }
        final KeySpec privateKeySpec = new PKCS8EncodedKeySpec(Bytes.concat(new byte[][] { X25519Conscrypt.x25519Pkcs8Prefix, privateValue }));
        final PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
        if (peersPublicValue.length != 32) {
            throw new InvalidKeyException("Invalid X25519 public key");
        }
        final KeySpec publicKeySpec = new X509EncodedKeySpec(Bytes.concat(new byte[][] { X25519Conscrypt.x25519X509Prefix, peersPublicValue }));
        final PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
        final KeyAgreement keyAgreementA = KeyAgreement.getInstance("XDH", this.provider);
        keyAgreementA.init(privateKey);
        keyAgreementA.doPhase(publicKey, true);
        return keyAgreementA.generateSecret();
    }
    
    static {
        x25519Pkcs8Prefix = new byte[] { 48, 46, 2, 1, 0, 48, 5, 6, 3, 43, 101, 110, 4, 34, 4, 32 };
        x25519X509Prefix = new byte[] { 48, 42, 48, 5, 6, 3, 43, 101, 110, 3, 33, 0 };
    }
}
