forked from mozilla-services/syncclient
-
Notifications
You must be signed in to change notification settings - Fork 3
/
crypto-tool.py
executable file
·136 lines (98 loc) · 4.01 KB
/
crypto-tool.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env python3
import os
import argparse
import base64
import json
from cryptography.hazmat.backends.openssl import backend as openssl
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives.kdf.scrypt import Scrypt
from nacl.public import PrivateKey, SealedBox
class CryptoTool(object):
def __init__(self, mode='base64'):
self._backend = openssl
self._mode = mode
def _print(self, data):
if isinstance(data, dict):
for key, value in data.items():
data[key] = self._print(value)
return json.dumps(data)
if isinstance(data, list) or isinstance(data, tuple):
return json.dumps([self._print(d) for d in data])
if isinstance(data, bytes):
m = self._mode
if m == 'base64':
return base64.b64encode(data).decode('ascii')
if m == 'hex':
return data.hex()
return data
return data
def hkdf_namespace(self, name, extra=None):
if isinstance(name, str):
name = name.encode("utf-8")
kw = b"identity.mozilla.com/picl/v1/" + name
if extra is not None:
if isinstance(extra, str):
extra = extra.encode("utf-8")
kw = kw + b":" + extra
return kw
def hkdf_derive(self, secret, obj_class, obj_id=None, size=32):
kdf = HKDF(algorithm=hashes.SHA256(), length=size, salt=None,
info=self.hkdf_namespace(obj_class, obj_id),
backend=self._backend)
return kdf.derive(secret)
def derive_key_scrypt(self, secret, info, n=16, size=32):
if isinstance(n, str):
n = int(n)
salt = info
if isinstance(salt, str):
salt = salt.encode('utf-8')
if isinstance(secret, str):
secret = secret.encode('utf-8')
kdf = Scrypt(salt=salt, length=size, n=2**n, r=8, p=1,
backend=self._backend)
return kdf.derive(secret)
def derive_key_scrypt_ext(self, secret, info, n=16, size=32):
return self._print(self.derive_key_scrypt(secret, info, n, size))
def generate_key(self, keyB, object_id):
if isinstance(keyB, str):
keyB = bytes.fromhex(keyB)
object_key = self.derive_key_scrypt(keyB, object_id)
return PrivateKey(object_key)
def generate_key_ext(self, keyB, object_id):
secret_key = self.generate_key(keyB, object_id)
public_key = secret_key.public_key
data = {"sk":secret_key._private_key, "pk":public_key._public_key}
return self._print(data)
def encrypt(self, keyB, filename):
key = self.generate_key(keyB, filename)
box = SealedBox(key.public_key)
with open(filename, "rb") as fp:
return box.encrypt(fp.read())
def encrypt_ext(self, keyB, filename):
data = self.encrypt(keyB, filename)
return self._print(data)
def decrypt(self, keyB, filename, filename_enc):
key = self.generate_key(keyB, filename)
box = SealedBox(key)
with open(filename_enc, "rb") as fp:
return box.decrypt(fp.read())
def decrypt_ext(self, keyB, filename, filename_enc):
data = self.decrypt(keyB, filename, filename_enc)
return self._print(data)
def main():
parser = argparse.ArgumentParser(
description="""CLI for invoking crypto utility functions""",
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument('-m', '--mode', dest='mode', default='base64',
choices=['base64','hex'],
help='The output mode')
parser.add_argument(dest='action', nargs='?',
help='The action to be executed')
args, extra = parser.parse_known_args()
func = args.action + "_ext"
tool = CryptoTool(mode=args.mode)
print(getattr(tool, func)(*extra))
if __name__ == '__main__':
main()