def split_rekey( self, pubkey: bytes, min_shares: int, num_shares: int) -> List[Tuple[tuple, Tuple[bytes, bytes]]]: priv_eph = self.pre.gen_priv() rks = self.pre.split_rekey(self._priv_key, priv_eph, min_shares, num_shares) encrypted_eph = self.encrypt(ec.serialize(priv_eph), pubkey=pubkey) return [((rk.id, ec.serialize(rk.key)), encrypted_eph) for rk in rks]
def rekey(self, pubkey: bytes) -> Tuple[tuple, Tuple[bytes, bytes]]: """ Create re-encryption key from private key which we have to public key pubkey. Internally, we create an ephemeral key priv_eph randomly and share data with it, and also attach encrypted priv_eph as the second part of the tuple """ priv_eph = self.pre.gen_priv() rk = self.pre.rekey(self._priv_key, priv_eph) encrypted_eph = self.encrypt(ec.serialize(priv_eph), pubkey=pubkey) return ((rk.id, ec.serialize(rk.key)), encrypted_eph)
def setUp(self): self.pre = umbral.PRE() self.privkey_a = self.pre.gen_priv() self.privkey_a_bytes = ec.serialize(self.privkey_a)[1:] self.privkey_b = self.pre.gen_priv() self.privkey_b_bytes = ec.serialize(self.privkey_b)[1:] self.pubkey_a = self.pre.priv2pub(self.privkey_a) self.pubkey_b = self.pre.priv2pub(self.privkey_b) self.pubkey_a_bytes = ec.serialize(self.pubkey_a)[1:] self.pubkey_b_bytes = ec.serialize(self.pubkey_b)[1:]
def reencrypt( self, rekey: Tuple[tuple, Tuple[bytes, bytes]], ciphertext: Tuple[bytes, bytes] ) -> Tuple[Tuple[bytes, bytes], Tuple[bytes, bytes]]: """ Re-encrypt for public key rekey is (rk, encrypted_eph), same as output of rekey() ciphertext is a tuple in the same format as output of encrypt() Output is two tuples: data encrypted with an ephemeral key and the ephemeral private key encrypted for recepient (Bob) """ rk, encrypted_eph = rekey rk = umbral.RekeyFrag(rk[0], ec.deserialize(self.pre.ecgroup, rk[1]), pre=PRE) ekey, edata = ciphertext ekey = umbral.EncryptedKey(ekey=ec.deserialize(self.pre.ecgroup, ekey[0]), re_id=ekey[1]) ekey = self.pre.reencrypt(rk, ekey) ekey = (ec.serialize(ekey.ekey), ekey.re_id) return (ekey, edata), encrypted_eph
def reencrypt(self, rk, emsg): if type(emsg) is str: emsg = emsg.encode() rk = self.load_key(rk) emsg = msgpack.loads(emsg) c1 = self.load_key(emsg[0]) c1 = c1**rk return msgpack.dumps([ec.serialize(c1)] + emsg[1:])
def kdf(self, ecdata, key_length): # XXX length ecdata = ec.serialize(ecdata)[1:] # Remove the first (type) bit # TODO: Handle salt somehow return HKDF(algorithm=hashes.SHA512(), length=key_length, salt=None, info=None, backend=default_backend()).derive(ecdata)
def test_pub_bytes2ec(self): pubkey = self.pre.priv2pub(self.privkey_a) self.assertEqual(ec.ec_element, type(pubkey)) pubkey_bytes = ec.serialize(pubkey)[1:] self.assertEqual(bytes, type(pubkey_bytes)) self.assertEqual(33, len(pubkey_bytes)) pubkey_ec = api.pub_bytes2ec(pubkey_bytes) self.assertEqual(ec.ec_element, type(pubkey_ec)) self.assertEqual(pubkey_ec, pubkey)
def ecies_gen_priv( to_bytes: bool = True) -> Union[bytes, elliptic_curve.ec_element]: """ Generates an ECIES private key. :param to_bytes: Return the byte serialization of the privkey? :return: An ECIES private key """ privkey = PRE.gen_priv() if to_bytes: return elliptic_curve.serialize(privkey)[1:] return privkey
def combine(self, shares: Tuple[Tuple[bytes, bytes], Tuple[bytes, bytes]] ) -> Tuple[Tuple[bytes, bytes], Tuple[bytes, bytes]]: ekeys = [umbral.EncryptedKey( ekey=ec.deserialize(self.pre.ecgroup, share[0][0][0]), re_id=share[0][0][1]) for share in shares] ekey = self.pre.combine(ekeys) ekey = (ec.serialize(ekey.ekey), ekey.re_id) # Everything except ekey is the same for all shares! # TODO instead of trusting the first share, trust the majority return (ekey, shares[0][0][1]), shares[0][1]
def priv2pub(self, priv: Union[bytes, 'elliptic_curve.Element']): """ Takes priv, a secret bytes or elliptic_curve.Element object to be used as a private key. Derives a matching public key and returns it. Returns a public key matching the type of priv. """ if type(priv) is bytes: # If priv is a bytes object, we need to "deserialize" it to an Element first, # then raise g to its power, then "reserialize" it to bytes. priv = ec.deserialize(self.ecgroup, priv) pub = self.g**priv return ec.serialize(pub) else: pub = self.g**priv return pub
def encrypt(self, pub, msg, padding=True): if type(msg) is str: msg = msg.encode() if padding: msg = pad(self.bitsize, msg) chunks = [ msg[i * self.bitsize:i * self.bitsize + self.bitsize] for i in range(len(msg) // self.bitsize) ] else: chunks = [msg] r = ec.random(self.ecgroup, ec.ZR) c1 = self.load_key(pub)**r c2 = [(self.g**r) * ec.encode(self.ecgroup, m, False) for m in chunks] c2 = map(ec.serialize, c2) return msgpack.dumps([ec.serialize(c1)] + list(c2))
def test_priv_bytes2ec(self): full_privkey_bytes = ec.serialize(self.privkey_a) privkey_bytes = full_privkey_bytes[1:] if len(privkey_bytes) is not 32: # Debug information here. print( "Hey everybody! Here's the weird len31 bug. The bytes were {}." .format(full_privkey_bytes)) self.assertEqual(bytes, type(privkey_bytes)) self.assertEqual(32, len(privkey_bytes)) privkey = api.priv_bytes2ec(privkey_bytes) self.assertEqual(ec.ec_element, type(privkey)) self.assertEqual(self.privkey_a, privkey)
def ecies_priv2pub( privkey: Union[bytes, elliptic_curve.ec_element], to_bytes: bool = True) -> Union[bytes, elliptic_curve.ec_element]: """ Takes a private key (secret bytes or an elliptic_curve.ec_element) and derives the Public key from it. :param privkey: The Private key to derive the public key from :param to_bytes: Return the byte serialization of the pubkey? :return: The Public component of the Private key provided """ if type(privkey) == bytes: privkey = priv_bytes2ec(privkey) pubkey = PRE.priv2pub(privkey) if to_bytes: return elliptic_curve.serialize(pubkey)[1:] return pubkey
def ecies_rekey(privkey_a: Union[bytes, elliptic_curve.ec_element], privkey_b: Union[bytes, elliptic_curve.ec_element], to_bytes: bool = True) -> Union[bytes, umbral.RekeyFrag]: """ Generates a re-encryption key from privkey_a to privkey_b. :param privkey_a: Private key to re-encrypt from :param privkey_b: Private key to re-encrypt to :param to_bytes: Format result as bytes? :return: Re-encryption key """ if type(privkey_a) == bytes: privkey_a = priv_bytes2ec(privkey_a) if type(privkey_b) == bytes: privkey_b = priv_bytes2ec(privkey_b) rk = PRE.rekey(privkey_a, privkey_b) if to_bytes: return elliptic_curve.serialize(rk.key)[1:] return rk
def encrypt(self, data: bytes, pubkey: bytes = None) -> Tuple[bytes, bytes]: """ :data: The data to encrypt. If derived per-subpath, it's a symmetric key to use for block ciphers. :pubkey: Optional public key to encrypt for. If not given, encrypt for ours :returns: (ekey, edata) where ekey is needed for recepient to reconstruct a DH secret, edata is data encrypted with this DH secret. The output should be treated as a monolithic ciphertext outside of this class """ if pubkey is None: pubkey = self._pub_key else: pubkey = ec.deserialize(self.pre.ecgroup, pubkey) key, ekey = self.pre.encapsulate(pubkey) cipher = SecretBox(key) return ((ec.serialize(ekey.ekey), None), cipher.encrypt(data))
def get_param(self): return ec.serialize(self.pre.g)
def save_key(self, key): # Same as in BBS98 return ec.serialize(key)
def pub_key(self): return ec.serialize(self._pub_key)
def __bytes__(self): return ec.serialize(self.id) + ec.serialize(self.key)
def save_key(self, key): return ec.serialize(key)
def to_dict(self): return {'g': ec.serialize(self.g), 'curve': self.curve}
def gen_priv(self, dtype='ec'): priv = ec.random(self.ecgroup, ec.ZR) if dtype in ('bytes', bytes): return ec.serialize(priv) else: return priv