def _decapsulate_reencrypted(receiving_privkey: UmbralPrivateKey, capsule: Capsule, key_length: int = DEM_KEYSIZE) -> bytes: """Derive the same symmetric key""" params = capsule._umbral_params pub_key = receiving_privkey.get_pubkey().point_key priv_key = receiving_privkey.bn_key ni = capsule._point_noninteractive d = CurveBN.hash(ni, pub_key, priv_key * ni, params=params) e_prime = capsule._point_e_prime v_prime = capsule._point_v_prime shared_key = d * (e_prime + v_prime) key = kdf(shared_key, key_length) e = capsule._point_e v = capsule._point_v s = capsule._bn_sig h = CurveBN.hash(e, v, params=params) inv_d = ~d orig_pub_key = capsule.get_correctness_keys()['delegating'].point_key if not (s * inv_d) * orig_pub_key == (h * e_prime) + v_prime: raise GenericUmbralError() return key
def _decapsulate_reencrypted(receiving_privkey: UmbralPrivateKey, capsule: Capsule, key_length: int = DEM_KEYSIZE) -> bytes: """Derive the same symmetric encapsulated_key""" params = capsule.params pub_key = receiving_privkey.get_pubkey().point_key priv_key = receiving_privkey.bn_key precursor = capsule._attached_cfrags[0]._point_precursor dh_point = priv_key * precursor from constant_sorrow import constants # Combination of CFrags via Shamir's Secret Sharing reconstruction if len(capsule._attached_cfrags) > 1: xs = [ CurveBN.hash(precursor, pub_key, dh_point, bytes(constants.X_COORDINATE), cfrag._kfrag_id, params=params) for cfrag in capsule._attached_cfrags ] e_summands, v_summands = list(), list() for cfrag, x in zip(capsule._attached_cfrags, xs): if precursor != cfrag._point_precursor: raise ValueError("Attached CFrags are not pairwise consistent") lambda_i = lambda_coeff(x, xs) e_summands.append(lambda_i * cfrag._point_e1) v_summands.append(lambda_i * cfrag._point_v1) e_prime = sum(e_summands[1:], e_summands[0]) v_prime = sum(v_summands[1:], v_summands[0]) else: e_prime = capsule._attached_cfrags[0]._point_e1 v_prime = capsule._attached_cfrags[0]._point_v1 # Secret value 'd' allows to make Umbral non-interactive d = CurveBN.hash(precursor, pub_key, dh_point, bytes(constants.NON_INTERACTIVE), params=params) e, v, s = capsule.components() h = CurveBN.hash(e, v, params=params) orig_pub_key = capsule.get_correctness_keys( )['delegating'].point_key # type: ignore if not (s / d) * orig_pub_key == (h * e_prime) + v_prime: raise GenericUmbralError() shared_key = d * (e_prime + v_prime) encapsulated_key = kdf(shared_key, key_length) return encapsulated_key
def _decapsulate_reencrypted(pub_key: Point, priv_key: CurveBN, orig_pub_key: Point, capsule: Capsule, key_length=32, params: UmbralParameters=None) -> bytes: """Derive the same symmetric key""" params = params if params is not None else default_params() xcomp = capsule._point_noninteractive d = CurveBN.hash_to_bn(xcomp, pub_key, priv_key * xcomp, params=params) e_prime = capsule._point_e_prime v_prime = capsule._point_v_prime shared_key = d * (e_prime + v_prime) key = kdf(shared_key, key_length) e = capsule._point_e v = capsule._point_v s = capsule._bn_sig h = CurveBN.hash_to_bn(e, v, params=params) inv_d = ~d if not (s*inv_d) * orig_pub_key == (h*e_prime) + v_prime: raise GenericUmbralError() return key
def _decapsulate_original(priv_key: UmbralPrivateKey, capsule: Capsule, key_length: int = DEM_KEYSIZE) -> bytes: """Derive the same symmetric key""" if not capsule.verify(): # Check correctness of original ciphertext raise capsule.NotValid("Capsule verification failed.") shared_key = priv_key.bn_key * (capsule._point_e + capsule._point_v ) # type: Any key = kdf(shared_key, key_length) return key
def _decapsulate_original(priv_key: CurveBN, capsule: Capsule, key_length=32, params: UmbralParameters=None) -> bytes: """Derive the same symmetric key""" params = params if params is not None else default_params() shared_key = priv_key * (capsule._point_e+capsule._point_v) key = kdf(shared_key, key_length) if not capsule.verify(params): # Check correctness of original ciphertext # (check nº 2) at the end to avoid timing oracles raise capsule.NotValid("Capsule verification failed.") return key
def encrypt(plaintext, associated_data=None): """ Encrypts plaintext with ChaCha20. They key used is the HKDF hash of the byte representation of a random point on the chosen elliptic curve. Returns (private_key_point, ciphertext). """ nonce = os.urandom(NONCE_SIZE) key_point = point.Point.gen_rand() key = utils.kdf(key_point, KEY_SIZE) ciphertext = ChaCha20Poly1305(key).encrypt(nonce, plaintext, associated_data) return key_point, nonce + ciphertext
def _decapsulate_original(priv_key: UmbralPrivateKey, capsule: Capsule, key_length: int = DEM_KEYSIZE) -> bytes: """Derive the same symmetric key""" priv_key = priv_key.bn_key shared_key = priv_key * (capsule._point_e + capsule._point_v) key = kdf(shared_key, key_length) if not capsule.verify(): # Check correctness of original ciphertext # (check nº 2) at the end to avoid timing oracles raise capsule.NotValid("Capsule verification failed.") return key
def decrypt(ciphertext, key, associated_data=None): """ Decrypts ciphertext. Returns plaintext. """ # the key returned by encrypt() is a point obj, has to be hashed for ChaCha if isinstance(key, point.Point): key = utils.kdf(key, KEY_SIZE) nonce = ciphertext[:NONCE_SIZE] cipher_without_nonce = ciphertext[NONCE_SIZE:] plaintext = ChaCha20Poly1305(key).decrypt( nonce, cipher_without_nonce, associated_data ) return plaintext
def _encapsulate(alice_pubkey: UmbralPublicKey, key_length: int = DEM_KEYSIZE) -> Tuple[bytes, Capsule]: """Generates a symmetric key and its associated KEM ciphertext""" params = alice_pubkey.params g = params.g priv_r = CurveBN.gen_rand(params.curve) pub_r = priv_r * g priv_u = CurveBN.gen_rand(params.curve) pub_u = priv_u * g h = CurveBN.hash(pub_r, pub_u, params=params) s = priv_u + (priv_r * h) shared_key = (priv_r + priv_u) * alice_pubkey.point_key # Key to be used for symmetric encryption key = kdf(shared_key, key_length) return key, Capsule(point_e=pub_r, point_v=pub_u, bn_sig=s, params=params)
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 = CurveBN.gen_rand(params.curve) pub_r = priv_r * g priv_u = CurveBN.gen_rand(params.curve) pub_u = priv_u * g h = CurveBN.hash_to_bn(pub_r, pub_u, params=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_e=pub_r, point_v=pub_u, bn_sig=s)