2

I know that this question has already been asked, but it seems I can't write the code to make it work.

Lets say that we have the following keypair:

Public Key (this is what I want to generate given the private key - base64 encoded string as Public key to use for Android Pay): BKmbVIGwZw3TUITg1NIppTrWXCGuXt1YdfAnY0ToqYaNzxdkY5ZUNO0WN8Q35rcnrQavsAfRtWYKKoXAcZ7MOVQ=

Private Key (this is known):

-----BEGIN PRIVATE KEY-----

MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgTA/wqrlbeVddorTlaT1AqhALrIBwS+DUdV3N1K1gImqhRANCAASpm1SBsGcN01CE4NTSKaU61lwhrl7dWHXwJ2NE6KmGjc8XZGOWVDTtFjfEN+a3J60Gr7AH0bVmCiqFwHGezDlU

-----END PRIVATE KEY-----

Here is the code that I use to generate the java.security.PrivateKey:

private static final Logger logger = LoggerFactory.getLogger(AndroidPayDecodingUtils.class);

private static final String SECURITY_PROVIDER = "BC";
private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private static final String KEY_AGREEMENT_ALGORITHM = "ECDH";
// OpenSSL name of the NIST P-126 Elliptic Curve
private static final String EC_CURVE = "prime256v1";
private static final String SYMMETRIC_KEY_TYPE = "AES";
private static final String SYMMETRIC_ALGORITHM = "AES/CTR/NoPadding";
private static final byte[] SYMMETRIC_IV = Hex.decode("00000000000000000000000000000000");
private static final int SYMMETRIC_KEY_BYTE_COUNT = 16;
private static final String MAC_ALGORITHM = "HmacSHA256";
private static final int MAC_KEY_BYTE_COUNT = 16;
private static final byte[] HKDF_INFO = "Android".getBytes(DEFAULT_CHARSET);
private static final byte[] HKDF_SALT = null /* equivalent to a zeroed salt of hashLen */;

public static final String EC_ASYMMETRIC_KEY_TYPE = "EC";


public static PrivateKey generatePrivateKey(String privateKey) {

    try {
        String pkcs8Pem = formatKey(privateKey);
        // Base64 decode the result
        byte[] pkcs8EncodedBytes = BaseEncoding.base64().decode(pkcs8Pem);
        // extract the private key
        KeyFactory asymmetricKeyFactory = KeyFactory.getInstance(EC_ASYMMETRIC_KEY_TYPE, SECURITY_PROVIDER);

        return asymmetricKeyFactory.generatePrivate(new PKCS8EncodedKeySpec(pkcs8EncodedBytes));

    } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException | NullPointerException e) {
        logger.error("Failed to create private key");
    }
    return null;
}

private static String formatKey(String key) {

    try {
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader rdr = new BufferedReader(new StringReader(key));

        String line;
        while ((line = rdr.readLine()) != null) {
            stringBuilder.append(line);
        }

        // Remove the "BEGIN" and "END" lines, as well as any whitespace
        String toReturn = stringBuilder.toString();
        // unix generated EC private key
        toReturn = toReturn.replace("-----BEGIN PRIVATE KEY-----", "");
        toReturn = toReturn.replace("-----END PRIVATE KEY-----", "");
        // mac generated EC private key
        toReturn = toReturn.replace("-----BEGIN EC PRIVATE KEY-----", "");
        toReturn = toReturn.replace("-----END EC PRIVATE KEY-----", "");
        //whitespace
        toReturn = toReturn.replaceAll("\\s+", "");

        return toReturn;

    } catch (IOException | NullPointerException e) {
        logger.error("Failed to read the key");
    }
    return null;
}

And this is the code that I use to generate the public key as Base64 encoded string, but it seems that I doing something wrong as I am not getting the desired result:

public static String generatePublicKeyFromPrivateKey(String privateKeyStr) {

    ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(EC_CURVE);
    ECDomainParameters ecDomainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
            parameterSpec.getN(), parameterSpec.getH(), parameterSpec.getSeed());

    ECPrivateKey privateKey = (ECPrivateKey) generatePrivateKey(privateKeyStr);

    byte[] privateKeyBytes = privateKey.getS().toByteArray();

    ECPoint ecPoint = ecDomainParameters.getG().multiply(new BigInteger(privateKeyBytes));

    String toReturn = new String(Base64.encode(ecPoint.getEncoded(true)));

    return toReturn;
}
Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263

0 Answers0