2016-03-30 20 views
5

Androidの有料号アンドロイドペイ:公開、非公開鍵ペア生成(NISTP-256との楕円曲線)

Androidの支払いで次のようにクレジットカードからトークンを生成するためのプロセスは次のとおりです。

生成このI呼び出しを行うには、公開鍵と秘密鍵(以下呼び出しがNISTP-256アルゴリズムと楕円曲線を使用して、キーを返す)

...

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; 
} 

...この成功私は公開鍵と秘密鍵を返しますが、鍵のフォーマット/エンコーディングが何であるかはわかりません。私はこれに関する文書を見つけることができませんでした。

質問1:これはAndroid Payの公開鍵と非公開鍵を生成する正しい方法ですか?

私は次の例外を取得します。ここ

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

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

(これの詳細はAndroidの有料文書である)のAndroidペイcreateMaskedWalletRequet方法にbase64でエンコードされた形式の公開鍵を渡します

03 -30 17:02:06.459 3786-15263 /? E/WalletClient:エラーが MaskedWalletRequest.paymentMethodTokenizationParametersの確認:あなたは私が私が間違っているのかを理解助けてください: パラメータ「公開」の最初のバイトは、(圧縮されていない点に フォーマットを示す)0x04の

質問2でなければなりません。私は、これがフォーマットの不一致に関連しているかもしれないとは思いますが、わからないし、それを修正する方法もわかりません。

あなたのお手伝いをよろしくお願いいたします。

答えて

5

回答1:

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

または使用することができ、秘密鍵の使用を生成その後 https://developers.google.com/android-pay/integration/gateway-processor-integration#example-using-openssl-to-generate-and-format-a-public-keyenter link description here

Androidの有料文書によると、あなたはこのようにOpenSSLによって公開鍵を生成することができますシェルスクリプトファイル(例:Android pay quickstartのgenkey.sh)
次のコードを使用します(.shファイルにダブルクリック)で秘密鍵を取得できます。

#!/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 

は、その後、端末にパブの文字列をコピーし、公開鍵を取得後

再び
#!/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 

を.SHファイルを作成するには、このコードを保存し、このコードに置き換えます。

回答2: あなたはこれらのキーでテストすることができます。

公開鍵: BKmbVIGwZw3TUITg1NIppTrWXCGuXt1YdfAnY0ToqYaNzxdkY5ZUNO0WN8Q35rcnrQavsAfRtWYKKoXAcZ7MOVQ =

(この公開鍵は、直接MaskedWalletRequetする文字列として渡すことができます)

プライベートキー: MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgTA/wqrlbeVddorTlaT1AqhALrIBwS + DUdV3N1K1gImqhRANCAASpm1SBsGcN01CE4NTSKaU61lwhrl7dWHXwJ2NE6KmGjc8XZGOWVDTtFjfEN + a3J60Gr7AH0bVmCiqFwHGezDlU

+0

ありがとうAndy、私たちはまったく同じようにして静的な公開鍵と秘密鍵のペアを生成し、アプリケーションで使用しました。私は動的にそれらを生成する方法があったと思っていたが、Googleは静的なキーのペアを使用して大丈夫だった –

0

問題はキーを生成することです。私も同様の問題に直面していました。これを解決するために、キーを生成するためにjavaコードからシェルコマンドを呼び出しています。 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

私はまだ問題は解決していないのですが、私はAndroidPay、プログラムECキーを必要と生成するために、いくつかの研究と作られたブローコードを作りました。

"AndroidPayのpublicKey"の出力はAndroidPayモバイルサイトAPIに "PaymentRequest"を作成し、 "encryptedMessage"、 "ephemeralPublicKey"、 "tag"で "paymentMethodToken"を生成するために適用できます。

問題は "encryptedMessage"を復号化できないことです。私はNetworkTokenDecryptionUtil(AndroidPay提供のトークン解読ツール)を使って自分のEC秘密鍵(PKCS#8形式で保存されている)を解読して暗号文を解読するが、MAC(タグ)検証に合格することさえできない。私は検証を無視しますが、復号化された値は読めません。

AndroidPayに必要なECキーをプログラムで生成する答えに近いと思います。ちょっとプッシュするだけです。あなたのアイデアをお伝えください。ありがとうございました。

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's 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)); 
    } 

} 

リファレンス:

[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 to generate 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]以上...

関連する問題