Apple Pay - 如何将商家公钥与支付令牌中的 publicKeyHash 进行比较?

Posted

技术标签:

【中文标题】Apple Pay - 如何将商家公钥与支付令牌中的 publicKeyHash 进行比较?【英文标题】:Apple Pay - How to compare merchant public key with publicKeyHash from payment token? 【发布时间】:2017-07-11 16:37:45 【问题描述】:

我正在处理 Apple Pay 支付令牌解密。 根据此指令Payment Token Format Reference 在步骤 2 中。我需要使用支付令牌标头中的 publicKeyHash 字段来确定哪个 Apple 使用了商家证书。

pulbicKeyHash 是商户证书的 X.509 编码公钥字节的 SHA-256 哈希,Base64 编码为字符串。

我有一张商家证书。所以我假设如果我将我的证书公钥的 sha-256 散列和 Base64 编码,我将得到与我在支付令牌的 publicKeyHash 字段中收到的相同的值。

但我不知道我应该散列证书的哪个特定部分。 Apple 提供的初始商户证书为 .cer 格式。 我已将公钥从中提取为 .pem 格式。比我尝试的都取散列 - >公钥的base64encode(-----BEGIN CERTIFICATE-----和-----END CERTIFICATE-----之间的字符串)和 获取base64解码的.pem的哈希,我认为应该是.der和base 64对其进行编码。

两者都未能匹配从 Apple Pay 收到的价值。它的长度也不同,我的 base64 编码哈希的长度为 88 个字符,publicKeyHash 字段的长度为 44 个字符。

当我尝试基于 64 位解码 publicKeyHash 时,我得到了像“D�đ���$�f���@c���$����WP��这样的不可读字符 但根据 Apple 文档,应该有不能包含此类符号的 sha-256 哈希。

谁能解释我应该执行哪些具体步骤才能完成此商家证书检查?

【问题讨论】:

嗯,Base64 SHA-256 哈希不应该是 44 个字符吗? ***.com/questions/2240973/… 据我所知,sha-256 有 64 个字符。但我真的不知道这个数字在 base 64 编码后是如何变化的。 二进制 SHA-256 哈希的长度为 256 位。在十六进制表示中,每个字符使用 4 位,因此结果是 64 个字符。 Base64 每 4 个字符使用 3 个字节加上一个填充字符,即 44 个字符。如果您要生成证书的二进制哈希并以 B64 对其进行编码,则结果必须包含 44 个字符。你应该检查你的哈希和 B64 算法,因为有问题 我已经设法在结果中获得了适量的字符。我还成功地从证书中提取了 .pem 格式的公钥。但它的哈希或 base 64 解码的公钥的哈希与 Apple 令牌的 publicKeyHash 字段不匹配......有人知道我应该以什么格式对哪些特定数据进行哈希以获得正确的结果? 【参考方案1】:

就我而言,主要问题和解决方案是使用支付处理证书的公钥哈希和NOT 商家身份证书的公钥哈希,女巫我试图与支付令牌中的 PublicKeyHash 进行比较。 在我的借​​口中,我可以说来自Apple Documentation 的以下文字非常模棱两可:

publicKeyHash SHA–256 哈希,Base64 编码为字符串的哈希 商家证书的 X.509 编码公钥字节。

因为我们有两种证书商家和支付处理。对我来说很明显,文档中的商家证书是商家 ID 证书。

仅在重新阅读付款处理证书说明后

支付处理证书。用于安全的证书 转移支付数据。 Apple Pay 服务器使用付款处理 证书的公钥加密支付数据。使用私人 处理付款时解密数据的密钥。

从Apple Pay JS 文档中我意识到我的错误。

所以我希望我的经验可以帮助人们不要踩到同样的耙子)

【讨论】:

【参考方案2】:

很遗憾,我无法找到直接从证书中提取哈希的 openssl 命令。因此,您必须先创建公钥才能获得公钥哈希。有两种方法可以提取公钥。

第一步

A.来自您的 ecc 私钥(支付处理私钥)

openssl ec -in ecc_private_key.key -pubout -out ec_public_key.pem

B.从苹果支付门户下载的证书(上传支付处理csr后)

openssl x509 -inform der -in apple_pay.cer -pubkey -noout > apple_pay_public_key.pem

两者都会为您提供以下格式的公钥

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENGbyXUzeZTdeyyNuXyc0nMzXmnLl
xMwd/t/sCZr3RPhytPbZpR/V4/xHqN/MVzozzq30I0/eUefbThEBl236Og==
-----END PUBLIC KEY-----

第 2 步 您可以使用以下代码从上面的公钥中提取 base64 哈希,记住删除页眉/页脚和换行符。

我希望我能想出如何使用 openssl 工具从公钥中获取哈希值,但无论如何遵循 c# 代码对我有用。它非常简单且易于移植到 java/python/php 或您喜欢的任何内容。或者在ideone.com在线使用以下代码

String publicKeyBase64 = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENGbyXUzeZTdeyyNuXyc0nMzXmnLlxMwd/t/sCZr3RPhytPbZpR/V4/xHqN/MVzozzq30I0/eUefbThEBl236Og==";

byte[] publicKey = Convert.FromBase64String(publicKeyBase64);
SHA256 sha256 = SHA256Managed.Create();
byte[] hash = sha256.ComputeHash(publicKey);
String publicKeyHash = Convert.ToBase64String(hash);

Console.WriteLine("Result: 0", publicKeyHash);

请记住,您的系统应该能够在任何给定时间接受多个密钥,而不是仅仅根据您从设备(iphone/ipad 等)收到的 publicKeyHash 验证您需要加载正确的私钥,考虑到这种情况当您当前的证书即将到期(或您出于任何原因撤销)时,否则您的系统可能无法在短时间内接受交易。根据我的一次遭遇,在门户中按下激活后,苹果花了一个多小时才激活新的支付处理键。

【讨论】:

【参考方案3】:

这个问题和接受的答案在细节上仍然有点模糊,所以这里是 java 中的精确测试方法来检查 token.paymentData.header.publicKeyHash 是否匹配 Apple Pay 支付处理证书:

private static void checkPublicKeyHash(String publicKeyHash, X509Certificate paymentProcessingCertificate)
        throws NoSuchAlgorithmException, CertificateException 

    String certHash = Base64.getEncoder().encodeToString(
            MessageDigest.getInstance("SHA-256").digest(
                    paymentProcessingCertificate.getPublicKey().getEncoded()));
    if (!Objects.equals(publicKeyHash, certHash)) 
        throw new DigestException(String.format(
                "publicKeyHash %s doesn't match Payment Processing Certificate hash %s",
                publicKeyHash, certHash));
    

【讨论】:

【参考方案4】:

首先,原始问题的答案似乎相隔几个月。其次,所有答案似乎都缺少一点关键信息; Payment Token Format Reference 第 2 步的唯一原因是您可以使用多个支付处理证书。如果你这样做了,那么苹果可能会使用任何人来加密数据。 如果你只有一个支付处理证书,那么你可以跳过这一步,只使用它的私钥。毕竟,第二步的最终结果是得到用于加密支付数据的支付处理证书的私钥。

【讨论】:

以上是关于Apple Pay - 如何将商家公钥与支付令牌中的 publicKeyHash 进行比较?的主要内容,如果未能解决你的问题,请参考以下文章

Java中的Apple Pay支付令牌解密

Apple Pay支付

在 Apple Pay 流程之后,支付令牌变得未定义

Apple Pay 令牌 transactionId 是全球唯一的吗?

Apple Pay编程指导

移动平台商家支付宝如何获取商户私钥,支付宝公钥