Android Pay问题
在Android Pay中,从信用卡生成令牌的过程如下:
生成公钥和私钥(下面的调用使用带有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;
}
Run Code Online (Sandbox Code Playgroud)
...这成功返回公钥和私钥,但我不确定密钥的格式/编码是什么.我找不到任何关于此的文档.
问题1:这是为Android Pay生成公钥和私钥的正确方法吗?
将base64编码格式的公钥传递给Android Pay createMaskedWalletRequet方法(详情请参阅Android Pay文档)
String publicKey = String (Base64.encodeBase64(pair.getPublic().getEncoded()));
PaymentMethodTokenizationParameters parameters = PaymentMethodTokenizationParameters.newBuilder().setPaymentMethodTokenizationType(PaymentMethodTokenizationType.NETWORK_TOKEN).addParameter("publicKey", publicKey).build();
Run Code Online (Sandbox Code Playgroud)
在这里,我得到以下异常:
03-30 17:02:06.459 3786-15263 /?E/WalletClient:错误验证MaskedWalletRequest.paymentMethodTokenizationParameters:参数"公钥"第一字节必须是0×04(表示未压缩的点格式)
问题2:你能帮我理解我做错了什么.我认为这可能与格式不匹配有关,但不确定,也不确定如何修复它.
感谢您的帮助!!
我正在尝试学习一些加密编码,并生成了当前保存在字节数组( byte[] privatekey )中的 32 字节私钥。我知道公钥是使用secp256k1命名的椭圆曲线参数和公式生成的,其中publickey = G * privatekey,其中 G 是椭圆曲线上的某个点(ECPoint?),但我无法将该命名参数规范和公式转换为实际编码公钥。java.security.*我知道自 java 7 以来,和包中包含一些类java.security.spec.*可以用简短的代码来执行此操作,但我找不到一个很好的示例来说明如何在不使用第三方库的情况下执行此操作。
这个比特币 stackexchange 链接包含所有理论答案以及出色的 python 和 C# 代码,但没有 Java 代码。
编辑/更新:我尝试使用以下代码获取我需要的内容:
String secp256k1_G_uncompressed_string = "0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8";
byte[] secp256k1_G_uncompressed_bytes = DatatypeConverter.parseHexBinary(secp256k1_G_uncompressed_string);
String privatekeystring = "1184CD2CDD640CA42CFC3A091C51D549B2F016D454B2774019C2B2D2E08529FD";
byte[] privatekeybytes = DatatypeConverter.parseHexBinary(privatekeystring);
BigInteger secp256k1_G_num = new BigInteger(1, secp256k1_G_uncompressed_bytes);
BigInteger privatekey_num = new BigInteger(1, privatekeybytes);
BigInteger curvepoint = secp256k1_G_num.multiply(privatekey_num);
byte[] publickeybytes = curvepoint.toByteArray();
System.out.println(DatatypeConverter.printHexBinary(privatekeybytes));
System.out.println(DatatypeConverter.printHexBinary(publickeybytes));
Run Code Online (Sandbox Code Playgroud)
应该使用正确编码生成的公钥是这样的:
04d0988bfa799f7d7ef9ab3de97ef481cd0f75d2367ad456607647edde665d6f6 fbdd594388756a7beaf73b4822bc22d36e9bda7db82df2b8b623673eefc0b7495
但正在生成的公钥是这样的:
4E6801418BB6EF9F462F69830F82EB51BB9224219B9D89C8C34FB746297F59779D8B986194181BD7AB99DC7E3086914EA13C4B37E05716CADCA0AE391CE81C4B85E0F09E8 628F0F81692B5D08D0D8B9E20615A5D23DE0F591D02C650554BB1D8
我正在尝试使用私钥和已知曲线生成公钥.以下是我的代码:
// Generate Keys
ECGenParameterSpec ecGenSpec = new ECGenParameterSpec("secp256r1");
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "BC");
keyPairGenerator.initialize(ecGenSpec, new SecureRandom());
java.security.KeyPair pair = keyPairGenerator.generateKeyPair();
ECPrivateKey privateKey = (ECPrivateKey) pair.getPrivate();
ECPublicKey publicKeyExpected = (ECPublicKey) pair.getPublic();
// Expected public key
System.out.print("Expected Public Key: " +
BaseEncoding.base64Url().encode(publicKeyExpected.getEncoded()));
// Generate public key from private key
X9ECParameters ecp = SECNamedCurves.getByName("secp256r1");
ECDomainParameters domainParams = new ECDomainParameters(ecp.getCurve(),
ecp.getG(), ecp.getN(), ecp.getH(),
ecp.getSeed());
ECPoint Q = domainParams.getG().multiply(privateKey.getS()); // is this correct?
KeyFactory kf = KeyFactory.getInstance("ECDSA", "BC");
ECPublicKey publicKeyGenerated =
(ECPublicKey) kf.generatePublic(new X509EncodedKeySpec(Q.getEncoded(false))); …Run Code Online (Sandbox Code Playgroud) 目前我正在更新我的 x.509 证书库以支持 ECC。大多数实现的构建器都采用 publicKey 并从密钥中导出算法等。在 RSA 中,这很简单,您可以检查密钥的算法并验证位长。但是对于 ECC,密钥基于曲线,曲线名称(当然)需要在证书中指定(作为 OID)。
我现在正在处理的问题是找到一种方法,从 java.security.interfaces.ECPublicKey 或 org.bouncycastle.jce.interfaces.ECPublicKey 到曲线名称。(两种实现完全不同......)
我能想到的一种方法是获取密钥的 ECPoint 并验证它是否在给定的曲线上。通过这种方式,我可以测试所有支持的曲线,但是在运行时感觉很麻烦,并且如果点重叠 2 条或更多曲线,则可能容易出错。
另一种方法是获取 ECCurve(bc 实现)或 EllipticCurve(jre 实现)并将曲线细节与支持的实现进行比较。这还涉及逐步遍历每条已知曲线。
有没有人知道仅使用 jre(8/9) 和 bc 根据曲线或公钥详细信息查找曲线名称的更好方法。您对第一个解决方案的感觉如何,获得误报的可能性有多大。