Skip to content

Commit 4635d61

Browse files
authored
Merge pull request IonicDev#3 from IonicDev/DX-457-decrypt-envelope
Removed local decrypt_envelop(). Updated assert for HTTP error. Updat…
2 parents 26f5da4 + c02daf6 commit 4635d61

17 files changed

+118
-160
lines changed

LICENSE.md

Lines changed: 26 additions & 53 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,46 @@
22

33
## Explanation
44

5-
This example code shows how to use the advanced Device Request APIs available from the Ionic Platform.
5+
This example code shows how to use the advanced [Device Request APIs](https://dev.ionic.com/api/device) available from the Machina Platform.
66
It is meant to serve as sample code for developers learning about those APIs to use as reference.
77

8-
Most developers will instead prefer to use Ionic's supported SDKs, which include a Python SDK which has the same
9-
functionality shown in these examples, as well as significant additional features.
8+
Most developers will instead prefer to use [Ionic's supported SDK](https://dev.ionic.com/sdk/features), which include a Python SDK which has the same
9+
functionality shown in these examples, as well as significant additional features. There are SDK examples for [Create Key](https://dev.ionic.com/sdk/tasks/create-key?language=python) and [Get Key](https://dev.ionic.com/sdk/tasks/get-key?language=python).
1010

1111
## Setting up Environment
1212

13+
You will need to obtain a tenant. A free tenant can be obtained [here](https://ionic.com/start-for-free/). By following the prompted path, your
14+
device will be enrolled.
15+
16+
## Setting up Development Environment
17+
1318
You may want to use Python's virtualenv toolkit to manage your environment.
1419

1520
Once loaded, install the pre-requisites:
16-
```bash
21+
22+
```
1723
pip install -r requirements.txt
1824
```
1925

2026
## Running Examples
2127

2228
### Create and Fetch Keys:
2329

24-
The `example.py` tool shows how to create keys, and then request them again.
30+
The `example.py` sample shows how to create keys, and then request them again.
2531
These two operations are usually done independently.
2632

27-
Using this example requires a Secure Enrollment Profile (SEP), which it expects via the plaintext profile persistor in a file `profiles.pt`.
33+
Using this example requires a Secure Enrollment Profile (SEP), which it expects via the plaintext profile persistor in a file `$HOME/.ionicsecurity/profiles.pt`.
2834
Read [Enrollment Overview](https://dev.ionic.com/registration.html) to learn more.
29-
See the Enrollment Example for obtaining one if you don't have one via another mechanism.
35+
See **Enrolling** below if you didn't enroll via another mechanism.
36+
37+
This example shows how to use the [Create Key API](https://dev.ionic.com/api/device/create-key) and the [Get Key API](https://dev.ionic.com/api/device/get-key).
3038

31-
### Enrolling:
39+
### Enrolling
3240

3341
The `example_enroll.py` tool shows enrolling a device and obtaining a SEP, and then storing it using the plaintext profile persistor.
3442

3543
Using this example requires first editing the code to define the correct values for the variables.
36-
After setting those values, it can be run and will produce `profiles.pt` which is the SEP stored in plaintext.
44+
After setting those values, it can be run and will produce `$HOME/.ionicsecurity/profiles.pt` which is the SEP stored in plaintext.
3745

3846
There are two options for setting the values:
3947

__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# using builtin and 3rd-party libraries instead of the #
66
# Ionic SDK. #
77
# #
8-
# (c) 2017 Ionic Security Inc. #
8+
# (c) 2017-2020 Ionic Security Inc. #
99
# Confidential and Proprietary #
1010
# By using this code, I agree to the Terms & Conditions #
1111
# (https://www.ionic.com/terms-of-use/) and the Privacy #

example.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
# using built-in and 3rd-party libraries instead of the #
66
# Ionic SDK. #
77
# #
8-
# This example uses Python 3.4.3 #
8+
# This example uses Python 3.4.3 or higher. #
99
# This example is best read with syntax highlighting on. #
1010
# #
11-
# (c) 2017 Ionic Security Inc. #
11+
# (c) 2017-2020 Ionic Security Inc. #
1212
# Confidential and Proprietary #
1313
# By using this code, I agree to the Terms & Conditions #
1414
# (https://www.ionic.com/terms-of-use/) and the Privacy #
1515
# Policy (https://www.ionic.com/privacy-notice/) #
16-
# Author = rmspeers, QA = #
1716
###########################################################
1817

18+
import os
1919
from keys import create_keys, fetch_keys
2020
from persistors import ProfilePersistorPlaintext
2121

@@ -29,8 +29,12 @@
2929

3030

3131
if __name__ == "__main__":
32-
persistor = ProfilePersistorPlaintext('profiles.pt')
32+
persistor_path = os.path.expanduser("~/.ionicsecurity/profiles.pt")
33+
persistor = ProfilePersistorPlaintext(persistor_path)
3334
ionic_sep = persistor.get_active_profile()
35+
print("")
36+
print("Current Device ID: " + getattr(ionic_sep, "deviceId"))
37+
print("")
3438

3539
# Best practice is to include key attributes to describe the type of data you will be using this key to protect:
3640
## These can either be `ionic-protected-*` prefixed so Ionic.com can't see them, and only other requestors who
@@ -41,6 +45,7 @@
4145
}
4246
created_keys = create_keys(ionic_sep, dictKeyAttrs)
4347
print('Created keys: {}'.format(created_keys))
48+
print("")
4449

4550
# Now we show fetching one of these keys back:
4651
# NOTE: We may or may not be able to get it depending on the current data policy.

example_enroll.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
# using built-in and 3rd-party libraries instead of the #
66
# Ionic SDK. #
77
# #
8-
# This example uses Python 3.4.3 #
8+
# This example uses Python 3.4.3 or higher. #
99
# This example is best read with syntax highlighting on. #
1010
# #
11-
# (c) 2017 Ionic Security Inc. #
11+
# (c) 2017-2020 Ionic Security Inc. #
1212
# Confidential and Proprietary #
1313
# By using this code, I agree to the Terms & Conditions #
1414
# (https://www.ionic.com/terms-of-use/) and the Privacy #
1515
# Policy (https://www.ionic.com/privacy-notice/) #
16-
# Author = rmspeers, QA = jmassey #
1716
###########################################################
1817

1918
import sys
19+
import os
2020

2121
from registration import create_device
2222
from registration import get_ionic_token
@@ -42,8 +42,10 @@
4242
stoken = ""
4343
uidauth = ""
4444

45-
api_url = "https://dev-api.ionic.com"
46-
enrollment_server_url = "https://dev-enrollment.ionic.com"
45+
# These URLs are valid if you obtained your tenant using Start for Free, https://ionic.com/start-for-free/.
46+
# Modify the keyspace to the keyspace of your tenant.
47+
api_url = "https://api.ionic.com"
48+
enrollment_server_url = "https://enrollment.ionic.com"
4749
keyspace = "ABcd"
4850

4951

@@ -68,6 +70,7 @@
6870
# NOTE: This will overwrite any existing content at that path.
6971
persistor = ProfilePersistorPlaintext()
7072
persistor.add_sep(sep, set_as_active=True)
71-
persistor.set_file_path("profiles.pt")
73+
persistor_path = os.path.expanduser("~/.ionicsecurity/profiles.pt")
74+
persistor.set_file_path(persister_path)
7275
print(persistor)
7376
persistor.save_to_json()

example_external_ids.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
# using built-in and 3rd-party libraries instead of the #
66
# Ionic SDK. #
77
# #
8-
# This example uses Python 3.4.3 #
8+
# This example uses Python 3.4.3 or higher. #
99
# This example is best read with syntax highlighting on. #
1010
# #
11-
# (c) 2017 Ionic Security Inc. #
11+
# (c) 2017-2020 Ionic Security Inc. #
1212
# Confidential and Proprietary #
1313
# By using this code, I agree to the Terms & Conditions #
1414
# (https://www.ionic.com/terms-of-use/) and the Privacy #
1515
# Policy (https://www.ionic.com/privacy-notice/) #
16-
# Author = rmspeers, QA = #
1716
###########################################################
1817

1918
from uuid import uuid4

keys/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# using builtin and 3rd-party libraries instead of the #
66
# Ionic SDK. #
77
# #
8-
# (c) 2017 Ionic Security Inc. #
8+
# (c) 2017-2020 Ionic Security Inc. #
99
# Confidential and Proprietary #
1010
# By using this code, I agree to the Terms & Conditions #
1111
# (https://www.ionic.com/terms-of-use/) and the Privacy #

keys/key_create.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
# using built-in and 3rd-party libraries instead of the #
66
# Ionic SDK. #
77
# #
8-
# This example uses Python 3.4.3 #
8+
# This example uses Python 3.4.3 or higher. #
99
# This example is best read with syntax highlighting on. #
1010
# #
11-
# (c) 2017 Ionic Security Inc. #
11+
# (c) 2017-2020 Ionic Security Inc. #
1212
# Confidential and Proprietary #
1313
# By using this code, I agree to the Terms & Conditions #
1414
# (https://www.ionic.com/terms-of-use/) and the Privacy #
1515
# Policy (https://www.ionic.com/privacy-notice/) #
16-
# Author = daniel/rmspeers, QA = jmassey #
1716
###########################################################
1817

1918
import base64
@@ -303,12 +302,15 @@ def create_key_transaction(ionic_sep, dictKeyAttrs, dictMetadata, send_full_hfp=
303302
### Handling the Key Create Response ###
304303
########################################
305304
# Assume the response from Ionic is a successful 200, and we have created keys with the provided attributes.
306-
assert (key_create_response.status_code == 200) or (key_create_response.status_code == 401)
305+
status_code = key_create_response.status_code
306+
assert (status_code == 200) or (status_code == 201), "\nKey Create response status code: %d\n" % status_code
307307

308308
return key_create_response, cid, b64encoded_signed_attributes_iv_cipher_text_aad_as_string
309309

310310

311311
def create_keys(ionic_sep, dictKeyAttrs = {}, dictMetadata = {}):
312+
# See https://dev.ionic.com/api/device/create-key for more information on key create.
313+
312314
key_create_response, cid, b64encoded_signed_attributes_iv_cipher_text_aad_as_string = create_key_transaction(ionic_sep, dictKeyAttrs, dictMetadata)
313315
decrypted_envelope, response_cid = utilities.decrypt_envelope(ionic_sep, key_create_response, cid)
314316

keys/key_fetch.py

Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
# using built-in and 3rd-party libraries instead of the #
66
# Ionic SDK. #
77
# #
8-
# This example uses Python 3.4.3 #
8+
# This example uses Python 3.4.3 or higher. #
99
# This example is best read with syntax highlighting on. #
1010
# #
11-
# (c) 2017 Ionic Security Inc. #
11+
# (c) 2017-2020 Ionic Security Inc. #
1212
# Confidential and Proprietary #
1313
# By using this code, I agree to the Terms & Conditions #
1414
# (https://www.ionic.com/terms-of-use/) and the Privacy #
1515
# Policy (https://www.ionic.com/privacy-notice/) #
16-
# Author = daniel, QA = jmassey #
1716
###########################################################
1817

1918
import base64
@@ -131,57 +130,19 @@ def fetch_key_request(ionic_sep, protection_keys, external_id=None, send_full_hf
131130
headers={'Content-Type': 'application/json'})
132131

133132
# Assume the response from Ionic is a successful 200 and that we have received keys for the provided key tags.
134-
assert (key_fetch_response.status_code == 200) or (key_fetch_response.status_code == 401)
133+
status_code = key_fetch_response.status_code
134+
assert (status_code == 200) or (status_code == 201), "\nKey Fetch response status code: %d\n" % status_code
135135

136136
return key_fetch_response, cid
137137

138138

139-
def decrypt_envelope(ionic_sep, key_fetch_response, cid):
140-
#######################################
141-
### Handling the Key Fetch Response ###
142-
#######################################
143-
144-
key_fetch_response_body = key_fetch_response.json()
145-
146-
# As a precaution, ensure that the client's CID is the same as the response's CID.
147-
response_cid = key_fetch_response_body['cid']
148-
assert cid == response_cid
149-
150-
# Base 64 decode the envelope's value.
151-
decoded_key_fetch_response_envelope_as_bytes = base64.b64decode(key_fetch_response_body['envelope'])
152-
153-
# Prepare to decrypt the `envelope` contents.
154-
155-
# Obtain the initialization vector which is the first 16 bytes.
156-
initialization_vector_from_response_envelope = decoded_key_fetch_response_envelope_as_bytes[:16]
157-
158-
# Obtain the data to decrypt which is the bytes between the initializaiton vector and the tag.
159-
cipher_text_from_response_envelope = decoded_key_fetch_response_envelope_as_bytes[16:-16]
160-
161-
# Obtain the tag which is the last 16 bytes.
162-
gcm_tag_from_response_envelope = decoded_key_fetch_response_envelope_as_bytes[-16:]
163-
164-
# Construct a cipher to decrypt the data.
165-
cipher = Cipher(algorithms.AES(ionic_sep.aesCdIdcKey),
166-
modes.GCM(initialization_vector_from_response_envelope,
167-
gcm_tag_from_response_envelope),
168-
backend=default_backend()
169-
).decryptor()
170-
171-
# Set the cipher's `aad` as the value of the `cid`.
172-
cipher.authenticate_additional_data(response_cid.encode(encoding='utf-8'))
173-
174-
# Decrypt the ciphertext.
175-
decrypted_key_response_bytes = cipher.update(cipher_text_from_response_envelope) + cipher.finalize()
176-
decrypted_envelope = json.loads(decrypted_key_response_bytes.decode(encoding='utf-8'))
177-
178-
return decrypted_envelope
179-
180-
181139
def fetch_keys(ionic_sep, protection_keys, external_ids=None):
182140
##########################################
183141
### Constructing the Key Fetch Request ###
184142
##########################################
143+
144+
# See https://dev.ionic.com/api/device/get-key for more information on key fetch.
145+
185146
example_key_fetch_body = """
186147
{
187148
"cid": "CID|MfyG..A.ec095b70-c1d0-4ac0-9d0f-2cafa82b8a1f|1487622171374|1487622171374|5bFnTQ==",
@@ -216,7 +177,7 @@ def fetch_keys(ionic_sep, protection_keys, external_ids=None):
216177
"the full HFP included.")
217178

218179
key_fetch_response, cid = fetch_key_request(ionic_sep, protection_keys, send_full_hfp=True)
219-
decrypted_envelope = decrypt_envelope(ionic_sep, key_fetch_response, cid)
180+
decrypted_envelope, _ = utilities.decrypt_envelope(ionic_sep, key_fetch_response, cid)
220181

221182
# Pull out any query results as well to return:
222183
query_results = decrypted_envelope['data'].get('query-results')

keys/utilities.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
# using built-in and 3rd-party libraries instead of the #
66
# Ionic SDK. #
77
# #
8-
# This example uses Python 3.4.3 #
8+
# This example uses Python 3.4.3 or higher. #
99
# This example is best read with syntax highlighting on. #
1010
# #
11-
# (c) 2017 Ionic Security Inc. #
11+
# (c) 2017-2020 Ionic Security Inc. #
1212
# Confidential and Proprietary #
1313
# By using this code, I agree to the Terms & Conditions #
1414
# (https://www.ionic.com/terms-of-use/) and the Privacy #
@@ -41,15 +41,23 @@ def make_cid(device_id):
4141

4242

4343
def decrypt_envelope(ionic_sep, server_response, cid):
44-
response_body = server_response.json()
44+
#######################################
45+
### Handling the Key Fetch Response ###
46+
#######################################
47+
48+
# See https://dev.ionic.com/api/device/get-key for more information on key fetch.
49+
50+
key_fetch_response_body = server_response.json()
4551

4652
# As a precaution, ensure that the client's CID is the same as the response's CID.
47-
response_cid = response_body['cid']
53+
response_cid = key_fetch_response_body['cid']
4854
if cid != response_cid:
4955
raise ValueError("The CID in the response did not match the one from the request.")
5056

5157
# Base 64 decode the envelope's value.
52-
decoded_response_envelope_as_bytes = base64.b64decode(response_body['envelope'])
58+
decoded_response_envelope_as_bytes = base64.b64decode(key_fetch_response_body['envelope'])
59+
# Prepare to decrypt the `envelope` contents.
60+
5361
# Prepare to decrypt the `envelope` contents.
5462

5563
# Obtain the initialization vector which is the first 16 bytes.
@@ -64,15 +72,15 @@ def decrypt_envelope(ionic_sep, server_response, cid):
6472
# Construct a cipher to decrypt the data.
6573
cipher = Cipher(algorithms.AES(ionic_sep.aesCdIdcKey),
6674
modes.GCM(initialization_vector_from_response_envelope,
67-
gcm_tag_from_response_envelope),
75+
gcm_tag_from_response_envelope),
6876
backend=default_backend()
6977
).decryptor()
7078

7179
# Set the cipher's `aad` as the value of the `cid`
7280
cipher.authenticate_additional_data(response_cid.encode(encoding='utf-8'))
73-
decrypted_key_response_bytes = cipher.update(cipher_text_from_response_envelope) + cipher.finalize()
7481

7582
# Decrypt the ciphertext.
83+
decrypted_key_response_bytes = cipher.update(cipher_text_from_response_envelope) + cipher.finalize()
7684
decrypted_envelope = json.loads(decrypted_key_response_bytes.decode(encoding='utf-8'))
7785

7886
return decrypted_envelope, response_cid

persistors/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# using builtin and 3rd-party libraries instead of the #
66
# Ionic SDK. #
77
# #
8-
# (c) 2017 Ionic Security Inc. #
8+
# (c) 2017-2020 Ionic Security Inc. #
99
# Confidential and Proprietary #
1010
# By using this code, I agree to the Terms & Conditions #
1111
# (https://www.ionic.com/terms-of-use/) and the Privacy #

persistors/profile.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
# using built-in and 3rd-party libraries instead of the #
66
# Ionic SDK. #
77
# #
8-
# This example uses Python 3.4.3 #
8+
# This example uses Python 3.4.3 or higher. #
99
# This example is best read with syntax highlighting on. #
1010
# #
11-
# (c) 2017 Ionic Security Inc. #
11+
# (c) 2017-2020 Ionic Security Inc. #
1212
# Confidential and Proprietary #
1313
# By using this code, I agree to the Terms & Conditions #
1414
# (https://www.ionic.com/terms-of-use/) and the Privacy #
1515
# Policy (https://www.ionic.com/privacy-notice/) #
16-
# Author = rmspeers, QA = #
1716
###########################################################
1817

1918
import binascii

0 commit comments

Comments
 (0)