6
votes

Android Pay Issue

In Android Pay the process to generate a token from a credit card is as follows:

Generate a public and private key (the calls below return the keys using an Elliptic Curve with NISTP-256 algorithm)

To do this I call ...

public static KeyPair generateKeyPair() {
  KeyPair pair =null;
  try {
    ECGenParameterSpec ecGenSpec = new ECGenParameterSpec("prime256v1");
    java.security.KeyPairGenerator g = KeyPairGenerator.getInstance("EC");
    g.initialize(ecGenSpec, new SecureRandom());
    pair = g.generateKeyPair();
    pair.getPrivate();
    pair.getPublic();
  }catch (Throwable e ){
    e.printStackTrace();
  }
  return pair;
}

… This successfully returns the public and private key, but I am not sure what the format/encoding of the keys is in. I could not find any documentation on this.

Question 1: Is this the right way to generate a public and private key for Android Pay?

Pass the public key in base64 encoded format to the Android Pay createMaskedWalletRequet method (details of this are in the Android Pay documentation)

String publicKey = String (Base64.encodeBase64(pair.getPublic().getEncoded()));

PaymentMethodTokenizationParameters parameters = PaymentMethodTokenizationParameters.newBuilder().setPaymentMethodTokenizationType(PaymentMethodTokenizationType.NETWORK_TOKEN).addParameter("publicKey", publicKey).build();

Here I get the following exception:

03-30 17:02:06.459 3786-15263/? E/WalletClient: Error validating MaskedWalletRequest.paymentMethodTokenizationParameters: first byte of parameter "publicKey" must be 0x04 (which indicates uncompressed point format)

Question 2: Can you please help me understand what I am doing wrong. I think this may be related to a format mismatch, but not sure, and not sure how to fix it.

Appreciate your help!!

2

2 Answers

5
votes

Answer 1:

According to Android Pay document you can generate public key by OpenSSL like this: https://developers.google.com/android-pay/integration/gateway-processor-integration#example-using-openssl-to-generate-and-format-a-public-keyenter link description here

Then generate private key use

openssl pkcs8 -topk8 -inform PEM -outform PEM -in merchant-key.pem -nocrypt

Or you can use a shell script file.(example: genkey.sh in Android pay quickstart)
Use the following code(copy code to .sh file and double click) you can get private key.

#!/bin/bash

# Generate key.pem file:
openssl ecparam -name prime256v1 -genkey -noout -out key.pem

# Print public and private key in hex form:
openssl ec -in key.pem -text -noout

openssl pkcs8 -topk8 -inform PEM -outform PEM -in key.pem -nocrypt

sleep 2m

Then copy pub string in terminal and replace in this code then save this code to create .sh file again

#!/bin/bash

KEY="04:a9:9b:54:81:b0:67:0d:d3:50:84:e0:d4:d2:29:
    a5:3a:d6:5c:21:ae:5e:dd:58:75:f0:27:63:44:e8:
    a9:86:8d:cf:17:64:63:96:54:34:ed:16:37:c4:37:
    e6:b7:27:ad:06:af:b0:07:d1:b5:66:0a:2a:85:c0:
    71:9e:cc:39:54"

echo $KEY | xxd -r -p | base64
sleep 2m

Then get public key.

Answer 2: You can test by these keys:

Public Key: BKmbVIGwZw3TUITg1NIppTrWXCGuXt1YdfAnY0ToqYaNzxdkY5ZUNO0WN8Q35rcnrQavsAfRtWYKKoXAcZ7MOVQ=

(This public key can pass as a string to MaskedWalletRequet directly)

Private Key: MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgTA/wqrlbeVddorTlaT1AqhALrIBwS+DUdV3N1K1gImqhRANCAASpm1SBsGcN01CE4NTSKaU61lwhrl7dWHXwJ2NE6KmGjc8XZGOWVDTtFjfEN+a3J60Gr7AH0bVmCiqFwHGezDlU

0
votes

The problem is in generating the keys. I had faced a similar issue. To resolve this I'm calling shell commands from java code to generate keys. PFB.

String pemPath = "/path for storing pem path";

//To generate pem file
executeSH("openssl ecparam -name prime256v1 -genkey -noout -out "+pemPath+"key.pem",true);

//To obtain publicKeyString from pem file
String publicKeyString = executeSH(new String[]{"/bin/sh", "-c", "openssl ec -in key.pem -pubout -text -noout | grep -A5 pub: | tail -5 | xxd -r -p | base64"},false);

//To obtain privateKeyString from pem file
String privateKeyString = executeSH("openssl pkcs8 -topk8 -inform PEM -outform PEM -in key.pem -nocrypt",false);
privateKeyString=privateKeyString.substring(27, 211);

//Deleteing PEM file
executeSH("rm "+ pemPath+"key.pem",false);

//executeSH function overload this function with commands[] parameter
private String executeSH(String command, boolean waitFor) throws IOException, InterruptedException {
        Process process = null;
        InputStream inputStream = null;
        InputStreamReader inputStreamReader = null;
        BufferedReader bufferedReader = null;
        String line,output="";
        try {
            Runtime runtime = Runtime.getRuntime();
            process = runtime.exec(command);
            inputStream = process.getInputStream();
            inputStreamReader = new InputStreamReader(inputStream);
            bufferedReader = new BufferedReader(inputStreamReader);

            while((line=bufferedReader.readLine())!=null){
                output += line;
            }
            if(waitFor){
                process.waitFor();
            }
            return output;
        } finally {
            if(bufferedReader!=null) bufferedReader.close();
            if(inputStreamReader!=null) inputStreamReader.close();
            if(inputStream!=null) inputStream.close();
            if(process!=null) process.destroy();
        }
    }