Message Level Encryption

Message Level Encryption provides an enhanced end-to-end security for message payload by using asymmetric encryption technique (public-key cryptography).

Getting Started with MLE

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:

  1. PII (Personal Identification Information)
  2. PAN (Personal Account Number)
  3. PAI (Personal Account Information)

MLE on Visa Developer Platform

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:

  1. Visa (Server) Encryption key pair: The client encrypts the request (message payload) using the public key and Visa would decrypt the payload using its private key.
  2. Client Encryption key pair: Visa will encrypt the response (message payload) using the public key (of client) and client would decrypt the payload using its private key.
Generated Certificates & Their Role

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.

Configuring MLE for Project

Key Management


Key-ID & Its Importance

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.

CSR Generation for each Key-ID

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.

Generating CSR with OpenSSL
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>"
		
Generating CSR with Keytool

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
		
MLE Certificate Management

Here are the steps to generate MLE certificates.

1. Click on Generate Key-ID

Click 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.

MLE Controls at API Level


Mandatory MLE

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). 

Optional MLE

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. 

Implementing MLE in API Calls

  1. Enable the APIs for which MLE needs to be active in VDP by toggling the API for which MLE needs to be enforced.
  2. Generate MLE keys by navigating to Project dashboard > Credentials > Encryption/Decryption.  Click on Generate Key-ID. Create and upload CSR or use autogenerated CSR and download the certificate private key. Next, download the server and client encryption certificates and also make note of the Key-ID.
  3. After generating Key-ID, upload the CSR or use auto generate CSR.
  4. Once upload CSR is done, you can check the MLE credentials.
  5. Add the keyId as an additional HTTP header.
  6. Follow the language-specific snippet guidelines for performing encryption and decryption. Some key points to check are that JWE header must contain fields kid mapped to MLE Key-ID, algorithm namely alg mapped to RSA-OAEP-256, ciphertext encryption algorithm enc equal to A128GCM or A256GCM and also iat which is issued at timestamp. The iat field will be valid for two minutes.
  7. For decryption, use the certificate private key.

Downloading required certificates for MLE


Note: Please ensure to add the keyId as an additional HTTP header.

Encrypting Request Payloads

/*
 * *© 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>>+"\"}";
		

Decrypting Response Payloads

/*
 * *© 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.