Android Pay Platform: Public, Private Key (elliptic curve with NISTP-256)

Android payment problem

In Android Pay, the process of creating a credit card token is as follows:

Generate public and private keys (the calls below return the keys using an elliptic curve with the 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'm not sure what the key format / encoding is. I could not find any documentation on this.

Question 1: The correct way to create a public and private key for Android Pay?

Pass the public key in base64 encoded format to the Android Pay createMaskedWalletRequet (for details, see 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 checking MaskedWalletRequest.paymentMethodTokenizationParameters: first byte The parameter "publicKey" must be 0x04 (which indicates an uncompressed format point)

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

Appreciate your help!

+5
source share
3 answers

Answer 1:

According to the Android Pay doc, you can generate the OpenSSL public key as follows: https://developers.google.com/android-pay/integration/gateway-processor-integration#example-using-openssl-to-generate-and-format -a-public-key enter the link here

Then create a 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 on Android for quick loading )
Use the following code (copy the code to the .sh file and double-click), you can get the 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 the pub line to the terminal and replace in this code, then save this code to create the .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 the public key.

Answer 2: You can check these keys:

Public key: BKmbVIGwZw3TUITg1NIppTrWXCGuXt1YdfAnY0ToqYaNzxdkY5ZUNO0WN8Q35rcnrQavsAfRtWYKKoXAcZ7MOVQ =

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

Private key: MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgTA / wqrlbeVddorTlaT1AqhALrIBwS + DUdV3N1K1gImqhRANCAASpm1SBsGcN01CE4NTSKaU61lwhrl7dWHXwJ2NE6KmGjc8XZGOWVDTtFjfEN + a3J60Gr7AH0bVmCiqFwHGezDlU

+5
source

The problem is key generation. I ran into a similar problem. To solve this problem, I call 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(); } } 
0
source

I haven't solved the problem yet, but I did some research and made codes for generating AndroidPay program code programmatically.

In the codes below, the output of "AndroidPay publicKey" can be successfully applied on the AndroidPay Android platform to create a "PaymentRequest", and then generate a "paymentMethodToken" using "encryptedMessage", "ephemeralPublicKey" and "tag".

The problem is that I cannot decrypt "encryptedMessage". I use NetworkTokenDecryptionUtil (AndroidPay, a token decryption tool provided) to read the EC private key (stored in PKCS # 8 format) to decrypt the encrypted text, but I can't even pass the MAC (tag) check. Although I ignore the check, the decrypted value is unreadable.

I believe this is close to answer to programmatically program AndroidPay soft keys. Just need a little push. Please share your idea. Thanks.

 package test; import java.io.StringWriter; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.SecureRandom; import java.security.Security; import javax.crypto.Cipher; import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.generators.KDF2BytesGenerator; import org.bouncycastle.crypto.kems.ECIESKeyEncapsulation; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyGenerationParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.jce.ECNamedCurveTable; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import org.bouncycastle.openssl.jcajce.JcaPEMWriter; import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.io.pem.PemObject; public class TestECKey { public static void main(String[] args) throws Throwable { // add instance of provider class Security.addProvider(new BouncyCastleProvider()); // Get domain parameters for example curve String name = "prime256v1"; // AndroidPay used ECNamedCurveParameterSpec ecp = ECNamedCurveTable.getParameterSpec(name); // when use prime256v1 // Buffer for ECIESKeyEncapsulation output byte[] kemOut = new byte[65]; // when use prime256v1 or secp256r1 ECDomainParameters domainParams = new ECDomainParameters(ecp.getCurve(), ecp.getG(), ecp.getN(), ecp.getH(), ecp.getSeed()); // Generate a private key and a public key System.out.println("name: " + name); AsymmetricCipherKeyPair keyPair; ECKeyGenerationParameters keyGenParams = new ECKeyGenerationParameters(domainParams, new SecureRandom()); ECKeyPairGenerator generator = new ECKeyPairGenerator(); generator.init(keyGenParams); keyPair = generator.generateKeyPair(); ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic(); System.out.println("====KEM===="); // Set ECIES-KEM parameters SecureRandom rnd = new SecureRandom(); ECIESKeyEncapsulation kem; // Test basic ECIES-KEM KDF2BytesGenerator kdf = new KDF2BytesGenerator(new SHA256Digest()); kem = new ECIESKeyEncapsulation(kdf, rnd); kem.init(publicKey); kem.encrypt(kemOut, 128); System.out.println("AndroidPay publicKey:"); System.out.println("out(Base64)[" + new String(Base64.encode(kemOut)) + "]"); System.out.println("====PKCS#8 (for private key)===="); KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME); kpg.initialize(ecp); // Key pair to store public and private key KeyPair keyPair4Cipher = kpg.generateKeyPair(); JcaPKCS8Generator gen2 = new JcaPKCS8Generator(keyPair4Cipher.getPrivate(), null); PemObject obj2 = gen2.generate(); StringWriter sw2 = new StringWriter(); try (JcaPEMWriter pw = new JcaPEMWriter(sw2)) { pw.writeObject(obj2); } String pkcs8Key2 = sw2.toString(); System.out.println(pkcs8Key2); System.out.println("====CIPHER (encryption)===="); Cipher iesCipher = Cipher.getInstance("ECIES", BouncyCastleProvider.PROVIDER_NAME); iesCipher.init(Cipher.ENCRYPT_MODE, keyPair4Cipher.getPublic()); byte[] plain = "plaintext".getBytes(); byte[] cipher = iesCipher.doFinal(plain); System.out.println("cipher:" + new String(Base64.encode(cipher))); System.out.println("====CIPHER (decryption)===="); Cipher iesCipher2 = Cipher.getInstance("ECIES", BouncyCastleProvider.PROVIDER_NAME); iesCipher2.init(Cipher.DECRYPT_MODE, keyPair4Cipher.getPrivate()); byte[] plain2 = iesCipher2.doFinal(cipher); System.out.println("plain2:" + new String(plain2)); } } 

Link:

[1] https://developers.google.com/android-pay/integration/payment-token-cryptography#retrieving-the-encrypted-payload

[2] Using BouncyCastle to Encrypt with ECIES in Java

[3] Codes for generating a public key in an elliptic curve algorithm using a given private key

[4] http://www.bouncycastle.org/wiki/display/JA1/Elliptic+Curve+Key+Pair+Generation+and+Key+Factories

[5] http://techxperiment.blogspot.tw/2016/10/create-and-read-pkcs-8-format-private.html

[6] and much more ...

0
source

Source: https://habr.com/ru/post/1246106/


All Articles