Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/390.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的Apple Pay支付令牌解密_Java_Applepay - Fatal编程技术网

Java中的Apple Pay支付令牌解密

Java中的Apple Pay支付令牌解密,java,applepay,Java,Applepay,我试图在服务器端使用Java中的ECC算法解密Apple Pay支付令牌中的数据字段。我如何实现它 我在Java中搜索这样的实现已经有一段时间了,但我没有找到。相反,我发现了一个使用Bouncy Castle C#库解密令牌的实现: 虽然Java中也有一个Bouncy Castle库,但我发现C#one和Java one在实现上存在一些差异,这导致我试图按照上面的C#实现编码时解密失败。 我已经在Apple Dev Center中生成了我的证书,并且我非常确定decrytion过程中需要的证书文

我试图在服务器端使用Java中的ECC算法解密Apple Pay支付令牌中的
数据
字段。我如何实现它

我在Java中搜索这样的实现已经有一段时间了,但我没有找到。相反,我发现了一个使用Bouncy Castle C#库解密令牌的实现: 虽然Java中也有一个Bouncy Castle库,但我发现C#one和Java one在实现上存在一些差异,这导致我试图按照上面的C#实现编码时解密失败。 我已经在Apple Dev Center中生成了我的证书,并且我非常确定decrytion过程中需要的证书文件是正确的。 有人成功地用Java解密了令牌吗?非常感谢您的帮助,非常感谢

以下是我进行测试支付时苹果公司回复信息的关键部分:

