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 test_activated_capsule_serialization(): priv_key = umbral.gen_priv() pub_key = umbral.priv2pub(priv_key) _unused_key, capsule = umbral._encapsulate(pub_key) kfrags, _unused_vkeys = umbral.split_rekey(priv_key, pub_key, 1, 2) cfrag = umbral.reencrypt(kfrags[0], capsule) capsule.attach_cfrag(cfrag) capsule._reconstruct_shamirs_secret() rec_capsule_bytes = capsule.to_bytes() # An activated Capsule is: # three points, representable as 33 bytes each (the original), and # two points and a bignum (32 bytes) (the activated components), for 197 total. assert len(rec_capsule_bytes) == (33 * 3) + (33 + 33 + 32) new_rec_capsule = umbral.Capsule.from_bytes(rec_capsule_bytes) # Again, the same three perspectives on equality. assert new_rec_capsule == capsule assert new_rec_capsule.activated_components() == capsule.activated_components() assert new_rec_capsule._point_eph_e_prime == capsule._point_eph_e_prime assert new_rec_capsule._point_eph_v_prime == capsule._point_eph_v_prime assert new_rec_capsule._point_noninteractive == capsule._point_noninteractive
def test_challenge_response_serialization(): priv_key = umbral.gen_priv() pub_key = umbral.priv2pub(priv_key) _unused_key, capsule = umbral._encapsulate(pub_key) kfrags, _unused_vkeys = umbral.split_rekey(priv_key, pub_key, 1, 2) cfrag = umbral.reencrypt(kfrags[0], capsule) capsule.attach_cfrag(cfrag) ch_resp = umbral.challenge(kfrags[0], capsule, cfrag) ch_resp_bytes = ch_resp.to_bytes() # A ChallengeResponse can be represented as # the 228 total bytes of four Points (33 each) and three BigNums (32 each). assert len(ch_resp_bytes) == (33 * 4) + (32 * 3) == 228 new_ch_resp = umbral.ChallengeResponse.from_bytes(ch_resp_bytes) assert new_ch_resp.point_eph_e2 == ch_resp.point_eph_e2 assert new_ch_resp.point_eph_v2 == ch_resp.point_eph_v2 assert new_ch_resp.point_kfrag_commitment == ch_resp.point_kfrag_commitment assert new_ch_resp.point_kfrag_pok == ch_resp.point_kfrag_pok assert new_ch_resp.bn_kfrag_sig1 == ch_resp.bn_kfrag_sig1 assert new_ch_resp.bn_kfrag_sig2 == ch_resp.bn_kfrag_sig2 assert new_ch_resp.bn_sig == ch_resp.bn_sig
def test_m_of_n(N, M, alices_keys, bobs_keys): priv_key_alice, pub_key_alice = alices_keys priv_key_bob, pub_key_bob = bobs_keys sym_key, capsule = umbral._encapsulate(pub_key_alice.point_key) kfrags, vkeys = umbral.split_rekey(priv_key_alice, pub_key_bob, M, N) for kfrag in kfrags: assert kfrag.verify(pub_key_alice.point_key, pub_key_bob.point_key) assert kfrag.is_consistent(vkeys) for kfrag in kfrags[:M]: cfrag = umbral.reencrypt(kfrag, capsule) capsule.attach_cfrag(cfrag) ch = umbral.challenge(kfrag, capsule, cfrag) assert umbral.check_challenge(capsule, cfrag, ch, pub_key_alice.point_key, pub_key_bob.point_key) # assert capsule.is_openable_by_bob() # TODO: Is it possible to check here if >= m cFrags have been attached? # capsule.open(pub_bob, priv_bob, pub_alice) capsule._reconstruct_shamirs_secret() sym_key_from_capsule = umbral.decapsulate_reencrypted(pub_key_bob.point_key, priv_key_bob.bn_key, pub_key_alice.point_key, capsule) assert sym_key == sym_key_from_capsule
def test_cheating_ursula_replays_old_reencryption(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() sym_key_alice1, capsule_alice1 = umbral._encapsulate(pub_key_alice.point_key) sym_key_alice2, capsule_alice2 = umbral._encapsulate(pub_key_alice.point_key) k_frags, v_keys = umbral.split_rekey(priv_key_alice, pub_key_bob, M, N) for k_frag in k_frags: assert k_frag.is_consistent(v_keys) c_frags, challenges = [], [] for index, k_frag in enumerate(k_frags): if index == 0: # Let's put the re-encryption of a different Alice ciphertext c_frag = umbral.reencrypt(k_frag, capsule_alice2) else: c_frag = umbral.reencrypt(k_frag, capsule_alice1) challenge = umbral.challenge(k_frag, capsule_alice1, c_frag) capsule_alice1.attach_cfrag(c_frag) challenges.append(challenge) c_frags.append(c_frag) capsule_alice1._reconstruct_shamirs_secret() # activate capsule with pytest.raises(umbral.GenericUmbralError): sym_key = umbral.decapsulate_reencrypted(pub_key_bob.point_key, priv_key_bob.bn_key, pub_key_alice.point_key, capsule_alice1) assert not sym_key == sym_key_alice1 assert not umbral.check_challenge(capsule_alice1, c_frags[0], challenges[0], pub_key_alice.point_key, pub_key_bob.point_key, ) # The response of cheating Ursula is in capsules[0], # so the rest of challenges chould be correct: for (c_frag, ch) in zip(c_frags[1:], challenges[1:]): assert umbral.check_challenge(capsule_alice1, c_frag, ch, pub_key_alice.point_key, pub_key_bob.point_key, )
def test_bad_capsule_fails_reencryption(alices_keys): priv_key_alice, pub_key_alice = alices_keys k_frags, _unused_vkeys = umbral.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): umbral.reencrypt(k_frags[0], bollocks_capsule)
def test_cheating_ursula_sends_garbage(N, M): priv_key_alice = keys.UmbralPrivateKey.gen_key() pub_key_alice = priv_key_alice.get_pubkey() # Bob priv_key_bob = keys.UmbralPrivateKey.gen_key() pub_key_bob = priv_key_bob.get_pubkey() sym_key, capsule_alice = umbral._encapsulate(pub_key_alice.point_key) k_frags, v_keys = umbral.split_rekey(priv_key_alice, pub_key_bob, M, N) for k_frag in k_frags: assert k_frag.is_consistent(v_keys) c_frags, challenges = [], [] for k_frag in k_frags[0:M]: c_frag = umbral.reencrypt(k_frag, capsule_alice) challenge = umbral.challenge(k_frag, capsule_alice, c_frag) capsule_alice.attach_cfrag(c_frag) assert umbral.check_challenge(capsule_alice, c_frag, challenge, pub_key_alice.point_key, pub_key_bob.point_key, ) c_frags.append(c_frag) challenges.append(challenge) # Let's put random garbage in one of the c_frags c_frags[0].point_eph_e1 = Point.gen_rand() c_frags[0].point_eph_v1 = Point.gen_rand() capsule_alice._reconstruct_shamirs_secret() # activate capsule with pytest.raises(umbral.GenericUmbralError): sym_key2 = umbral.decapsulate_reencrypted(pub_key_bob.point_key, priv_key_bob.bn_key, pub_key_alice.point_key, capsule_alice) assert sym_key2 != sym_key assert not umbral.check_challenge(capsule_alice, c_frags[0], challenges[0], pub_key_alice.point_key, pub_key_bob.point_key) # The response of cheating Ursula is in capsules[0], # so the rest of challenges chould be correct: for (c_frag, ch) in zip(c_frags[1:], challenges[1:]): assert umbral.check_challenge(capsule_alice, c_frag, ch, pub_key_alice.point_key, pub_key_bob.point_key)
def test_kfrag_serialization(alices_keys): priv_key_alice, pub_key_alice = alices_keys kfrags, _unused_vkeys = umbral.split_rekey(priv_key_alice, pub_key_alice, 1, 2) kfrag_bytes = kfrags[0].to_bytes() # A KFrag can be represented as the 194 total bytes of two Points (33 each) and four BigNums (32 each). assert len(kfrag_bytes) == 33 + 33 + (32 * 4) == 194 new_frag = umbral.KFrag.from_bytes(kfrag_bytes) assert new_frag.bn_id == kfrags[0].bn_id assert new_frag.bn_key == kfrags[0].bn_key assert new_frag.point_eph_ni == kfrags[0].point_eph_ni assert new_frag.point_commitment == kfrags[0].point_commitment assert new_frag.bn_sig1 == kfrags[0].bn_sig1 assert new_frag.bn_sig2 == kfrags[0].bn_sig2
def test_cfrag_serialization(alices_keys): priv_key_alice, pub_key_alice = alices_keys _unused_key, capsule = umbral._encapsulate(pub_key_alice.point_key) k_frags, _unused_vkeys = umbral.split_rekey(priv_key_alice, pub_key_alice, 1, 2) c_frag = umbral.reencrypt(k_frags[0], capsule) c_frag_bytes = c_frag.to_bytes() # A CFrag can be represented as the 131 total bytes of three Points (33 each) and a BigNum (32). assert len(c_frag_bytes) == 33 + 33 + 33 + 32 == 131 new_cfrag = umbral.CapsuleFrag.from_bytes(c_frag_bytes) assert new_cfrag.point_eph_e1 == c_frag.point_eph_e1 assert new_cfrag.point_eph_v1 == c_frag.point_eph_v1 assert new_cfrag.bn_kfrag_id == c_frag.bn_kfrag_id assert new_cfrag.point_eph_ni == c_frag.point_eph_ni
def test_simple_api(N, M, curve=default_curve()): """Manually injects umbralparameters for multi-curve testing.""" params = UmbralParameters(curve=curve) priv_key_alice = keys.UmbralPrivateKey.gen_key(params=params) pub_key_alice = priv_key_alice.get_pubkey() priv_key_bob = keys.UmbralPrivateKey.gen_key(params=params) pub_key_bob = priv_key_bob.get_pubkey() plain_data = b'attack at dawn' ciphertext, capsule = umbral.encrypt(pub_key_alice, plain_data) cleartext = umbral.decrypt(capsule, priv_key_alice, ciphertext) assert cleartext == plain_data rekeys, _unused_vkeys = umbral.split_rekey(priv_key_alice, pub_key_bob, M, N, params=params) for rekey in rekeys: c_frag = umbral.reencrypt(rekey, capsule, params=params) capsule.attach_cfrag(c_frag) reenc_cleartext = umbral.decrypt(capsule, priv_key_bob, ciphertext, pub_key_alice) assert reenc_cleartext == plain_data
# Bob receives a capsule through a side channel (s3, ipfs, Google cloud, etc) bob_capsule = umbral_capsule #6 # Attempt Bob's decryption (fail) try: fail_decrypted_data = umbral.decrypt(bob_capsule, bob_priv_key, alice_ciphertext, alice_pubkey) except: print("Decryption failed!") #7 # Generate threshold split re-encryption keys via Shamir's Secret Sharing # verification not ready yet, don't store vKeys # Use Alice's private key, and Bob's public key. # Use a minimum threshold of 10, and create 20 total shares kfrags, _ = umbral.split_rekey(alice_priv_key, bob_pub_key, 10, 20) #8 # Have Ursula perform re-encrypton. # Pick 10 random shares: rand_min_shares = random.sample(kfrags, 10) # Have Ursula re-encrypt the shares and attach them to the capsule: for kfrag in kfrags: cfrag = umbral.reencrypt(kfrag, umbral_capsule) bob_capsule.attach_cfrag(cfrag) #9 # Bob reconstructs the capsule and decrypts the ciphertext: bob_plaintext = umbral.decrypt(bob_capsule, bob_priv_key, alice_ciphertext, alice_pub_key) print("this is bob: ", bob_plaintext)
def reencrypt(): alice_priv = request.json.get('private_key') pub_key = request.json.get('pub_client') umbral_capsule = request.json.get('capsule') input_ciphertext = request.json.get('ciphertext') if not alice_priv: return jsonify({'Error': 'Missing required Data owner\' Private key - '}) if not pub_key: return jsonify({'Error': 'Missing required Bob\'s Public key - Data receiver'}) if not umbral_capsule: return jsonify({'Error': 'Missing required capsule'}) if not input_ciphertext: return jsonify({'Error': 'Missing required cipher text'}) alice_priv_key = keys.UmbralPrivateKey.from_bytes(alice_priv) alice_public_key = alice_priv_key.get_pubkey() bob_pub_key = keys.UmbralPublicKey.from_bytes(pub_key) # convert capsule input from base64 string to bytes, then to Capsule umbral_capsule_decoded_bytes = base64.b64decode(umbral_capsule) input_umbral_capsule = umbral.Capsule.from_bytes(umbral_capsule_decoded_bytes) ciphertext = base64.b64decode(input_ciphertext) # Have Ursula re-encrypt the shares and attach them to the capsule: kfrags,_ = umbral.split_rekey(alice_priv_key, bob_pub_key, 10, 20) umbral.split_rekey rand_min_shares = random.sample(kfrags,10); cfrags = list() bob_capsule = input_umbral_capsule for kfrag in rand_min_shares: cfrag= umbral.reencrypt(kfrag, input_umbral_capsule) cfrags.append(cfrag) # bob_capsule.attach_cfrag(cfrag) # cfrags2 = base64.b64decode(CapsuleFrag.from_bytes(base64.b64encode(cfrags.to_bytes()))) # for c in cfrags2: # bob_capsule.attach_cfrag(c) # umbral_capsule_encoded = base64.b64encode(bob_capsule.to_bytes()).decode("utf-8") print('##########') # print (umbral_capsule_encoded); print('##########') # cfrag_dump = json.dumps(bob_capsule._attached_cfrags); # bob_capsule._attached_cfrags = {} # bob_capsule._attached_cfrags = json.loads(cfrag_dump); bob_priv = request.json.get('private_client') bob_priv_key = keys.UmbralPrivateKey.from_bytes(bob_priv) # decrypted_plaintext = umbral.decrypt(bob_capsule, bob_priv_key, ciphertext, alice_public_key) # decrypted_plaintext_encoded = decrypted_plaintext.decode("utf-8") print('##########') # print (decrypted_plaintext_encoded); print('##########') # umbral_capsule_encoded = base64.b64encode(bob_capsule.to_bytes()).decode("utf-8") return jsonify({'capsule_bob': umbral_capsule_encoded, 'ciphertext': input_ciphertext, 'public_key':alice_public_key.to_bytes().decode("utf-8")})