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,174 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Contains all the auxillary functions to do linear secret sharing (LSS) over an access structure. Mainly, we represent the
|
|
3
|
+
access structure as a binary tree. This could also support matrices for representing access structures.
|
|
4
|
+
'''
|
|
5
|
+
from charm.core.math.pairing import ZR
|
|
6
|
+
from charm.toolbox.policytree import *
|
|
7
|
+
|
|
8
|
+
class SecretUtil:
|
|
9
|
+
def __init__(self, groupObj, verbose=True):
|
|
10
|
+
self.group = groupObj
|
|
11
|
+
# self.parser = PolicyParser()
|
|
12
|
+
|
|
13
|
+
def P(self, coeff, x):
|
|
14
|
+
share = 0
|
|
15
|
+
# evaluate polynomial
|
|
16
|
+
for i in range(0, len(coeff)):
|
|
17
|
+
share += (coeff[i] * (x ** i))
|
|
18
|
+
return share
|
|
19
|
+
|
|
20
|
+
def genShares(self, secret, k, n):
|
|
21
|
+
if(k <= n):
|
|
22
|
+
rand = self.group.random
|
|
23
|
+
a = [] # will hold polynomial coefficients
|
|
24
|
+
for i in range(0, k):
|
|
25
|
+
if (i == 0): a.append(secret) # a[0]
|
|
26
|
+
else: a.append(rand(ZR))
|
|
27
|
+
Pfunc = self.P
|
|
28
|
+
shares = [Pfunc(a, i) for i in range(0, n+1)]
|
|
29
|
+
return shares
|
|
30
|
+
|
|
31
|
+
# shares is a dictionary
|
|
32
|
+
def recoverCoefficients(self, list):
|
|
33
|
+
"""recovers the coefficients over a binary tree."""
|
|
34
|
+
coeff = {}
|
|
35
|
+
list2 = [self.group.init(ZR, i) for i in list]
|
|
36
|
+
for idx, i in enumerate(list):
|
|
37
|
+
i_zr = list2[idx] # self.group.init(ZR, i)
|
|
38
|
+
result = 1
|
|
39
|
+
for j_zr in list2:
|
|
40
|
+
if not (i_zr == j_zr):
|
|
41
|
+
# lagrange basis poly
|
|
42
|
+
result *= (0 - j_zr) / (i_zr - j_zr)
|
|
43
|
+
# print("coeff '%d' => '%s'" % (i, result))
|
|
44
|
+
coeff[int(i)] = result
|
|
45
|
+
return coeff
|
|
46
|
+
|
|
47
|
+
def recoverSecret(self, shares):
|
|
48
|
+
"""take shares and attempt to recover secret by taking sum of coeff * share for all shares.
|
|
49
|
+
if user indeed has at least k of n shares, then secret will be recovered."""
|
|
50
|
+
list = shares.keys()
|
|
51
|
+
if self.verbose: print(list)
|
|
52
|
+
coeff = self.recoverCoefficients(list)
|
|
53
|
+
secret = 0
|
|
54
|
+
for i in list:
|
|
55
|
+
secret += (coeff[i] * shares[i])
|
|
56
|
+
|
|
57
|
+
return secret
|
|
58
|
+
|
|
59
|
+
def getCoefficients(self, tree):
|
|
60
|
+
coeffs = {}
|
|
61
|
+
self._getCoefficientsDict(tree, coeffs)
|
|
62
|
+
return coeffs
|
|
63
|
+
|
|
64
|
+
def _getCoefficientsDict(self, tree, coeff_list, coeff=1):
|
|
65
|
+
"""recover coefficient over a binary tree where possible node types are OR = (1 of 2)
|
|
66
|
+
and AND = (2 of 2) secret sharing. The leaf nodes are attributes and the coefficients are
|
|
67
|
+
recorded in a coeff-list dictionary."""
|
|
68
|
+
if tree:
|
|
69
|
+
node = tree.getNodeType()
|
|
70
|
+
if(node == OpType.AND):
|
|
71
|
+
this_coeff = self.recoverCoefficients([1,2])
|
|
72
|
+
# left child => coeff[1], right child => coeff[2]
|
|
73
|
+
self._getCoefficientsDict(tree.getLeft(), coeff_list, coeff * this_coeff[1])
|
|
74
|
+
self._getCoefficientsDict(tree.getRight(), coeff_list, coeff * this_coeff[2])
|
|
75
|
+
elif(node == OpType.OR):
|
|
76
|
+
this_coeff = self.recoverCoefficients([1])
|
|
77
|
+
self._getCoefficientsDict(tree.getLeft(), coeff_list, coeff * this_coeff[1])
|
|
78
|
+
self._getCoefficientsDict(tree.getRight(), coeff_list, coeff * this_coeff[1])
|
|
79
|
+
elif(node == OpType.ATTR):
|
|
80
|
+
attr = tree.getAttributeAndIndex()
|
|
81
|
+
coeff_list[ attr ] = coeff
|
|
82
|
+
else:
|
|
83
|
+
return None
|
|
84
|
+
|
|
85
|
+
def _calculateShares(self, secret, tree, _type=dict):
|
|
86
|
+
"""performs secret sharing over a policy tree. could be adapted for LSSS matrices."""
|
|
87
|
+
attr_list = []
|
|
88
|
+
self._compute_shares(secret, tree, attr_list)
|
|
89
|
+
if _type == list:
|
|
90
|
+
return attr_list
|
|
91
|
+
else: # assume dict
|
|
92
|
+
share = {}
|
|
93
|
+
for i in range(0, len(attr_list)):
|
|
94
|
+
key = attr_list[i][0].getAttributeAndIndex()
|
|
95
|
+
if not key in share.keys():
|
|
96
|
+
share[ key ] = attr_list[i][1]
|
|
97
|
+
return share
|
|
98
|
+
|
|
99
|
+
def calculateSharesList(self, secret, tree):
|
|
100
|
+
"""calculate shares from given secret and returns a list of shares."""
|
|
101
|
+
return self._calculateShares(secret, tree, list)
|
|
102
|
+
|
|
103
|
+
def calculateSharesDict(self, secret, tree):
|
|
104
|
+
"""calculate shares from given secret and returns a dict as {attribute:shares} pairs"""
|
|
105
|
+
return self._calculateShares(secret, tree, dict)
|
|
106
|
+
|
|
107
|
+
def _compute_shares(self, secret, subtree, List):
|
|
108
|
+
"""computes recursive secret sharing over the binary tree. Start by splitting 1-of-2 (OR) or 2-of-2 (AND nodes).
|
|
109
|
+
Continues recursively down the tree doing a round of secret sharing at each boolean node type."""
|
|
110
|
+
k = 0
|
|
111
|
+
if(subtree == None):
|
|
112
|
+
return None
|
|
113
|
+
|
|
114
|
+
type = subtree.getNodeType()
|
|
115
|
+
if(type == OpType.ATTR):
|
|
116
|
+
# visiting a leaf node
|
|
117
|
+
# t = (subtree.getAttribute(), secret)
|
|
118
|
+
t = (subtree, secret)
|
|
119
|
+
List.append(t)
|
|
120
|
+
return None
|
|
121
|
+
elif(type == OpType.OR or type == OpType.AND):
|
|
122
|
+
k = subtree.threshold # 1-of-2 or 2-of-2
|
|
123
|
+
# elif(type == OpType.AND):
|
|
124
|
+
# k = 2 # 2-of-2
|
|
125
|
+
else:
|
|
126
|
+
return None
|
|
127
|
+
# generate shares for k and n
|
|
128
|
+
shares = self.genShares(secret, k, n=2)
|
|
129
|
+
# recursively generate shares for children nodes
|
|
130
|
+
self._compute_shares(shares[1], subtree.getLeft(), List)
|
|
131
|
+
self._compute_shares(shares[2], subtree.getRight(), List)
|
|
132
|
+
|
|
133
|
+
def strip_index(self, node_str):
|
|
134
|
+
if node_str.find('_') != -1: return node_str.split('_')[0]
|
|
135
|
+
return node_str
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def createPolicy(self, policy_string):
|
|
139
|
+
assert type(policy_string) == str, "invalid type for policy_string"
|
|
140
|
+
parser = PolicyParser()
|
|
141
|
+
policy_obj = parser.parse(policy_string)
|
|
142
|
+
_dictCount, _dictLabel = {}, {}
|
|
143
|
+
parser.findDuplicates(policy_obj, _dictCount)
|
|
144
|
+
for i in _dictCount.keys():
|
|
145
|
+
if _dictCount[ i ] > 1: _dictLabel[ i ] = 0
|
|
146
|
+
parser.labelDuplicates(policy_obj, _dictLabel)
|
|
147
|
+
return policy_obj
|
|
148
|
+
|
|
149
|
+
def prune(self, policy, attributes):
|
|
150
|
+
"""determine whether a given set of attributes satisfies the policy"""
|
|
151
|
+
parser = PolicyParser()
|
|
152
|
+
return parser.prune(policy, attributes)
|
|
153
|
+
|
|
154
|
+
def getAttributeList(self, Node):
|
|
155
|
+
aList = []
|
|
156
|
+
self._getAttributeList(Node, aList)
|
|
157
|
+
return aList
|
|
158
|
+
|
|
159
|
+
def _getAttributeList(self, Node, List):
|
|
160
|
+
"""retrieve the attributes that occur in a policy tree in order (left to right)"""
|
|
161
|
+
if(Node == None):
|
|
162
|
+
return None
|
|
163
|
+
# V, L, R
|
|
164
|
+
if(Node.getNodeType() == OpType.ATTR):
|
|
165
|
+
List.append(Node.getAttributeAndIndex()) # .getAttribute()
|
|
166
|
+
else:
|
|
167
|
+
self._getAttributeList(Node.getLeft(), List)
|
|
168
|
+
self._getAttributeList(Node.getRight(), List)
|
|
169
|
+
return None
|
|
170
|
+
|
|
171
|
+
# TODO: add test cases here for SecretUtil
|
|
172
|
+
if __name__ == "__main__":
|
|
173
|
+
pass
|
|
174
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Base class for cryptographic secure random number generation
|
|
3
|
+
:authors: Gary Belvin
|
|
4
|
+
'''
|
|
5
|
+
from charm.toolbox.bitstring import Bytes
|
|
6
|
+
from charm.toolbox.conversion import Conversion
|
|
7
|
+
from charm.core.math.integer import randomBits
|
|
8
|
+
import datetime
|
|
9
|
+
import math
|
|
10
|
+
import random
|
|
11
|
+
|
|
12
|
+
class SecureRandom():
|
|
13
|
+
def __init__(self):
|
|
14
|
+
pass
|
|
15
|
+
def getRandomBytes(self, length):
|
|
16
|
+
'''Returns a random bit string of length bytes'''
|
|
17
|
+
raise NotImplementedError
|
|
18
|
+
def addSeed(self, seed):
|
|
19
|
+
'''
|
|
20
|
+
Add randomness to the generator.
|
|
21
|
+
Always increases entropy
|
|
22
|
+
'''
|
|
23
|
+
raise NotImplementedError
|
|
24
|
+
|
|
25
|
+
class SecureRandomFactory():
|
|
26
|
+
'''
|
|
27
|
+
This class provides a central place to swap out the randomness engine
|
|
28
|
+
used by the charm framework.
|
|
29
|
+
Classes should call ``rand = SecureRandomFactory.getInstance()``
|
|
30
|
+
to acquire a randomnesss generator
|
|
31
|
+
'''
|
|
32
|
+
@classmethod
|
|
33
|
+
def getInstance(self):
|
|
34
|
+
return OpenSSLRand()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class OpenSSLRand(SecureRandom):
|
|
38
|
+
'''Uses the OpenSSL PRNG for random bits'''
|
|
39
|
+
def __init__(self):
|
|
40
|
+
SecureRandom.__init__(self)
|
|
41
|
+
#seed with a little bit of random data. This is not the only source
|
|
42
|
+
#of randomness. Internally, OpenSSL samples additional physical randomness.
|
|
43
|
+
|
|
44
|
+
def getRandomBytes(self, length):
|
|
45
|
+
bits = length * 8;
|
|
46
|
+
val = randomBits(bits)
|
|
47
|
+
return Conversion.IP2OS(val, length)
|
|
48
|
+
|
|
49
|
+
def getRandomBits(self, length):
|
|
50
|
+
i = randomBits(length)
|
|
51
|
+
len = math.ceil(length / 8)
|
|
52
|
+
return Conversion.IP2OS(i, len)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class WeakRandom(SecureRandom):
|
|
56
|
+
def __init__(self):
|
|
57
|
+
SecureRandom.__init__(self)
|
|
58
|
+
def getRandomBytes(self, length):
|
|
59
|
+
return self.myrandom(length, False)
|
|
60
|
+
def addSeed(self, seed):
|
|
61
|
+
raise NotImplementedError()
|
|
62
|
+
@classmethod
|
|
63
|
+
def myrandom(self, length, printable=False):
|
|
64
|
+
'''
|
|
65
|
+
This method does **NOT** provide cryptographically secure random numbers.
|
|
66
|
+
This should **NOT** be used for production code
|
|
67
|
+
'''
|
|
68
|
+
if(printable):
|
|
69
|
+
#Nice printable characters for testing purposes
|
|
70
|
+
return Bytes(random.randrange(0x20, 0x7E) for i in range(length))
|
|
71
|
+
else:
|
|
72
|
+
return Bytes(random.randrange(0, 256) for i in range(length))
|
|
73
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
from charm.core.engine.protocol import Protocol
|
|
3
|
+
from charm.core.engine.util import *
|
|
4
|
+
from charm. toolbox.enum import Enum
|
|
5
|
+
|
|
6
|
+
#party = Enum('Prover', 'Verifier')
|
|
7
|
+
|
|
8
|
+
class Sigma(Protocol):
|
|
9
|
+
def __init__(self, groupObj, common_input=None):
|
|
10
|
+
Protocol.__init__(self, None) # think of something for handling errors
|
|
11
|
+
self.verifier_states = { 2:self.verifier_state2, 4:self.verifier_state4, 6:self.verifier_state6 }
|
|
12
|
+
self.prover_states = { 1:self.prover_state1, 3:self.prover_state3, 5:self.prover_state5 }
|
|
13
|
+
self.PROVER, self.VERIFIER = 1, 2 # PROVER = 1, VERIFIER = 2
|
|
14
|
+
|
|
15
|
+
self.verifier_trans = { 2:4, 4:6 }
|
|
16
|
+
self.prover_trans = { 1:3, 3:5 }
|
|
17
|
+
# describe the parties involved and the valid transitions
|
|
18
|
+
Protocol.addPartyType(self, self.VERIFIER, self.verifier_states, self.verifier_trans)
|
|
19
|
+
Protocol.addPartyType(self, self.PROVER, self.prover_states, self.prover_trans, True)
|
|
20
|
+
|
|
21
|
+
self.group = groupObj
|
|
22
|
+
# proof parameter generation
|
|
23
|
+
if common_input == None: # generate common parameters to P and V
|
|
24
|
+
db = {}
|
|
25
|
+
else: # can be used as a sub-protocol if common_input is specified by caller
|
|
26
|
+
db = common_input
|
|
27
|
+
Protocol.setSubclassVars(self, self.group, db)
|
|
28
|
+
|
|
29
|
+
# must be implemented by sub class...
|
|
30
|
+
def prover_state1(self):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
def prover_state3(self, input):
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
def prover_state5(self, input):
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
def verifier_state2(self, input):
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
def verifier_state4(self, input):
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
def verifier_state6(self, input):
|
|
46
|
+
pass
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Generates a Blum-Williams integer, which is the product of two distinct primes
|
|
3
|
+
each congruent to 3 mod 4
|
|
4
|
+
'''
|
|
5
|
+
|
|
6
|
+
from charm.core.math.integer import integer,isPrime,randomPrime
|
|
7
|
+
|
|
8
|
+
class BlumWilliamsInteger:
|
|
9
|
+
def __init__(self):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
def generatePrimes(self, n):
|
|
13
|
+
# Add safety limit to prevent infinite loops on Python 3.12+
|
|
14
|
+
# Blum-Williams primes (p ≡ 3 mod 4) are approximately 50% of all primes
|
|
15
|
+
# so we should find one within a reasonable number of attempts
|
|
16
|
+
max_attempts = 10000
|
|
17
|
+
|
|
18
|
+
for attempt in range(max_attempts):
|
|
19
|
+
p = randomPrime(n)
|
|
20
|
+
if(isPrime(p) and (((p-3)%4) == 0)):
|
|
21
|
+
break
|
|
22
|
+
else:
|
|
23
|
+
raise RuntimeError(
|
|
24
|
+
f"Could not generate Blum-Williams prime p after {max_attempts} attempts"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
for attempt in range(max_attempts):
|
|
28
|
+
q = randomPrime(n)
|
|
29
|
+
if(isPrime(q) and (((q-3)%4) == 0) and not(q == p)):
|
|
30
|
+
break
|
|
31
|
+
else:
|
|
32
|
+
raise RuntimeError(
|
|
33
|
+
f"Could not generate Blum-Williams prime q after {max_attempts} attempts"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return (p, q)
|
|
37
|
+
|
|
38
|
+
def generateBlumWilliamsInteger(self, n, p=0, q=0):
|
|
39
|
+
if((p == 0) or (q == 0)):
|
|
40
|
+
(p,q) = self.generatePrimes(n)
|
|
41
|
+
N = p * q
|
|
42
|
+
return (p, q, N)
|
|
43
|
+
else:
|
|
44
|
+
N = p * q
|
|
45
|
+
return N
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
from charm.toolbox.paddingschemes import PKCS7Padding
|
|
2
|
+
from charm.toolbox.securerandom import OpenSSLRand
|
|
3
|
+
from charm.core.crypto.cryptobase import MODE_CBC,AES,selectPRP
|
|
4
|
+
from hashlib import sha256 as sha2
|
|
5
|
+
import json
|
|
6
|
+
import hmac
|
|
7
|
+
from base64 import b64encode, b64decode
|
|
8
|
+
|
|
9
|
+
class MessageAuthenticator(object):
|
|
10
|
+
""" Abstraction for constructing and verifying authenticated messages
|
|
11
|
+
|
|
12
|
+
A large number of the schemes can only encrypt group elements
|
|
13
|
+
and do not provide an efficient mechanism for encoding byte in
|
|
14
|
+
those elements. As such we don't pick a symmetric key and encrypt
|
|
15
|
+
it asymmetrically. Rather, we hash a random group element to get the
|
|
16
|
+
symmetric key.
|
|
17
|
+
|
|
18
|
+
>>> from charm.toolbox.pairinggroup import PairingGroup,GT,extract_key
|
|
19
|
+
>>> groupObj = PairingGroup('SS512')
|
|
20
|
+
>>> key = groupObj.random(GT)
|
|
21
|
+
>>> m = MessageAuthenticator(extract_key(key))
|
|
22
|
+
>>> AuthenticatedMessage = m.mac('Hello World')
|
|
23
|
+
>>> m.verify(AuthenticatedMessage)
|
|
24
|
+
True
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, key, alg="HMAC_SHA2"):
|
|
27
|
+
"""
|
|
28
|
+
Creates a message authenticator and verifier under the specified key
|
|
29
|
+
"""
|
|
30
|
+
if alg != "HMAC_SHA2":
|
|
31
|
+
raise ValueError("Currently only HMAC_SHA2 is supported as an algorithm")
|
|
32
|
+
self._algorithm = alg
|
|
33
|
+
self._key = key
|
|
34
|
+
|
|
35
|
+
def mac(self, msg, associatedData=b''):
|
|
36
|
+
"""
|
|
37
|
+
Authenticates (MAC) a message. The MAC is computed as:
|
|
38
|
+
MAC = HMAC(key, algorithm + associatedData + message).
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
msg : str or byte str
|
|
43
|
+
The message serving as input to the HMAC algorithm, in addition to the HMAC algorithm and associated data.
|
|
44
|
+
associatedData : str or byte str, optional
|
|
45
|
+
Associated data that will be MACed together with the ciphertext and algorithm; the associated data will not be encrypted.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
dict
|
|
50
|
+
Dictionary composed of the MAC algorithm, the MACed message (or ciphertext), and the digest computed by MACing HMAC_algorithm + associatedData + msg.
|
|
51
|
+
"""
|
|
52
|
+
# Ensure the associated data is in byte format, convert if necessary.
|
|
53
|
+
if type(associatedData) != bytes :
|
|
54
|
+
associatedData = bytes(associatedData, "utf-8")
|
|
55
|
+
return {
|
|
56
|
+
"alg": self._algorithm,
|
|
57
|
+
"msg": msg,
|
|
58
|
+
"digest": hmac.new(self._key, bytes(self._algorithm, "utf-8") + associatedData + bytes(msg, "utf-8"), digestmod=sha2).hexdigest()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
def verify(self, msgAndDigest, associatedData=b''):
|
|
62
|
+
"""
|
|
63
|
+
Verifies whether the MAC digest from input ciphertext and digest matches the computed one over ciphertext and associated data.
|
|
64
|
+
|
|
65
|
+
Parameters
|
|
66
|
+
----------
|
|
67
|
+
msgAndDigest : dict
|
|
68
|
+
Dictionary composed of the MAC algorithm, the MACed message (or ciphertext), and the digest computed by MACing HMAC_algorithm + associatedData + msg.
|
|
69
|
+
It is the format generated by the mac() function within this class.
|
|
70
|
+
associatedData : str or byte str, optional
|
|
71
|
+
Associated data that will be MACed together with the ciphertext and algorithm; the associated data will not be encrypted.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
bool
|
|
76
|
+
True if the digests match, False otherwise.
|
|
77
|
+
|
|
78
|
+
Raises
|
|
79
|
+
------
|
|
80
|
+
ValueError
|
|
81
|
+
If the HMAC algorithm is not supported.
|
|
82
|
+
"""
|
|
83
|
+
if msgAndDigest['alg'] != self._algorithm:
|
|
84
|
+
raise ValueError("Currently only HMAC_SHA2 is supported as an algorithm")
|
|
85
|
+
expected = bytes(self.mac(msgAndDigest['msg'], associatedData=associatedData)['digest'], 'utf-8')
|
|
86
|
+
received = bytes(msgAndDigest['digest'], 'utf-8')
|
|
87
|
+
# we compare the hash instead of the direct value to avoid a timing attack
|
|
88
|
+
return sha2(expected).digest() == sha2(received).digest()
|
|
89
|
+
|
|
90
|
+
class SymmetricCryptoAbstraction(object):
|
|
91
|
+
"""
|
|
92
|
+
Abstraction for symmetric encryption and decryption of data.
|
|
93
|
+
Ideally provide an INDCCA2 secure symmetric container for arbitrary data.
|
|
94
|
+
Currently only supports primitives that JSON can encode and decode.
|
|
95
|
+
|
|
96
|
+
A large number of the schemes can only encrypt group elements
|
|
97
|
+
and do not provide an efficient mechanism for encoding byte in
|
|
98
|
+
those elements. As such we don't pick a symmetric key and encrypt
|
|
99
|
+
it asymmetrically. Rather, we hash a random group element to get the
|
|
100
|
+
symmetric key.
|
|
101
|
+
|
|
102
|
+
>>> from charm.toolbox.pairinggroup import PairingGroup,GT,extract_key
|
|
103
|
+
>>> groupObj = PairingGroup('SS512')
|
|
104
|
+
>>> a = SymmetricCryptoAbstraction(extract_key(groupObj.random(GT)))
|
|
105
|
+
>>> ct = a.encrypt(b"Friendly Fire Isn't")
|
|
106
|
+
>>> a.decrypt(ct)
|
|
107
|
+
b"Friendly Fire Isn't"
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def __init__(self, key, alg = AES, mode = MODE_CBC):
|
|
111
|
+
self._alg = alg
|
|
112
|
+
self.key_len = 16
|
|
113
|
+
self._block_size = 16
|
|
114
|
+
self._mode = mode
|
|
115
|
+
self._key = key[0:self.key_len] # expected to be bytes
|
|
116
|
+
assert len(self._key) == self.key_len, "SymmetricCryptoAbstraction key too short"
|
|
117
|
+
self._padding = PKCS7Padding()
|
|
118
|
+
|
|
119
|
+
def _initCipher(self,IV = None):
|
|
120
|
+
if IV == None :
|
|
121
|
+
IV = OpenSSLRand().getRandomBytes(self._block_size)
|
|
122
|
+
self._IV = IV
|
|
123
|
+
return selectPRP(self._alg,(self._key,self._mode,self._IV))
|
|
124
|
+
|
|
125
|
+
def __encode_decode(self,data,func):
|
|
126
|
+
data['IV'] = func(data['IV'])
|
|
127
|
+
data['CipherText'] = func(data['CipherText'])
|
|
128
|
+
return data
|
|
129
|
+
|
|
130
|
+
#This code should be factored out into another class
|
|
131
|
+
#Because json is only defined over strings, we need to base64 encode the encrypted data
|
|
132
|
+
# and convert the base 64 byte array into a utf8 string
|
|
133
|
+
def _encode(self, data):
|
|
134
|
+
return self.__encode_decode(data, lambda x: b64encode(x).decode('utf-8'))
|
|
135
|
+
|
|
136
|
+
def _decode(self, data):
|
|
137
|
+
return self.__encode_decode(data, lambda x: b64decode(bytes(x, 'utf-8')))
|
|
138
|
+
|
|
139
|
+
def encrypt(self, message):
|
|
140
|
+
#This should be removed when all crypto functions deal with bytes"
|
|
141
|
+
if type(message) != bytes :
|
|
142
|
+
message = bytes(message, "utf-8")
|
|
143
|
+
ct = self._encrypt(message)
|
|
144
|
+
#JSON strings cannot have binary data in them, so we must base64 encode cipher
|
|
145
|
+
cte = json.dumps(self._encode(ct))
|
|
146
|
+
return cte
|
|
147
|
+
|
|
148
|
+
def _encrypt(self, message):
|
|
149
|
+
#Because the IV cannot be set after instantiation, decrypt and encrypt
|
|
150
|
+
# must operate on their own instances of the cipher
|
|
151
|
+
cipher = self._initCipher()
|
|
152
|
+
ct= {'ALG': self._alg,
|
|
153
|
+
'MODE': self._mode,
|
|
154
|
+
'IV': self._IV,
|
|
155
|
+
'CipherText': cipher.encrypt(self._padding.encode(message))
|
|
156
|
+
}
|
|
157
|
+
return ct
|
|
158
|
+
|
|
159
|
+
def decrypt(self, cipherText):
|
|
160
|
+
f = json.loads(cipherText)
|
|
161
|
+
return self._decrypt(self._decode(f))
|
|
162
|
+
|
|
163
|
+
def _decrypt(self, cipherText):
|
|
164
|
+
cipher = self._initCipher(cipherText['IV'])
|
|
165
|
+
msg = cipher.decrypt(cipherText['CipherText'])
|
|
166
|
+
return self._padding.decode(msg)
|
|
167
|
+
|
|
168
|
+
class AuthenticatedCryptoAbstraction(SymmetricCryptoAbstraction):
|
|
169
|
+
"""
|
|
170
|
+
Implements Authenticated Encryption with Associated Data (AEAD) abstraction. The associated data is optional, and this version is backwards compatible
|
|
171
|
+
with the same class without the associated data option.
|
|
172
|
+
|
|
173
|
+
Examples
|
|
174
|
+
--------
|
|
175
|
+
>>> from hashlib import sha256
|
|
176
|
+
>>> import charm.toolbox.symcrypto
|
|
177
|
+
>>> key = sha256(b'shameful secret key').digest()
|
|
178
|
+
>>> cipher = charm.toolbox.symcrypto.AuthenticatedCryptoAbstraction(key)
|
|
179
|
+
>>> ciphertext = cipher.encrypt('My age is 42.')
|
|
180
|
+
>>> cipher.decrypt(ciphertext)
|
|
181
|
+
b'My age is 42.'
|
|
182
|
+
>>> ciphertext2 = cipher.encrypt(b'My age is 42.')
|
|
183
|
+
>>> cipher.decrypt(ciphertext2)
|
|
184
|
+
b'My age is 42.'
|
|
185
|
+
>>> ad = b'\x10\x11\x11\x11'
|
|
186
|
+
>>> ciphertextAssociatedData = cipher.encrypt('Some network PDU.', associatedData=ad)
|
|
187
|
+
>>> cipher.decrypt(ciphertextAssociatedData)
|
|
188
|
+
Traceback (most recent call last):
|
|
189
|
+
File "<stdin>", line 1, in <module>
|
|
190
|
+
File "./charm/toolbox/symcrypto.py", line 233, in decrypt
|
|
191
|
+
raise ValueError("Invalid mac. Your data was tampered with or your key is wrong")
|
|
192
|
+
ValueError: Invalid mac. Your data was tampered with or your key is wrong
|
|
193
|
+
>>> cipher.decrypt(ciphertextAssociatedData, associatedData='wrong data')
|
|
194
|
+
Traceback (most recent call last):
|
|
195
|
+
File "<stdin>", line 1, in <module>
|
|
196
|
+
File "./charm/toolbox/symcrypto.py", line 233, in decrypt
|
|
197
|
+
raise ValueError("Invalid mac. Your data was tampered with or your key is wrong")
|
|
198
|
+
ValueError: Invalid mac. Your data was tampered with or your key is wrong
|
|
199
|
+
>>> cipher.decrypt(ciphertextAssociatedData, associatedData=b'\x10\x11\x11\x11')
|
|
200
|
+
b'Some network PDU.'
|
|
201
|
+
>>>
|
|
202
|
+
"""
|
|
203
|
+
def encrypt(self, msg, associatedData=''):
|
|
204
|
+
"""
|
|
205
|
+
Encrypts a message in AEAD mode (Authenticated Encryption with Associated Data) using the superclass symmetric encryption parameters.
|
|
206
|
+
The MAC is computed with both the ciphertext and associated data (and other cryptosystem parameters), but the associated data is not encrypted, nor
|
|
207
|
+
saved within the ciphertext structure.
|
|
208
|
+
|
|
209
|
+
Parameters
|
|
210
|
+
----------
|
|
211
|
+
msg : str or byte str
|
|
212
|
+
The message to be encrypted.
|
|
213
|
+
associatedData : str or byte str, optional
|
|
214
|
+
Associated data that will be MACed together with the ciphertext and algorithm; the associated data will not be encrypted.
|
|
215
|
+
|
|
216
|
+
Returns
|
|
217
|
+
-------
|
|
218
|
+
dict
|
|
219
|
+
Dictionary structure containing:
|
|
220
|
+
msg: {'ALG': symmetric cryptosystem.
|
|
221
|
+
'MODE': symmetric encryption mode.
|
|
222
|
+
'IV': the IV for the encryption algorithm.
|
|
223
|
+
'CipherText': the padded ciphertext (padding according to PKCS 7).
|
|
224
|
+
}
|
|
225
|
+
"alg": The HMAC algorithm.
|
|
226
|
+
"digest": The MAC computed as MAC = HMAC(key, alg + associatedData + msg)
|
|
227
|
+
|
|
228
|
+
Notes
|
|
229
|
+
-----
|
|
230
|
+
The IV is included in the computation of the MAC. In fact, all cipher parameters are included: the encryption function returns a JSON object from
|
|
231
|
+
a dictionary composed of the cipher parameters (e.g., algorithm, mode, IV), and the ciphertext. The MAC function uses the whole JSON object/string
|
|
232
|
+
to compute the MAC, prepended with the HMAC algorithm + associatedData.
|
|
233
|
+
|
|
234
|
+
The MAC key is computed as sha2(b'Poor Mans Key Extractor" + key).
|
|
235
|
+
"""
|
|
236
|
+
# warning only valid in the random oracle
|
|
237
|
+
mac_key = sha2(b'Poor Mans Key Extractor'+self._key).digest()
|
|
238
|
+
mac = MessageAuthenticator(mac_key)
|
|
239
|
+
enc = super(AuthenticatedCryptoAbstraction, self).encrypt(msg)
|
|
240
|
+
return mac.mac(enc, associatedData=associatedData)
|
|
241
|
+
|
|
242
|
+
def decrypt(self, cipherText, associatedData=''):
|
|
243
|
+
"""
|
|
244
|
+
Decrypts a ciphertext in AEAD mode (Authenticated Encryption with Associated Data) using the superclass symmetric encryption parameters.
|
|
245
|
+
The MAC is computed with both the ciphertext and associated data (and other cryptosystem parameters), but the associated data is not encrypted, nor
|
|
246
|
+
available within the ciphertext structure.
|
|
247
|
+
|
|
248
|
+
Parameters
|
|
249
|
+
----------
|
|
250
|
+
ciphertext : str or byte str
|
|
251
|
+
The message to be decrypted.
|
|
252
|
+
associatedData : str or byte str, optional
|
|
253
|
+
Associated data that will be MACed together with the ciphertext and algorithm. This associated text must be in plaintext.
|
|
254
|
+
|
|
255
|
+
Returns
|
|
256
|
+
-------
|
|
257
|
+
byte str
|
|
258
|
+
The decrypted plaintext, if the ciphertext was successfuly authenticated. Raise exception otherwise.
|
|
259
|
+
|
|
260
|
+
Raises
|
|
261
|
+
------
|
|
262
|
+
ValueError
|
|
263
|
+
If the MAC is invalid.
|
|
264
|
+
|
|
265
|
+
Notes
|
|
266
|
+
-----
|
|
267
|
+
The IV is included in the computation of the MAC. In fact, all cipher parameters are included: the encryption function returns a JSON object from
|
|
268
|
+
a dictionary composed of the cipher parameters (e.g., algorithm, mode, IV), and the ciphertext. The MAC function uses the whole JSON object/string
|
|
269
|
+
to compute the MAC, prepended with the HMAC algorithm + associatedData.
|
|
270
|
+
|
|
271
|
+
The MAC key is computed as sha2(b'Poor Mans Key Extractor" + key).
|
|
272
|
+
"""
|
|
273
|
+
# warning only valid in the random oracle
|
|
274
|
+
mac_key = sha2(b'Poor Mans Key Extractor'+self._key).digest()
|
|
275
|
+
mac = MessageAuthenticator(mac_key)
|
|
276
|
+
if not mac.verify(cipherText, associatedData=associatedData):
|
|
277
|
+
raise ValueError("Invalid mac. Your data was tampered with or your key is wrong")
|
|
278
|
+
else:
|
|
279
|
+
return super(AuthenticatedCryptoAbstraction, self).decrypt(cipherText['msg'])
|