@ethernity-cloud/sdk-js 1.6.2 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +86 -48
- package/cas/config.js +61 -3
- package/info.js +14 -5
- package/init.js +24 -6
- package/network.js +51 -0
- package/nodenithy/build/securelock/Dockerfile.tmpl +34 -32
- package/nodenithy/build/securelock/scripts/binary-fs-build.sh +7 -6
- package/nodenithy/build.mjs +80 -68
- package/nodenithy/run/docker-compose-final.yml.tmpl +36 -31
- package/nodenithy/run/docker-compose.yml.tmpl +34 -45
- package/nodenithy/run/image_registry.js +17 -4
- package/nodenithy/run.js +42 -28
- package/nodenithy/src/ec_helloworld_example.js +46 -42
- package/nodenithy/src/preStart.mjs +41 -51
- package/package.json +6 -3
- package/publish.js +4 -2
- package/pynithy/build/securelock/Dockerfile.base.tpl +13 -0
- package/pynithy/build/securelock/Dockerfile.tpl +131 -0
- package/pynithy/build/securelock/scripts/binary-fs-build.sh +25 -34
- package/pynithy/build/securelock/scripts/pyfreeze.sh +32 -0
- package/pynithy/build/securelock/src/{pox.abi → abi/etnyImplementationV2.abi} +1489 -1489
- package/pynithy/build/securelock/src/abi/image_registry.abi +1 -0
- package/pynithy/build/securelock/src/ecld_state.py +906 -0
- package/pynithy/build/securelock/src/esr.abi +1 -0
- package/pynithy/build/securelock/src/esr_local.py +267 -0
- package/pynithy/build/securelock/src/esr_wallet.py +150 -0
- package/pynithy/build/securelock/src/etny_crypto.py +208 -167
- package/pynithy/build/securelock/src/etny_exec.py +385 -79
- package/pynithy/build/securelock/src/etny_exec_flask.py +535 -0
- package/pynithy/build/securelock/src/etny_exec_serv.py +353 -0
- package/pynithy/build/securelock/src/etny_session_exec.py +245 -0
- package/pynithy/build/securelock/src/get_sgx_report.so +0 -0
- package/pynithy/build/securelock/src/image_registry.abi +1 -1
- package/pynithy/build/securelock/src/key_generation.py +17 -17
- package/pynithy/build/securelock/src/local_api.py +189 -0
- package/pynithy/build/securelock/src/models.py +200 -176
- package/pynithy/build/securelock/src/securelock.py.tmpl +1037 -731
- package/pynithy/build/securelock/src/swift_stream_service.py +206 -186
- package/pynithy/build.mjs +139 -89
- package/pynithy/run/docker-compose-final.yml.tmpl +58 -51
- package/pynithy/run/docker-compose.yml.tmpl +62 -48
- package/pynithy/run/etny-securelock-test.yaml.tpl +4 -1
- package/pynithy/run/image_registry.js +17 -4
- package/pynithy/run.js +44 -28
- package/pynithy/src/ec_helloworld_example.js +46 -42
- package/pynithy/src/preStart.mjs +41 -51
- package/pynithy/src/serverless/Dockerfile.serverless +8 -0
- package/pynithy/src/serverless/requirements.txt +6 -0
- package/run.js +37 -34
- package/nodenithy/build/las/Dockerfile +0 -5
- package/nodenithy/src/preStart.js +0 -45
- package/pynithy/build/docker-compose.yml +0 -70
- package/pynithy/build/las/Dockerfile +0 -11
- package/pynithy/build/las/src/etny_entrypoint.sh +0 -6
- package/pynithy/build/las/src/las_entrypoint.sh +0 -26
- package/pynithy/build/scripts/binary-fs-build.sh +0 -28
- package/pynithy/build/securelock/Dockerfile.tmpl +0 -95
|
@@ -1,167 +1,208 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import base64
|
|
4
|
-
import binascii
|
|
5
|
-
import codecs
|
|
6
|
-
import hashlib
|
|
7
|
-
import json
|
|
8
|
-
import secrets
|
|
9
|
-
from pyasn1.codec.der import decoder
|
|
10
|
-
from Crypto.Cipher import AES
|
|
11
|
-
from tinyec import registry
|
|
12
|
-
from tinyec import ec
|
|
13
|
-
from Crypto.PublicKey import ECC
|
|
14
|
-
from nacl.public import Box, PrivateKey, PublicKey
|
|
15
|
-
from base64 import a85encode
|
|
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
|
-
binascii.unhexlify(json_load['
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
result
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import binascii
|
|
5
|
+
import codecs
|
|
6
|
+
import hashlib
|
|
7
|
+
import json
|
|
8
|
+
import secrets
|
|
9
|
+
from pyasn1.codec.der import decoder
|
|
10
|
+
from Crypto.Cipher import AES
|
|
11
|
+
from tinyec import registry
|
|
12
|
+
from tinyec import ec
|
|
13
|
+
from Crypto.PublicKey import ECC
|
|
14
|
+
from nacl.public import Box, PrivateKey, PublicKey
|
|
15
|
+
from base64 import a85encode
|
|
16
|
+
from eth_account import Account
|
|
17
|
+
import ecdsa
|
|
18
|
+
from ecdsa.util import sigencode_der, sigdecode_der
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class etny_crypto:
|
|
22
|
+
curve = registry.get_curve('secp384r1')
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def compress_point(point):
|
|
26
|
+
return hex(point.x) + hex(point.y % 2)[2:]
|
|
27
|
+
|
|
28
|
+
@staticmethod
|
|
29
|
+
def ecc_point_to_256_bit_key(point):
|
|
30
|
+
value = str(point.x) + str(point.y)
|
|
31
|
+
sha = hashlib.sha256(value.encode())
|
|
32
|
+
return sha.digest()
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def encrypt_aes_gcm(msg, secret_key):
|
|
36
|
+
aes_cipher = AES.new(secret_key, AES.MODE_GCM)
|
|
37
|
+
cipher_text, auth_tag = aes_cipher.encrypt_and_digest(msg)
|
|
38
|
+
return (cipher_text, aes_cipher.nonce, auth_tag)
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
def encrypt_ecc(msg, public_key):
|
|
42
|
+
cipher_text_private_key = secrets.randbelow(etny_crypto.curve.field.n)
|
|
43
|
+
shared_ecc_key = cipher_text_private_key * public_key
|
|
44
|
+
secret_key = etny_crypto.ecc_point_to_256_bit_key(shared_ecc_key)
|
|
45
|
+
ciphertext, nonce, auth_tag = etny_crypto.encrypt_aes_gcm(msg, secret_key)
|
|
46
|
+
cipher_text_public_key = cipher_text_private_key * etny_crypto.curve.g
|
|
47
|
+
return (ciphertext, nonce, auth_tag, cipher_text_public_key)
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def decrypt_aes_gcm(ciphertext, nonce, auth_tag, secret_key):
|
|
51
|
+
aes_cipher = AES.new(secret_key, AES.MODE_GCM, nonce)
|
|
52
|
+
plaintext = aes_cipher.decrypt_and_verify(ciphertext, auth_tag)
|
|
53
|
+
return plaintext
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def decrypt_ecc(encrypted_msg, priv_key):
|
|
57
|
+
(ciphertext, nonce, authTag, ciphertextPubKey) = encrypted_msg
|
|
58
|
+
shared_ecc_key = priv_key * ciphertextPubKey
|
|
59
|
+
secret_key = etny_crypto.ecc_point_to_256_bit_key(shared_ecc_key)
|
|
60
|
+
plaintext = etny_crypto.decrypt_aes_gcm(ciphertext, nonce, authTag, secret_key)
|
|
61
|
+
return plaintext
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def ecc_read_key(public_key_file):
|
|
65
|
+
with open(public_key_file) as r:
|
|
66
|
+
key = ECC.import_key(r.read())
|
|
67
|
+
return key
|
|
68
|
+
|
|
69
|
+
@staticmethod
|
|
70
|
+
def encrypt(public_key_file, message):
|
|
71
|
+
with open(public_key_file) as f:
|
|
72
|
+
ecc_public_cert = ECC.import_key(f.read())
|
|
73
|
+
pub_key_ecc_point = ec.Point(etny_crypto.curve, ecc_public_cert.pointQ.x.__int__(),
|
|
74
|
+
ecc_public_cert.pointQ.y.__int__())
|
|
75
|
+
encrypted_msg = etny_crypto.encrypt_ecc(message, pub_key_ecc_point)
|
|
76
|
+
return encrypted_msg
|
|
77
|
+
|
|
78
|
+
@staticmethod
|
|
79
|
+
def encrypt_with_pub_key(pub_key_content, message):
|
|
80
|
+
ecc_public_cert = ECC.import_key(pub_key_content)
|
|
81
|
+
pub_key_ecc_point = ec.Point(etny_crypto.curve, ecc_public_cert.pointQ.x.__int__(),
|
|
82
|
+
ecc_public_cert.pointQ.y.__int__())
|
|
83
|
+
encrypted_msg = etny_crypto.encrypt_ecc(message, pub_key_ecc_point)
|
|
84
|
+
return encrypted_msg
|
|
85
|
+
|
|
86
|
+
@staticmethod
|
|
87
|
+
def clean_private_key(private_key_data):
|
|
88
|
+
private_key_data = private_key_data.replace(b"-----BEGIN PRIVATE KEY-----", b"")
|
|
89
|
+
private_key_data = private_key_data.replace(b"-----END PRIVATE KEY-----", b"")
|
|
90
|
+
private_key_data = codecs.decode(private_key_data, 'base64')
|
|
91
|
+
return private_key_data
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
def decrypt(private_key_pem, encrypted_msg):
|
|
95
|
+
private_key_data = etny_crypto.clean_private_key(private_key_pem)
|
|
96
|
+
# decode der with asn1 library
|
|
97
|
+
# - get the octet string (field-2) containing the raw key
|
|
98
|
+
asn1_object, _ = decoder.decode(private_key_data)
|
|
99
|
+
raw_keys = asn1_object.getComponentByName('field-2').asOctets()
|
|
100
|
+
# - get the octet string (field-1) containing the raw private key
|
|
101
|
+
# and the bit string (field-2) containing the uncompressed public key
|
|
102
|
+
asn1_object, _ = decoder.decode(raw_keys)
|
|
103
|
+
private_key = asn1_object.getComponentByName('field-1').asOctets()
|
|
104
|
+
|
|
105
|
+
# Generating keypair for tinyEC
|
|
106
|
+
priv_key_tec = int.from_bytes(private_key, byteorder="big")
|
|
107
|
+
decrypted_msg = etny_crypto.decrypt_ecc(encrypted_msg, priv_key_tec)
|
|
108
|
+
#print("\ndecrypted msg:", decrypted_msg)
|
|
109
|
+
return decrypted_msg
|
|
110
|
+
|
|
111
|
+
@staticmethod
|
|
112
|
+
def encrypted_data_to_base64_json(encrypted_msg):
|
|
113
|
+
json_obj = {
|
|
114
|
+
'ciphertext': binascii.hexlify(encrypted_msg[0]).decode(),
|
|
115
|
+
'nonce': binascii.hexlify(encrypted_msg[1]).decode(),
|
|
116
|
+
'authTag': binascii.hexlify(encrypted_msg[2]).decode(),
|
|
117
|
+
'x': hex(encrypted_msg[3].x),
|
|
118
|
+
'y': hex(encrypted_msg[3].y)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
json_string = json.dumps(json_obj)
|
|
122
|
+
binary_data = json_string.encode('utf-8')
|
|
123
|
+
base64_data = base64.b64encode(binary_data)
|
|
124
|
+
|
|
125
|
+
return base64_data
|
|
126
|
+
|
|
127
|
+
@staticmethod
|
|
128
|
+
def encrypted_data_from_base64_json(base64_data):
|
|
129
|
+
# decode the base64-encoded string back to a JSON string
|
|
130
|
+
decoded_json_data = base64.b64decode(base64_data).decode('utf-8')
|
|
131
|
+
|
|
132
|
+
json_load = json.loads(decoded_json_data)
|
|
133
|
+
return (binascii.unhexlify(json_load['ciphertext'].encode()),
|
|
134
|
+
binascii.unhexlify(json_load['nonce'].encode()),
|
|
135
|
+
binascii.unhexlify(json_load['authTag'].encode()),
|
|
136
|
+
ec.Point(etny_crypto.curve, int(json_load['x'], 16),
|
|
137
|
+
int(json_load['y'], 16)))
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
def hex_to_bytes(hex_str: str) -> bytes:
|
|
141
|
+
return bytes.fromhex(hex_str[2:] if hex_str[:2] == "0x" else hex_str)
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def encrypt_nacl(public_key: str, data: bytes) -> str:
|
|
145
|
+
"""Encryption function using NaCl box compatible with MetaMask
|
|
146
|
+
For implementation used in MetaMask look into: https://github.com/MetaMask/eth-sig-util
|
|
147
|
+
Args:
|
|
148
|
+
public_key: public key of recipient (32 bytes)
|
|
149
|
+
data: message data
|
|
150
|
+
Returns:
|
|
151
|
+
encrypted data
|
|
152
|
+
"""
|
|
153
|
+
emph_key = PrivateKey.generate()
|
|
154
|
+
enc_box = Box(emph_key, PublicKey(etny_crypto.hex_to_bytes(public_key)))
|
|
155
|
+
# Encryption must work with MetaMask decryption (requires valid utf-8)
|
|
156
|
+
data = a85encode(data)
|
|
157
|
+
ciphertext = enc_box.encrypt(data)
|
|
158
|
+
result = bytes(emph_key.public_key) + ciphertext
|
|
159
|
+
return result.hex()
|
|
160
|
+
|
|
161
|
+
@staticmethod
|
|
162
|
+
def get_private_key_int(private_key_pem: bytes) -> int:
|
|
163
|
+
"""
|
|
164
|
+
Extracts the raw private key integer from a PEM-encoded private key via ASN.1 decoding.
|
|
165
|
+
Args:
|
|
166
|
+
private_key_pem (bytes): PEM-encoded private key.
|
|
167
|
+
Returns:
|
|
168
|
+
int: The private key scalar.
|
|
169
|
+
"""
|
|
170
|
+
private_key = etny_crypto.clean_private_key(private_key_pem)
|
|
171
|
+
asn1_object, _ = decoder.decode(private_key)
|
|
172
|
+
raw_keys = asn1_object.getComponentByName('field-2').asOctets()
|
|
173
|
+
asn1_object, _ = decoder.decode(raw_keys)
|
|
174
|
+
private_key_bytes = asn1_object.getComponentByName('field-1').asOctets()
|
|
175
|
+
return int.from_bytes(private_key_bytes, byteorder="big")
|
|
176
|
+
|
|
177
|
+
@staticmethod
|
|
178
|
+
def sign_data(private_key_pem: bytes, data: bytes) -> bytes:
|
|
179
|
+
"""
|
|
180
|
+
Signs data using the private key with ECDSA (secp384r1, SHA-256) and returns DER-encoded signature.
|
|
181
|
+
Args:
|
|
182
|
+
private_key_pem (bytes): PEM-encoded private key.
|
|
183
|
+
data (bytes): Data to sign.
|
|
184
|
+
Returns:
|
|
185
|
+
bytes: DER-encoded signature.
|
|
186
|
+
"""
|
|
187
|
+
priv_int = etny_crypto.get_private_key_int(private_key_pem)
|
|
188
|
+
sk = ecdsa.SigningKey.from_secret_exponent(priv_int, curve=ecdsa.curves.NIST384p, hashfunc=hashlib.sha256)
|
|
189
|
+
sig_der = sk.sign_deterministic(data, hashfunc=hashlib.sha256, sigencode=sigencode_der)
|
|
190
|
+
return sig_der
|
|
191
|
+
|
|
192
|
+
@staticmethod
|
|
193
|
+
def verify_signature(public_key_hex: str, data: bytes, sig_der: bytes) -> bool:
|
|
194
|
+
if public_key_hex.startswith('0x'):
|
|
195
|
+
public_key_hex = public_key_hex[2:]
|
|
196
|
+
pub_bytes = bytes.fromhex(public_key_hex)
|
|
197
|
+
curve = ecdsa.curves.NIST384p
|
|
198
|
+
try:
|
|
199
|
+
vk = ecdsa.VerifyingKey.from_string(
|
|
200
|
+
pub_bytes,
|
|
201
|
+
curve=curve,
|
|
202
|
+
hashfunc=hashlib.sha256,
|
|
203
|
+
valid_encodings={"raw", "compressed", "uncompressed", "hybrid"} # Add 'raw' here
|
|
204
|
+
)
|
|
205
|
+
assert vk.verify(sig_der, data, hashfunc=hashlib.sha256, sigdecode=sigdecode_der)
|
|
206
|
+
return True
|
|
207
|
+
except:
|
|
208
|
+
return False
|