Message Level Encryption (MLE) allows you to store information or to communicate with other parties while helping to prevent uninvolved parties from understanding the stored information or understanding the communication. MLE can help address the threat of relying on TLS for message security. SSL is designed to provide point-to-point security, which falls short for web/restful services because of a need for end-to-end security. Where multiple intermediary nodes could exist between the two endpoints, MLE would provide that the message remains encrypted, even during these intermediate "hops" where the traffic itself is decrypted before it arrives at Visa servers. Both processes involve a mathematical formula (algorithm) and secret data (key).
MLE is required for APIs that primarily deal with sensitive transaction data (financial/non-financial) which could fall into one or several of the following categories:
MLE on the Visa Developer Platform provides enhanced security for message payload by using an asymmetric encryption technique (public-key cryptography). The message encryption is implemented via symmetric encryption using Advanced Encryption Standard (AES), Galois Counter Mode (GCM) with 128-bit or 256-bit key size. The encryption of keys is supported using RSA Optimal Asymmetric Encryption Padding (OAEP) with 2048-bit key size.The encryption service is based on JWE and works on top of SSL and requires separate key-pairs for Request and Response legs of the transaction:
There are two certificate pairs required for MLE:
Visa (Server) Encryption Key Pair
Visa generates the Server Encryption certificate based on the provided information for a particular Key-ID. Public key for this certificate is available for download via Visa Developer portal under the Encryption/Decryption section of the Credentials page for applicable projects. The client will use this public key to encrypt the request (message payload) and invoke the API call with relevant Key-ID as header attribute. Visa uses the private key associated with the Key-ID to decrypt this payload and process the API request.
Client Encryption Key
Client generates the Client Encryption certificate and uploads the CSR for the relevant Key-ID. Public key for this certificate is stored on Visa servers; public key is available for verification under the Encryption/Decryption section of the Credentials page for applicable projects. Visa will encrypt the response (message payload) using the public key (of client); client will use the applicable private key stored on their environment to decrypt the payload and process the API response.
Key-ID is a system generated unique identifier (UID), which is associated with your project and identifies the associated key-pairs. This Key-ID must be included as a request header in API calls. Key-ID can be generated and is accessible under Encryption/Decryption section of Credentials page for applicable projects. At any given time, client can have up to 3 pairs of Key-IDs active per project. This helps allow for more seamless migration to new MLE certificates.
Your KeyID is distinct to the certificates generated. When you renew these certificates, their KeyID will change and need to be updated in your API calls.
Once a Key-ID is generated, you can upload a CSR (Certificate Signing Request) for each Key-ID. In Sandbox, there are 2 options - ask VDP to generate a CSR for you OR submit your own CSR. If you are submitting your own CSR, the UID value should be the Key-ID. In either case make sure to securely save your private key file as you will need it to decrypt the response.
openssl genrsa -out example-key.pem 2048
openssl req -new -sha256 -key example-key.pem -out example.csr -subj "/CN=<common name>/OU=<organization unit>/O=<organization name>/L=<city/locality name>/ST=<state name>/C=<country name>/UID=<key ID>"
1.
Create JKS
keytool -genkeypair -alias client -keyalg RSA -keysize 2048 -keystore clientkeystore.jks -storepass <password> -keypass <password> -dname "CN=<common name>, OU=<organizational unit>, O=<organization name>, L=<city/locality name>, ST=<state name>, C=<country name>, UID=<MLE KeyId value>"
2.
Create CSR JKS
keytool -certreq -alias client -keystore clientkeystore.jks -storepass <password> -keypass <password> -file certreq1.csr
3.
Convert JKS keystore created in step 1 to PKCS12 format
keytool -importkeystore -srckeystore clientkeystore.jks -srcstorepass <password> -srckeypass <password> -srcalias client -destalias client -destkeystore clientkeystore.p12 -deststoretype PKCS12 -deststorepass <password> -destkeypass <password>
4.
Extract the private key
openssl pkcs12 -in clientkeystore.p12 -nodes -nocerts -out private-key.pem
If you are using our Message Level Encryption service for decryption, you will need the additional step below:
openssl rsa -in private-key.pem -out private-key_rsa.key
Here are the steps to generate MLE certificates.
1. Click on Generate Key-ID
2. Upload CSR for the generated Key-ID by clicking on Add CSR.
Here are the steps to regenerate new Key-ID and MLE certificates:
1. Click on Generate Key-ID.
2. Click on Add CSR.
3. Once valid CSR is uploaded, you would be able to see two sets of active MLE credentials.
Here are the steps for the business validations on revocation and impact of revocation.
1. In the Sandbox environment, you can revoke a set of MLE credentials. You should only revoke a set of MLE credentials if you have another set of active MLE credentials to use.
2. A click on Revoke will display a pop up as shown below. Once you confirm it will revoke MLE credentials for the Key-ID.
Some VDP APIs show up as Mandatory MLE. This means there is no choice given to the end user, on whether to opt to use MLE when sending payloads across to these API end points. These APIs have been identified as dealing with information falling into a sensitive category and VISA mandates that such API calls are by default encrypted using the MLE framework that is exposed. This works across all the environments (SBX, CERT & PROD).
Some VDP APIs allow the clients to be able to toggle the choice of whether MLE needs to be applied to the API or not - however, this is available only in SBX. The option to go with or without MLE at the time of project promotion to CERT and/or PROD lies with the VDP Admin's discretion. The client is able to view the selection on the project dashboard for CERT & PROD environments. In SBX, depending on whether the client has chosen to opt in to MLE or not, the validations applied at the time of processing the APIs calls will be modified accordingly. This ability gives the clients a migration path to consider for existing projects which would be moving from non-MLE to MLE scenarios, and also provide an option to experiment in a lower environment the checks and balances needed to make an encrypted call vs. a non-encrypted call.
MLE Optional OFF / Not Enforced
This state is where MLE is not expected to be applied to the payload. The API call can be made without encrypting the payload since the MLE is not enforced. However if the payload has been encrypted, MLE is supported. If a call is received with encrypted payload when MLE Optional is OFF then VISA will decrypt the payload and process it.
MLE Optional ON / Enforced
This state is where MLE is optional, but if toggled to ON, requires 'mandatory' encryption of the payload. The client will be provided with a key ID which will need to be used to generate the CSR and submitted for MLE certificate creation. Post this, the Key-ID will need to be included in the header at the time of making an encrypted API call. Once the toggle is ON, VISA will validate all calls coming on the API for the particular project and ensure that the payloads are encrypted. Un-encrypted payloads will be rejected.
In CERT and PROD environments, the client does not have the option to toggle the state of MLE - even for Optional MLE APIs. Mandatory MLE works the same way irrespective of the environment the client is engaged in. However in both CERT & PROD, the client will be able to view the state of MLE that has been preset by the VDP Admins so that the client is aware of the next steps. The client will also be able to view the Key-ID that they need to use to create the CSR, and be able to track the certificates and download the same from the portal once they have been provisioned for.
Note: Please ensure to add the keyId as an additional HTTP header.
/*
* *© Copyright 2018 - 2020 Visa. All Rights Reserved.**
*
* NOTICE: The software and accompanying information and documentation (together, the “Software”) remain the property of and are proprietary to Visa and its suppliers and affiliates. The Software remains protected by intellectual property rights and may be covered by U.S. and foreign patents or patent applications. The Software is licensed and not sold.*
*
* By accessing the Software you are agreeing to Visa's terms of use (developer.visa.com/terms) and privacy policy (developer.visa.com/privacy).In addition, all permissible uses of the Software must be in support of Visa products, programs and services provided through the Visa Developer Program (VDP) platform only (developer.visa.com). **THE SOFTWARE AND ANY ASSOCIATED INFORMATION OR DOCUMENTATION IS PROVIDED ON AN “AS IS,” “AS AVAILABLE,” “WITH ALL FAULTS” BASIS WITHOUT WARRANTY OR CONDITION OF ANY KIND. YOUR USE IS AT YOUR OWN RISK.** All brand names are the property of their respective owners, used for identification purposes only, and do not imply product endorsement or affiliation with Visa. Any links to third party sites are for your information only and equally do not constitute a Visa endorsement. Visa has no insight into and control over third party content and code and disclaims all liability for any such components, including continued availability and functionality. Benefits depend on implementation details and business factors and coding steps shown are exemplary only and do not reflect all necessary elements for the described capabilities. Capabilities and features are subject to Visa’s terms and conditions and may require development,implementation and resources by you based on your business and operational details. Please refer to the specific API documentation for details on the requirements, eligibility and geographic availability.*
*
* This Software includes programs, concepts and details under continuing development by Visa. Any Visa features,functionality, implementation, branding, and schedules may be amended, updated or canceled at Visa’s discretion.The timing of widespread availability of programs and functionality is also subject to a number of factors outside Visa’s control,including but not limited to deployment of necessary infrastructure by issuers, acquirers, merchants and mobile device manufacturers.*
*
*/
MLE calls with xml payload a new header “cty” is required to be present in JWE payload. For backward compatibility, the default content type is set as “application/json” if the cty is not present.
JWE payload has 5 parts. The first part represents the JWE header.
Currently the fields in JWE header are as follows:
{
"alg": "RSA-OAEP-256",
"enc": "A128GCM",
"iat": current timestamp in milliseconds,
"kid": "keyId"
}
If the plain text before encryption is “application/xml” the JWE header should be
{
"alg": "RSA-OAEP-256",
"enc": "A128GCM",
"iat": current timestamp in milliseconds,
"kid": "keyId",
“cty”: “application/xml”
}
Message Level Encryption is based on JOSE standards and there are many libraries which support/implement the same.
For Java, the example snippet, uses nimbus-jose-jwt which can be imported using maven or gradle as follows:
Maven:
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>5.8</version>
</dependency>
Gradle:
compile group: 'com.nimbusds', name: 'nimbus-jose-jwt', version: '5.8'
We also use bouncy castle for converting PEM file content to private key, bouncy castle can be included by Maven or gradle as follows from Maven repository as follows:
Maven :
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.59</version>
</dependency>
Gradle
compile group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.59'
The following snippets illustrate MLE encryption using this library:
class EncryptionUtils {
private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
private static final String END_CERT = "-----END CERTIFICATE-----";
private static final String BEGIN_RSA_PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----";
private static final String END_RSA_PRIVATE_KEY = "-----END RSA PRIVATE KEY-----";
private static final String ENC_DATA = "encData";
//Make sure you are reading and passing the correct keyId from credentials. This is required and is passed in headers.
public static String getEncryptedPayload(Object payload, String keyId) throws CertificateException, JOSEException, IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_NULL);
mapper.setSerializationInclusion(Include.NON_EMPTY);
String plainText = payload == null ? "" : mapper.writeValueAsString(payload);
JWEHeader.Builder headerBuilder = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128GCM);
headerBuilder.keyID(keyId);
headerBuilder.customParam("iat", System.currentTimeMillis());
JWEObject jweObject = new JWEObject(headerBuilder.build(), new Payload(plainText));
jweObject.encrypt(new RSAEncrypter(getRSAPublicKey()));
return "{\"encData\":\""+jweObject.serialize()+"\"}";
}
In the above snippet, JWEHeader, JWEObject and RSAEncrypter come from the library namespace namely com.nimbusds.jose.
The method getRSAPublicKey() converts PEM file content that is downloaded from VDP to RSAPublicKey as shown below:
/*
* Converts PEM file content to RSAPublicKey
*/
private static RSAPublicKey getRSAPublicKey() throws CertificateException, IOException {
String pemEncodedPublicKey = IOUtils.readFileToString(new File(mleServerPublicCertificatePath), Charset.forName("UTF-8"));
Base64 base64 = new Base64(
pemEncodedPublicKey.replaceAll(BEGIN_CERT, "").replaceAll(END_CERT, ""));
Certificate cf = CertificateFactory.getInstance("X.509")
.generateCertificate(new ByteArrayInputStream(base64.decode()));
return (RSAPublicKey) cf.getPublicKey();
}
}
Java import statements corresponding to the snippets are also listed below for any cross verification:
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSADecrypter;
import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jose.util.Base64;
import com.nimbusds.jose.util.IOUtils;
/*
* *© Copyright 2018 - 2020 Visa. All Rights Reserved.**
*
* NOTICE: The software and accompanying information and documentation (together, the “Software”) remain the property of and are proprietary to Visa and its suppliers and affiliates. The Software remains protected by intellectual property rights and may be covered by U.S. and foreign patents or patent applications. The Software is licensed and not sold.*
*
* By accessing the Software you are agreeing to Visa's terms of use (developer.visa.com/terms) and privacy policy (developer.visa.com/privacy).In addition, all permissible uses of the Software must be in support of Visa products, programs and services provided through the Visa Developer Program (VDP) platform only (developer.visa.com). **THE SOFTWARE AND ANY ASSOCIATED INFORMATION OR DOCUMENTATION IS PROVIDED ON AN “AS IS,” “AS AVAILABLE,” “WITH ALL FAULTS” BASIS WITHOUT WARRANTY OR CONDITION OF ANY KIND. YOUR USE IS AT YOUR OWN RISK.** All brand names are the property of their respective owners, used for identification purposes only, and do not imply product endorsement or affiliation with Visa. Any links to third party sites are for your information only and equally do not constitute a Visa endorsement. Visa has no insight into and control over third party content and code and disclaims all liability for any such components, including continued availability and functionality. Benefits depend on implementation details and business factors and coding steps shown are exemplary only and do not reflect all necessary elements for the described capabilities. Capabilities and features are subject to Visa’s terms and conditions and may require development,implementation and resources by you based on your business and operational details. Please refer to the specific API documentation for details on the requirements, eligibility and geographic availability.*
*
* This Software includes programs, concepts and details under continuing development by Visa. Any Visa features,functionality, implementation, branding, and schedules may be amended, updated or canceled at Visa’s discretion.The timing of widespread availability of programs and functionality is also subject to a number of factors outside Visa’s control,including but not limited to deployment of necessary infrastructure by issuers, acquirers, merchants and mobile device manufacturers.*
*
*/
The library used in the below snippet is node-jose.
node-jose can be installed with npm as follows:
npm install node-jose
Detailed documentation about the library can be found at :https://github.com/cisco/node-jose
The first step is adding keyId in the HTTP headers, the snippet shows howto encrypt/decrypt using the library:
let fs = require('fs');
let nodeJose = require('node-jose');
let request = require('request');
function createEncryptedPayload(payload) {
let payloadString = typeof payload === 'string' ? payload : JSON.stringify(payload);
let keystore = nodeJose.JWK.createKeyStore();
let encProps = {
kid: credentials.encryptionKey,
alg: 'RSA-OAEP-256',
enc: 'A128GCM'
};
let encryptionCert = fs.readFileSync(credentials.mleServerCert);
return keystore.add(encryptionCert, 'pem', encProps)
.then((key) => {
return nodeJose.JWE.createEncrypt({
format: 'compact',
fields: {
'enc': 'A128GCM',
'iat': Date.now()
}
}, key)
.update(payloadString)
.final()
.then((result) => {
return { encData: result };
});
});
}
/*
* *© Copyright 2018 - 2020 Visa. All Rights Reserved.**
*
* NOTICE: The software and accompanying information and documentation (together, the “Software”) remain the property of and are proprietary to Visa and its suppliers and affiliates. The Software remains protected by intellectual property rights and may be covered by U.S. and foreign patents or patent applications. The Software is licensed and not sold.*
*
* By accessing the Software you are agreeing to Visa's terms of use (developer.visa.com/terms) and privacy policy (developer.visa.com/privacy).In addition, all permissible uses of the Software must be in support of Visa products, programs and services provided through the Visa Developer Program (VDP) platform only (developer.visa.com). **THE SOFTWARE AND ANY ASSOCIATED INFORMATION OR DOCUMENTATION IS PROVIDED ON AN “AS IS,” “AS AVAILABLE,” “WITH ALL FAULTS” BASIS WITHOUT WARRANTY OR CONDITION OF ANY KIND. YOUR USE IS AT YOUR OWN RISK.** All brand names are the property of their respective owners, used for identification purposes only, and do not imply product endorsement or affiliation with Visa. Any links to third party sites are for your information only and equally do not constitute a Visa endorsement. Visa has no insight into and control over third party content and code and disclaims all liability for any such components, including continued availability and functionality. Benefits depend on implementation details and business factors and coding steps shown are exemplary only and do not reflect all necessary elements for the described capabilities. Capabilities and features are subject to Visa’s terms and conditions and may require development,implementation and resources by you based on your business and operational details. Please refer to the specific API documentation for details on the requirements, eligibility and geographic availability.*
*
* This Software includes programs, concepts and details under continuing development by Visa. Any Visa features,functionality, implementation, branding, and schedules may be amended, updated or canceled at Visa’s discretion.The timing of widespread availability of programs and functionality is also subject to a number of factors outside Visa’s control,including but not limited to deployment of necessary infrastructure by issuers, acquirers, merchants and mobile device manufacturers.*
*
*/
In Python, we can use one of the libraries namely: jwcrypto or python-jose.
Jwcrypto can be installed through pip as follows:
pip install jwcrypto
Detailed documentation for this library can be found at :https://jwcrypto.readthedocs.io/en/latest/#
The following snippet describes, how to do message level encryption and decryption with jwcrypto:
from jwcrypto import jwk, jwe
....
....
# Note: The input payload for encrypt method should be a json object
def encrypt(self, payload):
config = Configuration()
payload = json.dumps(payload)
protected_header = {
"alg": "RSA-OAEP-256",
"enc": "A128GCM",
"kid": config.api_key['keyId'],
"iat": int(round(time.time() * 1000))
}
jwetoken = jwe.JWE(payload.encode('utf-8'),
recipient=self.loadPem(config.encryption_public_key_path),
protected=protected_header)
encryptedPayload = jwetoken.serialize(compact=True)
return json.dumps({"encData": encryptedPayload})
def loadPem(self, filePath):
with open(filePath, "rb") as pemfile:
return jwk.JWK.from_pem(pemfile.read())
/*
* *© Copyright 2018 - 2020 Visa. All Rights Reserved.**
*
* NOTICE: The software and accompanying information and documentation (together, the “Software”) remain the property of and are proprietary to Visa and its suppliers and affiliates. The Software remains protected by intellectual property rights and may be covered by U.S. and foreign patents or patent applications. The Software is licensed and not sold.*
*
* By accessing the Software you are agreeing to Visa's terms of use (developer.visa.com/terms) and privacy policy (developer.visa.com/privacy).In addition, all permissible uses of the Software must be in support of Visa products, programs and services provided through the Visa Developer Program (VDP) platform only (developer.visa.com). **THE SOFTWARE AND ANY ASSOCIATED INFORMATION OR DOCUMENTATION IS PROVIDED ON AN “AS IS,” “AS AVAILABLE,” “WITH ALL FAULTS” BASIS WITHOUT WARRANTY OR CONDITION OF ANY KIND. YOUR USE IS AT YOUR OWN RISK.** All brand names are the property of their respective owners, used for identification purposes only, and do not imply product endorsement or affiliation with Visa. Any links to third party sites are for your information only and equally do not constitute a Visa endorsement. Visa has no insight into and control over third party content and code and disclaims all liability for any such components, including continued availability and functionality. Benefits depend on implementation details and business factors and coding steps shown are exemplary only and do not reflect all necessary elements for the described capabilities. Capabilities and features are subject to Visa’s terms and conditions and may require development,implementation and resources by you based on your business and operational details. Please refer to the specific API documentation for details on the requirements, eligibility and geographic availability.*
*
* This Software includes programs, concepts and details under continuing development by Visa. Any Visa features,functionality, implementation, branding, and schedules may be amended, updated or canceled at Visa’s discretion.The timing of widespread availability of programs and functionality is also subject to a number of factors outside Visa’s control,including but not limited to deployment of necessary infrastructure by issuers, acquirers, merchants and mobile device manufacturers.*
*
*/
Encryption Process pseudo code
1. Get Plain Text Payload
2. Construct JOSE Header Object using Algorithms RSA_OAEP_256 & A128GCM
3. Set the Key ID to the kid parameter in JOSE Header
4. Add a customer parameter with name "iat" to the JOSEHeader. Set the value of iat as current timestamp in milliseconds
5. Construct JWE Object
6. Set the JOSE header and plain text payload to JWE Object
7. Set the MLE Public Key a.k.a Server Encryption Certificate to JWE Object
8. Encrypt the JWE Object using the MLE Public Key
9. Return the Encrypted String in this JSON format --> "{\"encData\":\""+<<encryptedstring>>+"\"}";
/*
* *© Copyright 2018 - 2020 Visa. All Rights Reserved.**
*
* NOTICE: The software and accompanying information and documentation (together, the “Software”) remain the property of and are proprietary to Visa and its suppliers and affiliates. The Software remains protected by intellectual property rights and may be covered by U.S. and foreign patents or patent applications. The Software is licensed and not sold.*
*
* By accessing the Software you are agreeing to Visa's terms of use (developer.visa.com/terms) and privacy policy (developer.visa.com/privacy).In addition, all permissible uses of the Software must be in support of Visa products, programs and services provided through the Visa Developer Program (VDP) platform only (developer.visa.com). **THE SOFTWARE AND ANY ASSOCIATED INFORMATION OR DOCUMENTATION IS PROVIDED ON AN “AS IS,” “AS AVAILABLE,” “WITH ALL FAULTS” BASIS WITHOUT WARRANTY OR CONDITION OF ANY KIND. YOUR USE IS AT YOUR OWN RISK.** All brand names are the property of their respective owners, used for identification purposes only, and do not imply product endorsement or affiliation with Visa. Any links to third party sites are for your information only and equally do not constitute a Visa endorsement. Visa has no insight into and control over third party content and code and disclaims all liability for any such components, including continued availability and functionality. Benefits depend on implementation details and business factors and coding steps shown are exemplary only and do not reflect all necessary elements for the described capabilities. Capabilities and features are subject to Visa’s terms and conditions and may require development,implementation and resources by you based on your business and operational details. Please refer to the specific API documentation for details on the requirements, eligibility and geographic availability.*
*
* This Software includes programs, concepts and details under continuing development by Visa. Any Visa features,functionality, implementation, branding, and schedules may be amended, updated or canceled at Visa’s discretion.The timing of widespread availability of programs and functionality is also subject to a number of factors outside Visa’s control,including but not limited to deployment of necessary infrastructure by issuers, acquirers, merchants and mobile device manufacturers.*
*
*/
static class EncryptionUtils {
private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
private static final String END_CERT = "-----END CERTIFICATE-----";
private static final String BEGIN_RSA_PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----";
private static final String END_RSA_PRIVATE_KEY = "-----END RSA PRIVATE KEY-----";
private static final String ENC_DATA = "encData";
public static <T> T getDecryptedPayload(EncryptedResponse encryptedPayload, Class<T> returnType) {
String response = encryptedPayload.getEncData();
T decryptedResponse = null;
try {
JWEObject jweObject = JWEObject.parse(response);
//If you have used passphrase while generating the csr make sure you the same while getting the private key. Otherwise decryption will fail.
jweObject.decrypt(new RSADecrypter(getRSAPrivateKey()));
response = jweObject.getPayload().toString();
ObjectMapper mapper = new ObjectMapper();
decryptedResponse = mapper.readValue(response, returnType);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedResponse;
}
/*
* Converts PEM file content to RSAPrivateKey
*/
private static PrivateKey getRSAPrivateKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
//If you have used passphrase while generating the csr make sure you the same while reading the private key. Otherwise decryption will fail.
String pemEncodedKey = IOUtils.readFileToString(new File(mleClientPrivateKeyPath), Charset.forName("UTF-8"));
Base64 base64 = new Base64(pemEncodedKey.replaceAll(BEGIN_RSA_PRIVATE_KEY, "").replaceAll(END_RSA_PRIVATE_KEY, ""));
ASN1Sequence primitive = (ASN1Sequence) ASN1Sequence.fromByteArray(base64.decode());
Enumeration<?> e = primitive.getObjects();
BigInteger v = ((ASN1Integer) e.nextElement()).getValue();
int version = v.intValue();
if (version != 0 && version != 1) {
throw new IllegalArgumentException("wrong version for RSA private key");
}
BigInteger modulus = ((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
BigInteger privateExponent = ((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(modulus, privateExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return (PrivateKey) keyFactory.generatePrivate(privateKeySpec);
}
}
Java import statements corresponding to the snippets are also listed below for any cross verification:
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSADecrypter;
import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jose.util.Base64;
import com.nimbusds.jose.util.IOUtils;
/*
* *© Copyright 2018 - 2020 Visa. All Rights Reserved.**
*
* NOTICE: The software and accompanying information and documentation (together, the “Software”) remain the property of and are proprietary to Visa and its suppliers and affiliates. The Software remains protected by intellectual property rights and may be covered by U.S. and foreign patents or patent applications. The Software is licensed and not sold.*
*
* By accessing the Software you are agreeing to Visa's terms of use (developer.visa.com/terms) and privacy policy (developer.visa.com/privacy).In addition, all permissible uses of the Software must be in support of Visa products, programs and services provided through the Visa Developer Program (VDP) platform only (developer.visa.com). **THE SOFTWARE AND ANY ASSOCIATED INFORMATION OR DOCUMENTATION IS PROVIDED ON AN “AS IS,” “AS AVAILABLE,” “WITH ALL FAULTS” BASIS WITHOUT WARRANTY OR CONDITION OF ANY KIND. YOUR USE IS AT YOUR OWN RISK.** All brand names are the property of their respective owners, used for identification purposes only, and do not imply product endorsement or affiliation with Visa. Any links to third party sites are for your information only and equally do not constitute a Visa endorsement. Visa has no insight into and control over third party content and code and disclaims all liability for any such components, including continued availability and functionality. Benefits depend on implementation details and business factors and coding steps shown are exemplary only and do not reflect all necessary elements for the described capabilities. Capabilities and features are subject to Visa’s terms and conditions and may require development,implementation and resources by you based on your business and operational details. Please refer to the specific API documentation for details on the requirements, eligibility and geographic availability.*
*
* This Software includes programs, concepts and details under continuing development by Visa. Any Visa features,functionality, implementation, branding, and schedules may be amended, updated or canceled at Visa’s discretion.The timing of widespread availability of programs and functionality is also subject to a number of factors outside Visa’s control,including but not limited to deployment of necessary infrastructure by issuers, acquirers, merchants and mobile device manufacturers.*
*
*/
let fs = require('fs');
let nodeJose = require('node-jose');
let request = require('request');
function fetchDecryptedPayload(encryptedPayloadString) {
let encryptedPayload = typeof encryptedPayloadString == 'string' ? JSON.parse(encryptedPayloadString) : encryptedPayloadString;
let keystore = nodeJose.JWK.createKeyStore();
let decProps = {
kid: credentials.encryptionKey,
alg: 'RSA-OAEP-256',
enc: 'A128GCM'
};
let decryptionKey = fs.readFileSync(credentials.mleKey);
return keystore.add(decryptionKey, 'pem', decProps)
.then((key) => {
return nodeJose.JWE.createDecrypt(key)
.decrypt(encryptedPayload.encData)
.then((result) => {
return result;
});
});
}
/*
* *© Copyright 2018 - 2020 Visa. All Rights Reserved.**
*
* NOTICE: The software and accompanying information and documentation (together, the “Software”) remain the property of and are proprietary to Visa and its suppliers and affiliates. The Software remains protected by intellectual property rights and may be covered by U.S. and foreign patents or patent applications. The Software is licensed and not sold.*
*
* By accessing the Software you are agreeing to Visa's terms of use (developer.visa.com/terms) and privacy policy (developer.visa.com/privacy).In addition, all permissible uses of the Software must be in support of Visa products, programs and services provided through the Visa Developer Program (VDP) platform only (developer.visa.com). **THE SOFTWARE AND ANY ASSOCIATED INFORMATION OR DOCUMENTATION IS PROVIDED ON AN “AS IS,” “AS AVAILABLE,” “WITH ALL FAULTS” BASIS WITHOUT WARRANTY OR CONDITION OF ANY KIND. YOUR USE IS AT YOUR OWN RISK.** All brand names are the property of their respective owners, used for identification purposes only, and do not imply product endorsement or affiliation with Visa. Any links to third party sites are for your information only and equally do not constitute a Visa endorsement. Visa has no insight into and control over third party content and code and disclaims all liability for any such components, including continued availability and functionality. Benefits depend on implementation details and business factors and coding steps shown are exemplary only and do not reflect all necessary elements for the described capabilities. Capabilities and features are subject to Visa’s terms and conditions and may require development,implementation and resources by you based on your business and operational details. Please refer to the specific API documentation for details on the requirements, eligibility and geographic availability.*
*
* This Software includes programs, concepts and details under continuing development by Visa. Any Visa features,functionality, implementation, branding, and schedules may be amended, updated or canceled at Visa’s discretion.The timing of widespread availability of programs and functionality is also subject to a number of factors outside Visa’s control,including but not limited to deployment of necessary infrastructure by issuers, acquirers, merchants and mobile device manufacturers.*
*
*/
from jwcrypto import jwk, jwe
....
....
def decrypt(self, encPayload):
if type(encPayload) is str:
payload = json.loads(encPayload)
if payload.get('encData', False):
config = Configuration()
jwetoken = jwe.JWE()
jwetoken.deserialize(payload["encData"], key=self.loadPem(config.decryption_private_key_path))
return json.dumps(json.loads(jwetoken.payload))
return encPayload
def loadPem(self, filePath):
with open(filePath, "rb") as pemfile:
return jwk.JWK.from_pem(pemfile.read())
/*
* *© Copyright 2018 - 2020 Visa. All Rights Reserved.**
*
* NOTICE: The software and accompanying information and documentation (together, the “Software”) remain the property of and are proprietary to Visa and its suppliers and affiliates. The Software remains protected by intellectual property rights and may be covered by U.S. and foreign patents or patent applications. The Software is licensed and not sold.*
*
* By accessing the Software you are agreeing to Visa's terms of use (developer.visa.com/terms) and privacy policy (developer.visa.com/privacy).In addition, all permissible uses of the Software must be in support of Visa products, programs and services provided through the Visa Developer Program (VDP) platform only (developer.visa.com). **THE SOFTWARE AND ANY ASSOCIATED INFORMATION OR DOCUMENTATION IS PROVIDED ON AN “AS IS,” “AS AVAILABLE,” “WITH ALL FAULTS” BASIS WITHOUT WARRANTY OR CONDITION OF ANY KIND. YOUR USE IS AT YOUR OWN RISK.** All brand names are the property of their respective owners, used for identification purposes only, and do not imply product endorsement or affiliation with Visa. Any links to third party sites are for your information only and equally do not constitute a Visa endorsement. Visa has no insight into and control over third party content and code and disclaims all liability for any such components, including continued availability and functionality. Benefits depend on implementation details and business factors and coding steps shown are exemplary only and do not reflect all necessary elements for the described capabilities. Capabilities and features are subject to Visa’s terms and conditions and may require development,implementation and resources by you based on your business and operational details. Please refer to the specific API documentation for details on the requirements, eligibility and geographic availability.*
*
* This Software includes programs, concepts and details under continuing development by Visa. Any Visa features,functionality, implementation, branding, and schedules may be amended, updated or canceled at Visa’s discretion.The timing of widespread availability of programs and functionality is also subject to a number of factors outside Visa’s control,including but not limited to deployment of necessary infrastructure by issuers, acquirers, merchants and mobile device manufacturers.*
*
*/
Decryption Process
1. Get the encrypted response string from Visa
2. Parse the response using JWE Object
3. Set the MLE Private Key to the JWE Object
4. Decrypt the Payload using the private key(One which got generated during CSR Creation. If you have used passphrase please use the same while reading this private key in code)
Disclaimer: MLE IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND. VISA ESPECIALLY DOES NOT REPRESENT OR WARRANT THAT MLE OR ITS COMPONENTS WILL BE SECURE, ERROR-FREE OR SUFFICIENT TO SAFEGUARD THE CONFIDENTIALITY OF YOUR DATA.