Apple Pay SDK Payload Decryption Sometimes Fails on Occation

Good day,

A few months ago, we started noticing that we are getting occasional ApplePay SDK Data decryption errors when we attempt to decrypt the SDK Data payload that comes back from the ApplePay SDK.

We are using the C# BouncyCastle Dotnet package to handle the EllipticCurve decryption.

We find on average that about 2% of all our deposits are failing because the library fails to decrypt the ApplePay SDK Data payload with the error: "Mac check in GCM failed". It appears like ApplePay is maybe sending faulty payloads to us on occasion? Unless there is an issue with the BouncyCastle library? This is causing only a few transactions to fail per day, but we still need a solution for this.

Is anyone having the same issue or is there a contact from Apple I can get in touch with directly to share examples to assist with troubleshooting this?

Kind regards, Reon Fourie

Hi  @Reon,

You wrote:

[...] We are using the C# BouncyCastle Dotnet package to handle the EllipticCurve decryption.

Apple does not support third-party libraries or services, so I'd advise you to contact the support channels for BouncyCastle directly. However, I will provide some guidance based on some commonly known issues regarding .NET decryption below.

Then, you wrote:

[...] We find on average that about 2% of all our deposits are failing because the library fails to decrypt the ApplePay SDK Data payload with the error: "Mac check in GCM failed". [...]

This low rate of failure may be partially due to a race condition if your encryption/decryption processes are configured in a multithreaded environment.

Although rare, one potential failure point is during the auth handshake. One way to troubleshoot this locally is to perform the handshake and decryption on a single thread and process. This should factor out any issues related to corrupted data or unpaired handshakes due to race conditions or poor network performance.

Cheers,

Paris

@Reon - We noticed something similar, and it was due to the calculation of the 32-byte shared/agreed secret. If the secret had any leading zero bytes (0x00), then the secret was calculated as < 32 bytes.

If using Bouncy Castle, and if you are doing this...

IBasicAgreement agreement = AgreementUtilities.GetBasicAgreement("ECDH");
agreement.Init(privateKeyParams);
BigInteger agreedSecretValue = agreement.CalculateAgreement(publicKeyParams);
byte[] agreedSecret = agreedSecretValue.ToByteArrayUnsigned();

...then do this instead...

IBasicAgreement agreement = AgreementUtilities.GetBasicAgreement("ECDH");
agreement.Init(privateKeyParams);
BigInteger agreedSecretValue = agreement.CalculateAgreement(publicKeyParams);
byte[] sharedSecretBytes = BigIntegers.AsUnsignedByteArray(agreement.GetFieldSize(), agreedSecretValue);

That will make sure the agreed secret is returned in a correctly sized byte array, regardless of any leading zeros.

Hope this helps.

Apple Pay SDK Payload Decryption Sometimes Fails on Occation
 
 
Q