The following Java code, using the JOSE4j API jose4j-0.6.5.jar, provides an example of decrypting the payload.
package ...;
import java.security.MessageDigest;
import javax.crypto.spec.SecretKeySpec; import org.jose4j.jwe.JsonWebEncryption;
public class DecryptJWE {
public static String decryptJWE(String secret, String jwe) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] digest = md.digest(secret.getBytes("UTF-8"));
JsonWebEncryption jweDecryptor = new JsonWebEncryption(); jweDecryptor.setCompactSerialization(jwe); jweDecryptor.setKey(new SecretKeySpec(digest, "AES"));
return jweDecryptor.getPlaintextString();
}
}
var jose = require('node-jose'); var crypto = require('crypto');
module.exports = {
decryptJWE: function (secret, payload) {
return new Promise(function (resolve, reject) {
var SS_Hashed =
crypto.createHash('sha256').update(secret).digest('hex'); jose.JWK.asKey({
kty: 'oct', k: Buffer.from(SS_Hashed,
'hex')
})
.then(function (key) {
jose.JWE.createDecrypt(key)
.decrypt(payload)
.then(function (result) {
resolve(result);
})
.catch(function (error) {
reject(error);
});
})
.catch(function (error) {
reject(error);
});
});
}
};
This code snippet is used for creating PAN JWE on the browser side. This example uses the node-jose library in browserify format.
// getNodeJoseLib(); Get node-jose library in browserify format
// Code to generate JWE using node-jose library
/**
* @param kid kid for public certificate. Contact Visa representative for this value
* @param keys Public key to be used for encryption.
Contact Visa representative for *
@param payload Card information to be encrypted,
{"card":{ "primaryAccountNumber":"424..2", "panExpirationMonth":"10",
.."panExpirationYear":"2022", "cardSecurityCode":"123",
.."cardholderFullName":"cardholder name"}
}
* @param cb Returning encrypted PAN as JWE string to this callback function */
function generateJWE(kid, keys, payload, cb) {
const keyInput = {
"kty": "RSA",
"e": keys.e, // Public key exponent "kid": kid,
"use": "enc",
"n": keys.n, // Public key modulus "alg": "RSA-OAEP-256",
"ext_content": "payload"
};
jose.JWK.asKey(keyInput)
.then((key) => {
console.log("JWK ", JSON.stringify(key)); const contentAlg = 'A25..CM';
let options = {
format: 'compact',
contentAlg: contentAlg, fields: {
kid: key.kid, typ: 'JOSE',
iat: Date.now(), alg: key.alg, enc: contentAlg
}
};
jose.JWE.createEncrypt(options, key).update(payload).
final().then((serializedJWE) => {
console.log("Encrypted data: ", JSON.stringify(serializedJWE));
cb(serializedJWE);
}, (error) => {
console.log("Error occurred: ", error.message); cb(null);
});
}, (error) => {
console.log("Error occurred: ", error.message); cb(null);
})
}
The encryption key provided during onboarding is used to encrypt and decrypt payloads. JSON Web Encryption (JWE) content should be signed or encrypted using the shared secret that was provided to client at the time of onboarding.
Visa uses JSON Web Encryption (JWE) to encode sensitive field level information. Encrypted input parameters should be constructed before sending them in API requests.
Visa Installment Solutions APIs use the following naming convention for fields that require encryption in this document.
"enc<FIELD>" : "JWE ( ... ) "
See the complete specification for JWE: https://tools.ietf.org/html/draft-ietf-jose-json-web- encryption-40.
BASE64URL (UTF8 (JWE Header)) || ‘.’ ||
BASE64URL (JWE Encrypted Key) || ‘.’ || BASE64URL (JWE IV) || ‘.’ ||
BASE64URL (JWE Ciphertext) || ‘.’ || BASE64URL (JWE Authentication Tag)
The conventions are as follows:
Note: The JWE Protected Header is input as the AAD (Additional Authenticated Data) parameter of the authenticated encryption (AES-GCM) of the “text to encrypt”.
"header": {
"alg": "RSA-OAEP-256""typ": "JOSE",
"kid": "50charAPIKey", // API key "enc": "A256GCM"
}
"header": {
"alg": "AGCM256KW""typ": "JOSE",
"tag": "<128bitvalue>", // HMAC generated from applying AES-256-GCM-KW to the CEK
"kid": "50charAPIKey", // API key "enc": "AGCM256"
}
“encrypted_key”: “UghIOgu ... MR4gp_A=”, “iv”: “AxY8DctDa….GlsbGljb3RoZQ=”,
“ciphertext”: “KDlTthhZTGufMY…….xPSUrfmqCHXaI9wOGY=”, “tag”: “Mz-VPPyU4…RlcuYv1IwIvzw=”