naeural-client 2.3.6__py3-none-any.whl → 2.4.0__py3-none-any.whl
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.
- naeural_client/_ver.py +1 -1
- naeural_client/bc/base.py +4 -1
- naeural_client/bc/ec.py +265 -6
- {naeural_client-2.3.6.dist-info → naeural_client-2.4.0.dist-info}/METADATA +1 -1
- {naeural_client-2.3.6.dist-info → naeural_client-2.4.0.dist-info}/RECORD +8 -8
- {naeural_client-2.3.6.dist-info → naeural_client-2.4.0.dist-info}/WHEEL +0 -0
- {naeural_client-2.3.6.dist-info → naeural_client-2.4.0.dist-info}/entry_points.txt +0 -0
- {naeural_client-2.3.6.dist-info → naeural_client-2.4.0.dist-info}/licenses/LICENSE +0 -0
naeural_client/_ver.py
CHANGED
naeural_client/bc/base.py
CHANGED
naeural_client/bc/ec.py
CHANGED
@@ -3,6 +3,7 @@ import hashlib
|
|
3
3
|
import os
|
4
4
|
import binascii
|
5
5
|
import zlib
|
6
|
+
import json
|
6
7
|
|
7
8
|
from cryptography.hazmat.primitives import hashes
|
8
9
|
from cryptography.hazmat.primitives.asymmetric import ec
|
@@ -273,16 +274,16 @@ class BaseBCEllipticCurveEngine(BaseBlockEngine):
|
|
273
274
|
if debug:
|
274
275
|
print('derived-shared_key: ', base64.b64encode(derived_key))
|
275
276
|
return derived_key
|
276
|
-
|
277
277
|
|
278
|
-
|
278
|
+
|
279
|
+
def _encrypt(
|
279
280
|
self,
|
280
281
|
plaintext: str,
|
281
282
|
receiver_address: str,
|
282
|
-
compressed: bool = True,
|
283
|
-
embed_compressed: bool = True,
|
283
|
+
compressed: bool = True, # compressed is always True
|
284
|
+
embed_compressed: bool = True, # embed_compressed is always True
|
284
285
|
info: str = BCct.DEFAULT_INFO,
|
285
|
-
debug: bool = False
|
286
|
+
debug: bool = False,
|
286
287
|
):
|
287
288
|
"""
|
288
289
|
Encrypts plaintext using the sender's private key and receiver's public key,
|
@@ -307,6 +308,7 @@ class BaseBCEllipticCurveEngine(BaseBlockEngine):
|
|
307
308
|
str
|
308
309
|
The base64 encoded nonce and ciphertext.
|
309
310
|
"""
|
311
|
+
|
310
312
|
if compressed:
|
311
313
|
to_encrypt_data = zlib.compress(plaintext.encode())
|
312
314
|
compressed_flag = (1).to_bytes(1, byteorder='big')
|
@@ -325,8 +327,51 @@ class BaseBCEllipticCurveEngine(BaseBlockEngine):
|
|
325
327
|
encrypted_data = nonce + ciphertext # Prepend the nonce to the ciphertext
|
326
328
|
#end if
|
327
329
|
return base64.b64encode(encrypted_data).decode() # Encode to base64
|
330
|
+
|
331
|
+
|
332
|
+
def encrypt(
|
333
|
+
self,
|
334
|
+
plaintext: str,
|
335
|
+
receiver_address: str,
|
336
|
+
info: str = BCct.DEFAULT_INFO,
|
337
|
+
debug: bool = False,
|
338
|
+
**kwargs
|
339
|
+
):
|
340
|
+
"""
|
341
|
+
Encrypts plaintext using the sender's private key and receiver's public key,
|
342
|
+
then base64 encodes the output.
|
343
|
+
|
344
|
+
Parameters
|
345
|
+
----------
|
346
|
+
receiver_address : str
|
347
|
+
The receiver's address
|
348
|
+
|
349
|
+
plaintext : str
|
350
|
+
The plaintext to encrypt.
|
351
|
+
|
352
|
+
Obsolete:
|
353
|
+
compressed : bool, optional
|
354
|
+
Whether to compress the plaintext before encryption. The default is True.
|
355
|
+
|
356
|
+
embed_compressed : bool, optional
|
357
|
+
Whether to embed the compressed flag in the encrypted data. The default is True.
|
328
358
|
|
329
|
-
|
359
|
+
Returns
|
360
|
+
-------
|
361
|
+
str
|
362
|
+
The base64 encoded nonce and ciphertext.
|
363
|
+
"""
|
364
|
+
return self._encrypt(
|
365
|
+
plaintext=plaintext,
|
366
|
+
receiver_address=receiver_address,
|
367
|
+
compressed=True,
|
368
|
+
embed_compressed=True,
|
369
|
+
info=info,
|
370
|
+
debug=debug,
|
371
|
+
)
|
372
|
+
|
373
|
+
|
374
|
+
def _decrypt(
|
330
375
|
self,
|
331
376
|
encrypted_data_b64 : str,
|
332
377
|
sender_address : str,
|
@@ -395,6 +440,220 @@ class BaseBCEllipticCurveEngine(BaseBlockEngine):
|
|
395
440
|
result = None
|
396
441
|
return result
|
397
442
|
|
443
|
+
|
444
|
+
## Multi destination encryption
|
445
|
+
def encrypt_for_multi(
|
446
|
+
self,
|
447
|
+
plaintext: str,
|
448
|
+
receiver_addresses: list,
|
449
|
+
info: str = BCct.DEFAULT_INFO,
|
450
|
+
debug: bool = False
|
451
|
+
):
|
452
|
+
"""
|
453
|
+
Encrypts plaintext for multiple receivers.
|
454
|
+
|
455
|
+
The overall approach is to encrypt the plaintext with a symmetric key,
|
456
|
+
then encrypt the symmetric key with the public key of each receiver.
|
457
|
+
|
458
|
+
Parameters
|
459
|
+
----------
|
460
|
+
plaintext : str
|
461
|
+
The plaintext to encrypt.
|
462
|
+
|
463
|
+
receiver_addresses : list
|
464
|
+
List of receiver addresses.
|
465
|
+
|
466
|
+
Returns
|
467
|
+
-------
|
468
|
+
str
|
469
|
+
The base64 encoded encrypted package.
|
470
|
+
"""
|
471
|
+
to_encrypt_data = zlib.compress(plaintext.encode())
|
472
|
+
compressed_flag = (1).to_bytes(1, byteorder='big')
|
473
|
+
|
474
|
+
# Generate a random symmetric key
|
475
|
+
symmetric_key = os.urandom(32) # 256-bit key
|
476
|
+
|
477
|
+
# Encrypt the plaintext with the symmetric key
|
478
|
+
nonce = os.urandom(12)
|
479
|
+
aesgcm = AESGCM(symmetric_key)
|
480
|
+
ciphertext = aesgcm.encrypt(nonce, to_encrypt_data, None)
|
481
|
+
|
482
|
+
# For each receiver, encrypt the symmetric key
|
483
|
+
encrypted_keys = []
|
484
|
+
for receiver_address in receiver_addresses:
|
485
|
+
receiver_pk = self._address_to_pk(receiver_address)
|
486
|
+
shared_key = self.__derive_shared_key(receiver_pk, info=info, debug=debug)
|
487
|
+
# Use shared_key to encrypt the symmetric key
|
488
|
+
aesgcm_shared = AESGCM(shared_key)
|
489
|
+
nonce_shared = os.urandom(12)
|
490
|
+
encrypted_symmetric_key = aesgcm_shared.encrypt(nonce_shared, symmetric_key, None)
|
491
|
+
full_enc_key = nonce_shared + encrypted_symmetric_key
|
492
|
+
encrypted_keys.append({
|
493
|
+
'a': receiver_address, # Address of the receiver
|
494
|
+
'k': full_enc_key.hex() # Encrypted symmetric key
|
495
|
+
})
|
496
|
+
|
497
|
+
# Package the encrypted symmetric keys and the ciphertext
|
498
|
+
encrypted_package = {
|
499
|
+
'M': True, # Multi-recipient flag
|
500
|
+
'c': compressed_flag.hex(), # Compressed flag
|
501
|
+
'n': nonce.hex(), # Nonce
|
502
|
+
'd': ciphertext.hex(), # Ciphertext
|
503
|
+
'k': encrypted_keys # Encrypted symmetric keys
|
504
|
+
}
|
505
|
+
|
506
|
+
# Convert to JSON, compress, and base64 encode
|
507
|
+
enc_data = json.dumps(encrypted_package)
|
508
|
+
enc_data_compressed = zlib.compress(enc_data.encode())
|
509
|
+
enc_data_compressed_b64 = base64.b64encode(enc_data_compressed).decode()
|
510
|
+
return enc_data_compressed_b64
|
511
|
+
|
512
|
+
|
513
|
+
def decrypt_for_multi(
|
514
|
+
self,
|
515
|
+
encrypted_data_b64: str,
|
516
|
+
sender_address: str,
|
517
|
+
info: str = BCct.DEFAULT_INFO,
|
518
|
+
debug: bool = False
|
519
|
+
):
|
520
|
+
"""
|
521
|
+
Decrypts data encrypted for multiple receivers.
|
522
|
+
|
523
|
+
Parameters
|
524
|
+
----------
|
525
|
+
encrypted_data_b64 : str
|
526
|
+
The base64 encoded encrypted package as produced by encrypt_for_multi.
|
527
|
+
|
528
|
+
sender_address : str
|
529
|
+
The sender's address (public key address) used to derive the shared key.
|
530
|
+
|
531
|
+
info : str, optional
|
532
|
+
Additional info used in the HKDF for shared key derivation.
|
533
|
+
|
534
|
+
debug : bool, optional
|
535
|
+
If True, prints debug information.
|
536
|
+
|
537
|
+
Returns
|
538
|
+
-------
|
539
|
+
str or None
|
540
|
+
The decrypted plaintext as a string, or None if decryption fails.
|
541
|
+
"""
|
542
|
+
try:
|
543
|
+
# 1. Base64 decode
|
544
|
+
enc_data_compressed = base64.b64decode(encrypted_data_b64)
|
545
|
+
|
546
|
+
# 2. Decompress the JSON structure
|
547
|
+
enc_data_json = zlib.decompress(enc_data_compressed).decode()
|
548
|
+
|
549
|
+
# 3. Parse JSON
|
550
|
+
encrypted_package = json.loads(enc_data_json)
|
551
|
+
|
552
|
+
# Expecting keys: 'M', 'c', 'n', 'd', 'k'
|
553
|
+
# 'M' = True indicates multi-recipient
|
554
|
+
if 'M' not in encrypted_package or encrypted_package['M'] != True:
|
555
|
+
if debug:
|
556
|
+
self.P("Not a multi-recipient package.", color='y')
|
557
|
+
return None
|
558
|
+
|
559
|
+
# 'c' = compressed flag (hex)
|
560
|
+
compressed_flag_hex = encrypted_package['c']
|
561
|
+
compressed_flag = int(compressed_flag_hex, 16)
|
562
|
+
|
563
|
+
# 'n' = nonce (hex)
|
564
|
+
nonce = bytes.fromhex(encrypted_package['n'])
|
565
|
+
|
566
|
+
# 'd' = ciphertext (hex)
|
567
|
+
ciphertext = bytes.fromhex(encrypted_package['d'])
|
568
|
+
|
569
|
+
# 'k' = list of encrypted symmetric keys
|
570
|
+
encrypted_keys = encrypted_package['k']
|
571
|
+
|
572
|
+
# 4. Identify this receiver's encrypted symmetric key
|
573
|
+
my_address = self.address
|
574
|
+
my_encrypted_key_hex = None
|
575
|
+
for ek in encrypted_keys:
|
576
|
+
if ek['a'] == my_address:
|
577
|
+
my_encrypted_key_hex = ek['k']
|
578
|
+
break
|
579
|
+
|
580
|
+
if my_encrypted_key_hex is None:
|
581
|
+
if debug:
|
582
|
+
self.P("No encrypted symmetric key for this receiver.", color='r')
|
583
|
+
return None
|
584
|
+
|
585
|
+
# Decode the encrypted symmetric key
|
586
|
+
my_encrypted_key = bytes.fromhex(my_encrypted_key_hex)
|
587
|
+
|
588
|
+
# The first 12 bytes are nonce_shared, rest is encrypted symmetric key
|
589
|
+
nonce_shared = my_encrypted_key[:12]
|
590
|
+
encrypted_symmetric_key = my_encrypted_key[12:]
|
591
|
+
|
592
|
+
# 5. Derive shared key using sender's public key
|
593
|
+
sender_pk = self._address_to_pk(sender_address)
|
594
|
+
shared_key = self.__derive_shared_key(sender_pk, info=info, debug=debug)
|
595
|
+
|
596
|
+
# 6. Decrypt the symmetric key
|
597
|
+
aesgcm_shared = AESGCM(shared_key)
|
598
|
+
symmetric_key = aesgcm_shared.decrypt(nonce_shared, encrypted_symmetric_key, None)
|
599
|
+
|
600
|
+
# 7. Decrypt the ciphertext using the symmetric key
|
601
|
+
aesgcm = AESGCM(symmetric_key)
|
602
|
+
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
|
603
|
+
|
604
|
+
# 8. Decompress the plaintext if compressed_flag == 1
|
605
|
+
if compressed_flag == 1:
|
606
|
+
plaintext = zlib.decompress(plaintext)
|
607
|
+
|
608
|
+
return plaintext.decode()
|
609
|
+
|
610
|
+
except Exception as exc:
|
611
|
+
if debug:
|
612
|
+
self.P(f"Error decrypting multi scenario: {exc}", color='r')
|
613
|
+
return None
|
614
|
+
|
615
|
+
def decrypt(
|
616
|
+
self,
|
617
|
+
encrypted_data_b64: str,
|
618
|
+
sender_address: str,
|
619
|
+
info: str = BCct.DEFAULT_INFO,
|
620
|
+
debug: bool = False,
|
621
|
+
is_multi: bool = True
|
622
|
+
):
|
623
|
+
"""
|
624
|
+
Decrypts data encrypted for a single or multi receiver.
|
625
|
+
|
626
|
+
Parameters
|
627
|
+
----------
|
628
|
+
encrypted_data_b64 : str
|
629
|
+
The base64 encoded encrypted data.
|
630
|
+
|
631
|
+
sender_address : str
|
632
|
+
The sender's address (public key address) used to derive the shared key.
|
633
|
+
|
634
|
+
info : str, optional
|
635
|
+
Additional info used in the HKDF for shared key derivation.
|
636
|
+
|
637
|
+
debug : bool, optional
|
638
|
+
If True, prints debug information.
|
639
|
+
|
640
|
+
is_multi : bool, optional
|
641
|
+
If True, decrypts as multi-recipient package.
|
642
|
+
|
643
|
+
Returns
|
644
|
+
-------
|
645
|
+
str or None
|
646
|
+
The decrypted plaintext as a string, or None if decryption fails.
|
647
|
+
"""
|
648
|
+
result = None
|
649
|
+
if is_multi:
|
650
|
+
result = self.decrypt_for_multi(encrypted_data_b64, sender_address, info=info, debug=debug)
|
651
|
+
if result is None:
|
652
|
+
result = self._decrypt(encrypted_data_b64, sender_address, decompress=True, embed_compressed=True, info=info, debug=debug)
|
653
|
+
return result
|
654
|
+
|
655
|
+
|
656
|
+
## end multi destination encryption
|
398
657
|
|
399
658
|
|
400
659
|
### ETH
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: naeural_client
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.4.0
|
4
4
|
Summary: `naeural_client` is the Python SDK required for client app development for the Naeural Edge Protocol Edge Protocol framework
|
5
5
|
Project-URL: Homepage, https://github.com/NaeuralEdgeProtocol/naeural_client
|
6
6
|
Project-URL: Bug Tracker, https://github.com/NaeuralEdgeProtocol/naeural_client/issues
|
@@ -1,5 +1,5 @@
|
|
1
1
|
naeural_client/__init__.py,sha256=UKEDGS0wFYyxwmhEAKJGecO2vYbIfRYUP4SQgnK10IE,578
|
2
|
-
naeural_client/_ver.py,sha256=
|
2
|
+
naeural_client/_ver.py,sha256=0vYACBG2i5GW9sUazveVQKoboeDHa3NgO4La5KF2aQg,330
|
3
3
|
naeural_client/base_decentra_object.py,sha256=wXjl65gWxxkhV6Tq48wFfNGITvdYdkKPT-wLurGB5vc,4287
|
4
4
|
naeural_client/plugins_manager_mixin.py,sha256=X1JdGLDz0gN1rPnTN_5mJXR8JmqoBFQISJXmPR9yvCo,11106
|
5
5
|
naeural_client/base/__init__.py,sha256=hACh83_cIv7-PwYMM3bQm2IBmNqiHw-3PAfDfAEKz9A,259
|
@@ -13,9 +13,9 @@ naeural_client/base/transaction.py,sha256=bfs6td5M0fINgPQNxhrl_AUjb1YiilLDQ-Cd_o
|
|
13
13
|
naeural_client/base/payload/__init__.py,sha256=y8fBI8tG2ObNfaXFWjyWZXwu878FRYj_I8GIbHT4GKE,29
|
14
14
|
naeural_client/base/payload/payload.py,sha256=v50D7mBBD2WwWzvpbRGMSr-X6vv5ie21IY1aDxTqe1c,2275
|
15
15
|
naeural_client/bc/__init__.py,sha256=FQj23D1PrY06NUOARiKQi4cdj0-VxnoYgYDEht8lpr8,158
|
16
|
-
naeural_client/bc/base.py,sha256=
|
16
|
+
naeural_client/bc/base.py,sha256=i8xv19VBhWXcN4IRpphQS9YYmoM_6rWvPiCzBxV3KZY,30840
|
17
17
|
naeural_client/bc/chain.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
|
-
naeural_client/bc/ec.py,sha256=
|
18
|
+
naeural_client/bc/ec.py,sha256=L0KWdlsaR7lD--LtnwyBGbpiKHperxq1JLFYcNnFB50,22456
|
19
19
|
naeural_client/certs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
20
|
naeural_client/certs/r9092118.ala.eu-central-1.emqxsl.com.crt,sha256=y-6io0tseyx9-a4Pmde1z1gPULtJNSYUpG_YFkYaMKU,1337
|
21
21
|
naeural_client/cli/README.md,sha256=WPdI_EjzAbUW1aPyj1sSR8rLydcJKZtoiaEtklQrjHo,74
|
@@ -80,8 +80,8 @@ naeural_client/utils/__init__.py,sha256=mAnke3-MeRzz3nhQvhuHqLnpaaCSmDxicd7Ck9uw
|
|
80
80
|
naeural_client/utils/comm_utils.py,sha256=4cS9llRr_pK_3rNgDcRMCQwYPO0kcNU7AdWy_LtMyCY,1072
|
81
81
|
naeural_client/utils/config.py,sha256=t_VzyBnRHJa-Kt71HUu9gXxeDOri1Aqf_-gjO04gAYs,3681
|
82
82
|
naeural_client/utils/dotenv.py,sha256=_AgSo35n7EnQv5yDyu7C7i0kHragLJoCGydHjvOkrYY,2008
|
83
|
-
naeural_client-2.
|
84
|
-
naeural_client-2.
|
85
|
-
naeural_client-2.
|
86
|
-
naeural_client-2.
|
87
|
-
naeural_client-2.
|
83
|
+
naeural_client-2.4.0.dist-info/METADATA,sha256=mzcnBsvg7KtWXTjGruh8XKzuxxF7wp9UYuRPfUl-GR0,14449
|
84
|
+
naeural_client-2.4.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
|
85
|
+
naeural_client-2.4.0.dist-info/entry_points.txt,sha256=PNdyotDaQBAslZREx5luVyj0kqpQnwNACwkFNTPIHU4,55
|
86
|
+
naeural_client-2.4.0.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
|
87
|
+
naeural_client-2.4.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|