passKit={"version":"EC_v1","data":"AK7UZehTHQRXYzgPCD5ijZfloc9ZfUjAutl+7v/83V7U6YjsWSrBVzILQlp2xLP4E4QXxRwadIh0Y9Vg6297BV2ljginDwoR5nneEIQP6fNCXYwll5hUYYlL0ZO7pD/8KXStAh8pnOAyFtEVrDqIRCWZbftzdsAi76qFMXd3Z2bRSjl5zrt8Qfua6Nu1b3MNNVlPQVMJsskEQFncnViNLDkRulgt5WezVF8N1m62nEqminLBF7m+36/pLi0t9JTfqQ0qNYahczAzyyCJhABkXRXXf9iF3YJ77gBD9mBFRVrePPNW0PnJyoQPvDikGzDTc4k5+NBBSEAJjBLlt94okHmh9eO2A9/xoUh7/ktI+Vjk2k+8PWDOAWIkVM4+7vPCrESYedVzTBd6BYIL7+oPmbAW5EJ1JC2twafmmVhL4lXwdz296aBtNDTIzV+of+Oc6JrEutzjVYm8qGdv4MO0DJ3eWG/r9G1QPaTR84CRXXxmoL/EAH9fLYGfQeJsGHmLKieX2b2IfHwTtTnFVloqwt0ywd47PnqLbZ+pETZgsUegZIUAPH6Hl3WMo2eXKbybyxuY70WV+OoIxKBGHQnPYndPA3aG7XeSiUXF/2vW/Qq+UVfxQc0O4X6A/qTYy5c1HlQVq7PloE2+jkGCtKpuvsuVnnRF7sxxG3Wke7Vlz6at/+CHdT0K91+a29U1E8JVwhjnXvT8E/FcvrwHaCMmK1eK8/sMFGQ=","signature":"MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0BBwEAAKCAMIID7jCCA5SgAwIBAgIIOSxBHvsgmD0wCgYIKoZIzj0EAwIwejEuMCwGA1UEAwwlQXBwbGUgQXBwbGljYXRpb24gSW50ZWdyYXRpb24gQ0EgLSBHMzEmMCQGA1UECwwdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMB4XDTE2MDExMTIxMDc0NloXDTIxMDEwOTIxMDc0NlowazExMC8GA1UEAwwoZWNjLXNtcC1icm9rZXItc2lnbl9VQzQtUFJPRF9LcnlwdG9uX0VDQzEUMBIGA1UECwwLaU9TIFN5c3RlbXMxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZuDqDnh9yz9mvFMxidor2gjtlXTkIRF6oa8swxD2qLGco+d+0A+oTo3yrIaI5SmGbnbrrYntpbfDNuDw2KfQXaOCAhEwggINMEUGCCsGAQUFBwEBBDkwNzA1BggrBgEFBQcwAYYpaHR0cDovL29jc3AuYXBwbGUuY29tL29jc3AwNC1hcHBsZWFpY2EzMDIwHQYDVR0OBBYEFFfHNZQqvZ6i/szTy+ft4KN8jMX6MAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUI/JJxE+T5O8n5sT2KGw/orv9LkswggEdBgNVHSAEggEUMIIBEDCCAQwGCSqGSIb3Y2QFATCB/jCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjA2BggrBgEFBQcCARYqaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNhdGVhdXRob3JpdHkvMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwuYXBwbGUuY29tL2FwcGxlYWljYTMuY3JsMA4GA1UdDwEB/wQEAwIHgDAPBgkqhkiG92NkBh0EAgUAMAoGCCqGSM49BAMCA0gAMEUCIESIU8bEgwEjtEq2dDbRO+C10CsxjVVVISgpzdjEylGWAiEAkOZ+sj5vSzNlDlOy5vyJ5ZO3b5G5PpnvwJx1gc4A9eYwggLuMIICdaADAgECAghJbS+/OpjalzAKBggqhkjOPQQDAjBnMRswGQYDVQQDDBJBcHBsZSBSb290IENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzAeFw0xNDA1MDYyMzQ2MzBaFw0yOTA1MDYyMzQ2MzBaMHoxLjAsBgNVBAMMJUFwcGxlIEFwcGxpY2F0aW9uIEludGVncmF0aW9uIENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPAXEYQZ12SF1RpeJYEHduiAou/ee65N4I38S5PhM1bVZls1riLQl3YNIk57ugj9dhfOiMt2u2ZwvsjoKYT/VEWjgfcwgfQwRgYIKwYBBQUHAQEEOjA4MDYGCCsGAQUFBzABhipodHRwOi8vb2NzcC5hcHBsZS5jb20vb2NzcDA0LWFwcGxlcm9vdGNhZzMwHQYDVR0OBBYEFCPyScRPk+TvJ+bE9ihsP6K7/S5LMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUu7DeoVgziJqkipnevr3rr9rLJKswNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5hcHBsZS5jb20vYXBwbGVyb290Y2FnMy5jcmwwDgYDVR0PAQH/BAQDAgEGMBAGCiqGSIb3Y2QGAg4EAgUAMAoGCCqGSM49BAMCA2cAMGQCMDrPcoNRFpmxhvs1w1bKYr/0F+3ZD3VNoo6+8ZyBXkK3ifiY95tZn5jVQQ2PnenC/gIwMi3VRCGwowV3bF3zODuQZ/0XfCwhbZZPxnJpghJvVPh6fRuZy5sJiSFhBpkPCZIdAAAxggGMMIIBiAIBATCBhjB6MS4wLAYDVQQDDCVBcHBsZSBBcHBsaWNhdGlvbiBJbnRlZ3JhdGlvbiBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMCCDksQR77IJg9MA0GCWCGSAFlAwQCAQUAoIGVMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE5MDkxNzA2MzEyOVowKgYJKoZIhvcNAQk0MR0wGzANBglghkgBZQMEAgEFAKEKBggqhkjOPQQDAjAvBgkqhkiG9w0BCQQxIgQgi0pw8YTdD5wAw9Wct6Io9DQGiB1iXyGcK9XCWnSu/08wCgYIKoZIzj0EAwIERzBFAiEA+H89sz2Jo8GPM86s7sZ7nQ1RKu/R9I0fkkRBclcppFICIGJbrR764YuHK7ptg9Ch50muHKEuYUa0BjsVhtgCgJvyAAAAAAAA","header":{"ephemeralPublicKey":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFnF0WIB3GTpyaP7rgW0kzUMgqfwsTecb7/JrSQXZSuILCBPBs2YQQXFfIHNYtFFMzMTY24/tgbolbKjkmIUwIw==","applicationData":"5cd2d027aa6372ea5420770272ef47a596e60f4299c16c6591c3e7e532208394","publicKeyHash":"sRANn6djBkx5m//vTDU6HFOX4j1Nn/X4bNlgxJYRZgo=","transactionId":"947a5fc21adcc692bd204fa4e1a7a4f83ab8383283f3fa46b204b514559adede"}}
此代码(JAVA)将解密ApplePay令牌。要使此代码正常工作,请将证书文件转换为JKS(检索商户ID)和pk8(私钥)格式

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.bouncycastle.asn1.ASN1UTCTime;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.cms.CMSAttributes;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import static org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;

import java.io.*;
import java.nio.charset.Charset;
import java.security.*;
import java.security.cert.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

public class ApplePayDecrypt {
    public static final String MERCHANT_ID = "merchant.Id";

    private static KeyStore keyStore;
    private static PrivateKey merchantPrivateKey;

    static {
        if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
        Security.addProvider(new BouncyCastleProvider());
        }
    }

    public static AppleDecryptData decrypt(TokenData tokenData) {
        try {
        // Load merchant private key

        byte[] merchantbyte = IOUtils.toByteArray(Application.class.getResource("/apple_pay.pk8"));
        String key = new String(merchantbyte);
        key = key.replace("-----BEGIN PRIVATE KEY-----", "");
        key = key.replace("-----END PRIVATE KEY-----", "");
        key = key.replaceAll("\\s+", "");
        byte[] merchantPrivateKeyBytes = Base64.decodeBase64(key);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(merchantPrivateKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("EC", PROVIDER_NAME);
        merchantPrivateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        // Load Apple root certificate
        keyStore = KeyStore.getInstance("BKS");
        keyStore.load(GoSecureApplication.class.getResourceAsStream("/appleCA-G3"), "apple123".toCharArray());

        return unwrap(tokenData);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }

}

@SuppressWarnings({ "unused", "unchecked" })
public static AppleDecryptData unwrap(TokenData tokenData) throws Exception {
    // Merchants should use the 'version' field to determine how to verify and
    // decrypt the message payload.
    // At this time the only published version is 'EC_v1' which is demonstrated
    // here.
    String version = tokenData.version;

    byte[] signatureBytes = Base64.decodeBase64(tokenData.signature);
    byte[] dataBytes = Base64.decodeBase64(tokenData.data);
    // JsonObject headerJsonObject =
    // jsonObject.get(PAYMENT_HEADER).getAsJsonObject();
    byte[] transactionIdBytes = Hex.decode(tokenData.header.transactionId);
    byte[] ephemeralPublicKeyBytes = Base64.decodeBase64(tokenData.header.ephemeralPublicKey);

    // Merchants that have more than one certificate may use the 'publicKeyHash'
    // field to determine which
    // certificate was used to encrypt this payload.
    byte[] publicKeyHash = Base64.decodeBase64(tokenData.header.publicKeyHash);

    // Application data is a conditional field, present when the merchant has
    // supplied it to the iOS SDK.
    byte[] applicationDataBytes = null;
    byte[] signedBytes = ArrayUtils.addAll(ephemeralPublicKeyBytes, dataBytes);
    signedBytes = ArrayUtils.addAll(signedBytes, transactionIdBytes);
    signedBytes = ArrayUtils.addAll(signedBytes, applicationDataBytes);

    CMSSignedData signedData = new CMSSignedData(new CMSProcessableByteArray(signedBytes), signatureBytes);

    // Check certificate path
    Store<?> certificateStore = signedData.getCertificates();
    List<X509Certificate> certificates = new ArrayList<X509Certificate>();
    JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter();
    certificateConverter.setProvider(PROVIDER_NAME);
    for (Object o : certificateStore.getMatches(null)) {
        X509CertificateHolder certificateHolder = (X509CertificateHolder) o;
        certificates.add(certificateConverter.getCertificate(certificateHolder));
    }
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", PROVIDER_NAME);
    CertPath certificatePath = certificateFactory.generateCertPath(certificates);

    PKIXParameters params = new PKIXParameters(keyStore);
    params.setRevocationEnabled(false);

    // TODO: Test certificate has no CRLs. Merchants must perform revocation checks
    // in production.
    // TODO: Verify certificate attributes per instructions at
    // https://developer.apple.com/library/ios/documentation/PassKit/Reference/PaymentTokenJSON/PaymentTokenJSON.html#//apple_ref/doc/uid/TP40014929

    CertPathValidator validator = CertPathValidator.getInstance("PKIX", PROVIDER_NAME);
    PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) validator.validate(certificatePath, params);
    System.out.println(result);

    // Verify signature
    SignerInformationStore signerInformationStore = signedData.getSignerInfos();
    boolean verified = false;
    for (Object o : signerInformationStore.getSigners()) {
        SignerInformation signer = (SignerInformation) o;
        Collection<?> matches = certificateStore.getMatches(signer.getSID());
        if (!matches.isEmpty()) {
            X509CertificateHolder certificateHolder = (X509CertificateHolder) matches.iterator().next();
            if (signer.verify(
                    new JcaSimpleSignerInfoVerifierBuilder().setProvider(PROVIDER_NAME).build(certificateHolder))) {
                DERSequence sequence = (DERSequence) signer.getSignedAttributes().get(CMSAttributes.signingTime)
                        .toASN1Primitive();
                DERSet set = (DERSet) sequence.getObjectAt(1);
                ASN1UTCTime signingTime = (ASN1UTCTime) set.getObjectAt(0).toASN1Primitive();
                // Merchants can check the signing time of this payment to determine its
                // freshness.
                System.out.println("Signature verified.  Signing time is " + signingTime.getDate());
                verified = true;
            }
        }
    }

    if (verified) {
        // Ephemeral public key
        KeyFactory keyFactory = KeyFactory.getInstance("EC", PROVIDER_NAME);
        PublicKey ephemeralPublicKey = keyFactory.generatePublic(new X509EncodedKeySpec(ephemeralPublicKeyBytes));

        // Key agreement
        String asymmetricKeyInfo = "ECDH";
        KeyAgreement agreement = KeyAgreement.getInstance(asymmetricKeyInfo, PROVIDER_NAME);
        agreement.init(merchantPrivateKey);
        agreement.doPhase(ephemeralPublicKey, true);
        byte[] sharedSecret = agreement.generateSecret();

        byte[] derivedSecret = performKDF(sharedSecret, extractMerchantIdFromCertificateOid());

        // Decrypt the payment data
        String symmetricKeyInfo = "AES/GCM/NoPadding";
        Cipher cipher = Cipher.getInstance(symmetricKeyInfo, PROVIDER_NAME);

        SecretKeySpec key = new SecretKeySpec(derivedSecret, cipher.getAlgorithm());
        IvParameterSpec ivspec = new IvParameterSpec(new byte[16]);
        cipher.init(Cipher.DECRYPT_MODE, key, ivspec);
        byte[] decryptedPaymentData = cipher.doFinal(dataBytes);

        // JSON payload
        String data = new String(decryptedPaymentData, "UTF-8");
        // System.out.println(data);
        AppleDecryptData decryptDat = ObjMapper.getInstance().readValue(data, AppleDecryptData.class);
        return decryptDat;
    } else {
        return null;
    }
}

private static final byte[] APPLE_OEM = "Apple".getBytes(Charset.forName("US-ASCII"));
private static final byte[] COUNTER = { 0x00, 0x00, 0x00, 0x01 };
private static final byte[] ALG_IDENTIFIER_BYTES = "id-aes256-GCM".getBytes(Charset.forName("US-ASCII"));

/**
 * 00000001_16 || sharedSecret || length("AES/GCM/NoPadding") ||
 * "AES/GCM/NoPadding" || "Apple" || merchantID
 */
private static byte[] performKDF(byte[] sharedSecret, byte[] merchantId) throws Exception {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    baos.write(COUNTER);
    baos.write(sharedSecret);
    baos.write(ALG_IDENTIFIER_BYTES.length);
    baos.write(ALG_IDENTIFIER_BYTES);
    baos.write(APPLE_OEM);
    baos.write(merchantId);
    MessageDigest messageDigest = MessageDigest.getInstance("SHA256", PROVIDER_NAME);
    return messageDigest.digest(baos.toByteArray());
}

@SuppressWarnings("unused")
private static byte[] performKDF(byte[] sharedSecret, String merchantId) throws Exception {
    MessageDigest messageDigest = MessageDigest.getInstance("SHA256", PROVIDER_NAME);
    return performKDF(sharedSecret, messageDigest.digest(merchantId.getBytes("UTF-8")));
}

protected static byte[] extractMerchantIdFromCertificateOid() throws Exception {
    KeyStore vkeyStore = KeyStore.getInstance("JKS");
vkeyStore.load(GoSecureApplication.class.getResourceAsStream("/kapple_pay.jks"), "".toCharArray());
    Enumeration<String> aliases = vkeyStore.aliases();
    String alias = null;
    while (aliases.hasMoreElements()) {
        alias = aliases.nextElement();
    }
    X509Certificate cert = (X509Certificate) vkeyStore.getCertificate(alias);
    byte[] merchantIdentifierTlv = cert.getExtensionValue("1.2.840.113635.100.6.32");
    byte[] merchantIdentifier = new byte[64];
    System.arraycopy(merchantIdentifierTlv, 4, merchantIdentifier, 0, 64);

    return Hex.decode(merchantIdentifier);
}

}
import org.apache.commons.codec.binary.Base64;
导入org.apache.commons.io.IOUtils;
导入org.apache.commons.lang3.ArrayUtils;
导入org.bouncycastle.asn1.ASN1UTCTime;
导入org.bouncycastle.asn1.DERSequence;
导入org.bouncycastle.asn1.DERSet;
导入org.bouncycastle.asn1.cms.CMSAttributes;
导入org.bouncycastle.cert.X509CertificateHolder;
导入org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
导入org.bouncycastle.cms.cms可由tearray处理;
导入org.bouncycastle.cms.CMSSignedData;
导入org.bouncycastle.cms.SignerInformation;
导入org.bouncycastle.cms.SignerInformationStore;
导入org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
导入org.bouncycastle.jce.provider.BouncyCastleProvider;
导入org.bouncycastle.util.Store;
导入org.bouncycastle.util.encoders.Hex;
导入javax.crypto.Cipher;
导入javax.crypto.KeyAgreement;
导入javax.crypto.spec.IvParameterSpec;
导入javax.crypto.spec.SecretKeySpec;
导入静态org.bouncycastle.jce.provider.BouncyCastleProvider.provider\u NAME;
导入java.io.*;
导入java.nio.charset.charset;
导入java.security.*;
导入java.security.cert.*;
导入java.security.spec.PKCS8EncodedKeySpec;
导入java.security.spec.X509EncodedKeySpec;
导入java.util.*;
公共类ApplePayDecrypt{
公共静态最终字符串MERCHANT\u ID=“MERCHANT.ID”;
私有静态密钥库;
私有静态私钥merchantPrivateKey;
静止的{
if(Security.getProvider(BouncyCastleProvider.PROVIDER_NAME)==null){
addProvider(新的BouncyCastleProvider());
}
}
公共静态AppledCryptData解密(令牌数据令牌数据){
试一试{
//加载商户私钥
byte[]merchantbyte=IOUtils.toByteArray(Application.class.getResource(“/apple\u pay.pk8”);
字符串键=新字符串(merchantbyte);
key=key.replace(“----BEGIN PRIVATE key------”,“”);
key=key.replace(“----结束私钥----”,“”);
key=key.replaceAll(\\s+,“”);
byte[]merchantPrivateKeyBytes=Base64.decodeBase64(键);
PKCS8EncodedKeySpec PKCS8EncodedKeySpec=新的PKCS8EncodedKeySpec(merchantPrivateKeyBytes);
KeyFactory KeyFactory=KeyFactory.getInstance(“EC”,提供者名称);
merchantPrivateKey=keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//加载苹果根证书
keyStore=keyStore.getInstance(“BKS”);
load(GoSecureApplication.class.getResourceAsStream(“/appleCA-G3”),“apple123.toCharArray());
返回展开(标记数据);
}捕获(例外e){
e、 printStackTrace();
返回null;
}
}
@SuppressWarnings({“未使用”、“未选中”})
公共静态AppledCryptData展开(TokenData TokenData)引发异常{
//商户应使用“版本”字段确定如何验证和
//解密消息负载。
//目前唯一发布的版本是“EC_v1”,已演示
//在这里。
字符串版本=tokenData.version;
字节[]signatureBytes=Base64.decodeBase64(tokenData.signature);
字节[]数据字节=Base64.decodeBase64(tokenData.data);
//JsonObject标题JsonObject=
//get(PAYMENT_HEADER.getAsJsonObject();
字节[]transactionIdBytes=Hex.decode(tokenData.header.transactionId);
字节[]EphemeralPubliceBytes=Base64.decodeBase64(tokenData.header.EphemeralPubliceY);
//拥有多个证书的商户可以使用“publicKeyHash”
//字段来确定
//证书用于加密此有效负载。
字节[]publicKeyHash=Base64.decodeBase64(tokenData.header.publicKeyHash);
//应用程序数据是一个条件字段,当商户
//已将其提供给iOS SDK。
字节[]applicationDataBytes=null;
byte[]signedBytes=ArrayUtils.addAll(临时公共字节,数据字节);
signedBytes=ArrayUtils.addAll(signedBytes,transactionIdBytes);
signedBytes=ArrayUtils.addAll(signedBytes,applicationDataBytes);
CMSSignedData signedData=新的CMSSignedData(新的CMSProcessableByteArray(signedBytes),SignatureByBytes);
//检查证书路径
Store certificateStore=signedData.getCertificates();
列表证书=新的ArrayList();
JcaX509CertificateConverter certificateConverter=新的JcaX509CertificateConverter();
certificateConverter.setProvider(提供者名称);
for(对象o:certificateStore.getMatches(null)){
X509CertificateHolder certificateHolder=(X509CertificateHolder)o;
添加(certificateConverter.getCertificate(certificateHolder));
}
CertificateFactory CertificateFactory=CertificateFactory.getInstance(“X.509”,提供者名称);
CertPath certificatePath=certificateFactory.generateCertPath(证书