charm-crypto-framework 0.61.1__cp313-cp313-macosx_10_13_universal2.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.
- charm/__init__.py +5 -0
- charm/adapters/__init__.py +0 -0
- charm/adapters/abenc_adapt_hybrid.py +90 -0
- charm/adapters/dabenc_adapt_hybrid.py +145 -0
- charm/adapters/ibenc_adapt_hybrid.py +72 -0
- charm/adapters/ibenc_adapt_identityhash.py +80 -0
- charm/adapters/kpabenc_adapt_hybrid.py +91 -0
- charm/adapters/pkenc_adapt_bchk05.py +121 -0
- charm/adapters/pkenc_adapt_chk04.py +91 -0
- charm/adapters/pkenc_adapt_hybrid.py +98 -0
- charm/adapters/pksig_adapt_naor01.py +89 -0
- charm/config.py +7 -0
- charm/core/__init__.py +0 -0
- charm/core/benchmark/benchmark_util.c +353 -0
- charm/core/benchmark/benchmark_util.h +61 -0
- charm/core/benchmark/benchmarkmodule.c +476 -0
- charm/core/benchmark/benchmarkmodule.h +162 -0
- charm/core/benchmark.cpython-313-darwin.so +0 -0
- charm/core/crypto/AES/AES.c +1464 -0
- charm/core/crypto/AES.cpython-313-darwin.so +0 -0
- charm/core/crypto/DES/DES.c +113 -0
- charm/core/crypto/DES.cpython-313-darwin.so +0 -0
- charm/core/crypto/DES3/DES3.c +26 -0
- charm/core/crypto/DES3.cpython-313-darwin.so +0 -0
- charm/core/crypto/__init__.py +0 -0
- charm/core/crypto/cryptobase/XOR.c +80 -0
- charm/core/crypto/cryptobase/_counter.c +496 -0
- charm/core/crypto/cryptobase/_counter.h +54 -0
- charm/core/crypto/cryptobase/block_template.c +900 -0
- charm/core/crypto/cryptobase/block_template.h +69 -0
- charm/core/crypto/cryptobase/cryptobasemodule.c +220 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt.h +90 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_argchk.h +44 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_cfg.h +186 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_cipher.h +941 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_custom.h +556 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_des.c +1912 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_hash.h +407 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_mac.h +496 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_macros.h +435 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_math.h +534 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_misc.h +103 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_pk.h +653 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_pkcs.h +90 -0
- charm/core/crypto/cryptobase/libtom/tomcrypt_prng.h +199 -0
- charm/core/crypto/cryptobase/stream_template.c +271 -0
- charm/core/crypto/cryptobase/strxor.c +229 -0
- charm/core/crypto/cryptobase.cpython-313-darwin.so +0 -0
- charm/core/engine/__init__.py +5 -0
- charm/core/engine/protocol.py +293 -0
- charm/core/engine/util.py +174 -0
- charm/core/math/__init__.py +0 -0
- charm/core/math/elliptic_curve/ecmodule.c +1986 -0
- charm/core/math/elliptic_curve/ecmodule.h +230 -0
- charm/core/math/elliptic_curve.cpython-313-darwin.so +0 -0
- charm/core/math/elliptic_curve.pyi +63 -0
- charm/core/math/integer/integermodule.c +2539 -0
- charm/core/math/integer/integermodule.h +145 -0
- charm/core/math/integer.cpython-313-darwin.so +0 -0
- charm/core/math/integer.pyi +76 -0
- charm/core/math/pairing/miracl/miracl_config.h +37 -0
- charm/core/math/pairing/miracl/miracl_interface.h +118 -0
- charm/core/math/pairing/miracl/miracl_interface2.h +126 -0
- charm/core/math/pairing/miracl/pairingmodule2.c +2094 -0
- charm/core/math/pairing/miracl/pairingmodule2.h +307 -0
- charm/core/math/pairing/pairingmodule.c +2230 -0
- charm/core/math/pairing/pairingmodule.h +241 -0
- charm/core/math/pairing/relic/pairingmodule3.c +1853 -0
- charm/core/math/pairing/relic/pairingmodule3.h +233 -0
- charm/core/math/pairing/relic/relic_interface.c +1337 -0
- charm/core/math/pairing/relic/relic_interface.h +217 -0
- charm/core/math/pairing/relic/test_relic.c +171 -0
- charm/core/math/pairing.cpython-313-darwin.so +0 -0
- charm/core/math/pairing.pyi +69 -0
- charm/core/utilities/base64.c +248 -0
- charm/core/utilities/base64.h +15 -0
- charm/schemes/__init__.py +0 -0
- charm/schemes/abenc/__init__.py +0 -0
- charm/schemes/abenc/abenc_accountability_jyjxgd20.py +647 -0
- charm/schemes/abenc/abenc_bsw07.py +146 -0
- charm/schemes/abenc/abenc_ca_cpabe_ar17.py +684 -0
- charm/schemes/abenc/abenc_dacmacs_yj14.py +298 -0
- charm/schemes/abenc/abenc_lsw08.py +159 -0
- charm/schemes/abenc/abenc_maabe_rw15.py +236 -0
- charm/schemes/abenc/abenc_maabe_yj14.py +297 -0
- charm/schemes/abenc/abenc_tbpre_lww14.py +309 -0
- charm/schemes/abenc/abenc_unmcpabe_yahk14.py +223 -0
- charm/schemes/abenc/abenc_waters09.py +144 -0
- charm/schemes/abenc/abenc_yct14.py +208 -0
- charm/schemes/abenc/abenc_yllc15.py +178 -0
- charm/schemes/abenc/ac17.py +248 -0
- charm/schemes/abenc/bsw07.py +141 -0
- charm/schemes/abenc/cgw15.py +277 -0
- charm/schemes/abenc/dabe_aw11.py +204 -0
- charm/schemes/abenc/dfa_fe12.py +144 -0
- charm/schemes/abenc/pk_hve08.py +179 -0
- charm/schemes/abenc/waters11.py +143 -0
- charm/schemes/aggrsign_MuSig.py +150 -0
- charm/schemes/aggrsign_bls.py +267 -0
- charm/schemes/blindsig_ps16.py +654 -0
- charm/schemes/chamhash_adm05.py +113 -0
- charm/schemes/chamhash_rsa_hw09.py +100 -0
- charm/schemes/commit/__init__.py +0 -0
- charm/schemes/commit/commit_gs08.py +77 -0
- charm/schemes/commit/commit_pedersen92.py +53 -0
- charm/schemes/encap_bchk05.py +62 -0
- charm/schemes/grpsig/__init__.py +0 -0
- charm/schemes/grpsig/groupsig_bgls04.py +114 -0
- charm/schemes/grpsig/groupsig_bgls04_var.py +115 -0
- charm/schemes/hibenc/__init__.py +0 -0
- charm/schemes/hibenc/hibenc_bb04.py +105 -0
- charm/schemes/hibenc/hibenc_lew11.py +193 -0
- charm/schemes/ibenc/__init__.py +0 -0
- charm/schemes/ibenc/clpkc_rp03.py +119 -0
- charm/schemes/ibenc/ibenc_CW13_z.py +168 -0
- charm/schemes/ibenc/ibenc_bb03.py +94 -0
- charm/schemes/ibenc/ibenc_bf01.py +121 -0
- charm/schemes/ibenc/ibenc_ckrs09.py +120 -0
- charm/schemes/ibenc/ibenc_cllww12_z.py +172 -0
- charm/schemes/ibenc/ibenc_lsw08.py +120 -0
- charm/schemes/ibenc/ibenc_sw05.py +238 -0
- charm/schemes/ibenc/ibenc_waters05.py +144 -0
- charm/schemes/ibenc/ibenc_waters05_z.py +164 -0
- charm/schemes/ibenc/ibenc_waters09.py +107 -0
- charm/schemes/ibenc/ibenc_waters09_z.py +147 -0
- charm/schemes/joye_scheme.py +106 -0
- charm/schemes/lem_scheme.py +207 -0
- charm/schemes/pk_fre_ccv11.py +107 -0
- charm/schemes/pk_vrf.py +127 -0
- charm/schemes/pkenc/__init__.py +0 -0
- charm/schemes/pkenc/pkenc_cs98.py +108 -0
- charm/schemes/pkenc/pkenc_elgamal85.py +122 -0
- charm/schemes/pkenc/pkenc_gm82.py +98 -0
- charm/schemes/pkenc/pkenc_paillier99.py +118 -0
- charm/schemes/pkenc/pkenc_rabin.py +254 -0
- charm/schemes/pkenc/pkenc_rsa.py +186 -0
- charm/schemes/pksig/__init__.py +0 -0
- charm/schemes/pksig/pksig_CW13_z.py +135 -0
- charm/schemes/pksig/pksig_bls04.py +87 -0
- charm/schemes/pksig/pksig_boyen.py +156 -0
- charm/schemes/pksig/pksig_chch.py +97 -0
- charm/schemes/pksig/pksig_chp.py +70 -0
- charm/schemes/pksig/pksig_cl03.py +150 -0
- charm/schemes/pksig/pksig_cl04.py +87 -0
- charm/schemes/pksig/pksig_cllww12_z.py +142 -0
- charm/schemes/pksig/pksig_cyh.py +132 -0
- charm/schemes/pksig/pksig_dsa.py +76 -0
- charm/schemes/pksig/pksig_ecdsa.py +71 -0
- charm/schemes/pksig/pksig_hess.py +104 -0
- charm/schemes/pksig/pksig_hw.py +110 -0
- charm/schemes/pksig/pksig_lamport.py +63 -0
- charm/schemes/pksig/pksig_ps01.py +135 -0
- charm/schemes/pksig/pksig_ps02.py +124 -0
- charm/schemes/pksig/pksig_ps03.py +119 -0
- charm/schemes/pksig/pksig_rsa_hw09.py +206 -0
- charm/schemes/pksig/pksig_schnorr91.py +77 -0
- charm/schemes/pksig/pksig_waters.py +115 -0
- charm/schemes/pksig/pksig_waters05.py +121 -0
- charm/schemes/pksig/pksig_waters09.py +121 -0
- charm/schemes/pre_mg07.py +150 -0
- charm/schemes/prenc/pre_afgh06.py +126 -0
- charm/schemes/prenc/pre_bbs98.py +123 -0
- charm/schemes/prenc/pre_nal16.py +216 -0
- charm/schemes/protocol_a01.py +272 -0
- charm/schemes/protocol_ao00.py +215 -0
- charm/schemes/protocol_cns07.py +274 -0
- charm/schemes/protocol_schnorr91.py +125 -0
- charm/schemes/sigma1.py +64 -0
- charm/schemes/sigma2.py +129 -0
- charm/schemes/sigma3.py +126 -0
- charm/schemes/threshold/__init__.py +59 -0
- charm/schemes/threshold/dkls23_dkg.py +556 -0
- charm/schemes/threshold/dkls23_presign.py +1089 -0
- charm/schemes/threshold/dkls23_sign.py +761 -0
- charm/schemes/threshold/xrpl_wallet.py +967 -0
- charm/test/__init__.py +0 -0
- charm/test/adapters/__init__.py +0 -0
- charm/test/adapters/abenc_adapt_hybrid_test.py +29 -0
- charm/test/adapters/dabenc_adapt_hybrid_test.py +56 -0
- charm/test/adapters/ibenc_adapt_hybrid_test.py +36 -0
- charm/test/adapters/ibenc_adapt_identityhash_test.py +32 -0
- charm/test/adapters/kpabenc_adapt_hybrid_test.py +30 -0
- charm/test/benchmark/abenc_yllc15_bench.py +92 -0
- charm/test/benchmark/benchmark_test.py +148 -0
- charm/test/benchmark_threshold.py +260 -0
- charm/test/conftest.py +38 -0
- charm/test/fuzz/__init__.py +1 -0
- charm/test/fuzz/conftest.py +5 -0
- charm/test/fuzz/fuzz_policy_parser.py +76 -0
- charm/test/fuzz/fuzz_serialization.py +83 -0
- charm/test/schemes/__init__.py +0 -0
- charm/test/schemes/abenc/__init__.py +0 -0
- charm/test/schemes/abenc/abenc_bsw07_test.py +39 -0
- charm/test/schemes/abenc/abenc_dacmacs_yj14_test.py +16 -0
- charm/test/schemes/abenc/abenc_lsw08_test.py +33 -0
- charm/test/schemes/abenc/abenc_maabe_yj14_test.py +16 -0
- charm/test/schemes/abenc/abenc_tbpre_lww14_test.py +16 -0
- charm/test/schemes/abenc/abenc_waters09_test.py +38 -0
- charm/test/schemes/abenc/abenc_yllc15_test.py +74 -0
- charm/test/schemes/chamhash_adm05_test.py +31 -0
- charm/test/schemes/chamhash_rsa_hw09_test.py +29 -0
- charm/test/schemes/commit/__init__.py +0 -0
- charm/test/schemes/commit/commit_gs08_test.py +24 -0
- charm/test/schemes/commit/commit_pedersen92_test.py +26 -0
- charm/test/schemes/dabe_aw11_test.py +45 -0
- charm/test/schemes/encap_bchk05_test.py +21 -0
- charm/test/schemes/grpsig/__init__.py +0 -0
- charm/test/schemes/grpsig/groupsig_bgls04_test.py +35 -0
- charm/test/schemes/grpsig/groupsig_bgls04_var_test.py +39 -0
- charm/test/schemes/hibenc/__init__.py +0 -0
- charm/test/schemes/hibenc/hibenc_bb04_test.py +28 -0
- charm/test/schemes/ibenc/__init__.py +0 -0
- charm/test/schemes/ibenc/ibenc_bb03_test.py +26 -0
- charm/test/schemes/ibenc/ibenc_bf01_test.py +24 -0
- charm/test/schemes/ibenc/ibenc_ckrs09_test.py +25 -0
- charm/test/schemes/ibenc/ibenc_lsw08_test.py +31 -0
- charm/test/schemes/ibenc/ibenc_sw05_test.py +32 -0
- charm/test/schemes/ibenc/ibenc_waters05_test.py +31 -0
- charm/test/schemes/ibenc/ibenc_waters09_test.py +27 -0
- charm/test/schemes/pk_vrf_test.py +29 -0
- charm/test/schemes/pkenc/__init__.py +0 -0
- charm/test/schemes/pkenc_test.py +255 -0
- charm/test/schemes/pksig/__init__.py +0 -0
- charm/test/schemes/pksig_test.py +376 -0
- charm/test/schemes/rsa_alg_test.py +340 -0
- charm/test/schemes/threshold_test.py +1792 -0
- charm/test/serialize/__init__.py +0 -0
- charm/test/serialize/serialize_test.py +40 -0
- charm/test/toolbox/__init__.py +0 -0
- charm/test/toolbox/conversion_test.py +30 -0
- charm/test/toolbox/ecgroup_test.py +53 -0
- charm/test/toolbox/integer_arithmetic_test.py +441 -0
- charm/test/toolbox/paddingschemes_test.py +238 -0
- charm/test/toolbox/policy_parser_stress_test.py +969 -0
- charm/test/toolbox/secretshare_test.py +28 -0
- charm/test/toolbox/symcrypto_test.py +108 -0
- charm/test/toolbox/test_policy_expression.py +16 -0
- charm/test/vectors/__init__.py +1 -0
- charm/test/vectors/test_bls_vectors.py +289 -0
- charm/test/vectors/test_pedersen_vectors.py +315 -0
- charm/test/vectors/test_schnorr_vectors.py +368 -0
- charm/test/zkp_compiler/__init__.py +9 -0
- charm/test/zkp_compiler/benchmark_zkp.py +258 -0
- charm/test/zkp_compiler/test_and_proof.py +240 -0
- charm/test/zkp_compiler/test_batch_verify.py +248 -0
- charm/test/zkp_compiler/test_dleq_proof.py +264 -0
- charm/test/zkp_compiler/test_or_proof.py +231 -0
- charm/test/zkp_compiler/test_proof_serialization.py +121 -0
- charm/test/zkp_compiler/test_range_proof.py +241 -0
- charm/test/zkp_compiler/test_representation_proof.py +325 -0
- charm/test/zkp_compiler/test_schnorr_proof.py +221 -0
- charm/test/zkp_compiler/test_thread_safety.py +169 -0
- charm/test/zkp_compiler/test_zkp_parser.py +139 -0
- charm/toolbox/ABEnc.py +26 -0
- charm/toolbox/ABEncMultiAuth.py +66 -0
- charm/toolbox/ABEnumeric.py +800 -0
- charm/toolbox/Commit.py +24 -0
- charm/toolbox/DFA.py +89 -0
- charm/toolbox/FSA.py +1254 -0
- charm/toolbox/Hash.py +39 -0
- charm/toolbox/IBEnc.py +62 -0
- charm/toolbox/IBSig.py +64 -0
- charm/toolbox/PKEnc.py +66 -0
- charm/toolbox/PKSig.py +56 -0
- charm/toolbox/PREnc.py +32 -0
- charm/toolbox/ZKProof.py +289 -0
- charm/toolbox/__init__.py +0 -0
- charm/toolbox/bitstring.py +49 -0
- charm/toolbox/broadcast.py +220 -0
- charm/toolbox/conversion.py +100 -0
- charm/toolbox/eccurve.py +149 -0
- charm/toolbox/ecgroup.py +143 -0
- charm/toolbox/enum.py +60 -0
- charm/toolbox/hash_module.py +91 -0
- charm/toolbox/integergroup.py +323 -0
- charm/toolbox/iterate.py +22 -0
- charm/toolbox/matrixops.py +76 -0
- charm/toolbox/mpc_utils.py +296 -0
- charm/toolbox/msp.py +175 -0
- charm/toolbox/mta.py +985 -0
- charm/toolbox/node.py +120 -0
- charm/toolbox/ot/__init__.py +22 -0
- charm/toolbox/ot/base_ot.py +374 -0
- charm/toolbox/ot/dpf.py +642 -0
- charm/toolbox/ot/mpfss.py +228 -0
- charm/toolbox/ot/ot_extension.py +589 -0
- charm/toolbox/ot/silent_ot.py +378 -0
- charm/toolbox/paddingschemes.py +423 -0
- charm/toolbox/paddingschemes_test.py +238 -0
- charm/toolbox/pairingcurves.py +85 -0
- charm/toolbox/pairinggroup.py +186 -0
- charm/toolbox/policy_expression_spec.py +70 -0
- charm/toolbox/policytree.py +189 -0
- charm/toolbox/reCompiler.py +346 -0
- charm/toolbox/redundancyschemes.py +65 -0
- charm/toolbox/schemebase.py +188 -0
- charm/toolbox/secretshare.py +104 -0
- charm/toolbox/secretutil.py +174 -0
- charm/toolbox/securerandom.py +73 -0
- charm/toolbox/sigmaprotocol.py +46 -0
- charm/toolbox/specialprimes.py +45 -0
- charm/toolbox/symcrypto.py +279 -0
- charm/toolbox/threshold_sharing.py +553 -0
- charm/toolbox/xmlserialize.py +94 -0
- charm/toolbox/zknode.py +105 -0
- charm/zkp_compiler/__init__.py +89 -0
- charm/zkp_compiler/and_proof.py +460 -0
- charm/zkp_compiler/batch_verify.py +324 -0
- charm/zkp_compiler/dleq_proof.py +423 -0
- charm/zkp_compiler/or_proof.py +305 -0
- charm/zkp_compiler/range_proof.py +417 -0
- charm/zkp_compiler/representation_proof.py +466 -0
- charm/zkp_compiler/schnorr_proof.py +273 -0
- charm/zkp_compiler/thread_safe.py +150 -0
- charm/zkp_compiler/zk_demo.py +489 -0
- charm/zkp_compiler/zkp_factory.py +330 -0
- charm/zkp_compiler/zkp_generator.py +370 -0
- charm/zkp_compiler/zkparser.py +269 -0
- charm_crypto_framework-0.61.1.dist-info/METADATA +337 -0
- charm_crypto_framework-0.61.1.dist-info/RECORD +323 -0
- charm_crypto_framework-0.61.1.dist-info/WHEEL +5 -0
- charm_crypto_framework-0.61.1.dist-info/licenses/LICENSE.txt +165 -0
- charm_crypto_framework-0.61.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
'''
|
|
2
|
+
**User Collusion Avoidance CP-ABE (AR17)**
|
|
3
|
+
|
|
4
|
+
*Authors:* Jiguo Li, Wei Yao, Jinguang Han, Yichen Zhang, Jian Shen
|
|
5
|
+
|
|
6
|
+
| **Title:** "User Collusion Avoidance CP-ABE With Efficient Attribute Revocation for Cloud Storage"
|
|
7
|
+
| **Published in:** IEEE Systems Journal, 2017
|
|
8
|
+
| **Available from:** https://ieeexplore.ieee.org/abstract/document/7867082
|
|
9
|
+
| **Notes:** Supports user collusion avoidance with efficient attribute revocation
|
|
10
|
+
|
|
11
|
+
.. rubric:: Scheme Properties
|
|
12
|
+
|
|
13
|
+
* **Type:** ciphertext-policy attribute-based encryption (public key)
|
|
14
|
+
* **Setting:** Pairing groups
|
|
15
|
+
* **Assumption:** Decisional Bilinear Diffie-Hellman
|
|
16
|
+
|
|
17
|
+
.. rubric:: Implementation
|
|
18
|
+
|
|
19
|
+
:Authors: Ahmed Bakr
|
|
20
|
+
:Date: 07/2023
|
|
21
|
+
'''
|
|
22
|
+
from charm.toolbox.pairinggroup import PairingGroup,ZR,G1,G2,GT,pair
|
|
23
|
+
from charm.toolbox.secretutil import SecretUtil
|
|
24
|
+
from charm.toolbox.ABEnc import ABEnc, Input, Output
|
|
25
|
+
|
|
26
|
+
from typing import Dict, List, Tuple
|
|
27
|
+
import queue
|
|
28
|
+
|
|
29
|
+
# type annotations
|
|
30
|
+
mk_t = {'beta':ZR, 'g_alpha':G1 }
|
|
31
|
+
pp_t = { 'g':G1, 'g_beta':G1, 'g_1_over_beta':G1, 'e_gg_alpha':GT }
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TreeNode:
|
|
36
|
+
def __init__(self, sequence_number, value, parent=None):
|
|
37
|
+
self.parent = parent
|
|
38
|
+
self.sequence_number = sequence_number
|
|
39
|
+
self.value = value
|
|
40
|
+
self.left = None
|
|
41
|
+
self.right = None
|
|
42
|
+
|
|
43
|
+
def __str__(self):
|
|
44
|
+
return str(self.sequence_number)
|
|
45
|
+
|
|
46
|
+
def __repr__(self):
|
|
47
|
+
return self.__str__()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class UsersBinaryTree:
|
|
51
|
+
"""
|
|
52
|
+
A binary tree that is used to assign users to leafs in a deterministic way.
|
|
53
|
+
The tree is created and maintained by the AM.
|
|
54
|
+
"""
|
|
55
|
+
def __init__(self, group_obj):
|
|
56
|
+
self.group = group_obj
|
|
57
|
+
self.leafs_queue = queue.Queue()
|
|
58
|
+
self.sequence_number = 0
|
|
59
|
+
self.root = self.create_node()
|
|
60
|
+
self.leafs_queue.put(self.root)
|
|
61
|
+
self.__curr_node = self.leafs_queue.get()
|
|
62
|
+
|
|
63
|
+
def create_node(self) -> TreeNode:
|
|
64
|
+
self.sequence_number += 1
|
|
65
|
+
return TreeNode(self.sequence_number, self.group.random(ZR))
|
|
66
|
+
|
|
67
|
+
def add_node_to_tree(self, tree_node: TreeNode):
|
|
68
|
+
"""
|
|
69
|
+
Add a node to the tree.
|
|
70
|
+
Inputs:
|
|
71
|
+
- tree_node: a node to be added to the tree
|
|
72
|
+
"""
|
|
73
|
+
if self.__curr_node.left and self.__curr_node.right:
|
|
74
|
+
assert not self.leafs_queue.empty(), "Leafs queue is empty and pull attempts was made"
|
|
75
|
+
self.__curr_node = self.leafs_queue.get()
|
|
76
|
+
if not self.__curr_node.left:
|
|
77
|
+
self.__curr_node.left = tree_node
|
|
78
|
+
elif not self.__curr_node.right:
|
|
79
|
+
self.__curr_node.right = tree_node
|
|
80
|
+
else:
|
|
81
|
+
assert True, "This statement should not be reached"
|
|
82
|
+
tree_node.parent = self.__curr_node
|
|
83
|
+
self.leafs_queue.put(tree_node)
|
|
84
|
+
|
|
85
|
+
def print_tree(self):
|
|
86
|
+
print("{", end='')
|
|
87
|
+
self.__print_tree_rec(self.root)
|
|
88
|
+
print("}")
|
|
89
|
+
|
|
90
|
+
def __print_tree_rec(self, node: TreeNode):
|
|
91
|
+
print(node, end=', ')
|
|
92
|
+
if node.left:
|
|
93
|
+
self.__print_tree_rec(node.left)
|
|
94
|
+
if node.right:
|
|
95
|
+
self.__print_tree_rec(node.right)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class AM:
|
|
99
|
+
"""Attribute Manager (AM)"""
|
|
100
|
+
def __init__(self, group_obj):
|
|
101
|
+
self.users_to_attrs_dict: Dict[str, list] = {}
|
|
102
|
+
self.attrs_to_users_dict: Dict[str, list] = {}
|
|
103
|
+
|
|
104
|
+
self.users_binary_tree = UsersBinaryTree(group_obj)
|
|
105
|
+
|
|
106
|
+
def add_attr_to_user(self, attr_str: str, user_name: str):
|
|
107
|
+
if user_name not in self.users_to_attrs_dict:
|
|
108
|
+
self.users_to_attrs_dict[user_name] = []
|
|
109
|
+
self.__create_node_in_binary_tree_for_new_user()
|
|
110
|
+
|
|
111
|
+
if attr_str not in self.attrs_to_users_dict:
|
|
112
|
+
self.attrs_to_users_dict[attr_str] = []
|
|
113
|
+
|
|
114
|
+
self.users_to_attrs_dict[user_name].append(attr_str) # AB: It is assumed that this attribute does not already
|
|
115
|
+
# exist in the list
|
|
116
|
+
self.attrs_to_users_dict[attr_str].append(user_name) # AB: It is assumed that the username does not already
|
|
117
|
+
# exist in the list
|
|
118
|
+
|
|
119
|
+
def __create_node_in_binary_tree_for_new_user(self):
|
|
120
|
+
current_number_of_users = len(list(self.users_to_attrs_dict.keys())) # AB: make sure to add the new user to the
|
|
121
|
+
# dict first before calling this function
|
|
122
|
+
while not current_number_of_users == self.users_binary_tree.leafs_queue.qsize():
|
|
123
|
+
new_node = self.users_binary_tree.create_node()
|
|
124
|
+
self.users_binary_tree.add_node_to_tree(new_node)
|
|
125
|
+
|
|
126
|
+
def remove_attr_from_user(self, attr_str: str, user_name: str):
|
|
127
|
+
index = self.attrs_to_users_dict[attr_str].index(user_name)
|
|
128
|
+
self.attrs_to_users_dict[attr_str].pop(index)
|
|
129
|
+
|
|
130
|
+
index = self.users_to_attrs_dict[user_name].index(attr_str)
|
|
131
|
+
self.users_to_attrs_dict[user_name].pop(index)
|
|
132
|
+
|
|
133
|
+
def get_user_assignation_to_leafs_dict(self) -> Dict[str, TreeNode]:
|
|
134
|
+
user_names_list = list(self.users_to_attrs_dict.keys())
|
|
135
|
+
assert len(user_names_list) == self.users_binary_tree.leafs_queue.qsize(), "The number of usernames list ({})" \
|
|
136
|
+
" has to match the number of leaf" \
|
|
137
|
+
" elements ({}) in the binary tree".format(
|
|
138
|
+
len(user_names_list), self.users_binary_tree.leafs_queue.qsize())
|
|
139
|
+
ret_dict: Dict[str, TreeNode] = {}
|
|
140
|
+
for user_name, leaf in zip(user_names_list, self.users_binary_tree.leafs_queue.queue):
|
|
141
|
+
ret_dict[user_name] = leaf
|
|
142
|
+
|
|
143
|
+
return ret_dict
|
|
144
|
+
|
|
145
|
+
def get_minimum_nodes_list_that_represent_users_list(self, user_names_list: List[str]) -> List[TreeNode]:
|
|
146
|
+
"""
|
|
147
|
+
This is represented in the paper as calculating node(Gi)
|
|
148
|
+
"""
|
|
149
|
+
visited_arr = [False] * (self.users_binary_tree.sequence_number + 1)
|
|
150
|
+
list_of_leaves_to_traverse = []
|
|
151
|
+
|
|
152
|
+
user_assignation_to_leafs_dict = self.get_user_assignation_to_leafs_dict()
|
|
153
|
+
for user_name in user_names_list:
|
|
154
|
+
user_leaf_node = user_assignation_to_leafs_dict[user_name]
|
|
155
|
+
visited_arr[user_leaf_node.sequence_number] = True
|
|
156
|
+
list_of_leaves_to_traverse.append(user_leaf_node)
|
|
157
|
+
|
|
158
|
+
self.__traverse_to_mark_all_children_visited_arr(self.users_binary_tree.root, visited_arr)
|
|
159
|
+
|
|
160
|
+
return self.__traverse_bfs_to_get_minimum_number_nodes_to_cover_users_list(visited_arr)
|
|
161
|
+
|
|
162
|
+
def __traverse_to_mark_all_children_visited_arr(self, node: TreeNode, visited_arr: List[bool]):
|
|
163
|
+
is_leaf = not node.left and not node.right
|
|
164
|
+
if is_leaf:
|
|
165
|
+
return
|
|
166
|
+
if node.left:
|
|
167
|
+
self.__traverse_to_mark_all_children_visited_arr(node.left, visited_arr)
|
|
168
|
+
if node.right:
|
|
169
|
+
self.__traverse_to_mark_all_children_visited_arr(node.right, visited_arr)
|
|
170
|
+
|
|
171
|
+
visited_arr[node.sequence_number] = visited_arr[node.left.sequence_number] and visited_arr[
|
|
172
|
+
node.right.sequence_number]
|
|
173
|
+
|
|
174
|
+
def __traverse_bfs_to_get_minimum_number_nodes_to_cover_users_list(self, visited_arr) -> List[TreeNode]:
|
|
175
|
+
ret_list = []
|
|
176
|
+
q = queue.Queue()
|
|
177
|
+
q.put(self.users_binary_tree.root)
|
|
178
|
+
|
|
179
|
+
while not q.empty():
|
|
180
|
+
node: TreeNode = q.get()
|
|
181
|
+
if visited_arr[node.sequence_number]:
|
|
182
|
+
ret_list.append(node)
|
|
183
|
+
else:
|
|
184
|
+
if node.left:
|
|
185
|
+
q.put(node.left)
|
|
186
|
+
if node.right:
|
|
187
|
+
q.put(node.right)
|
|
188
|
+
|
|
189
|
+
return ret_list
|
|
190
|
+
|
|
191
|
+
def get_user_path(self, user_name) -> List[TreeNode]:
|
|
192
|
+
ret_list = []
|
|
193
|
+
user_assignation_to_leafs_dict = self.get_user_assignation_to_leafs_dict()
|
|
194
|
+
assert user_name in user_assignation_to_leafs_dict, \
|
|
195
|
+
"Username ({}) must be inside user_assignation_to_leafs_dict ({})".format(user_name,
|
|
196
|
+
user_assignation_to_leafs_dict)
|
|
197
|
+
user_leaf_node = user_assignation_to_leafs_dict[user_name]
|
|
198
|
+
curr_node: TreeNode = user_leaf_node
|
|
199
|
+
while curr_node:
|
|
200
|
+
ret_list.append(curr_node)
|
|
201
|
+
curr_node = curr_node.parent
|
|
202
|
+
|
|
203
|
+
return ret_list
|
|
204
|
+
|
|
205
|
+
@staticmethod
|
|
206
|
+
def get_user_path_intersection_with_node_gi(user_path: List[TreeNode], node_gi: List[TreeNode]) -> List[TreeNode]:
|
|
207
|
+
ret_intersection_list = []
|
|
208
|
+
for user_node in user_path:
|
|
209
|
+
if user_node in node_gi:
|
|
210
|
+
ret_intersection_list.append(user_node)
|
|
211
|
+
|
|
212
|
+
return ret_intersection_list
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
class CaCpabeAr(ABEnc):
|
|
216
|
+
def __init__(self, group_obj):
|
|
217
|
+
ABEnc.__init__(self)
|
|
218
|
+
self.util = SecretUtil(group_obj, verbose=False)
|
|
219
|
+
self.group = group_obj
|
|
220
|
+
|
|
221
|
+
def system_setup(self) -> (mk_t, pp_t):
|
|
222
|
+
"""
|
|
223
|
+
System Setup algorithm. This algorithm is performed by TA
|
|
224
|
+
Inputs:
|
|
225
|
+
- None
|
|
226
|
+
Outputs:
|
|
227
|
+
- MK: TA's master secret key.
|
|
228
|
+
- PP: Public Parameters.
|
|
229
|
+
"""
|
|
230
|
+
alpha, beta = self.group.random(ZR), self.group.random(ZR)
|
|
231
|
+
g = self.group.random(G1)
|
|
232
|
+
|
|
233
|
+
MK = {'beta': beta, 'g_alpha': g ** alpha}
|
|
234
|
+
e_gg_alpha = pair(g, g) ** alpha
|
|
235
|
+
PP = {'g': g, 'g_beta': g ** beta, 'g_1_over_beta': g ** ~beta, 'e_gg_alpha': e_gg_alpha}
|
|
236
|
+
|
|
237
|
+
return MK, PP
|
|
238
|
+
|
|
239
|
+
def manager_setup(self, attribute_names: List[str], PP: pp_t):
|
|
240
|
+
"""
|
|
241
|
+
Manager Setup algorithm performed by AM.
|
|
242
|
+
Inputs:
|
|
243
|
+
- attribute_names: The name of attributes that AM is responsible for.
|
|
244
|
+
- PP: Public Parameters from the system setup algorithm.
|
|
245
|
+
Outputs:
|
|
246
|
+
- MMK: Manager master key represented as a dictionary.
|
|
247
|
+
- MPK: Manager public key represented as a dictionary.
|
|
248
|
+
"""
|
|
249
|
+
MMK = {}
|
|
250
|
+
MPK = {}
|
|
251
|
+
for attr in attribute_names:
|
|
252
|
+
t_i = self.group.random(ZR)
|
|
253
|
+
g = PP['g']
|
|
254
|
+
T_i = g ** t_i
|
|
255
|
+
MMK[attr] = t_i
|
|
256
|
+
MPK[attr] = T_i
|
|
257
|
+
|
|
258
|
+
return MMK, MPK
|
|
259
|
+
|
|
260
|
+
def key_generation(self, PP, MK, MPK, user_attribute_names_list: List[str], user_name: str,
|
|
261
|
+
attributes_manager: AM, UMK, users_TA_KEK):
|
|
262
|
+
"""
|
|
263
|
+
This function is responsible for generating the decryption keys used by the user according to his list of
|
|
264
|
+
attributes.
|
|
265
|
+
Inputs:
|
|
266
|
+
- PP: Public Parameters from the system setup algorithm.
|
|
267
|
+
- MK: TA's master secret key.
|
|
268
|
+
- MPK: Manager public key represented as a dictionary.
|
|
269
|
+
- user_attribute_names_list: Attribute names hold by the user.
|
|
270
|
+
- user_name: User name.
|
|
271
|
+
- attributes_manager: AM.
|
|
272
|
+
Inputs/outputs:
|
|
273
|
+
- UMK: User Master Key. A value stored privately by TA for each user. Represented as a dictionary, where the
|
|
274
|
+
user_name is the key and a group element is the value.
|
|
275
|
+
Outputs:
|
|
276
|
+
- DSK: Attributes decryption keys as in the original CP-ABE paper (abenc_bsw07.py). (shared with the user)
|
|
277
|
+
- KEK: Key Encryption Keys generated for each attribute hold by the user using the users binary tree
|
|
278
|
+
generated by AM. (shared with the user)
|
|
279
|
+
- users_TA_KEK: A dictionary that holds the TA KEK for each user. (stored privately by AM)
|
|
280
|
+
"""
|
|
281
|
+
# Attribute key generation. Executed by TA.
|
|
282
|
+
DSK, TA_KEK = self.user_attributes_key_gen(MK, MPK, PP, user_attribute_names_list, user_name, UMK)
|
|
283
|
+
|
|
284
|
+
users_TA_KEK[user_name] = TA_KEK
|
|
285
|
+
|
|
286
|
+
# KEK generation by AM.
|
|
287
|
+
KEK = self.user_attributes_kek_generation(TA_KEK, attributes_manager, user_attribute_names_list, user_name)
|
|
288
|
+
|
|
289
|
+
return DSK, KEK
|
|
290
|
+
|
|
291
|
+
def user_attributes_key_gen(self, MK, MPK, PP, user_attribute_names_list, user_name, UMK):
|
|
292
|
+
"""
|
|
293
|
+
This function is executed by TA and considered as part of key generation procedure.
|
|
294
|
+
Inputs:
|
|
295
|
+
- MK: TA's master secret key.
|
|
296
|
+
- MPK: Manager public key represented as a dictionary.
|
|
297
|
+
- PP: Public Parameters from the system setup algorithm.
|
|
298
|
+
- user_attribute_names_list: Attribute names hold by the user.
|
|
299
|
+
- user_name: User name.
|
|
300
|
+
Inputs/outputs:
|
|
301
|
+
- UMK: User Master Key. A value stored privately by TA for each user. Represented as a dictionary, where the
|
|
302
|
+
user_name is the key and a group element is the value.
|
|
303
|
+
Outputs:
|
|
304
|
+
- DSK: Attributes decryption keys as in the original CP-ABE paper (abenc_bsw07.py). (shared with the user)
|
|
305
|
+
- KEK: Key Encryption Keys generated for each attribute hold by the user using the users binary tree
|
|
306
|
+
generated by AM. It is a preliminary one that will be changed by AM in the next algorithm.
|
|
307
|
+
"""
|
|
308
|
+
r = self.group.random(ZR)
|
|
309
|
+
g = PP['g']
|
|
310
|
+
g_r = g ** r
|
|
311
|
+
D = (MK['g_alpha'] * g_r) ** (1 / MK['beta'])
|
|
312
|
+
D_i = {}
|
|
313
|
+
D_i_dash = {}
|
|
314
|
+
KEK = {}
|
|
315
|
+
for attr in user_attribute_names_list:
|
|
316
|
+
r_i = self.group.random(ZR)
|
|
317
|
+
D_i[attr] = g_r * (self.group.hash(attr, G1) ** r_i)
|
|
318
|
+
D_i_dash[attr] = g ** r_i
|
|
319
|
+
|
|
320
|
+
kek_i = MPK[attr] ** r_i
|
|
321
|
+
KEK[attr] = kek_i
|
|
322
|
+
DSK = {'D': D, 'D_i': D_i, 'D_i_dash': D_i_dash, 'attrs': user_attribute_names_list}
|
|
323
|
+
UMK[user_name] = g_r
|
|
324
|
+
|
|
325
|
+
return DSK, KEK
|
|
326
|
+
|
|
327
|
+
def user_attributes_kek_generation(self, TA_KEK, attributes_manager, user_attribute_names_list, user_name):
|
|
328
|
+
"""
|
|
329
|
+
This function is executed by AM and considered as part of key generation procedure.
|
|
330
|
+
Inputs:
|
|
331
|
+
- TA_KEK: Preliminary KEK list generated by TA.
|
|
332
|
+
- attributes_manager: AM.
|
|
333
|
+
- user_attribute_names_list: Attribute names hold by the user.
|
|
334
|
+
- user_name: User name.
|
|
335
|
+
Outputs:
|
|
336
|
+
- KEK: Key Encryption Keys generated for each attribute hold by the user using the users binary tree
|
|
337
|
+
generated by AM.
|
|
338
|
+
"""
|
|
339
|
+
KEK = {}
|
|
340
|
+
for attr in user_attribute_names_list:
|
|
341
|
+
KEK_attr = self.generate_kek_for_user_with_attr(TA_KEK, attr, attributes_manager, user_name)
|
|
342
|
+
KEK[attr] = KEK_attr
|
|
343
|
+
return KEK
|
|
344
|
+
|
|
345
|
+
def generate_kek_for_user_with_attr(self, TA_KEK, attr, attributes_manager, user_name):
|
|
346
|
+
"""
|
|
347
|
+
This function is executed by AM and considered as part of key generation procedure.
|
|
348
|
+
Inputs:
|
|
349
|
+
- TA_KEK: Preliminary KEK list generated by TA.
|
|
350
|
+
- attributes_manager: AM.
|
|
351
|
+
- user_attribute_names_list: Attribute names hold by the user.
|
|
352
|
+
- user_name: User name.
|
|
353
|
+
Outputs:
|
|
354
|
+
- KEK: Key Encryption Key generated for a specific attribute hold by the user using the users binary tree
|
|
355
|
+
generated by AM.
|
|
356
|
+
"""
|
|
357
|
+
list_of_users_hold_attr = attributes_manager.attrs_to_users_dict[attr]
|
|
358
|
+
node_G_i = attributes_manager.get_minimum_nodes_list_that_represent_users_list(list_of_users_hold_attr)
|
|
359
|
+
user_path = attributes_manager.get_user_path(user_name)
|
|
360
|
+
intersection = attributes_manager.get_user_path_intersection_with_node_gi(user_path, node_G_i)
|
|
361
|
+
if len(intersection) == 0:
|
|
362
|
+
# AB: Do nothing, as mentioned in the paper.
|
|
363
|
+
return None
|
|
364
|
+
else:
|
|
365
|
+
assert len(intersection) == 1, "The intersection list should have only one element."
|
|
366
|
+
vj_node: TreeNode = intersection[0]
|
|
367
|
+
kek_i = TA_KEK[attr] # TODO: AB: The attribute has to be added before to any other user in the system setup.
|
|
368
|
+
# Consider fixing it later if this functionality is needed.
|
|
369
|
+
KEK_i = kek_i ** (1 / vj_node.value)
|
|
370
|
+
KEK_attr = {'seq(vj)': vj_node.sequence_number, 'kek_i': kek_i, 'KEK_i': KEK_i}
|
|
371
|
+
return KEK_attr
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def encrypt(self, PP, MMK, M, A: str, attributes_manager: AM):
|
|
375
|
+
"""
|
|
376
|
+
This function is executed by anyone who wants to encrypt a message with an access policy, then by AM to
|
|
377
|
+
perform the re-encryption.
|
|
378
|
+
Inputs:
|
|
379
|
+
- PP: Public Parameters from the system setup algorithm.
|
|
380
|
+
- MMK: Manager master key represented as a dictionary.
|
|
381
|
+
- M: Message to by encrypted.
|
|
382
|
+
- A: Access policy represented as a boolean expression string.
|
|
383
|
+
Outputs:
|
|
384
|
+
- CT_dash: Ciphertext.
|
|
385
|
+
- Hdr: Header message.
|
|
386
|
+
"""
|
|
387
|
+
# Local Encryption
|
|
388
|
+
CT = self.local_encryption(A, M, PP)
|
|
389
|
+
CT, Hdr = self.reencryption(CT, MMK, PP, attributes_manager)
|
|
390
|
+
return CT, Hdr
|
|
391
|
+
|
|
392
|
+
def reencryption(self, CT, MMK, PP, attributes_manager):
|
|
393
|
+
"""
|
|
394
|
+
This function is performed by AM and it is the second part of the encryption procedure.
|
|
395
|
+
"""
|
|
396
|
+
Hdr = {} # AB: TODO:
|
|
397
|
+
g = PP['g']
|
|
398
|
+
kys_dict = {}
|
|
399
|
+
for attr_name_with_idx in CT['Cy_tilde']:
|
|
400
|
+
# Index is appended only if the attribute is repeated more than one time to the access policy
|
|
401
|
+
k_y = self.group.random(ZR)
|
|
402
|
+
kys_dict[attr_name_with_idx] = k_y
|
|
403
|
+
g_k_y = g ** k_y
|
|
404
|
+
CT['Cy_tilde'][attr_name_with_idx] = CT['Cy_tilde'][attr_name_with_idx] * g_k_y
|
|
405
|
+
|
|
406
|
+
attr_name_without_idx = self.__get_attr_name_without_idx(attr_name_with_idx)
|
|
407
|
+
if not attr_name_without_idx in attributes_manager.attrs_to_users_dict:
|
|
408
|
+
# Attribute manager is not responsible for this attribute
|
|
409
|
+
# AB: TODO: Attention here. You might need to revisit this part.
|
|
410
|
+
continue
|
|
411
|
+
Gi = attributes_manager.attrs_to_users_dict[attr_name_without_idx]
|
|
412
|
+
node_Gi = attributes_manager.get_minimum_nodes_list_that_represent_users_list(Gi)
|
|
413
|
+
if not attr_name_with_idx in Hdr:
|
|
414
|
+
Hdr[attr_name_with_idx] = []
|
|
415
|
+
for a_node_Gi in node_Gi:
|
|
416
|
+
a_node_Gi: TreeNode = a_node_Gi
|
|
417
|
+
E_k_y = g_k_y ** (a_node_Gi.value / MMK[attr_name_without_idx])
|
|
418
|
+
Hdr[attr_name_with_idx].append({'seq': a_node_Gi.sequence_number, 'E(k_y)': E_k_y})
|
|
419
|
+
return CT, Hdr
|
|
420
|
+
|
|
421
|
+
def __get_attr_name_without_idx(self, attr_name: str):
|
|
422
|
+
if attr_name.find('_') == -1:
|
|
423
|
+
return attr_name
|
|
424
|
+
val = attr_name.split('_')
|
|
425
|
+
return val[0]
|
|
426
|
+
|
|
427
|
+
def local_encryption(self, A, M, PP):
|
|
428
|
+
"""
|
|
429
|
+
This function is executed by anyone who wants to encrypt a message with an access policy.
|
|
430
|
+
Inputs:
|
|
431
|
+
- A: Access policy represented as a boolean expression string.
|
|
432
|
+
- M: Message to by encrypted.
|
|
433
|
+
- PP: Public Parameters from the system setup algorithm.
|
|
434
|
+
Outputs:
|
|
435
|
+
- CT: Ciphertext.
|
|
436
|
+
"""
|
|
437
|
+
s = self.group.random(ZR)
|
|
438
|
+
e_gg_alpha_s = PP['e_gg_alpha'] ** s
|
|
439
|
+
g = PP['g']
|
|
440
|
+
policy = self.util.createPolicy(A)
|
|
441
|
+
a_list = self.util.getAttributeList(policy)
|
|
442
|
+
shares = self.util.calculateSharesDict(s, policy)
|
|
443
|
+
C0 = e_gg_alpha_s * M
|
|
444
|
+
C1 = PP['g_beta'] ** s
|
|
445
|
+
C_y, C_y_pr = {}, {}
|
|
446
|
+
for i in shares.keys():
|
|
447
|
+
j = self.util.strip_index(i)
|
|
448
|
+
C_y[i] = g ** shares[i]
|
|
449
|
+
C_y_pr[i] = self.group.hash(j, G1) ** shares[i]
|
|
450
|
+
CT = {'C0': C0, 'C1': C1, 'Cy': C_y, 'Cy_tilde': C_y_pr, 'A': A, 'attributes': a_list}
|
|
451
|
+
return CT
|
|
452
|
+
|
|
453
|
+
def decrypt(self, PP, CT_tilde, Hdr, DSK, KEK, user_name: str, attributes_manager: AM):
|
|
454
|
+
"""
|
|
455
|
+
This function is used by any user who has sufficient, non revoked attributes to decrypted a message under a
|
|
456
|
+
specific access policy.
|
|
457
|
+
Inputs:
|
|
458
|
+
- PP: Public Parameters from the system setup algorithm.
|
|
459
|
+
- CT_tilde: Ciphertext after re-encryption by the AM.
|
|
460
|
+
- Hdr: Header message.
|
|
461
|
+
- DSK: Attributes decryption keys as in the original CP-ABE paper (abenc_bsw07.py). (shared with the user).
|
|
462
|
+
- KEK: Key Encryption Keys generated for each attribute hold by the user using the users binary tree
|
|
463
|
+
- user_name: Username who is decrypting the ciphertext.
|
|
464
|
+
- attributes_manager: AM.
|
|
465
|
+
Outputs:
|
|
466
|
+
- M: Recovered message, if the user has the decryption keys of the attributes that satisfy the policy.
|
|
467
|
+
"""
|
|
468
|
+
ct = CT_tilde
|
|
469
|
+
policy_str = ct['A']
|
|
470
|
+
policy = self.util.createPolicy(policy_str)
|
|
471
|
+
pruned_list = self.util.prune(policy, DSK['attrs'])
|
|
472
|
+
if not pruned_list:
|
|
473
|
+
return False
|
|
474
|
+
z = self.util.getCoefficients(policy)
|
|
475
|
+
A = 1
|
|
476
|
+
for i in pruned_list:
|
|
477
|
+
j = i.getAttributeAndIndex()
|
|
478
|
+
k = i.getAttribute()
|
|
479
|
+
KEK_i = KEK[k]['KEK_i']
|
|
480
|
+
Hdr_for_attr: list = Hdr[j]
|
|
481
|
+
chosen_Hdr_element = None
|
|
482
|
+
user_path = attributes_manager.get_user_path(user_name)
|
|
483
|
+
for hdr_elem in Hdr_for_attr:
|
|
484
|
+
# If hdr_ele intersect with the user path, then it is the chosen element
|
|
485
|
+
found = False
|
|
486
|
+
for user_node in user_path:
|
|
487
|
+
if user_node.sequence_number == hdr_elem['seq']:
|
|
488
|
+
found = True
|
|
489
|
+
if found:
|
|
490
|
+
chosen_Hdr_element = hdr_elem
|
|
491
|
+
E_k_y = chosen_Hdr_element['E(k_y)']
|
|
492
|
+
A *= ( (pair(ct['Cy'][j], DSK['D_i'][k]) * pair(KEK_i, E_k_y) )/ pair(DSK['D_i_dash'][k], ct['Cy_tilde'][j]) ) ** z[j]
|
|
493
|
+
|
|
494
|
+
return ct['C0'] / (pair(ct['C1'], DSK['D']) / A)
|
|
495
|
+
|
|
496
|
+
def revoke_attribute(self, revoked_user_name, attribute_name, attributes_manager: AM, PP, users_kek_i, MMK, MPK):
|
|
497
|
+
"""
|
|
498
|
+
This function is executed by AM when an attribute is revoked from a user.
|
|
499
|
+
Inputs:
|
|
500
|
+
- revoked_user_name: The name of the revoked user.
|
|
501
|
+
- attribute_name: revoked attribute name.
|
|
502
|
+
- attributes_manager: AM.
|
|
503
|
+
- PP: Public Parameters from the system setup algorithm.
|
|
504
|
+
- users_kek_i: A list privately acquired by AM from TA as part of key_generation function.
|
|
505
|
+
Inputs/Outputs:
|
|
506
|
+
- MMK: Manager master key represented as a dictionary.
|
|
507
|
+
- MPK: Manager public key represented as a dictionary.
|
|
508
|
+
Outputs:
|
|
509
|
+
- updated_KEK_dict: The key is the user-name of the user whose KEK key is updated and the value is the
|
|
510
|
+
updated KEK key value.
|
|
511
|
+
"""
|
|
512
|
+
attributes_manager.remove_attr_from_user(attribute_name, revoked_user_name)
|
|
513
|
+
|
|
514
|
+
# Key Updating
|
|
515
|
+
g = PP['g']
|
|
516
|
+
t_i = self.group.random(ZR)
|
|
517
|
+
old_t_i = MMK[attribute_name]
|
|
518
|
+
t_i = t_i * old_t_i
|
|
519
|
+
T_i = g ** t_i
|
|
520
|
+
MMK[attribute_name] = t_i
|
|
521
|
+
MPK[attribute_name] = T_i
|
|
522
|
+
|
|
523
|
+
# Get List of the users affects. (The users who hold this attribute)
|
|
524
|
+
affected_users_names = attributes_manager.attrs_to_users_dict[attribute_name]
|
|
525
|
+
updated_KEK_dict = {}
|
|
526
|
+
for a_user_name in affected_users_names:
|
|
527
|
+
users_kek_i[a_user_name][attribute_name] = users_kek_i[a_user_name][attribute_name] ** t_i
|
|
528
|
+
user_attribute_names_list = attributes_manager.users_to_attrs_dict[a_user_name]
|
|
529
|
+
# KEK generation by AM
|
|
530
|
+
new_user_KEK = self.user_attributes_kek_generation(users_kek_i[a_user_name], attributes_manager,
|
|
531
|
+
user_attribute_names_list, a_user_name)
|
|
532
|
+
updated_KEK_dict[a_user_name] = new_user_KEK
|
|
533
|
+
return updated_KEK_dict
|
|
534
|
+
|
|
535
|
+
def add_attribute(self, user_name, attribute_name, attributes_manager: AM, PP, UMK, users_kek_i, MMK, MPK):
|
|
536
|
+
"""
|
|
537
|
+
This function is executed by AM when an attribute is added to a user.
|
|
538
|
+
Inputs:
|
|
539
|
+
- user_name: The name of the user who has an attribute to be added.
|
|
540
|
+
- attribute_name: To be added attribute name.
|
|
541
|
+
- attributes_manager: AM.
|
|
542
|
+
- PP: Public Parameters from the system setup algorithm.
|
|
543
|
+
- UMK: User Master Key. A value stored privately by TA for each user. Represented as a dictionary, where the
|
|
544
|
+
user_name is the key and a group element is the value.
|
|
545
|
+
- users_kek_i: A list privately acquired by AM from TA as part of key_generation function.
|
|
546
|
+
Inputs/Outputs:
|
|
547
|
+
- MMK: Manager master key represented as a dictionary.
|
|
548
|
+
- MPK: Manager public key represented as a dictionary.
|
|
549
|
+
Outputs:
|
|
550
|
+
- updated_KEK_dict: The key is the user-name of the user whose KEK key is updated and the value is the
|
|
551
|
+
updated KEK key value.
|
|
552
|
+
"""
|
|
553
|
+
# TA updates D_i, D_i_tilde and send it to the user for him to append it to his DSK
|
|
554
|
+
g = PP['g']
|
|
555
|
+
r_i = self.group.random(ZR)
|
|
556
|
+
g_r = UMK[user_name]
|
|
557
|
+
D_i = g_r * self.group.hash(attribute_name, G1) ** r_i
|
|
558
|
+
D_i_tilde = g ** r_i
|
|
559
|
+
kek_i = MPK[attribute_name] ** r_i
|
|
560
|
+
users_kek_i[user_name][attribute_name] = kek_i
|
|
561
|
+
|
|
562
|
+
# AM updates the users tree and returns to each affected user its updated KEK for this attribute.
|
|
563
|
+
attributes_manager.add_attr_to_user(attribute_name, user_name)
|
|
564
|
+
list_of_users_hold_attr = attributes_manager.attrs_to_users_dict[attribute_name]
|
|
565
|
+
node_G_i = attributes_manager.get_minimum_nodes_list_that_represent_users_list(list_of_users_hold_attr)
|
|
566
|
+
KEK_user_names_dict_for_attr = {} # Each user gets an entry from this dict that is associated to him and
|
|
567
|
+
# adds/updates it in his KEK.
|
|
568
|
+
for a_user in list_of_users_hold_attr:
|
|
569
|
+
KEK_attr = self.generate_kek_for_user_with_attr(users_kek_i[a_user], attribute_name, attributes_manager,
|
|
570
|
+
a_user)
|
|
571
|
+
KEK_user_names_dict_for_attr[a_user] = KEK_attr
|
|
572
|
+
|
|
573
|
+
return D_i, D_i_tilde, KEK_user_names_dict_for_attr
|
|
574
|
+
|
|
575
|
+
def main():
|
|
576
|
+
group_obj = PairingGroup('SS512')
|
|
577
|
+
|
|
578
|
+
attributes_manager = AM(group_obj)
|
|
579
|
+
user_names_list = ['U1', 'U2', 'U3', 'U4', 'U5', 'U6', 'U7', 'U8']
|
|
580
|
+
attributes_manager.add_attr_to_user('ONE', 'U1')
|
|
581
|
+
attributes_manager.add_attr_to_user('FOUR', 'U1')
|
|
582
|
+
attributes_manager.add_attr_to_user('TWO', 'U1')
|
|
583
|
+
attributes_manager.add_attr_to_user('ONE', 'U2')
|
|
584
|
+
attributes_manager.add_attr_to_user('THREE', 'U2')
|
|
585
|
+
attributes_manager.add_attr_to_user('ONE', 'U3')
|
|
586
|
+
attributes_manager.add_attr_to_user('THREE', 'U4')
|
|
587
|
+
attributes_manager.add_attr_to_user('ONE', 'U5')
|
|
588
|
+
attributes_manager.add_attr_to_user('TWO', 'U6')
|
|
589
|
+
attributes_manager.add_attr_to_user('ONE', 'U7')
|
|
590
|
+
attributes_manager.add_attr_to_user('THREE', 'U8')
|
|
591
|
+
print("Users attributes list: ", attributes_manager.users_to_attrs_dict)
|
|
592
|
+
|
|
593
|
+
ca_cpabe_ar = CaCpabeAr(group_obj)
|
|
594
|
+
MK, PP = ca_cpabe_ar.system_setup()
|
|
595
|
+
print("MK: ", MK)
|
|
596
|
+
print("PP: ", PP)
|
|
597
|
+
|
|
598
|
+
attributes_names = ['ONE', 'TWO', 'THREE', 'FOUR']
|
|
599
|
+
MMK, MPK = ca_cpabe_ar.manager_setup(attributes_names, PP)
|
|
600
|
+
print("MMK: ", MMK)
|
|
601
|
+
print("MPK: ", MPK)
|
|
602
|
+
|
|
603
|
+
UMK = {} # A value stored privately by TA for each user.
|
|
604
|
+
users_private_keys_dict = {}
|
|
605
|
+
users_kek_i = {} # Held privately by AM
|
|
606
|
+
for user_name in user_names_list:
|
|
607
|
+
# Attribute key generation. Executed by TA.
|
|
608
|
+
user_attribute_names_list = attributes_manager.users_to_attrs_dict[user_name]
|
|
609
|
+
# KEK generation by AM.
|
|
610
|
+
DSK, KEK = ca_cpabe_ar.key_generation(PP, MK, MPK, user_attribute_names_list, user_name, attributes_manager,
|
|
611
|
+
UMK, users_kek_i)
|
|
612
|
+
users_private_keys_dict[user_name] = {'DSK': DSK, 'KEK': KEK}
|
|
613
|
+
print("KEK for {}: {}".format(user_name, users_private_keys_dict[user_name]))
|
|
614
|
+
|
|
615
|
+
rand_msg = group_obj.random(GT)
|
|
616
|
+
print("Message: ", rand_msg)
|
|
617
|
+
policy_str = '((four or three) and (three or one))'
|
|
618
|
+
CT_tilde, Hdr = ca_cpabe_ar.encrypt(PP, MMK, rand_msg, policy_str, attributes_manager)
|
|
619
|
+
print("CT: ", CT_tilde)
|
|
620
|
+
user_private_keys_dict = users_private_keys_dict['U2']
|
|
621
|
+
DSK = user_private_keys_dict['DSK']
|
|
622
|
+
KEK = user_private_keys_dict['KEK']
|
|
623
|
+
recovered_M = ca_cpabe_ar.decrypt(PP, CT_tilde, Hdr, DSK, KEK, 'U2', attributes_manager)
|
|
624
|
+
print('Recovered Message: ', recovered_M)
|
|
625
|
+
assert rand_msg == recovered_M, "FAILED Decryption: message is incorrect"
|
|
626
|
+
|
|
627
|
+
# Revoke the attribute `THREE` from user `U2`
|
|
628
|
+
updated_users_kek_values = ca_cpabe_ar.revoke_attribute('U2', 'THREE', attributes_manager, PP, users_kek_i, MMK,
|
|
629
|
+
MPK)
|
|
630
|
+
for a_user_name in updated_users_kek_values: # The updated users KEK keys need to be distributed to the users
|
|
631
|
+
users_private_keys_dict[user_name]['KEK'] = updated_users_kek_values[a_user_name]
|
|
632
|
+
|
|
633
|
+
# Now `U7` does not have the ability to decrypt the message because his attributes ['ONE'] does not match the policy
|
|
634
|
+
user_private_keys_dict = users_private_keys_dict['U7']
|
|
635
|
+
DSK = user_private_keys_dict['DSK']
|
|
636
|
+
KEK = user_private_keys_dict['KEK']
|
|
637
|
+
recovered_M = ca_cpabe_ar.decrypt(PP, CT_tilde, Hdr, DSK, KEK, 'U7', attributes_manager)
|
|
638
|
+
print("Wrong recovered M for U7: ", recovered_M)
|
|
639
|
+
# Uncomment the following line and an error will be raised
|
|
640
|
+
# assert rand_msg == recovered_M, "FAILED Decryption: message is incorrect"
|
|
641
|
+
|
|
642
|
+
# Add attribute `FOUR` to user `U7`
|
|
643
|
+
attr_to_be_added = 'FOUR'
|
|
644
|
+
D_i, D_i_tilde, KEK_user_names_dict_for_attr = ca_cpabe_ar.add_attribute('U7', attr_to_be_added, attributes_manager,
|
|
645
|
+
PP, UMK, users_kek_i, MMK, MPK)
|
|
646
|
+
user_private_keys_dict = users_private_keys_dict['U7']
|
|
647
|
+
# Update DSK for the user
|
|
648
|
+
DSK = user_private_keys_dict['DSK']
|
|
649
|
+
DSK['D_i'][attr_to_be_added] = D_i
|
|
650
|
+
DSK['D_i_dash'][attr_to_be_added] = D_i_tilde
|
|
651
|
+
DSK['attrs'].append(attr_to_be_added)
|
|
652
|
+
# Each user receives the updated KEK for the attribute 'U7'
|
|
653
|
+
for a_user_name in KEK_user_names_dict_for_attr:
|
|
654
|
+
user_KEK_for_added_attr = KEK_user_names_dict_for_attr[a_user_name] # KEK for attribute 'FOUR' for a specific
|
|
655
|
+
# user.
|
|
656
|
+
user_private_keys_dict = users_private_keys_dict[a_user_name]
|
|
657
|
+
KEK_for_user = user_private_keys_dict['KEK']
|
|
658
|
+
KEK_for_user[attr_to_be_added] = user_KEK_for_added_attr
|
|
659
|
+
|
|
660
|
+
# Encrypt the same message again.
|
|
661
|
+
CT_tilde, Hdr = ca_cpabe_ar.encrypt(PP, MMK, rand_msg, policy_str, attributes_manager)
|
|
662
|
+
print("CT: ", CT_tilde)
|
|
663
|
+
user_private_keys_dict = users_private_keys_dict['U2']
|
|
664
|
+
DSK = user_private_keys_dict['DSK']
|
|
665
|
+
KEK = user_private_keys_dict['KEK']
|
|
666
|
+
# Now `U2` does not have the ability to decrypt the message because his attributes no longer match the policy after
|
|
667
|
+
# one of his attributes was revoked.
|
|
668
|
+
recovered_M = ca_cpabe_ar.decrypt(PP, CT_tilde, Hdr, DSK, KEK, 'U2', attributes_manager)
|
|
669
|
+
print("Wrong recovered M for U2: ", recovered_M)
|
|
670
|
+
# Uncomment the following line and an error will be raised
|
|
671
|
+
# assert rand_msg == recovered_M, "FAILED Decryption: message is incorrect"
|
|
672
|
+
|
|
673
|
+
# U7 now has the ability to decrypt the message after because his attributes now match the policy [ONE, FOUR]
|
|
674
|
+
user_private_keys_dict = users_private_keys_dict['U7']
|
|
675
|
+
DSK = user_private_keys_dict['DSK']
|
|
676
|
+
KEK = user_private_keys_dict['KEK']
|
|
677
|
+
# `U7` has the ability to decrypt the message because his attributes match the policy after adding attribute FOUR
|
|
678
|
+
recovered_M = ca_cpabe_ar.decrypt(PP, CT_tilde, Hdr, DSK, KEK, 'U7', attributes_manager)
|
|
679
|
+
print("Recovered M for U7: ", recovered_M)
|
|
680
|
+
assert rand_msg == recovered_M, "FAILED Decryption: message is incorrect"
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
if __name__ == "__main__":
|
|
684
|
+
main()
|