Skip to content

Commit 0bb7281

Browse files
committed
initial commit
0 parents  commit 0bb7281

File tree

5 files changed

+308
-0
lines changed

5 files changed

+308
-0
lines changed

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Keygen LLC
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Example Python Cryptographic Machine Files
2+
3+
This is an example of how to verify and decrypt [cryptographic machine files](https://keygen.sh/docs/api/cryptography/#cryptographic-lic)
4+
in Python, using Ed25519 signing and AES-256-GCM encryption. This example
5+
verifies the `aes-256-gcm+ed25519` algorithm.
6+
7+
## Running the example
8+
9+
First up, add an environment variable containing your Ed25519 public key:
10+
```bash
11+
export KEYGEN_PUBLIC_KEY='799efc7752286e6c3815b13358d98fc0f0b566764458adcb48f1be2c10a55906'
12+
```
13+
14+
You can either run each line above within your terminal session before
15+
starting the app, or you can add the above contents to your `~/.bashrc`
16+
file and then run `source ~/.bashrc` after saving the file.
17+
18+
Next, install dependencies with [`pip`](https://packaging.python.org/):
19+
20+
```
21+
pip install -r requirements.txt
22+
```
23+
24+
Then run the script, passing in a `path` to a machine file, and a `license`
25+
key as arguments:
26+
27+
```bash
28+
python main.py --license 'A_LICENSE_KEY' \
29+
--path /etc/keygen/machine.lic
30+
```
31+
32+
Or run one of the pre-defined examples:
33+
34+
```bash
35+
KEYGEN_PUBLIC_KEY='e8601e48b69383ba520245fd07971e983d06d22c4257cfd82304601479cee788' python main.py \
36+
--fingerprint '198e9fe586114844f6a4eaca5069b41a7ed43fb5a2df84892b69826d64573e39' \
37+
--license 'B10760-1B177D-656D1F-C03298-9AF89E-V3' \
38+
--path examples/machine.lic
39+
```
40+
41+
The following will happen:
42+
43+
1. The current device will be fingerprinted, using a SHA-256 digest of the
44+
device's MAC address. You may want to look into alternative fingerprinting,
45+
depending on your expected environment.
46+
1. The machine file's authenticity will be verified using Ed25519, by verifing
47+
its signature using the public key.
48+
1. The machine file will be decrypted using the license key and fingerprint
49+
as the decryption key.
50+
51+
If everything checks out, the script will print the decrypted contents of
52+
the machine file — the machine object, with any included data. If it
53+
fails, check your inputs.
54+
55+
## Questions?
56+
57+
Reach out at [support@keygen.sh](mailto:support@keygen.sh) if you have any
58+
questions or concerns!

examples/machine.lic

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
-----BEGIN MACHINE FILE-----
2+
eyJlbmMiOiJ0S3JYUmw4NCtDSTJ6WDVpN1NSUWJqdkt1d1BpRWFhZDdudlF2
3+
bWNVVnd2L3B2ajEvcDdLb0NzWVVvbWJzT0tQdkwyS0xUcTBhNUtKeGpLRmNP
4+
RG1oc3JUR2NSNUF4bktoSVRJWTA0THFJelJzNW9tZzRpbWRDSVpZZWdzbzdK
5+
Rk9ISDVZaFBnaEFYK1FkK0U4aDUzZWlkNXM4KzVXL0xwN1h2ZUJVamhHeEFZ
6+
SjhTb3VwOFZpOXQwTmlDSHlaL1hIMDRNM0YwSm83MmI0b1VXSWlQT3NNcm9n
7+
VVhudllTckk1TU9abWNhZWlIN1NtNTlDWWozeUVhOE1BcW0xOTdCWktEU0k3
8+
cDdUV2l2VW5FeHprRUhFN2xaUHVleDdGbCtHaURQRHhGbjlkamRRQ3hyamp2
9+
OWRVUG0rdXkzS0Rzb0RwRjZWMWp4OU8wVWNpNFdZZzlUaWNoVm5KK0Yxd3g4
10+
aFJmQ25lU3QvSmo3SHVXSDZ4MC9DS0ZHczFZU0NicUU5VmMxaHFDWTdYNCsw
11+
KzdYQmNhZWpRSituUU5TemVkdXNya0JTa0NEcm1PUHpzUW9JNzJFUWUxS20x
12+
dkY0MlRxbHBXUzB3aFVFSml2a1VlcmZqVFQ4aGpPZTlJZEFzTEphQytqS3F3
13+
S2hmQ0QxVERqZVQ4QnMwT0JLOXpZV0JUbmlDY2Q1bUlUSFVySWZDanhmOGNh
14+
MDdmaW1TdnV0UTdCN3FNNlMvWEJ6VWhqNXAvNlJ2OU9TQS9pcDFkT0RuWHhm
15+
K2FOempTM1planB1Q2M3UGkzM0ltejZabCtZUWl0cklnMUpaaXhmZ0l0aGpr
16+
VS9BakVqaW1PekdxcS9NTjlSdjIwTUk3RWRrWE40Z3VhNGFjMGJNQzNQQnhs
17+
a3BZK0hMQW1HSWlxckJZSVAzVDRMNzBFMk5JRkl5bldtKzk2aHdKazBVR1RQ
18+
cUlVdCt1QmIzdWRueWhuS3h6bnR5eXR1eTBuNzVOaVpndlFONE14MUc5dWlF
19+
a2xIOWVQN2Jjbk5PWGEvRW9Mdm9NKy9NZDNZc01KdlkzZ09Sd2w0R0FFZ1Bv
20+
Z3VMZTc4L3R3T1dsU3NSS2ZrWlM1QW1GdWd2cU13dmdwOVhzT3NwOFRPa1F0
21+
MEtCdHVZejFFSjh5TmthSzBReXMwMUNjWDUzelJHZDJYc0dKMEo0TTBnR2FX
22+
QVBJZndVTm5iSThnRTV6eEZ0T2lGdXZXMTRML1JHRXdJZUxVaXhhbkVpa28z
23+
TjMrMHdhdGhjTzlVcGJreXR1VlpFOGprR0t3OHRZdGdyaFRDalc0bllEQW5O
24+
b2Z2Tm9hUkt2ZHp2RzEvODg0SDZuVWhYbEw5ZVBvaE1pZXJVOE9iYWhIQTR4
25+
T0dnQjhGQXp6QVhndGtaK3ZFRUpBOUl5Y2x5QWdzWjR3elVHMEpZcDF6bEhL
26+
RmdjMjA4eldxeUcxdW9VR3czTEtMZjRjZklNRlBkS2ozOWpCNms1TVFSOXc4
27+
UnBmSkJvU2pnemt3eS9GSnhVcnk0Ni9Pdlk4VDNSMGFxb0VOZHVrRHVvOUF2
28+
a1N3VmY2WkRadjR4Qk1FVmFJUFRxbUxIc1pyZmkwcTdRa3RjdklzNHpmSEZK
29+
SW15MnZHQndMb0ZzOGhteXNOOVQzbnB2MzFiM0ZaVmQ3VUR4SmxTR21qa281
30+
enNaNEVFeDFEUjhHRzMzYjg5Q1Yxc09GUytBWWxXem9iM0sza3NnREt5NzhY
31+
Qk9ucEttY3ZKZnNvWm83ZSt2dTZtOHAzQzVzak53UVJycUJJb1Z1K0czbWIv
32+
U2dvTHRkWExZcGlEaE5pTzVFS3hDVSsvUCtNcEFPbERRU211cy85N0VadlRP
33+
R05RVDZGWkVjWEpocUl0Zm9DemFYZGQxenJYamhXbGpCNng3Q0F0Y3Fudkl5
34+
MlZ0UHplSlB6Z2hFSzZlZ1VyL2MybDBHU3ZVNjNmTnFxUzZoQzJpZUZaWTg0
35+
T2ptZ1hKb1BZU2YxODAwTlRlMUkyRzdrZi9LaTh0S2FqMVVONndDQ1Y0RDk0
36+
d3B1WElJdVZiaXl0U1ArYktudGtiQ1NUZ1ZpZEwyZHdZTnE0Y2o1bHdTM0xn
37+
R1BpVnpQZDNPMWs3V2tlemlpRVJ0K0xKNTFNbHZIVS9kVkI2RTZIREY2dFVt
38+
UHpHaDhaSTFUTGhOUU1GV3pSMWJUaFhzdFRuZ2FrR3ZKc0I4WFd1Y1R5RGg5
39+
cXdnYlhWYytqNmFQZ0FBb3M0enh3VVowdTJTV2lGWHpVTWxlUUtqWTM4VGk4
40+
dFp1ZTlac1ZBUEJVUFo2TTVSV0dEQVZ1OGttVno3VjFVTkhEQS9OTTA5dGZS
41+
aFVkUjVJNlhlRXZ0ZWJFdmM1YktNNnFXOTBId3V0QWx2b0dXcmFpak9qbGti
42+
VmZZV2d3RlloYmg0eEdJL2NoYkR0OWtBcVFIMDhPUCsyZVhTbmxZWU1GSVdI
43+
Qk8rK1g5WGd0RktmK2dJb3N5K2hKZjVIekhZL3hGWHFiVzJzWnE4U0lZaUhW
44+
RTVWMXA1cGVKbUNHaVZnTEV0YUZSU0o1bWxWeUxWdldLSmdIRG9SWUlPaFR4
45+
WFUvVnkxM3hXVmF3c0dTa2s0NDU5bHZoVEt1bUhIK3o4aTkyOG9EY2dsWnk0
46+
bENtbTFGTUhEQ3dHMUkzUjJNbzR3ZkQ1MXhVNHVCTW1iR0dBckowSlBJZHNV
47+
ZUZUeEFpS2lLV25KRzBrbGF5cWNUR0huTGR0QUY0TWJ0R0N5YytsMldzZ0xh
48+
cFZlOE9ablJ1MWZUY1M3TGE0RjZudUdrMVpxeVhJeEhlU3RVUlFWOVZ0ZFI3
49+
ZGwzcHFsaXh1eDZHTTRBNVhMbVp1NG9DeWtqU1c5SGp2MFhQdjFwdnFsemtq
50+
b2xoTjF6RzlHbmJVQ2c2cExmMGJ4VFcwdlJSV0kwWU9NZm1kNkZMeURRZ1ZE
51+
YkY3L2UwVS9jRXllRHZTWkM0KzZCcTFjdFhTZlZ4NDFqaHBMV3E2eG9WT3hl
52+
NHg3UXZreEEzM3JkdFVYeWNEa0RneFNDQ1lSZzFxckFWOUx5SjdRMlIwOVZs
53+
cnd5YitMWm1RQkVRMGRxdlVmNVB0UU1LQVRnWXlvclo2cEFTWmI4QUdMeis3
54+
QzNXTjJHbnNoR1dwZUlCV2RzSGJFTXZnR0ZTUGt1NlpCaDR3MVlTRm44NUwr
55+
a3FGNnJTTUVscVRtdjcyVVJRdTRyNE85L0FSa3VOMHFYRmZNMldVNlpTUTkz
56+
TzR4STdpbW92SWMyWktaUHFKOG5nRUR4UEIyMFhpaUFFSmM2Y0tCUUNmYTA1
57+
SnlRYWt2Z0ZnQ0gvTDl3YkQxcUJMVDRRSTJ3d0M0TnlYcHlHNm9mMWpaVElN
58+
SFprVVBhMDlwYVNnVXZvVDRTaUtYZXBObG41dzdIWHdVY1JMQjBRUzVvUHZL
59+
OXBoYW0zcTBMbHlFMHVkUFhINEkvdEFWZThIcDJwQWRiUkl5c0E0dHJ1bUFv
60+
VS9EN3E5czZVc0JiMW02azBwQ0w1Z3ZLV3Z2M096YnBGOXRNbEFhYW12ZnFG
61+
a1dIanNQK2pwZnVoeGhsL3llTEl3ZU5lZjJmTmxIOVNtWjExbzVsL3lpVTJ1
62+
QWVrd0dabGVQUmx2QzgrS3ovd3o4ejgxUllLVnVWSGNvcVc2dkY3OEJadkFa
63+
VDgvbVZyQzR5TElpcXp3NkhvYmpQWnhsNW5rRXhVSHdLalRsRXdPWExWNFJu
64+
dlY1ZitjZlk3Qnh1RGhCdlpGU2dEb0NiUmpOK2JIOTRxM3A3SDQzUlV4SG9N
65+
azY4M1pOMmZCM09nNW1CSUZxOFA0SU94c0dSWGltcDZvR1FzQTcxMGdxV1Z1
66+
YWdVbWJ5YWhjWWRsQW1majVlWC8zV2RCN3VOdm5idDViZmlTL05GS21LTWxy
67+
T2NoSUNLUU56bU1IZ2xPZW95SzA3ZlAwUVZLc2hsZEJhZzNicXF0MSsxU3hi
68+
akFwVTN3UHNjakVuSVBhUjBUemhrcFVuMm5rR25iWDhxSVVOcURsMlkyc3RI
69+
S3V5VmEybUpZaUVLVm1sdE9GakYyVm92ZFZPY3lqT3lTOWFlUTduY0tlZTdp
70+
c1E1RC9NdURlK091aWhLY3RzLzRobnRCMHV3a0x5SVZKdE5xSHgwQzlxVE9D
71+
NEtNbjdlcGlDT0ltdjBHRVdaQkZyS2kvOXJEbE1FOXBnWTZPTU5ySXZhK1Br
72+
UWVRQllmRXo1bnAzTzJNZm5zS1B2dHVjamF2OWg5TlQyUjkwcVBDSXkzcjl5
73+
YUFZV1hTR1cyTlZtNFdXcENnM05jdjFDTDhZTEMwR1I5OFI3LzgwdUxEQ1A0
74+
a04wRG1PLzFZN2wxb2VXVlVVY0ZvTnFBSmo2NCtGS1BsL21CUDNYY0FDMWhE
75+
cmlENTlDYVFNWVhkOGdXVkJiRzVYeEpIdU5mNmdvZjRidEhFVUM3UHdaUjVp
76+
cDROai9OdUh4Vk4rVVhselVFUmh1UTR2a2daWkFpVE9IbE5Pc3ZlLzJmNTlt
77+
VkhMSnpDRTF3Wlc1c09TZlVuN2Zwb2hzUUMrRVROdHhRemdURkU3N1NFUDVi
78+
dFdSZytFWDNmU1Fibjh6LzBiektUYTc3VFpmdzYrL2g3SXN6UmNCTDVZOFN5
79+
UzZnbGxjbmtoVTVLZjVwc0dJc0JXaklDMjhwQnhMMkhqaWF4ZlowVkpKTVNF
80+
MWkzSFVQU29RbmdUaFdxckQvd3dzN1Fjb280VVdrbWF4VlF5Z3k4MWRaZlhr
81+
amdMcmxvQVhodSthb0lxa0I2ZkxYbTUxT2JUK3dEVHQ3SHpwVkRTb0VDamEy
82+
VUR3MDRPNXNOcitDR3p6aGc0LzdYZTQvZWhQbW85MmhyeVFPRUFaK3pveVRp
83+
TGx1bWhtbE1zMUhTeHRxSGw2TU93VnZNV3lEVW9BWXNCc3MzTWpGazk4b0hM
84+
RTFIajVCMUNxYTBKbk9kQXF2UE0wOUZ0UjZxdlVRSFVLbE9mRnhuY2xlSlpm
85+
WnJreVBlV0tCeld6RHhYL1hGR1BpT3JldUVLeE9hZWRyaUQ5STNHalg4clpk
86+
Y08xUUVmWlFCN1NQdkc2Q25XZUVzWDFWV2RNclVTQlJLaldUQkVlRlVjdmdH
87+
QzhRamVFS1RlcXpuTFpkZFh5MmdpVnl5ejdMSW1kOWVNUkJpOHNmbzZYSTgr
88+
TWsyOXJUZksvNGZJd0tub0ZtNVdCS1hSWENvalJMVTV1MGw1MUwyVmtkZHNR
89+
VUlzZjc1UlFIZkxKUVZEODY3elJJM2JaZTJOUkRMOEtQQU95bUVMd3hKMmRq
90+
OURJa1N2WXJSR3kxOGE4VXdzRVNrS1RtZFRyYlhRQ0ZCYUMxeXlhTng1dUJo
91+
dU85eTJSMlEzRWE0NGJlQmFXaHRZVm9uQ0ZQM01WSTQ5bXI2MzNyM3F3QlAz
92+
RW1yMHBrck9aczA0NUNDa3diTktLdmlYREtBbm1FcUduRmxBMmNtQnl2TURP
93+
NktadEpyR2wvUWFqZ05wck1PQnNycE5wWFZjdVNhRVIrT0JFQXR1WnNXYUZT
94+
T1RUaFFVVWRBbFN3NWN4N3BnL2xTRlV5aWdudFBBWVVjVllzM3N1NEZpU0Zl
95+
L0UwT3Qzek5CL2wzUHIyb1g1bHFYNG9mVEZEZ2NySm5FVDBmU1ZhaW5zR3Zy
96+
TXNtTXV5UHhMcjJiSTJWWEIxMXNWNDhKQmR5aXhDNGxWSTZEUCtWNWs2MW01
97+
Qzd4bEFPYUFtSXVLWHBkdjROV3dkRXdrZmk2d3ZnSjluMGh4K09ORk1GT20y
98+
S0ZoR1NFeEpxQ1JNOXREa255elNtZWN4YnRqRllkdGp1bm4vL2kvTFNZdVhh
99+
bzFWQUFXcUVPNEloVXcwQUxJM0Z2ZUt3TDhUdWxIL05OWEpkVXJUOGh3Rllu
100+
ak1RMC9yYWhMTmpqNkEzeVB5YU1aWnFpYjJLbVlQcnRBOWxSc1pDN1h6SEJx
101+
cVJrTUMxVjlFRnJEcjBsYjNaeUNWUzlVYzNWZmUvWlhwSjlmZXBhQUlpb096
102+
OEt3N1JaUlZERVNmS3VFN2dYY2RsYkF6V2x2UjhWR3k5OWswMUo1Vms0Q2wy
103+
NS9mMmR1UERHUmgvMzR2V2hNbGhpc3A3bjE2VjM0a3NrcFgra2JkTjVwcC94
104+
UGc1M2VWcHVIVWNheHlhQ3pLWHdTZUlFY2xQQTM2SFJ5SGwrU2o5aUEvS0Fn
105+
NWJ2enVIQU9RVm1nNkVxVml3aE1Ub1pJRUlaZE85K1pGZ2pnd0U0LzVlOTMv
106+
bXN6RC8vazdSU2RkdkZKaTJTdjMvV2xwMHhkTUFIbkQwM0dWNTdNaFEzelRw
107+
V1ZnRGlscmo0RzA0R2dCVjBGUkd6dUxqMDNQNy9iZk84Z08zOUFScEh1Tlo1
108+
cjJmT2dVcTllOWZYTGNGS0tDdFltbk5iLy85NmljQzJ5QUhqUGR6NHlac1gz
109+
T085TEFYek5wOVJWK3RrU0p0S1hZRjh6Wk1rWTg5WmZEbEh5QkFleDByVFlZ
110+
ZlVVUS84OXFCR1Uwd2g3WVhGdWtPMUVqMkhCN0ZIb1lxSlNyMG5SeVFLMlJw
111+
SDBTeEhHR1NwK2lnaWpMbHp5VkJTVFZwL2EvdUpuZHRvOHhhOGJXZ3BiTkhn
112+
ZE9XaHNWMDRLQ0hFNWlXTS9BQ1RwVW9EOVU5QzdPZzRBPS5sTWhWTEpOV1VF
113+
S3lHcGt4LmMyUmhDbEJZWGY0SVRmcEV0WHRUdmc9PSIsInNpZyI6ImlHMGh2
114+
Y1VaeGUwU3BDZWlNWi95aldFcEFnV2t6Ly9vV2FNRmFkUjRmWGd1UkozTGZO
115+
K3FIOCt4eFhhRmRoSS8rbVFvdTdnZzRSRzdxSVUwdjRoUERRPT0iLCJhbGci
116+
OiJhZXMtMjU2LWdjbStlZDI1NTE5In0=
117+
-----END MACHINE FILE-----

main.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
2+
from cryptography.hazmat.primitives import hashes
3+
from cryptography.hazmat.backends import default_backend
4+
from cryptography.exceptions import InvalidKey, InvalidTag
5+
from ed25519 import BadSignatureError
6+
from uuid import getnode as get_mac
7+
import argparse
8+
import ed25519
9+
import base64
10+
import json
11+
import sys
12+
import os
13+
14+
def fingerprint():
15+
"""
16+
fingerprint returns a hex-encoded SHA-256 digest of the current MAC address.
17+
"""
18+
mac = str(get_mac())
19+
digest = hashes.Hash(hashes.SHA256())
20+
digest.update(mac.encode())
21+
return digest.finalize().hex()
22+
23+
parser = argparse.ArgumentParser()
24+
25+
parser.add_argument('-p', '--path', dest='path', required=True, help='Path to machine file (required)')
26+
parser.add_argument('-l', '--license', dest='license', required=True, help='License key (required)')
27+
parser.add_argument('-f', '--fingerprint', dest='fingerprint', default=fingerprint(), help='Machine fingerprint')
28+
29+
args = parser.parse_args()
30+
31+
# Read the machine file
32+
machine_file = None
33+
34+
try:
35+
with open(args.path) as f:
36+
machine_file = f.read()
37+
except (FileNotFoundError, PermissionError):
38+
print('[error] path does not exist! (or permission was denied)')
39+
40+
sys.exit(1)
41+
42+
# Strip the header and footer from the machine file certificate
43+
payload = machine_file.lstrip('-----BEGIN MACHINE FILE-----\n') \
44+
.rstrip('-----END MACHINE FILE-----\n')
45+
46+
# Decode the payload and parse the JSON object
47+
data = json.loads(base64.b64decode(payload))
48+
49+
# Retrieve the enc and sig properties
50+
enc = data['enc']
51+
sig = data['sig']
52+
alg = data['alg']
53+
54+
if alg != 'aes-256-gcm+ed25519':
55+
print('[error] algorithm is not supported!')
56+
57+
sys.exit(1)
58+
59+
# Verify using Ed25519
60+
try:
61+
verify_key = ed25519.VerifyingKey(
62+
os.environ['KEYGEN_PUBLIC_KEY'].encode(),
63+
encoding='hex',
64+
)
65+
66+
verify_key.verify(
67+
base64.b64decode(sig),
68+
('machine/%s' % enc).encode(),
69+
)
70+
except (AssertionError, BadSignatureError):
71+
print('[error] verification failed!')
72+
73+
sys.exit(1)
74+
75+
print('[info] verification successful!')
76+
77+
# Hash the license key using SHA256
78+
digest = hashes.Hash(hashes.SHA256())
79+
digest.update(args.license.encode())
80+
digest.update(args.fingerprint.encode())
81+
key = digest.finalize()
82+
83+
# Split and decode the enc value
84+
ciphertext, iv, tag = map(
85+
lambda p: base64.b64decode(p),
86+
enc.split('.'),
87+
)
88+
89+
# Decrypt ciphertext
90+
try:
91+
aes = Cipher(
92+
algorithms.AES(key),
93+
modes.GCM(iv, None, len(tag)),
94+
default_backend(),
95+
)
96+
dec = aes.decryptor()
97+
98+
plaintext = dec.update(ciphertext) + \
99+
dec.finalize_with_tag(tag)
100+
except (InvalidKey, InvalidTag):
101+
print('[error] decryption failed!')
102+
103+
sys.exit(1)
104+
105+
print('[info] decryption successful!')
106+
print(
107+
json.dumps(json.loads(plaintext.decode()), indent=2)
108+
)

requirements.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
argparse
2+
cryptography
3+
ed25519
4+
uuid

0 commit comments

Comments
 (0)