Ruby library for Mastercard API compliant payload encryption/decryption.
- Ruby 2.4.4+
- Truffle Ruby 1.0.0+
Before using this library, you will need to set up a project in the Mastercard Developers Portal.
As part of this set up, you'll receive:
- A public request encryption certificate (aka Client Encryption Keys)
- A private response decryption key (aka Mastercard Encryption Keys)
If you want to use mastercard-client-encryption with Ruby, it is available as Gem:
Adding the library to your project
Add this line to your application's Gemfile:
gem 'mastercard-client-encryption'
And then execute:
$ bundle
Or install it yourself as:
$ gem install mastercard-client-encryption
Import the library:
require 'mcapi/encryption/openapi_interceptor' # to add the interceptor
# or
require 'mcapi/encryption/field_level_encryption' # to perform ad-hoc Mastercard encryption/decryption
require 'mcapi/encryption/jwe_encryption' # to perform ad-hoc JWE encryption/decryption
This library supports two types of encryption/decryption, both of which support field level and entire payload encryption: JWE encryption and what the library refers to as Field Level Encryption (Mastercard encryption), a scheme used by many services hosted on Mastercard Developers before the library added support for JWE.
This library uses JWE compact serialization for the encryption of sensitive data.
The core methods responsible for payload encryption and decryption are encrypt
and decrypt
in the JweEncryption
class.
encrypt()
usage:
jwe = McAPI::Encryption::JweEncryption.new(@config)
encrypted_request_payload = jwe.encrypt(endpoint, body)
decrypt()
usage:
jwe = McAPI::Encryption::JweEncryption.new(@config)
decrypted_response_payload = jwe.decrypt(encrypted_response_payload)
JweEncryption
needs a config object to instruct how to decrypt/decrypt the payloads. Example:
{
"paths": [
{
"path": "/resource",
"toEncrypt": [
{
"element": "path.to.foo",
"obj": "path.to.encryptedFoo"
}
],
"toDecrypt": [
{
"element": "path.to.encryptedFoo",
"obj": "path.to.foo"
}
]
}
],
"encryptedValueFieldName": "encryptedData",
"encryptionCertificate": "./path/to/public.cert",
"privateKey": "./path/to/your/private.key",
}
For all config options, please see:
- Configuration object for all config options
We have a predefined set of configurations to use with Mastercard services:
Call JweEncryption.encrypt()
with a JSON request payload.
Example using the configuration above:
payload = JSON.generate({
path: {
to: {
foo: {
sensitiveField1: 'sensitiveValue1',
sensitiveField2: 'sensitiveValue2'
}
}
}
})
jwe = McAPI::Encryption::JweEncryption.new(@config)
request_payload = jwe.encrypt("/resource", header, payload)
Output:
{
"path": {
"to": {
"encryptedFoo": {
"encryptedValue": "eyJraWQiOiI3NjFiMDAzYzFlYWRlM….Y+oPYKZEMTKyYcSIVEgtQw"
}
}
}
}
Call JweEncryption.decrypt()
with an (encrypted) response
object with the following fields:
body
: json payloadrequest.url
: requesting url
Example using the configuration above:
response = {}
response[:request] = { url: '/resource1' }
response[:body] =
{
"path": {
"to": {
"encryptedFoo": {
"encryptedValue": "eyJraWQiOiI3NjFiMDAzYzFlYWRlM….Y+oPYKZEMTKyYcSIVEgtQw"
}
}
}
}
jwe = McAPI::Encryption::JweEncryption.new(@config)
response_payload = jwe.decrypt(response)
Output:
{
"path": {
"to": {
"foo": {
"sensitiveField1": "sensitiveValue1",
"sensitiveField2": "sensitiveValue2"
}
}
}
}
- Introduction
- Configuring the Mastercard Encryption
- Performing Mastercard Encryption
- Performing Mastercard Decryption
The core methods responsible for payload encryption and decryption are encrypt
and decrypt
in the FieldLevelEncryption
class.
encrypt()
usage:
fle = McAPI::Encryption::FieldLevelEncryption.new(@config)
encrypted_request_payload = fle.encrypt(endpoint, header, body)
decrypt()
usage:
fle = McAPI::Encryption::FieldLevelEncryption.new(@config)
decrypted_response_payload = fle.decrypt(encrypted_response_payload)
FieldLevelEncryption
needs a config object to instruct how to decrypt/decrypt the payloads. Example:
{
"paths": [
{
"path": "/resource",
"toEncrypt": [
{
"element": "path.to.foo",
"obj": "path.to.encryptedFoo"
}
],
"toDecrypt": [
{
"element": "path.to.encryptedFoo",
"obj": "path.to.foo"
}
]
}
],
"ivFieldName": "iv",
"encryptedKeyFieldName": "encryptedKey",
"encryptedValueFieldName": "encryptedData",
"dataEncoding": "hex",
"encryptionCertificate": "./path/to/public.cert",
"privateKey": "./path/to/your/private.key",
"oaepPaddingDigestAlgorithm": "SHA-256"
}
For all config options, please see:
- Configuration object for all config options
We have a predefined set of configurations to use with Mastercard services:
Call FieldLevelEncryption.encrypt()
with a JSON request payload, and optional header
object.
Example using the configuration above:
payload = JSON.generate({
path: {
to: {
foo: {
sensitiveField1: 'sensitiveValue1',
sensitiveField2: 'sensitiveValue2'
}
}
}
})
fle = McAPI::Encryption::FieldLevelEncryption.new(@config)
request_payload = fle.encrypt("/resource", header, payload)
Output:
{
"path": {
"to": {
"encryptedFoo": {
"iv": "7f1105fb0c684864a189fb3709ce3d28",
"encryptedKey": "67f467d1b653d98411a0c6d3c…ffd4c09dd42f713a51bff2b48f937c8",
"encryptedData": "b73aabd267517fc09ed72455c2…dffb5fa04bf6e6ce9ade1ff514ed6141",
"publicKeyFingerprint": "80810fc13a8319fcf0e2e…82cc3ce671176343cfe8160c2279",
"oaepHashingAlgorithm": "SHA256"
}
}
}
}
Call FieldLevelEncryption.decrypt()
with an (encrypted) response
object with the following fields:
body
: json payloadrequest.url
: requesting urlheader
: optional, header object
Example using the configuration above:
response = {}
response[:request] = { url: '/resource1' }
response[:body] =
{
path: {
to: {
encryptedFoo: {
iv: 'e5d313c056c411170bf07ac82ede78c9',
encryptedKey: 'e3a56746c0f9109d18b3a2652b76…f16d8afeff36b2479652f5c24ae7bd',
encryptedData: '809a09d78257af5379df0c454dcdf…353ed59fe72fd4a7735c69da4080e74f',
oaepHashingAlgorithm: 'SHA256',
publicKeyFingerprint: '80810fc13a8319fcf0e2e…3ce671176343cfe8160c2279'
}
}
}
}
fle = McAPI::Encryption::FieldLevelEncryption.new(@config)
response_payload = fle.decrypt(response)
Output:
{
"path": {
"to": {
"foo": {
"sensitiveField1": "sensitiveValue1",
"sensitiveField2": "sensitiveValue2"
}
}
}
}
OpenAPI Generator generates API client libraries from OpenAPI Specs. It provides generators and library templates for supporting multiple languages and frameworks.
The client-encryption-ruby library provides a method you can use to integrate the OpenAPI generated client with this library:
# JWE Encryption
McAPI::Encryption::OpenAPIInterceptor.install_jwe_encryption(open_api_client, config)
# Mastercard Encryption
McAPI::Encryption::OpenAPIInterceptor.install_field_level_encryption(open_api_client, config)
The above methods will handle the encryption in the generated OpenApi client, taking care of encrypting request and decrypting response payloads, but also of updating HTTP headers when needed, automatically, without manually calling encrypt()
/decrypt()
functions for each API request or response.
OpenAPI client can be generated, starting from your OpenAPI Spec / Swagger using the following command:
openapi-generator-cli generate -i openapi-spec.yaml -l ruby -o out
Client library will be generated in the out
folder.
See also:
To use it:
-
Generate the OpenAPI client, as above
-
Import the mastercard-client-encryption OpenAPI Interceptor and the generated OpenApi client
require 'mcapi/encryption/openapi_interceptor' require_relative './out/generated_open_apiclient' #import generated OpenAPI client
-
Install the Mastercard/JWE encryption in the generated client:
# Read the service configuration obj @config = File.read('./config.json') # Create a new instance of the generated client @api_client = client::ApiClient.new # Use 1 of the below 2 methods (depending on the encryption type) to enable encryption # Enable Mastercard encryption McAPI::Encryption::OpenAPIInterceptor.install_field_level_encryption(@api_client, @config) # Enable JWE encryption McAPI::Encryption::OpenAPIInterceptor.install_jwe_encryption(@api_client, @config)
-
Use the
api_client
object with the Field Level Encryption enabled:Example:
api_instance = OpenApiService::ServiceApi.new @api_client body = # … # response = api_instance.create_merchants(body) # requests and responses will be automatically encrypted and decrypted # accordingly with the configuration object used # … use the (decrypted) response object here …