Я использую следующий код для расшифровки токена Apple Pay в java. Интересно, есть ли эквивалентный способ сделать это с помощью Google Tink. (следующий фрагмент кода работает отлично, но, на мой взгляд, он слишком подробный и нечитаемый.
public DecryptedPaymentData performDecryptOperation(PaymentToken paymentToken) {
byte[] ephemeralKey = Base64.decode(paymentToken.getPaymentData().getHeader().getEphemeralPublicKey());
byte[] paymentData = Base64.decode(paymentToken.getPaymentData().getData());
PrivateKey privateKey = performKeyVerification();
byte[] decryptedByte = decrypt(privateKey, ephemeralKey, paymentData);
String decryptedJsonData = new String(decryptedByte, UTF_8);
DecryptedPaymentData decryptedPaymentData = convertJsonToObject(decryptedJsonData);
log.debug("Decrypted Response: {}", decryptedPaymentData);
return decryptedPaymentData;
}
private PrivateKey performKeyVerification() throws ResponseStatusException {
try {
if (!AsymmetricKeyVerifier.verify(privateKey, certificate.getPublicKey())) {
throw new ResponseStatusException(HttpStatus.EXPECTATION_FAILED, "Asymmetric keys do not match!");
}
return privateKey;
} catch (Exception e) {
log.error("Decryption Failed: {}", e);
throw new ResponseStatusException(HttpStatus.EXPECTATION_FAILED, "Decryption failed", e);
}
}
private byte[] decrypt(PrivateKey merchantPrivateKey, byte[] ephemeralPublicKeyBytes, byte[] data) throws ResponseStatusException {
// Reconstitute Ephemeral Public Key
try {
KeyFactory keyFactory = KeyFactory.getInstance("ECDH", "BC");
X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(ephemeralPublicKeyBytes);
ECPublicKey ephemeralPublicKey = (ECPublicKey) keyFactory.generatePublic(encodedKeySpec);
// Perform KeyAgreement
KeyAgreement agreement = KeyAgreement.getInstance("ECDH", "BC");
agreement.init(merchantPrivateKey);
agreement.doPhase(ephemeralPublicKey, true);
byte[] sharedSecret = agreement.generateSecret();
// Perform KDF
byte[] derivedSecret = performKeyDerivationFunction(sharedSecret);
// Use the derived secret to decrypt the data
SecretKeySpec key = new SecretKeySpec(derivedSecret, "AES");
byte[] ivBytes = new byte[16];
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
Cipher aesCipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
aesCipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
return aesCipher.doFinal(data);
} catch (Exception e) {
log.error("Decryption Failed: {}", e);
throw new ResponseStatusException(HttpStatus.EXPECTATION_FAILED, "Decryption failed", e);
}
}