Skip to content

Commit 2e20daf

Browse files
- Adding JWE support
1 parent d65a71c commit 2e20daf

16 files changed

+755
-73
lines changed

README.md

Lines changed: 175 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
- [Usage](#usage)
1717
* [Prerequisites](#prerequisites)
1818
* [Adding the Library to Your Project](#adding-the-library-to-your-project)
19-
* [Performing Field Level Encryption and Decryption](#performing-field-level-encryption-and-decryption)
19+
* [Performing Payload Encryption and Decryption](#performing-payload-encryption-and-decryption)
20+
* [JWE Encryption and Decryption](#jwe-encryption-and-decryption)
21+
* [Mastercard Encryption and Decryption](#mastercard-encryption-and-decryption)
2022
* [Integrating with OpenAPI Generator API Client Libraries](#integrating-with-openapi-generator-api-client-libraries)
2123

2224

@@ -27,28 +29,22 @@ This is the Python version of the Mastercard compliant payload encryption/decryp
2729
Python 3.6+
2830

2931
### References <a name="references"></a>
30-
31-
<img src="https://user-images.githubusercontent.com/3964455/55345820-c520a280-54a8-11e9-8235-407199fa1d97.png" alt="Encryption of sensitive data" width="75%" height="75%"/>
32+
* [JSON Web Encryption (JWE)](https://datatracker.ietf.org/doc/html/rfc7516)
33+
* [Securing Sensitive Data Using Payload Encryption](https://developer.mastercard.com/platform/documentation/security-and-authentication/securing-sensitive-data-using-payload-encryption/)
3234

3335
## Usage <a name="usage"></a>
34-
3536
### Prerequisites <a name="prerequisites"></a>
36-
3737
Before using this library, you will need to set up a project in the [Mastercard Developers Portal](https://developer.mastercard.com).
3838

3939
As part of this set up, you'll receive:
40-
4140
- A public request encryption certificate (aka _Client Encryption Keys_)
4241
- A private response decryption key (aka _Mastercard Encryption Keys_)
4342

4443
### Installation <a name="adding-the-libraries-to-your-project"></a>
45-
4644
If you want to use **mastercard-client-encryption** with [Python](https://www.python.org/), it is available through `PyPI`:
47-
4845
- [https://pypi.org/project/mastercard-client-encryption](https://pypi.org/project/mastercard-client-encryption)
4946

5047
**Adding the library to your project**
51-
5248
Install the library by pip:
5349

5450
```bash
@@ -70,16 +66,169 @@ $ python3 setup.py install
7066
You can then use it as a regular module:
7167

7268
```python
69+
# Mastercard Encryption/Decryption
7370
from client_encryption.field_level_encryption_config import FieldLevelEncryptionConfig
7471
from client_encryption.field_level_encryption import encrypt_payload, decrypt_payload
7572
```
7673

77-
### Performing Field Level Encryption and Decryption <a name="performing-field-level-encryption-and-decryption"></a>
74+
```python
75+
# JWE Encryption/Decryption
76+
from client_encryption.field_level_encryption_config import FieldLevelEncryptionConfig
77+
from client_encryption.field_level_encryption import encrypt_payload, decrypt_payload
78+
```
7879

79-
- [Introduction](#introduction)
80-
- [Configuring the Field Level Encryption](#configuring-the-field-level-encryption)
81-
- [Performing Encryption](#performing-encryption)
82-
- [Performing Decryption](#performing-decryption)
80+
### Performing Payload Encryption and Decryption <a name="performing-payload-encryption-and-decryption"></a>
81+
82+
+ [Introduction](#introduction)
83+
+ [JWE Encryption and Decryption](#jwe-encryption-and-decryption)
84+
+ [Mastercard Encryption and Decryption](#mastercard-encryption-and-decryption)
85+
86+
#### Introduction <a name="introduction"></a>
87+
88+
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.
89+
90+
#### JWE Encryption and Decryption <a name="jwe-encryption-and-decryption"></a>
91+
92+
+ [Introduction](#jwe-introduction)
93+
+ [Configuring the JWE Encryption](#configuring-the-jwe-encryption)
94+
+ [Performing JWE Encryption](#performing-jwe-encryption)
95+
+ [Performing JWE Decryption](#performing-jwe-decryption)
96+
97+
#### Introduction <a name="jwe-introduction"></a>
98+
99+
This library uses [JWE compact serialization](https://datatracker.ietf.org/doc/html/rfc7516#section-7.1) for the encryption of sensitive data.
100+
The core methods responsible for payload encryption and decryption are `encrypt_payload` and `decrypt_payload` in the `jwe_encryption` module.
101+
102+
- `encrypt_payload()` usage:
103+
104+
```python
105+
config = JweEncryptionConfig(config_dictionary)
106+
encrypted_request_payload = encrypt_payload(body, config)
107+
```
108+
109+
- `decrypt_payload()` usage:
110+
111+
```python
112+
config = JweEncryptionConfig(config_dictionary)
113+
decrypted_response_payload = decrypt_payload(body, config)
114+
```
115+
116+
#### Configuring the JWE Encryption <a name="configuring-the-jwe-encryption"></a>
117+
118+
`jwe_encryption` needs a config dictionary to instruct how to decrypt/decrypt the payloads. Example:
119+
120+
```json
121+
{
122+
"paths": {
123+
"$": {
124+
"toEncrypt": {
125+
"path.to.foo": "path.to.encryptedFoo"
126+
},
127+
"toDecrypt": {
128+
"path.to.encryptedFoo": "path.to.foo"
129+
}
130+
}
131+
},
132+
"encryptedValueFieldName": "encryptedData",
133+
"encryptionCertificate": "./path/to/public.cert",
134+
"decryptionKey": "./path/to/your/private.key",
135+
}
136+
```
137+
138+
The above can be either stored to a file or passed to 'JweEncryptionConfig' as dictionary:
139+
```python
140+
config_dictionary = {
141+
"paths": {…},
142+
143+
"decryptionKey": "./path/to/your/private.key"
144+
}
145+
146+
config = JweEncryptionConfig(config_dictionary)
147+
148+
config_file_path = "./config.json"
149+
config = JweEncryptionConfig(config_file_path)
150+
```
151+
152+
#### Performing JWE Encryption <a name="performing-jwe-encryption"></a>
153+
154+
Call `jwe_encryption.encrypt_payload()` with a JSON (dict) request payload, and optional `params` object.
155+
156+
Example using the configuration [above](#configuring-the-jwe-encryption):
157+
158+
```python
159+
from client_encryption.session_key_params import SessionKeyParams
160+
161+
payload = {
162+
"path": {
163+
"to": {
164+
"foo": {
165+
"sensitiveField1": "sensitiveValue1",
166+
"sensitiveField2": "sensitiveValue2"
167+
}
168+
}
169+
}
170+
}
171+
172+
params = SessionKeyParams.generate(conf) # optional
173+
request_payload = encrypt_payload(payload, config, params)
174+
```
175+
176+
Output:
177+
178+
```json
179+
{
180+
"path": {
181+
"to": {
182+
"encryptedFoo": {
183+
"encryptedValue": "eyJraWQiOiI3NjFiMDAzYzFlYWRlM(...)==.Y+oPYKZEMTKyYcSIVEgtQw=="
184+
}
185+
}
186+
}
187+
}
188+
```
189+
190+
#### Performing JWE Decryption <a name="performing-jwe-decryption"></a>
191+
192+
Call `jwe_encryption.decrypt_payload()` with a JSON (dict) encrypted response payload.
193+
194+
Example using the configuration [above](#configuring-the-jwe-encryption):
195+
196+
```python
197+
response = {
198+
"path": {
199+
"to": {
200+
"encryptedFoo": {
201+
"encryptedValue": "eyJraWQiOiI3NjFiMDAzYzFlYWRlM(...)==.Y+oPYKZEMTKyYcSIVEgtQw=="
202+
}
203+
}
204+
}
205+
}
206+
207+
response_payload = decrypt_payload(response, config)
208+
209+
```
210+
211+
Output:
212+
213+
```json
214+
{
215+
"path": {
216+
"to": {
217+
"foo": {
218+
"sensitiveField1": "sensitiveValue1",
219+
"sensitiveField2": "sensitiveValue2"
220+
}
221+
}
222+
}
223+
}
224+
```
225+
226+
#### Mastercard Encryption and Decryption <a name="mastercard-encryption-and-decryption"></a>
227+
228+
+ [Introduction](#mastercard-introduction)
229+
+ [Configuring the Mastercard Encryption](#configuring-the-mastercard-encryption)
230+
+ [Performing Mastercard Encryption](#performing-mastercard-encryption)
231+
+ [Performing Mastercard Decryption](#performing-mastercard-decryption)
83232

84233
#### Introduction <a name="introduction"></a>
85234

@@ -99,7 +248,7 @@ config = FieldLevelEncryptionConfig(config_dictionary)
99248
decrypted_response_payload = decrypt_payload(body, config)
100249
```
101250

102-
#### Configuring the Field Level Encryption <a name="configuring-the-field-level-encryption"></a>
251+
#### Configuring the Mastercard Encryption <a name="configuring-the-mastercard-encryption"></a>
103252

104253
`field_level_encryption` needs a config dictionary to instruct how to decrypt/decrypt the payloads. Example:
105254

@@ -150,7 +299,7 @@ We have a predefined set of configurations to use with Mastercard services:
150299

151300

152301

153-
#### Performing Encryption <a name="performing-encryption"></a>
302+
#### Performing Mastercard Encryption <a name="performing-mastercard-encryption"></a>
154303

155304
Call `field_level_encryption.encrypt_payload()` with a JSON (dict) request payload, and optional `params` object.
156305

@@ -192,7 +341,7 @@ Output:
192341
}
193342
```
194343

195-
#### Performing Decryption <a name="performing-decryption"></a>
344+
#### Performing Mastercard Decryption <a name="performing-mastercard-decryption"></a>
196345

197346
Call `field_level_encryption.decrypt_payload()` with a JSON (dict) encrypted response payload.
198347

@@ -247,10 +396,9 @@ config = {
247396
248397
}
249398
},
250-
"ivFieldName": "iv",
251-
"encryptedKeyFieldName": "encryptedKey",
399+
"encryptionCertificate": "path/to/cert.pem",
252400
253-
"oaepPaddingDigestAlgorithm": "SHA256"
401+
"decryptionKey": "path/to/to/key.pem"
254402
}
255403

256404
add_encryption_layer(api_client, config)
@@ -263,7 +411,7 @@ from client_encryption.api_encryption import add_encryption_layer
263411
add_encryption_layer(api_client, "path/to/my/config.json")
264412
```
265413

266-
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.
414+
This method will add the Mastercard/JWE 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.
267415

268416
##### OpenAPI Generator <a name="openapi-generator"></a>
269417

@@ -273,7 +421,7 @@ OpenAPI client can be generated, starting from your OpenAPI Spec using the follo
273421
openapi-generator-cli generate -i openapi-spec.yaml -l python -o out
274422
```
275423

276-
Client library will be generated in the `out` folder.
424+
The client library will be generated in the `out` folder.
277425

278426
See also:
279427

@@ -292,16 +440,16 @@ To use it:
292440
from openapi_client.api_client import ApiClient # import generated OpenAPI client
293441
```
294442

295-
3. Add the field level encryption layer to the generated client:
443+
3. Add the encryption layer to the generated client:
296444

297445
```python
298446
# Create a new instance of the generated client
299447
api_client = ApiClient()
300-
# Enable field level encryption
448+
# Enable encryption
301449
add_encryption_layer(api_client, "path/to/my/config.json")
302450
```
303451

304-
4. Use the `ApiClient` instance with the Field Level Encryption enabled:
452+
4. Use the `ApiClient` instance with Encryption enabled:
305453

306454
Example:
307455

@@ -340,14 +488,13 @@ According to the above the signing layer must be applied first in order to work
340488
add_signing_layer(api_client, key_file, key_password, consumer_key)
341489
```
342490
343-
4. Then add the field level encryption layer:
491+
4. Then add the encryption layer:
344492
```python
345493
add_encryption_layer(api_client, "path/to/my/config.json")
346494
```
347495

348-
5. Use the `ApiClient` instance with Authentication and Field Level Encryption both enabled:
496+
5. Use the `ApiClient` instance with Authentication and Encryption both enabled:
349497
```python
350498
response = MyServiceApi(api_client).do_some_action_post(body=request_body)
351499
decrypted = response.json()
352-
353500
```

0 commit comments

Comments
 (0)