2018-07-25 17:55:12 +00:00
|
|
|
"""
|
|
|
|
Copyright (C) 2018 NuCypher
|
|
|
|
|
|
|
|
This file is part of pyUmbral.
|
|
|
|
|
|
|
|
pyUmbral is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
pyUmbral is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with pyUmbral. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
"""
|
|
|
|
|
2018-02-16 20:36:07 +00:00
|
|
|
#1
|
|
|
|
# Sets a default curve (secp256k1)
|
|
|
|
import random
|
2018-07-26 13:18:09 +00:00
|
|
|
from umbral import pre, keys, config, signing
|
2018-02-16 20:36:07 +00:00
|
|
|
|
|
|
|
config.set_default_curve()
|
|
|
|
|
|
|
|
#2
|
2018-07-26 13:18:09 +00:00
|
|
|
# Generate an Umbral key pair
|
|
|
|
# ---------------------------
|
|
|
|
# First, Let's generate two asymmetric key pairs for Alice:
|
|
|
|
# A delegating key pair and a Signing key pair.
|
2018-02-16 20:36:07 +00:00
|
|
|
|
2018-07-26 13:18:09 +00:00
|
|
|
alices_private_key = keys.UmbralPrivateKey.gen_key()
|
|
|
|
alices_public_key = alices_private_key.get_pubkey()
|
|
|
|
|
|
|
|
alices_signing_key = keys.UmbralPrivateKey.gen_key()
|
|
|
|
alices_verifying_key = alices_signing_key.get_pubkey()
|
|
|
|
alices_signer = signing.Signer(private_key=alices_signing_key)
|
2018-02-16 20:36:07 +00:00
|
|
|
|
|
|
|
#3
|
|
|
|
# Encrypt some data for Alice
|
2018-07-26 13:18:09 +00:00
|
|
|
# ---------------------------
|
|
|
|
# Now let's encrypt data with Alice's public key.
|
|
|
|
# Invocation of `pre.encrypt` returns both the `ciphertext`,
|
2018-07-29 06:22:25 +00:00
|
|
|
# and a `capsule`. Anyone with Alice's public key can perform
|
2018-07-26 13:18:09 +00:00
|
|
|
# this operation.
|
|
|
|
|
|
|
|
plaintext = b'Proxy Re-encryption is cool!'
|
|
|
|
ciphertext, capsule = pre.encrypt(alices_public_key, plaintext)
|
|
|
|
print(ciphertext)
|
2018-02-16 20:36:07 +00:00
|
|
|
|
|
|
|
#4
|
|
|
|
# Decrypt data for Alice
|
2018-07-26 13:18:09 +00:00
|
|
|
# ----------------------
|
|
|
|
# Since data was encrypted with Alice's public key,
|
|
|
|
# Alice can open the capsule and decrypt the ciphertext with her private key.
|
|
|
|
|
|
|
|
cleartext = pre.decrypt(ciphertext=ciphertext,
|
|
|
|
capsule=capsule,
|
|
|
|
decrypting_key=alices_private_key)
|
|
|
|
print(cleartext)
|
|
|
|
|
2018-02-16 20:36:07 +00:00
|
|
|
|
|
|
|
#5
|
2018-07-26 13:18:09 +00:00
|
|
|
# Bob Exists
|
|
|
|
# -----------
|
|
|
|
|
|
|
|
bobs_private_key = keys.UmbralPrivateKey.gen_key()
|
|
|
|
bobs_public_key = bobs_private_key.get_pubkey()
|
2018-02-16 20:36:07 +00:00
|
|
|
|
|
|
|
#6
|
2018-07-26 13:18:09 +00:00
|
|
|
# Bob receives a capsule through a side channel (s3, ipfs, Google cloud, etc)
|
|
|
|
bob_capsule = capsule
|
|
|
|
|
|
|
|
#7
|
2018-02-16 20:36:07 +00:00
|
|
|
# Attempt Bob's decryption (fail)
|
|
|
|
try:
|
2018-07-26 13:18:09 +00:00
|
|
|
fail_decrypted_data = pre.decrypt(ciphertext=ciphertext,
|
|
|
|
capsule=bob_capsule,
|
|
|
|
decrypting_key=bobs_private_key)
|
2018-02-16 20:36:07 +00:00
|
|
|
except:
|
2018-07-26 13:18:09 +00:00
|
|
|
print("Decryption failed! Bob doesn't has access granted yet.")
|
2018-02-16 20:36:07 +00:00
|
|
|
|
|
|
|
#8
|
2018-07-26 13:18:09 +00:00
|
|
|
# Alice grants access to Bob by generating kfrags
|
|
|
|
# -----------------------------------------------
|
|
|
|
# When Alice wants to grant Bob access to open her encrypted messages,
|
|
|
|
# she creates *threshold split re-encryption keys*, or *"kfrags"*,
|
|
|
|
# which are next sent to N proxies or *Ursulas*.
|
|
|
|
# She uses her private key, and Bob's public key, and she sets a minimum
|
|
|
|
# threshold of 10, for 20 total shares
|
|
|
|
|
|
|
|
kfrags = pre.split_rekey(delegating_privkey=alices_private_key,
|
|
|
|
signer=alices_signer,
|
|
|
|
receiving_pubkey=bobs_public_key,
|
|
|
|
threshold=10,
|
|
|
|
N=20)
|
2018-02-16 20:36:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
#9
|
2018-07-26 13:18:09 +00:00
|
|
|
# Ursulas perform re-encryption
|
|
|
|
# ------------------------------
|
|
|
|
# Bob asks several Ursulas to re-encrypt the capsule so he can open it.
|
|
|
|
# Each Ursula performs re-encryption on the capsule using the `kfrag`
|
2018-07-29 06:22:25 +00:00
|
|
|
# provided by Alice, obtaining this way a "capsule fragment", or `cfrag`.
|
2018-07-26 13:18:09 +00:00
|
|
|
# Let's mock a network or transport layer by sampling `threshold` random `kfrags`,
|
|
|
|
# one for each required Ursula.
|
|
|
|
|
|
|
|
import random
|
|
|
|
kfrags = random.sample(kfrags, # All kfrags from above
|
|
|
|
10) # M - Threshold
|
|
|
|
|
|
|
|
# Bob collects the resulting `cfrags` from several Ursulas.
|
|
|
|
# Bob must gather at least `threshold` `cfrags` in order to activate the capsule.
|
|
|
|
|
|
|
|
cfrags = list() # Bob's cfrag collection
|
|
|
|
for kfrag in kfrags:
|
|
|
|
cfrag = pre.reencrypt(kfrag=kfrag, capsule=bob_capsule)
|
|
|
|
cfrags.append(cfrag) # Bob collects a cfrag
|
|
|
|
|
|
|
|
assert len(cfrags) == 10
|
|
|
|
|
|
|
|
|
|
|
|
#10
|
|
|
|
# Bob attaches cfrags to the capsule
|
|
|
|
# ----------------------------------
|
|
|
|
# Bob attaches at least `threshold` `cfrags` to the capsule;
|
|
|
|
# then it can become *activated*.
|
|
|
|
|
|
|
|
bob_capsule.set_correctness_keys(delegating=alices_public_key,
|
|
|
|
receiving=bobs_public_key,
|
|
|
|
verifying=alices_verifying_key)
|
|
|
|
|
|
|
|
for cfrag in cfrags:
|
|
|
|
bob_capsule.attach_cfrag(cfrag)
|
|
|
|
|
|
|
|
#11
|
|
|
|
# Bob activates and opens the capsule
|
|
|
|
# ------------------------------------
|
|
|
|
# Finally, Bob activates and opens the capsule,
|
|
|
|
# then decrypts the re-encrypted ciphertext.
|
|
|
|
|
|
|
|
|
|
|
|
bob_cleartext = pre.decrypt(ciphertext=ciphertext, capsule=bob_capsule, decrypting_key=bobs_private_key)
|
|
|
|
print(bob_cleartext)
|
|
|
|
assert bob_cleartext == plaintext
|