-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add method for decoding sealed results
- Loading branch information
1 parent
d433558
commit 1acdeea
Showing
11 changed files
with
378 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,3 +28,4 @@ git_push.sh | |
tox.ini | ||
test/*.py | ||
fingerprint_pro_server_api_sdk/models/many_requests_response.py | ||
requirements.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# DecryptionKey | ||
|
||
## Properties | ||
|
||
| Name | Type | Description | Notes | | ||
|---------------|-------------------------|-----------------------------------------------------------------------------------|-------| | ||
| **Key** | **bytes** | Key generated in dashboard that will be used to decrypt sealed result | | | ||
| **Algorithm** | **DecryptionAlgorithm** | Algorithm to use for decryption. Currently only "aes-256-gcm" value is supported. | | | ||
|
||
|
||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# Sealed results | ||
|
||
## **UnsealEventsResponse** | ||
> unseal_events_response(sealed bytes, keys DecryptionKey[]) -> EventResponse | ||
Decrypts the sealed response with provided keys. | ||
### Required Parameters | ||
|
||
| Name | Type | Description | Notes | | ||
|------------|---------------------|------------------------------------------------------------------------------------------|-------| | ||
| **sealed** | **bytes** | Base64 encoded sealed data | | | ||
| **keys** | **DecryptionKey[]** | Decryption keys. The SDK will try to decrypt the result with each key until it succeeds. | | | ||
|
||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import json | ||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes | ||
from cryptography.hazmat.backends import default_backend | ||
import zlib | ||
|
||
from fingerprint_pro_server_api_sdk.models.event_response import EventResponse | ||
|
||
SEALED_HEADER = bytes([0x9e, 0x85, 0xdc, 0xed]) | ||
DecryptionAlgorithm = { | ||
'Aes256Gcm': 'aes-256-gcm', | ||
} | ||
|
||
|
||
class DecryptionKey: | ||
def __init__(self, key, algorithm): | ||
self.key = key | ||
self.algorithm = algorithm | ||
|
||
|
||
class UnsealError(Exception): | ||
exception: Exception | ||
key: DecryptionKey | ||
|
||
def __init__(self, exception, key): | ||
self.exception = exception | ||
self.key = key | ||
|
||
|
||
class UnsealAggregateError(Exception): | ||
def __init__(self, errors): | ||
self.errors = errors | ||
super().__init__("Unable to decrypt sealed data") | ||
|
||
|
||
def parse_events_response(unsealed): | ||
json_data = json.loads(unsealed) | ||
|
||
if 'products' not in json_data: | ||
raise ValueError('Sealed data is not valid events response') | ||
|
||
return EventResponse(json_data['products']) | ||
|
||
|
||
def unseal_events_response(sealed_data, decryption_keys): | ||
unsealed = unseal(sealed_data, decryption_keys) | ||
return parse_events_response(unsealed) | ||
|
||
|
||
def unseal(sealed_data, decryption_keys): | ||
if sealed_data[:len(SEALED_HEADER)].hex() != SEALED_HEADER.hex(): | ||
raise ValueError('Invalid sealed data header') | ||
|
||
errors = [] | ||
for decryption_key in decryption_keys: | ||
if decryption_key.algorithm == DecryptionAlgorithm['Aes256Gcm']: | ||
try: | ||
return unseal_aes256gcm(sealed_data, decryption_key.key) | ||
except Exception as e: | ||
errors.append(UnsealError(e, decryption_key)) | ||
continue | ||
else: | ||
raise ValueError(f"Unsupported decryption algorithm: {decryption_key.algorithm}") | ||
|
||
raise UnsealAggregateError(errors) | ||
|
||
|
||
def unseal_aes256gcm(sealed_data, decryption_key): | ||
nonce_length = 12 | ||
nonce = sealed_data[len(SEALED_HEADER):len(SEALED_HEADER) + nonce_length] | ||
|
||
auth_tag_length = 16 | ||
auth_tag = sealed_data[-auth_tag_length:] | ||
|
||
ciphertext = sealed_data[len(SEALED_HEADER) + nonce_length:-auth_tag_length] | ||
|
||
decipher = Cipher( | ||
algorithms.AES(decryption_key), | ||
modes.GCM(nonce, auth_tag), | ||
backend=default_backend() | ||
).decryptor() | ||
|
||
compressed = decipher.update(ciphertext) + decipher.finalize() | ||
|
||
payload = zlib.decompress(compressed, -zlib.MAX_WBITS) | ||
|
||
return payload.decode('utf-8') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,3 +4,4 @@ python_dateutil >= 2.5.3 | |
setuptools >= 21.0.0 | ||
urllib3<1.27,>=1.21.1 | ||
python-dotenv | ||
cryptography |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import base64 | ||
import os | ||
|
||
from dotenv import load_dotenv | ||
|
||
from fingerprint_pro_server_api_sdk import EventResponse | ||
from fingerprint_pro_server_api_sdk.sealed import unseal_events_response, DecryptionKey, DecryptionAlgorithm | ||
|
||
load_dotenv() | ||
|
||
sealed_result = base64.b64decode(os.environ["BASE64_SEALED_RESULT"]) | ||
key = base64.b64decode(os.environ["BASE64_KEY"]) | ||
|
||
try: | ||
events_response: EventResponse = unseal_events_response(sealed_result, [DecryptionKey(key, DecryptionAlgorithm['Aes256Gcm'])]) | ||
print("\n\n\nEvent response: \n", events_response.products) | ||
except Exception as e: | ||
print("Exception when calling unsealing events response: %s\n" % e) | ||
exit(1) | ||
|
||
print("Unseal successful!") | ||
|
||
exit(0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
{ | ||
"products": { | ||
"identification": { | ||
"data": { | ||
"visitorId": "2ZEDCZEfOfXjEmMuE3tq", | ||
"requestId": "1703067132750.Z5hutJ", | ||
"browserDetails": { | ||
"browserName": "Safari", | ||
"browserMajorVersion": "17", | ||
"browserFullVersion": "17.3", | ||
"os": "Mac OS X", | ||
"osVersion": "10.15.7", | ||
"device": "Other", | ||
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Safari/605.1.15" | ||
}, | ||
"incognito": false, | ||
"ip": "::1", | ||
"ipLocation": { | ||
"accuracyRadius": 1000, | ||
"latitude": 59.3241, | ||
"longitude": 18.0517, | ||
"postalCode": "100 05", | ||
"timezone": "Europe/Stockholm", | ||
"city": { | ||
"name": "Stockholm" | ||
}, | ||
"country": { | ||
"code": "SE", | ||
"name": "Sweden" | ||
}, | ||
"continent": { | ||
"code": "EU", | ||
"name": "Europe" | ||
}, | ||
"subdivisions": [ | ||
{ | ||
"isoCode": "AB", | ||
"name": "Stockholm County" | ||
} | ||
] | ||
}, | ||
"timestamp": 1703067136286, | ||
"time": "2023-12-20T10:12:16Z", | ||
"url": "http://localhost:8080/", | ||
"tag": { | ||
"foo": "bar" | ||
}, | ||
"confidence": { | ||
"score": 1 | ||
}, | ||
"visitorFound": true, | ||
"firstSeenAt": { | ||
"global": "2023-12-15T12:13:55.103Z", | ||
"subscription": "2023-12-15T12:13:55.103Z" | ||
}, | ||
"lastSeenAt": { | ||
"global": "2023-12-19T11:39:51.52Z", | ||
"subscription": "2023-12-19T11:39:51.52Z" | ||
} | ||
} | ||
}, | ||
"botd": { | ||
"data": { | ||
"bot": { | ||
"result": "notDetected" | ||
}, | ||
"meta": { | ||
"foo": "bar" | ||
}, | ||
"url": "http://localhost:8080/", | ||
"ip": "::1", | ||
"time": "2023-12-20T10:12:13.894Z", | ||
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.3 Safari/605.1.15", | ||
"requestId": "1703067132750.Z5hutJ" | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.