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 decrypt(self, edata: Tuple[bytes, bytes], privkey: bytes = None) -> bytes: """ Decrypt data encrypted by ECIES edata = (ekey, edata) ekey is needed to reconstruct a DH secret edata encrypted by the block cipher privkey is optional private key if we want to use something else than what keypair uses """ if isinstance(edata[0], tuple) and isinstance(edata[1], tuple): # In case it was re-encrypted data return self.decrypt_reencrypted(edata) ekey, edata = edata # When it comes to decrypt(), ekey[1] is always None # we could use that and save 2 bytes, # but it makes the code less readable ekey = umbral.EncryptedKey(ekey=ec.deserialize(API.PRE.ecgroup, ekey[0]), re_id=ekey[1]) if privkey is None: privkey = self._priv_key else: privkey = ec.deserialize(API.PRE.ecgroup, privkey) key = self.pre.decapsulate(privkey, ekey) cipher = SecretBox(key) return cipher.decrypt(edata)
def from_bytes(cls, kfrag_bytes, pre=None): pre = pre or cls._pre return RekeyFrag( id=ec.deserialize(pre.ecgroup, kfrag_bytes[:len(kfrag_bytes) // 2]), key=ec.deserialize(pre.ecgroup, kfrag_bytes[len(kfrag_bytes) // 2:]), pre=pre)
def encapsulate(self, pubkey: bytes = None): if pubkey is None: pubkey = self._pub_key else: pubkey = ec.deserialize(self.pre.ecgroup, pubkey) key, ekey = self.pre.encapsulate(pubkey) return (key, ekey)
def __init__(self, curve=curves.secp256k1, g=None): self.curve = curves.secp256k1 self.ecgroup = ec.elliptic_curve(nid=self.curve) if g is None: self.g = ec.random(self.ecgroup, ec.G) else: self.g = ec.deserialize(self.ecgroup, g) self.bitsize = ec.bitsize(self.ecgroup)
def pub_bytes2ec(pubkey: bytes, ) -> elliptic_curve.ec_element: """ Turns a public key, in bytes, into an elliptic_curve.ec_element. :param pubkey: Public key to turn into an elliptic_curve.ec_element. :return: elliptic_curve.ec_element """ return elliptic_curve.deserialize(PRE.ecgroup, b'\x01' + pubkey)
def priv_bytes2ec(privkey: bytes) -> elliptic_curve.ec_element: """ Turns a private key, in bytes, into an elliptic_curve.ec_element. :param privkey: Private key to turn into an elliptic_curve.ec_element. :return: elliptic_curve.ec_element """ return elliptic_curve.deserialize(PRE.ecgroup, b'\x00' + privkey)
def __init__(self, curve=curves.secp256k1, g=None): self.curve = curve self.ecgroup = ec.elliptic_curve(nid=self.curve) if g is None: self.g = ec.getGenerator(self.ecgroup) else: if isinstance(g, ec.ec_element): self.g = g else: self.g = ec.deserialize(self.ecgroup, g) self.bitsize = ec.bitsize(self.ecgroup)
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 __init__(self, privkey: bytes = None) -> None: """ :privkey: Optional private key in a serialized form (32-byte string) If not given, a random one is generated. """ # Creating PRE object is slow # so let's reuse it per-thread if not _tl.pre: _tl.pre = umbral.PRE() self.pre = _tl.pre if not privkey: self._priv_key = self.pre.gen_priv() else: self._priv_key = ec.deserialize(self.pre.ecgroup, b'\x00' + privkey) # We don't always need a public key, so let's make it lazily self.__pub_key = None
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 load_key(self, key): # Same as in BBS98 if type(key) is bytes: return ec.deserialize(self.ecgroup, key) else: return key