def split_rekey(priv_a: Union[UmbralPrivateKey, BigNum], pub_b: Union[UmbralPublicKey, Point], threshold: int, N: int, params: UmbralParameters = None) -> List[KFrag]: """ Creates a re-encryption key from Alice to Bob and splits it in KFrags, using Shamir's Secret Sharing. Requires a threshold number of KFrags out of N to guarantee correctness of re-encryption. Returns a list of KFrags. """ params = params if params is not None else default_params() if isinstance(priv_a, UmbralPrivateKey): priv_a = priv_a.bn_key if isinstance(pub_b, UmbralPublicKey): pub_b = pub_b.point_key g = params.g pub_a = priv_a * g x = BigNum.gen_rand(params.curve) xcomp = x * g d = hash_to_bn([xcomp, pub_b, pub_b * x], params) coeffs = [priv_a * (~d)] coeffs += [BigNum.gen_rand(params.curve) for _ in range(threshold - 1)] u = params.u g_ab = priv_a * pub_b blake2b = hashes.Hash(hashes.BLAKE2b(64), backend=backend) blake2b.update(pub_a.to_bytes()) blake2b.update(pub_b.to_bytes()) blake2b.update(g_ab.to_bytes()) hashed_dh_tuple = blake2b.finalize() kfrags = [] for _ in range(N): id_kfrag = BigNum.gen_rand(params.curve) share_x = hash_to_bn([id_kfrag, hashed_dh_tuple], params) rk = poly_eval(coeffs, share_x) u1 = rk * u y = BigNum.gen_rand(params.curve) z1 = hash_to_bn([y * g, id_kfrag, pub_a, pub_b, u1, xcomp], params) z2 = y - priv_a * z1 kfrag = KFrag(id_=id_kfrag, key=rk, x=xcomp, u1=u1, z1=z1, z2=z2) kfrags.append(kfrag) return kfrags
def split_rekey( priv_a: Union[UmbralPrivateKey, BigNum], pub_b: Union[UmbralPublicKey, Point], threshold: int, N: int, params: UmbralParameters = None) -> Tuple[List[KFrag], List[Point]]: """ Creates a re-encryption key and splits it using Shamir's Secret Sharing. Requires a threshold number of fragments out of N to rebuild rekey. Returns rekeys and the vKeys. """ params = params if params is not None else default_params() if isinstance(priv_a, UmbralPrivateKey): priv_a = priv_a.bn_key if isinstance(pub_b, UmbralPublicKey): pub_b = pub_b.point_key g = params.g pub_a = priv_a * g x = BigNum.gen_rand(params.curve) xcomp = x * g d = hash_to_bn([xcomp, pub_b, pub_b * x], params) coeffs = [priv_a * (~d)] coeffs += [BigNum.gen_rand(params.curve) for _ in range(threshold - 1)] h = params.h u = params.u v_keys = [coeff * h for coeff in coeffs] rk_shares = [] for _ in range(N): id_kfrag = BigNum.gen_rand(params.curve) rk = poly_eval(coeffs, id_kfrag) u1 = rk * u y = BigNum.gen_rand(params.curve) z1 = hash_to_bn([y * g, id_kfrag, pub_a, pub_b, u1, xcomp], params) z2 = y - priv_a * z1 kFrag = KFrag(id_=id_kfrag, key=rk, x=xcomp, u1=u1, z1=z1, z2=z2) rk_shares.append(kFrag) return rk_shares, v_keys
def gen_rand(cls, curve: ec.EllipticCurve = None): """ Returns a Point object with a cryptographically secure EC_POINT based on the provided curve. """ curve = curve if curve is not None else default_curve() curve_nid = backend._elliptic_curve_to_nid(curve) group = backend._lib.EC_GROUP_new_by_curve_name(curve_nid) backend.openssl_assert(group != backend._ffi.NULL) generator = backend._lib.EC_GROUP_get0_generator(group) backend.openssl_assert(generator != backend._ffi.NULL) rand_point = backend._lib.EC_POINT_new(group) backend.openssl_assert(rand_point != backend._ffi.NULL) rand_point = backend._ffi.gc(rand_point, backend._lib.EC_POINT_clear_free) rand_bn = BigNum.gen_rand(curve).bignum with backend._tmp_bn_ctx() as bn_ctx: res = backend._lib.EC_POINT_mul(group, rand_point, backend._ffi.NULL, generator, rand_bn, bn_ctx) backend.openssl_assert(res == 1) return Point(rand_point, curve_nid, group)
def test_capsule_equality(): one_capsule = Capsule(point_eph_e=Point.gen_rand(), point_eph_v=Point.gen_rand(), bn_sig=BigNum.gen_rand()) another_capsule = Capsule(point_eph_e=Point.gen_rand(), point_eph_v=Point.gen_rand(), bn_sig=BigNum.gen_rand()) assert one_capsule != another_capsule activated_capsule = Capsule(e_prime=Point.gen_rand(), v_prime=Point.gen_rand(), noninteractive_point=Point.gen_rand()) assert activated_capsule != one_capsule
def test_alice_sends_fake_kfrag_to_ursula(N, M): priv_key_alice = keys.UmbralPrivateKey.gen_key() pub_key_alice = priv_key_alice.get_pubkey() priv_key_bob = keys.UmbralPrivateKey.gen_key() pub_key_bob = priv_key_bob.get_pubkey() plaintext = b'attack at dawn' ciphertext, capsule = umbral.encrypt(pub_key_alice, plaintext) cleartext = umbral.decrypt(capsule, priv_key_alice, ciphertext) assert cleartext == plaintext k_frags, vkeys = umbral.split_rekey(priv_key_alice, pub_key_bob, M, N) # Alice tries to frame the first Ursula by sending her a random kFrag k_frags[0].bn_key = BigNum.gen_rand() for k_frag in k_frags: c_frag = umbral.reencrypt(k_frag, capsule) capsule.attach_cfrag(c_frag) with pytest.raises(Exception): _ = umbral.decrypt(capsule, priv_key_bob, ciphertext, pub_key_alice)
def gen_key(cls, params: UmbralParameters = None): """ Generates a private key and returns it. """ if params is None: params = default_params() bn_key = BigNum.gen_rand(params.curve) return cls(bn_key, params)
def test_cast_bignum_to_int(): x = BigNum.gen_rand() x_as_int_from_dunder = x.__int__() x_as_int_type_caster = int(x) assert x_as_int_from_dunder == x_as_int_type_caster x = x_as_int_type_caster y = BigNum.from_int(x) assert x == y
def test_bad_capsule_fails_reencryption(alices_keys): priv_key_alice, pub_key_alice = alices_keys kfrags = pre.split_rekey(priv_key_alice, pub_key_alice, 1, 2) bollocks_capsule = Capsule(point_eph_e=Point.gen_rand(), point_eph_v=Point.gen_rand(), bn_sig=BigNum.gen_rand()) with pytest.raises(Capsule.NotValid): pre.reencrypt(kfrags[0], bollocks_capsule)
def _encapsulate(alice_pub_key: Point, key_length=32, params: UmbralParameters = None) -> Tuple[bytes, Capsule]: """Generates a symmetric key and its associated KEM ciphertext""" params = params if params is not None else default_params() g = params.g priv_r = BigNum.gen_rand(params.curve) pub_r = priv_r * g priv_u = BigNum.gen_rand(params.curve) pub_u = priv_u * g h = hash_to_bn([pub_r, pub_u], params) s = priv_u + (priv_r * h) shared_key = (priv_r + priv_u) * alice_pub_key # Key to be used for symmetric encryption key = kdf(shared_key, key_length) return key, Capsule(point_eph_e=pub_r, point_eph_v=pub_u, bn_sig=s)
def test_capsule_creation(alices_keys): with pytest.raises(TypeError): rare_capsule = Capsule() # Alice cannot make a capsule this way. # Some users may create capsules their own way. custom_capsule = Capsule(point_eph_e=Point.gen_rand(), point_eph_v=Point.gen_rand(), bn_sig=BigNum.gen_rand()) assert isinstance(custom_capsule, Capsule) # Typical Alice, constructing a typical capsule _, alices_public_key = alices_keys plaintext = b'peace at dawn' ciphertext, typical_capsule = pre.encrypt(alices_public_key, plaintext) assert isinstance(typical_capsule, Capsule)
def _challenge(kfrag: KFrag, capsule: Capsule, cfrag: CapsuleFrag, challenge_metadata: bytes = None, params: UmbralParameters = None) -> ChallengeResponse: params = params if params is not None else default_params() e1 = cfrag.point_eph_e1 v1 = cfrag.point_eph_v1 e = capsule._point_eph_e v = capsule._point_eph_v u = params.u u1 = kfrag.point_commitment t = BigNum.gen_rand(params.curve) e2 = t * e v2 = t * v u2 = t * u hash_input = [e, e1, e2, v, v1, v2, u, u1, u2] if challenge_metadata is not None: hash_input.append(challenge_metadata) h = hash_to_bn(hash_input, params) z3 = t + h * kfrag.bn_key ch_resp = ChallengeResponse(e2=e2, v2=v2, u1=u1, u2=u2, z1=kfrag.bn_sig1, z2=kfrag.bn_sig2, z3=z3) # Check correctness of original ciphertext (check nÂș 2) at the end # to avoid timing oracles if not capsule.verify(params): raise capsule.NotValid("Capsule verification failed.") return ch_resp
def test_cannot_create_capsule_from_bogus_material(alices_keys): with pytest.raises(TypeError): capsule_of_questionable_parentage = pre.Capsule(point_eph_e=Point.gen_rand(), point_eph_v=42, bn_sig=BigNum.gen_rand()) with pytest.raises(TypeError): capsule_of_questionable_parentage = pre.Capsule(point_eph_e=Point.gen_rand(), point_eph_v=Point.gen_rand(), bn_sig=42) with pytest.raises(TypeError): capsule_of_questionable_parentage = pre.Capsule(e_prime=Point.gen_rand(), v_prime=42, noninteractive_point=Point.gen_rand()) with pytest.raises(TypeError): capsule_of_questionable_parentage = pre.Capsule(e_prime=Point.gen_rand(), v_prime=Point.gen_rand(), noninteractive_point=42)
def test_bn_to_cryptography_privkey(): bn = BigNum.gen_rand() crypto_privkey = bn.to_cryptography_priv_key() assert int(bn) == crypto_privkey.private_numbers().private_value
def random_ec_bignum2(): yield BigNum.gen_rand()
def gen_priv(curve: ec.EllipticCurve = None) -> BigNum: curve = curve if curve is not None else default_curve() return BigNum.gen_rand(curve)