|
| 1 | +# client-encryption-python |
| 2 | + |
| 3 | +[](https://api.travis-ci.org/Mastercard/client-encryption-python) |
| 4 | +[](https://sonarcloud.io/dashboard?id=Mastercard_client-encryption-python) |
| 5 | +[](https://sonarcloud.io/dashboard?id=Mastercard_client-encryption-python) |
| 6 | +[](https://sonarcloud.io/dashboard?id=Mastercard_client-encryption-python) |
| 7 | +[](https://pypi.org/project/mastercard-client-encryption) |
| 8 | +[](https://github.com/Mastercard/client-encryption-python/blob/master/LICENSE) |
| 9 | + |
| 10 | +## Table of Contents |
| 11 | +- [Overview](#overview) |
| 12 | + * [Compatibility](#compatibility) |
| 13 | + * [References](#references) |
| 14 | +- [Usage](#usage) |
| 15 | + * [Prerequisites](#prerequisites) |
| 16 | + * [Adding the Library to Your Project](#adding-the-library-to-your-project) |
| 17 | + * [Performing Field Level Encryption and Decryption](#performing-field-level-encryption-and-decryption) |
| 18 | + * [Integrating with OpenAPI Generator API Client Libraries](#integrating-with-openapi-generator-api-client-libraries) |
| 19 | + |
| 20 | + |
| 21 | +## Overview <a name="overview"></a> |
| 22 | +This is the Python version of the Mastercard compliant payload encryption/decryption. |
| 23 | + |
| 24 | +### Compatibility <a name="compatibility"></a> |
| 25 | +Python 3.6, 3.7 |
| 26 | + |
| 27 | +### References <a name="references"></a> |
| 28 | + |
| 29 | +<img src="https://user-images.githubusercontent.com/3964455/55345820-c520a280-54a8-11e9-8235-407199fa1d97.png" alt="Encryption of sensitive data" width="75%" height="75%"/> |
| 30 | + |
| 31 | +## Usage <a name="usage"></a> |
| 32 | + |
| 33 | +### Prerequisites <a name="prerequisites"></a> |
| 34 | + |
| 35 | +Before using this library, you will need to set up a project in the [Mastercard Developers Portal](https://developer.mastercard.com). |
| 36 | + |
| 37 | +As part of this set up, you'll receive: |
| 38 | + |
| 39 | +- A public request encryption certificate (aka _Client Encryption Keys_) |
| 40 | +- A private response decryption key (aka _Mastercard Encryption Keys_) |
| 41 | + |
| 42 | +### Installation <a name="adding-the-libraries-to-your-project"></a> |
| 43 | + |
| 44 | +If you want to use **mastercard-client-encryption** with [Python](https://www.python.org/), it is available through `pypy`: |
| 45 | + |
| 46 | +- [https://pypi.org/project/mastercard-client-encryption](https://pypi.org/project/mastercard-client-encryption) |
| 47 | + |
| 48 | +**Adding the library to your project** |
| 49 | + |
| 50 | +Install the library by pip: |
| 51 | + |
| 52 | +```bash |
| 53 | +$ pip install mastercard-client-encryption |
| 54 | +``` |
| 55 | + |
| 56 | +Or clone it from git: |
| 57 | + |
| 58 | +```bash |
| 59 | +$ git clone https://github.com/Mastercard/client-encryption-python.git |
| 60 | +``` |
| 61 | + |
| 62 | +and then execute from the repo folder: |
| 63 | + |
| 64 | +```bash |
| 65 | +$ python3 setup.py install |
| 66 | +``` |
| 67 | + |
| 68 | +You can then use it as a regular module: |
| 69 | + |
| 70 | +```python |
| 71 | +from client_encryption.field_level_encryption_config import FieldLevelEncryptionConfig |
| 72 | +from client_encryption.field_level_encryption import encrypt_payload, decrypt_payload |
| 73 | +``` |
| 74 | + |
| 75 | +### Performing Field Level Encryption and Decryption <a name="performing-field-level-encryption-and-decryption"></a> |
| 76 | + |
| 77 | +- [Introduction](#introduction) |
| 78 | +- [Configuring the Field Level Encryption](#configuring-the-field-level-encryption) |
| 79 | +- [Performing Encryption](#performing-encryption) |
| 80 | +- [Performing Decryption](#performing-decryption) |
| 81 | + |
| 82 | +#### Introduction <a name="introduction"></a> |
| 83 | + |
| 84 | +The core methods responsible for payload encryption and decryption are `encrypt_payload` and `decrypt_payload` in the `field_level_encryption` module. |
| 85 | + |
| 86 | +- `encrypt_payload()` usage: |
| 87 | + |
| 88 | +```python |
| 89 | +config = FieldLevelEncryptionConfig(config_dictionary) |
| 90 | +encrypted_request_payload = encrypt_payload(body, config) |
| 91 | +``` |
| 92 | + |
| 93 | +- `decrypt_payload()` usage: |
| 94 | + |
| 95 | +```python |
| 96 | +config = FieldLevelEncryptionConfig(config_dictionary) |
| 97 | +decrypted_response_payload = decrypt_payload(body, config) |
| 98 | +``` |
| 99 | + |
| 100 | +#### Configuring the Field Level Encryption <a name="configuring-the-field-level-encryption"></a> |
| 101 | + |
| 102 | +`field_level_encryption` needs a config dictionary to instruct how to decrypt/decrypt the payloads. Example: |
| 103 | + |
| 104 | +```json |
| 105 | +{ |
| 106 | + "paths": { |
| 107 | + "$": { |
| 108 | + "toEncrypt": { |
| 109 | + "element": "path.to.foo", |
| 110 | + "obj": "path.to.encryptedFoo" |
| 111 | + }, |
| 112 | + "toDecrypt": { |
| 113 | + "element": "path.to.encryptedFoo", |
| 114 | + "obj": "path.to.foo" |
| 115 | + } |
| 116 | + } |
| 117 | + }, |
| 118 | + "ivFieldName": "iv", |
| 119 | + "encryptedKeyFieldName": "encryptedKey", |
| 120 | + "encryptedValueFieldName": "encryptedData", |
| 121 | + "dataEncoding": "hex", |
| 122 | + "encryptionCertificate": "./path/to/public.cert", |
| 123 | + "decryptionKey": "./path/to/your/private.key", |
| 124 | + "oaepPaddingDigestAlgorithm": "SHA256" |
| 125 | +} |
| 126 | +``` |
| 127 | + |
| 128 | +The above can be either stored to a file or passed to 'FieldLevelEncryptionConfig' as dictionary: |
| 129 | +```python |
| 130 | +config_dictionary = {"paths": {...}, |
| 131 | + (...) |
| 132 | + "decryptionKey": "./path/to/your/private.key", |
| 133 | + "oaepPaddingDigestAlgorithm": "SHA256" |
| 134 | + } |
| 135 | +config = FieldLevelEncryptionConfig(config_dictionary) |
| 136 | + |
| 137 | +config_file_path = "./config.json" |
| 138 | +config = FieldLevelEncryptionConfig(config_file_path) |
| 139 | +``` |
| 140 | + |
| 141 | +For all config options, please see: |
| 142 | + |
| 143 | +- [Configuration object](https://github.com/Mastercard/client-encryption-python/wiki/Configuration-Object) for all config options |
| 144 | + |
| 145 | +We have a predefined set of configurations to use with Mastercard services: |
| 146 | + |
| 147 | +- [Service configurations](https://github.com/Mastercard/client-encryption-python/wiki/Mastercard-Services-Configuration) wiki page |
| 148 | + |
| 149 | + |
| 150 | + |
| 151 | +#### Performing Encryption <a name="performing-encryption"></a> |
| 152 | + |
| 153 | +Call `field_level_encryption.encrypt_payload()` with a JSON (dict) request payload, and optional `params` object. |
| 154 | + |
| 155 | +Example using the configuration [above](#configuring-the-field-level-encryption): |
| 156 | + |
| 157 | +```python |
| 158 | +from client_encryption.session_key_params import SessionKeyParams |
| 159 | + |
| 160 | +payload = { |
| 161 | + path: { |
| 162 | + to: { |
| 163 | + foo: { |
| 164 | + sensitiveField1: 'sensitiveValue1', |
| 165 | + sensitiveField2: 'sensitiveValue2' |
| 166 | + } |
| 167 | + } |
| 168 | + } |
| 169 | +} |
| 170 | + |
| 171 | +params = SessionKeyParams.generate(conf) # optional |
| 172 | +request_payload = encrypt_payload(payload, config, params) |
| 173 | +``` |
| 174 | + |
| 175 | +Output: |
| 176 | + |
| 177 | +```json |
| 178 | +{ |
| 179 | + "path": { |
| 180 | + "to": { |
| 181 | + "encryptedFoo": { |
| 182 | + "iv": "7f1105fb0c684864a189fb3709ce3d28", |
| 183 | + "encryptedKey": "67f467d1b653d98411a0c6d3c(...)ffd4c09dd42f713a51bff2b48f937c8", |
| 184 | + "encryptedData": "b73aabd267517fc09ed72455c2(...)dffb5fa04bf6e6ce9ade1ff514ed6141", |
| 185 | + "publicKeyFingerprint": "80810fc13a8319fcf0e2e(...)82cc3ce671176343cfe8160c2279", |
| 186 | + "oaepHashingAlgorithm": "SHA256" |
| 187 | + } |
| 188 | + } |
| 189 | + } |
| 190 | +} |
| 191 | +``` |
| 192 | + |
| 193 | +#### Performing Decryption <a name="performing-decryption"></a> |
| 194 | + |
| 195 | +Call `field_level_encryption.decrypt_payload()` with a JSON (dict) encrypted response payload. |
| 196 | + |
| 197 | +Example using the configuration [above](#configuring-the-field-level-encryption): |
| 198 | + |
| 199 | +```python |
| 200 | +response = { |
| 201 | + path: { |
| 202 | + to: { |
| 203 | + encryptedFoo: { |
| 204 | + iv: 'e5d313c056c411170bf07ac82ede78c9', |
| 205 | + encryptedKey: 'e3a56746c0f9109d18b3a2652b76(...)f16d8afeff36b2479652f5c24ae7bd', |
| 206 | + encryptedData: '809a09d78257af5379df0c454dcdf(...)353ed59fe72fd4a7735c69da4080e74f', |
| 207 | + oaepHashingAlgorithm: 'SHA256', |
| 208 | + publicKeyFingerprint: '80810fc13a8319fcf0e2e(...)3ce671176343cfe8160c2279' |
| 209 | + } |
| 210 | + } |
| 211 | + } |
| 212 | +} |
| 213 | + |
| 214 | +response_payload = decrypt_payload(response, config) |
| 215 | + |
| 216 | +``` |
| 217 | + |
| 218 | +Output: |
| 219 | + |
| 220 | +```json |
| 221 | +{ |
| 222 | + "path": { |
| 223 | + "to": { |
| 224 | + "foo": { |
| 225 | + "sensitiveField1": "sensitiveValue1", |
| 226 | + "sensitiveField2": "sensitiveValue2" |
| 227 | + } |
| 228 | + } |
| 229 | + } |
| 230 | +} |
| 231 | +``` |
| 232 | + |
| 233 | +### Integrating with OpenAPI Generator API Client Libraries <a name="integrating-with-openapi-generator-api-client-libraries"></a> |
| 234 | + |
| 235 | +[OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator) generates API client libraries from [OpenAPI Specs](https://github.com/OAI/OpenAPI-Specification). |
| 236 | +It provides generators and library templates for supporting multiple languages and frameworks. |
| 237 | + |
| 238 | +The **client-encryption-python** library provides a method you can use to integrate the OpenAPI generated client with this library: |
| 239 | +```python |
| 240 | +from client_encryption.field_level_encryption_config import FieldLevelEncryptionConfig |
| 241 | +from client_encryption.api_encryption import add_encryption_layer |
| 242 | + |
| 243 | +api_encryption.add_encryption_layer(api_client, config) |
| 244 | +``` |
| 245 | +This method will add the field level 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_payload()`/`decrypt_payload()` functions for each API request or response. |
| 246 | + |
| 247 | +##### OpenAPI Generator <a name="openapi-generator"></a> |
| 248 | + |
| 249 | +OpenAPI client can be generated, starting from your OpenAPI Spec / Swagger using the following command: |
| 250 | + |
| 251 | +```shell |
| 252 | +java -jar openapi-generator-cli.jar generate -i openapi-spec.yaml -l python -o out |
| 253 | +``` |
| 254 | + |
| 255 | +Client library will be generated in the `out` folder. |
| 256 | + |
| 257 | +See also: |
| 258 | + |
| 259 | +- [OpenAPI Generator (executable)](https://mvnrepository.com/artifact/org.openapitools/openapi-generator-cli) |
| 260 | + |
| 261 | +##### Usage of the `api_encryption.add_encryption_layer`: |
| 262 | + |
| 263 | +To use it: |
| 264 | + |
| 265 | +1. Generate the OpenAPI client, as [above](#openapi-generator) |
| 266 | + |
| 267 | +2. Import the **mastercard-client-encryption** module and the generated swagger ApiClient |
| 268 | + |
| 269 | + ```python |
| 270 | + from client_encryption.field_level_encryption_config import FieldLevelEncryptionConfig |
| 271 | + from client_encryption.api_encryption import add_encryption_layer |
| 272 | + from swagger_client.api_client import ApiClient # import generated swagger ApiClient |
| 273 | + ``` |
| 274 | + |
| 275 | +3. Add the field level encryption layer to the generated client: |
| 276 | + |
| 277 | + ```python |
| 278 | + # Read the service configuration file |
| 279 | + config_file_path = "./config.json" |
| 280 | + config = FieldLevelEncryptionConfig(config_file_path) |
| 281 | + # Create a new instance of the generated client |
| 282 | + api_client = ApiClient() |
| 283 | + # Enable field level encryption |
| 284 | + api_encryption.add_encryption_layer(api_client, config) |
| 285 | + ``` |
| 286 | + |
| 287 | +4. Use the `ApiClient` instance with the Field Level Encryption enabled: |
| 288 | + |
| 289 | + Example: |
| 290 | + |
| 291 | + ```python |
| 292 | + request_body = {...} |
| 293 | + response =MyServiceApi(api_client).do_some_action_post(body=request_body) |
| 294 | + # requests and responses will be automatically encrypted and decrypted |
| 295 | + # accordingly with the configuration object used |
| 296 | + |
| 297 | + # ... use the (decrypted) response object here ... |
| 298 | + decrypted = response.json() |
| 299 | + |
| 300 | + ``` |
0 commit comments