Client-Side Encryption
Overview
Client-side encryption removes the need for merchants to handle sensitive account data (for example, credit card numbers) on the server side. All sensitive data can be encrypted within the customer's browser and/or card reader device and decrypted by the Payment API. Since the merchant never handles any unencrypted data, the scope of PCI compliance is greatly reduced. The basic flow of an authorization with an encrypted account number is shown in the following image.
Card Not Present Transaction
Encryption Keys
Key Pair
Asymmetric encryption uses two cryptographic keys: a public key used for encryption and a private key used for decryption. These key pairs are created and managed on the Payment API side. The current public key that needs to be passed to Braintree.js and/or the card reader device can be retrieved using the PublicKey API, as described below.
The key pair for a given store will need to be rotated at regular intervals. During a rotation, both the old key pair and the new key pair will be enabled for some amount of time to give external systems enough time to update to the new key pair. To prevent outages during a key rotation, set up an automated job for calling the PublicKey API at least once a day. The key in the response should then be made available to the webstore for use with Braintree.js. This approach makes key changes completely transparent to the client system.
PublicKey URI Description
Action | URI Template | URI Example | Non-URI Request | Response |
---|---|---|---|---|
POST | /vM.m/stores/[StoreId]/payments/ publickey/lookup.xml | /v1.0/stores/ABCXYZ/payments/ publickey/lookup.xml | XML | 200 + XML Response. |
PublicKeyRequest XML Example
<?xml version="1.0" encoding="UTF-8"?>
<PublicKeyRequest xmlns="http://api.gsicommerce.com/schema/checkout/1.0">
<AlgorithmVersion>bt4</AlgorithmVersion>
</PublicKeyRequest>
PublicKeyRequest Parameters Description
Element | Required | Description | Type | Restriction |
---|---|---|---|---|
AlgorithmVersion | Yes | Algorithm identifier provided as a part of the on-boarding process. | String | 3 characters minimum, 8 characters maximum |
PublicKeyReply XML Example
<?xml version="1.0" encoding="UTF-8"?>
<PublicKeyReply xmlns="http://api.gsicommerce.com/schema/checkout/1.0">
<PublicKey>MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnlVFCGRVsChkN9
NoWc/5jjlmfnsbJ1n/D6+IcDA2T+dccx6HMDrQqfBdu+fM4j2iXZcDCWPHD1veTXPeZn1lB8
0ZSALH9ZVmncy0SarywfQBM4ZfGK+7Do1zZqYpS2UEuHpyaYWvi3yOUhl9CD7sx09hNwoHef
DnTC1zpWl7cGxX/2Q3elq2dpxX3UyyOiOM1fs+DneF59Dqm+rRen6f8ZLRtPLUbeipDM8Gfz
VSUsEErMjUlSeBJEfjopSzR4/pOfbkcHHRMb68C+zW46d70aJ524H+kDYmmEgoL/v3TRtqM6
0uG1hwGNM82wIoprYteA6MXRHl75YSUBAcxiAGm9nrO3lhkCq3zb37EJFQCn8XfF3EV7TtSM
Cf/EcL0QkCUFBwwxXPFRXpAtvVrDJfTmzltYSt6Q+/HYa7uAhqZEmTk4LR4v8VRq7kYuC4vQ
hwd+6B7iWwxpuAi2linaWdIW64txjJvWiArge4p9hzBpzLuBlQyA/64PewSEXwGpgMu2xLqo
QE1bypMkRJ2A9Dj9vNxfOg2WHWYicxiiZ2dRTtx+bikdolmfuYl8AjWC9dLfa405icsriK3L
A9vDjxjFzlOMEqWtVbg7fSxScjaGMxAmjEXMa4xLVAdIipihyvbcv9+eBQkmAeT6o1SbCEEl
FjPUN4NwTSbS4SDJW5TfkCAwEAAQ==</PublicKey>
</PublicKeyReply>
PublicKeyReply Parameters Description
Element | Required | Description | Type | Restriction |
---|---|---|---|---|
PublicKey | Yes | Current public key for use with Braintree.js. The full, unaltered value of this element should be passed to Braintree.create() | String | 2000 characters maximum |
Example Messages: Encrypting Form Data
Example Form
Encryption within the customer's browser is performed using Braintree.js (MIT license), which in turn uses the Stanford Javascript Crypto Library. The following procedure is a step-by-step example of how Braintree.js can be used.
- Create a sample payment form:
Copy this code sample.
<form action="/submit" method="POST" id="payment-form">
<p>
<label>Card Number</label>
<input type="text" size="20" autocomplete="off" data-encrypted-name="number" />
</p>
<p>
<label>CVV</label>
<input type="text" size="4" autocomplete="off" data-encrypted-name="cvv" />
</p>
<input type="submit" id="submit" />
</form> - Add the include for Braintree.js after the form. You can download the Braintree.js source
here. After downloading the source, copy it to your server.Copy this code sample.
<script type="text/javascript"
src="http://localhost/store/resources/js/braintree/braintree-1.3.9.js">
</script> - Add the following script to encrypt the form data on submit. The "base64-public-key" value passed to Braintree.create is described
in more detail in the Encryption Key Pair section.
Copy this code sample.After submission, the http request contains encrypted data in the fields indicated by the "data-encrypted-name" value in the form's inputs.
<script type="text/javascript">
var braintree = Braintree.create("base64-public-key");
braintree.onSubmitEncryptForm('payment-form');
</script>
CreditCardAuthRequest with Encrypted PAN and CSC
<CreditCardAuthRequest xmlns="http://api.gsicommerce.com/schema/checkout/1.0"
requestId="1234567">
<PaymentContext>
<OrderId>123456abcd</OrderId>
<EncryptedPaymentAccountUniqueId>$bt4|javascript_1_3_9$iRTKyoL4wN2Tpm
JCK3FAQz4U2XNWvWPIJo99R+8kHuj1ZtyeqlBy95g5xBmNF8koHdkC1ej9jRnUaFcoKLUQwVzbSkj
wev/ZghW9SJFyHj1RF6wy0g8Zq9FpGJANjnB2H3N5Y0qY139A86d4yh8RfWTzZBcdaOUz93CjyXny
sRtJWktgUdltmWkuceN2zW/aMyr1zgTz/JmCcJBF5wre4X/xCD8K/efme3egHO35FIEjVxpSvTm6t
WpS+DegmEdJB0X730lcYWLFwCuVLPYajQrEYmgDRWH9cN0H5rI7ueh1qg7jBWXa5/atXItcuZYL5R
r5sXOg+agoyl69u65VUA==$qt9hZbgX37c/1lOBR1+yxQz88CDI/JqC1vBlUhURh2B+om8WUVENRw
y5lN+YnZQr$lATEKERFQw7jSr4y+3sANVHMR3Um+VlORB8as1dxMi8=
</EncryptedPaymentAccountUniqueId>
</PaymentContext>
<ExpirationDate>2020-09</ExpirationDate>
<EncryptedCardSecurityCode>$bt4|javascript_1_3_9$NpdBY78Wwe4cT/f9e3lLies8
TUgDUX6zlBBTct//itTAM0hu1I+Y59lMo+rQTanaQ6RbnAF0O5qdp50EVpxkjyHU8Mfm8cR487dIl
bsqIsELan9/XxdcivF/wrsTFzhiCcU0U8P5SO0DsU/QYNpvUJTzhl4MKVqjCQHAgyPHcsc6ILoByI
fTkN2uMk+W53/m6HTIuvPVL+VNdyE6sisg1pijbodflDQM1JCY1TU6HCG5pTkQNC/UBQfTkaR7hjP
dLSnEU0KrQj/Pc/nh/e+4T11p7hYBUg6oCl0etJzyTCmIRGyvovujpbP36Bfz32u+LJmB3d9VrOJJ
Jw0kiiAJrw==$vr8reIhhsNtyPT3ehW/S3kFktBVaHaOdhh8eb/qwxj0=$xMsnT9So3A8rvHfdp3S
4Jq+Qs/NoJ2xaXc7BEB6f7BE=</EncryptedCardSecurityCode>
<Amount currencyCode="USD">50.00</Amount>
<BillingFirstName>John</BillingFirstName>
<BillingLastName>Smith</BillingLastName>
<BillingPhoneNo>6101234567</BillingPhoneNo>
<BillingAddress>
<Line1>123 Main St</Line1>
<City>Philadelphia</City>
<MainDivision>PA</MainDivision>
<CountryCode>US</CountryCode>
<PostalCode>19019</PostalCode>
</BillingAddress>
<CustomerEmail>customer@sample.com</CustomerEmail>
<CustomerIPAddress>208.247.73.130</CustomerIPAddress>
<ShipToFirstName>John</ShipToFirstName>
<ShipToLastName>Smith</ShipToLastName>
<ShipToPhoneNo>6101234567</ShipToPhoneNo>
<ShippingAddress>
<Line1>123 Main St</Line1>
<City>Philadelphia</City>
<MainDivision>PA</MainDivision>
<CountryCode>US</CountryCode>
<PostalCode>19019</PostalCode>
</ShippingAddress>
<isRequestToCorrectCVVOrAVSError>false</isRequestToCorrectCVVOrAVSError>
</CreditCardAuthRequest>
CreditCardAuthReply for Encrypted PAN and CSC
Note that a token is returned instead of the encrypted data. This token should be sent to the OMS for use in the settlement message and the RiskAssessment message.
<?xml version="1.0" encoding="UTF-8"?>
<CreditCardAuthReply xmlns="http://api.gsicommerce.com/schema/checkout/1.0">
<PaymentContext>
<OrderId>123456abcd</OrderId>
<PaymentAccountUniqueId isToken="true">4111110PASeK1111</PaymentAccountUniqueId>
</PaymentContext>
<AuthorizationResponseCode>AP01</AuthorizationResponseCode>
<BankAuthorizationCode>000789</BankAuthorizationCode>
<CVV2ResponseCode>M</CVV2ResponseCode>
<AVSResponseCode>M</AVSResponseCode>
<PhoneResponseCode/>
<NameResponseCode/>
<EmailResponseCode/>
<AmountAuthorized currencyCode="USD">50.00</AmountAuthorized>
</CreditCardAuthReply>
StoredValueBalanceInquiryRequest with Encrypted PAN and PIN
<?xml version="1.0" encoding="UTF-8"?>
<StoredValueBalanceRequest xmlns="http://api.gsicommerce.com/schema/checkout/1.0">
<EncryptedPaymentAccountUniqueId>$bt4|javascript_1_3_9$InFd6VBWu3BUSp83dU4bt7y
xMiwaklXT3hIyhb0/JZDJhUAtWUejkfGavTvba65rg+y0nrKqdVFa3EfbAYAuCwzqgl0/uBcXbvST27cY5
Hw4KWWqIdEHMijrG6d4QZzdOIOQIG6fP6b1VwAMtJtIoHl9WSRph8/6sL9LaELtF9DsXRD+1pPiTiNQhk5
GxyxK64ydE5sC2K0FrkB3dw9hPlQ65SrXS3yQMd4Li5pRTMcRfsYfeMf0cxqJc7R0ZucgAQv1+leDNzZRc
L1G1p/lG2epJiccks9w4rjUe2A1a1/Xvb6A7tlGVKfYuSCddAL6z2/cPVs9f+eRoeQCBaujVA==$5BLNIi
wGdMBNWoQa7fbIEgWI6jYZGOgwI/IQ6Hgl9Gw75s3eyJ1+xuZzD1pf/2vN$Dvb16jPF8wbIxnnnCsOrUSg
Ft4T25hbLLJfxrVXz2JE=</EncryptedPaymentAccountUniqueId>
<EncryptedPin>$bt4|javascript_1_3_9$MSUkcD80LmQUNmfYU9JeMZERB9GWH1vGnwzWfP6a/9
ZrFjZNCnYQNmHgliqshnup1zgSzcO+NMpoJdGlR2sTo82P5AxUrxQcXtA8H9/NjIjKO69nLsPfyjbMeTgV
s5AsiHqlp3/M1iL3UZEdBTUudORH+WB6k3VHv5ElwprqEkO6RBSHKUB5a0amuWKcWRxMnKeOWrJ2/Ore+Y
bGO6oDmqNWjYBCh860t28uyUySGgyWakwsCEHs4hKyogM1CRF04pQdj63e0mGelpwQqgo7HzKyrpLzaCLy
cyZvF10q8hOOeeGpymvpEu4eCuNbpJ/Ur9amD+TjqL0ip+WR2Y/fMw==$83D7HGoXjD/w+fZlPvFae8/+V
BOQbes+8wq7KdNWybQ=$bhdGK6K6WQoDUr1BlqpeCFchOxoAm/DQ2jliwDJxwOI=</EncryptedPin>
<CurrencyCode>USD</CurrencyCode>
</StoredValueBalanceRequest>
StoredValueBalanceInquiryReply with Encrypted PAN and PIN
<?xml version="1.0" encoding="UTF-8"?>
<StoredValueBalanceReply
xmlns="http://api.gsicommerce.com/schema/checkout/1.0">
<PaymentAccountUniqueId isToken="true">8111110xNpAW1112</PaymentAccountUniqueId>
<ResponseCode>Success</ResponseCode>
<BalanceAmount currencyCode="USD">999.99</BalanceAmount>
</StoredValueBalanceReply>