Skip to content

Removed local decrypt_envelop(). Updated assert for HTTP error. Updat… #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 26 additions & 53 deletions LICENSE.md

Large diffs are not rendered by default.

26 changes: 17 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,46 @@

## Explanation

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

Most developers will instead prefer to use Ionic's supported SDKs, which include a Python SDK which has the same
functionality shown in these examples, as well as significant additional features.
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
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).

## Setting up Environment

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
device will be enrolled.

## Setting up Development Environment

You may want to use Python's virtualenv toolkit to manage your environment.

Once loaded, install the pre-requisites:
```bash

```
pip install -r requirements.txt
```

## Running Examples

### Create and Fetch Keys:

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

Using this example requires a Secure Enrollment Profile (SEP), which it expects via the plaintext profile persistor in a file `profiles.pt`.
Using this example requires a Secure Enrollment Profile (SEP), which it expects via the plaintext profile persistor in a file `$HOME/.ionicsecurity/profiles.pt`.
Read [Enrollment Overview](https://dev.ionic.com/registration.html) to learn more.
See the Enrollment Example for obtaining one if you don't have one via another mechanism.
See **Enrolling** below if you didn't enroll via another mechanism.

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).

### Enrolling:
### Enrolling

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

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

There are two options for setting the values:

Expand Down
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# using builtin and 3rd-party libraries instead of the #
# Ionic SDK. #
# #
# (c) 2017 Ionic Security Inc. #
# (c) 2017-2020 Ionic Security Inc. #
# Confidential and Proprietary #
# By using this code, I agree to the Terms & Conditions #
# (https://www.ionic.com/terms-of-use/) and the Privacy #
Expand Down
13 changes: 9 additions & 4 deletions example.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
# using built-in and 3rd-party libraries instead of the #
# Ionic SDK. #
# #
# This example uses Python 3.4.3 #
# This example uses Python 3.4.3 or higher. #
# This example is best read with syntax highlighting on. #
# #
# (c) 2017 Ionic Security Inc. #
# (c) 2017-2020 Ionic Security Inc. #
# Confidential and Proprietary #
# By using this code, I agree to the Terms & Conditions #
# (https://www.ionic.com/terms-of-use/) and the Privacy #
# Policy (https://www.ionic.com/privacy-notice/) #
# Author = rmspeers, QA = #
###########################################################

import os
from keys import create_keys, fetch_keys
from persistors import ProfilePersistorPlaintext

Expand All @@ -29,8 +29,12 @@


if __name__ == "__main__":
persistor = ProfilePersistorPlaintext('profiles.pt')
persistor_path = os.path.expanduser("~/.ionicsecurity/profiles.pt")
persistor = ProfilePersistorPlaintext(persistor_path)
ionic_sep = persistor.get_active_profile()
print("")
print("Current Device ID: " + getattr(ionic_sep, "deviceId"))
print("")

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

# Now we show fetching one of these keys back:
# NOTE: We may or may not be able to get it depending on the current data policy.
Expand Down
15 changes: 9 additions & 6 deletions example_enroll.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
# using built-in and 3rd-party libraries instead of the #
# Ionic SDK. #
# #
# This example uses Python 3.4.3 #
# This example uses Python 3.4.3 or higher. #
# This example is best read with syntax highlighting on. #
# #
# (c) 2017 Ionic Security Inc. #
# (c) 2017-2020 Ionic Security Inc. #
# Confidential and Proprietary #
# By using this code, I agree to the Terms & Conditions #
# (https://www.ionic.com/terms-of-use/) and the Privacy #
# Policy (https://www.ionic.com/privacy-notice/) #
# Author = rmspeers, QA = jmassey #
###########################################################

import sys
import os

from registration import create_device
from registration import get_ionic_token
Expand All @@ -42,8 +42,10 @@
stoken = ""
uidauth = ""

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


Expand All @@ -68,6 +70,7 @@
# NOTE: This will overwrite any existing content at that path.
persistor = ProfilePersistorPlaintext()
persistor.add_sep(sep, set_as_active=True)
persistor.set_file_path("profiles.pt")
persistor_path = os.path.expanduser("~/.ionicsecurity/profiles.pt")
persistor.set_file_path(persister_path)
print(persistor)
persistor.save_to_json()
5 changes: 2 additions & 3 deletions example_external_ids.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
# using built-in and 3rd-party libraries instead of the #
# Ionic SDK. #
# #
# This example uses Python 3.4.3 #
# This example uses Python 3.4.3 or higher. #
# This example is best read with syntax highlighting on. #
# #
# (c) 2017 Ionic Security Inc. #
# (c) 2017-2020 Ionic Security Inc. #
# Confidential and Proprietary #
# By using this code, I agree to the Terms & Conditions #
# (https://www.ionic.com/terms-of-use/) and the Privacy #
# Policy (https://www.ionic.com/privacy-notice/) #
# Author = rmspeers, QA = #
###########################################################

from uuid import uuid4
Expand Down
2 changes: 1 addition & 1 deletion keys/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# using builtin and 3rd-party libraries instead of the #
# Ionic SDK. #
# #
# (c) 2017 Ionic Security Inc. #
# (c) 2017-2020 Ionic Security Inc. #
# Confidential and Proprietary #
# By using this code, I agree to the Terms & Conditions #
# (https://www.ionic.com/terms-of-use/) and the Privacy #
Expand Down
10 changes: 6 additions & 4 deletions keys/key_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
# using built-in and 3rd-party libraries instead of the #
# Ionic SDK. #
# #
# This example uses Python 3.4.3 #
# This example uses Python 3.4.3 or higher. #
# This example is best read with syntax highlighting on. #
# #
# (c) 2017 Ionic Security Inc. #
# (c) 2017-2020 Ionic Security Inc. #
# Confidential and Proprietary #
# By using this code, I agree to the Terms & Conditions #
# (https://www.ionic.com/terms-of-use/) and the Privacy #
# Policy (https://www.ionic.com/privacy-notice/) #
# Author = daniel/rmspeers, QA = jmassey #
###########################################################

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

return key_create_response, cid, b64encoded_signed_attributes_iv_cipher_text_aad_as_string


def create_keys(ionic_sep, dictKeyAttrs = {}, dictMetadata = {}):
# See https://dev.ionic.com/api/device/create-key for more information on key create.

key_create_response, cid, b64encoded_signed_attributes_iv_cipher_text_aad_as_string = create_key_transaction(ionic_sep, dictKeyAttrs, dictMetadata)
decrypted_envelope, response_cid = utilities.decrypt_envelope(ionic_sep, key_create_response, cid)

Expand Down
55 changes: 8 additions & 47 deletions keys/key_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
# using built-in and 3rd-party libraries instead of the #
# Ionic SDK. #
# #
# This example uses Python 3.4.3 #
# This example uses Python 3.4.3 or higher. #
# This example is best read with syntax highlighting on. #
# #
# (c) 2017 Ionic Security Inc. #
# (c) 2017-2020 Ionic Security Inc. #
# Confidential and Proprietary #
# By using this code, I agree to the Terms & Conditions #
# (https://www.ionic.com/terms-of-use/) and the Privacy #
# Policy (https://www.ionic.com/privacy-notice/) #
# Author = daniel, QA = jmassey #
###########################################################

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

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

return key_fetch_response, cid


def decrypt_envelope(ionic_sep, key_fetch_response, cid):
#######################################
### Handling the Key Fetch Response ###
#######################################

key_fetch_response_body = key_fetch_response.json()

# As a precaution, ensure that the client's CID is the same as the response's CID.
response_cid = key_fetch_response_body['cid']
assert cid == response_cid

# Base 64 decode the envelope's value.
decoded_key_fetch_response_envelope_as_bytes = base64.b64decode(key_fetch_response_body['envelope'])

# Prepare to decrypt the `envelope` contents.

# Obtain the initialization vector which is the first 16 bytes.
initialization_vector_from_response_envelope = decoded_key_fetch_response_envelope_as_bytes[:16]

# Obtain the data to decrypt which is the bytes between the initializaiton vector and the tag.
cipher_text_from_response_envelope = decoded_key_fetch_response_envelope_as_bytes[16:-16]

# Obtain the tag which is the last 16 bytes.
gcm_tag_from_response_envelope = decoded_key_fetch_response_envelope_as_bytes[-16:]

# Construct a cipher to decrypt the data.
cipher = Cipher(algorithms.AES(ionic_sep.aesCdIdcKey),
modes.GCM(initialization_vector_from_response_envelope,
gcm_tag_from_response_envelope),
backend=default_backend()
).decryptor()

# Set the cipher's `aad` as the value of the `cid`.
cipher.authenticate_additional_data(response_cid.encode(encoding='utf-8'))

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

return decrypted_envelope


def fetch_keys(ionic_sep, protection_keys, external_ids=None):
##########################################
### Constructing the Key Fetch Request ###
##########################################

# See https://dev.ionic.com/api/device/get-key for more information on key fetch.

example_key_fetch_body = """
{
"cid": "CID|MfyG..A.ec095b70-c1d0-4ac0-9d0f-2cafa82b8a1f|1487622171374|1487622171374|5bFnTQ==",
Expand Down Expand Up @@ -216,7 +177,7 @@ def fetch_keys(ionic_sep, protection_keys, external_ids=None):
"the full HFP included.")

key_fetch_response, cid = fetch_key_request(ionic_sep, protection_keys, send_full_hfp=True)
decrypted_envelope = decrypt_envelope(ionic_sep, key_fetch_response, cid)
decrypted_envelope, _ = utilities.decrypt_envelope(ionic_sep, key_fetch_response, cid)

# Pull out any query results as well to return:
query_results = decrypted_envelope['data'].get('query-results')
Expand Down
22 changes: 15 additions & 7 deletions keys/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
# using built-in and 3rd-party libraries instead of the #
# Ionic SDK. #
# #
# This example uses Python 3.4.3 #
# This example uses Python 3.4.3 or higher. #
# This example is best read with syntax highlighting on. #
# #
# (c) 2017 Ionic Security Inc. #
# (c) 2017-2020 Ionic Security Inc. #
# Confidential and Proprietary #
# By using this code, I agree to the Terms & Conditions #
# (https://www.ionic.com/terms-of-use/) and the Privacy #
Expand Down Expand Up @@ -41,15 +41,23 @@ def make_cid(device_id):


def decrypt_envelope(ionic_sep, server_response, cid):
response_body = server_response.json()
#######################################
### Handling the Key Fetch Response ###
#######################################

# See https://dev.ionic.com/api/device/get-key for more information on key fetch.

key_fetch_response_body = server_response.json()

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

# Base 64 decode the envelope's value.
decoded_response_envelope_as_bytes = base64.b64decode(response_body['envelope'])
decoded_response_envelope_as_bytes = base64.b64decode(key_fetch_response_body['envelope'])
# Prepare to decrypt the `envelope` contents.

# Prepare to decrypt the `envelope` contents.

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

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

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

return decrypted_envelope, response_cid
2 changes: 1 addition & 1 deletion persistors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# using builtin and 3rd-party libraries instead of the #
# Ionic SDK. #
# #
# (c) 2017 Ionic Security Inc. #
# (c) 2017-2020 Ionic Security Inc. #
# Confidential and Proprietary #
# By using this code, I agree to the Terms & Conditions #
# (https://www.ionic.com/terms-of-use/) and the Privacy #
Expand Down
5 changes: 2 additions & 3 deletions persistors/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
# using built-in and 3rd-party libraries instead of the #
# Ionic SDK. #
# #
# This example uses Python 3.4.3 #
# This example uses Python 3.4.3 or higher. #
# This example is best read with syntax highlighting on. #
# #
# (c) 2017 Ionic Security Inc. #
# (c) 2017-2020 Ionic Security Inc. #
# Confidential and Proprietary #
# By using this code, I agree to the Terms & Conditions #
# (https://www.ionic.com/terms-of-use/) and the Privacy #
# Policy (https://www.ionic.com/privacy-notice/) #
# Author = rmspeers, QA = #
###########################################################

import binascii
Expand Down
Loading