def get_sharedkey(a, B): # Alice Computes Shared Secret: s = B^a mod p x = pow(B, a, sharedPrime) aKDF = Hkdf(None, str(x).encode(), hash=hashlib.sha512) aKey = aKDF.expand(b"context1", 32) return x, aKey
def test_vectors(self): for vector in HKDF_TEST_VECTORS: salt = unhexlify(vector["salt"].encode("ascii")) IKM = unhexlify(vector["IKM"].encode("ascii")) info = unhexlify(vector["info"].encode("ascii")) h = Hkdf(salt=salt, input_key_material=IKM, hash=sha256) digest = h.expand(info, vector["L"]) self.assertEqual(digest, myHKDF(IKM, vector["L"], salt, info)) #print(hexlify(digest)) expected = vector["OKM"].encode("ascii") self.assertEqual(hexlify(digest), expected, vector)
def deriveSecrets(self, inputKeyMaterial, salt, info): from hkdf import Hkdf if salt == None: salt = b"\x00" * self.HASH_OUTPUT_SIZE tshkdf = Hkdf(salt, inputKeyMaterial) okm = tshkdf.expand(info, self.KEY_MATERIAL_SIZE) cipherKey = okm[self.CIPHER_KEYS_OFFSET:self.HASH_OUTPUT_SIZE] macKey = okm[self.MAC_KEYS_OFFSET:self.MAC_KEYS_OFFSET + self.HASH_OUTPUT_SIZE] return ( cipherKey, macKey )
def deriveSecrets(self, inputKeyMaterial, salt, info): from hkdf import Hkdf if salt == None: salt = b"\x00" * self.HASH_OUTPUT_SIZE tshkdf = Hkdf(salt, inputKeyMaterial) okm = tshkdf.expand(info, self.KEY_MATERIAL_SIZE) cipherKey = okm[self.CIPHER_KEYS_OFFSET:self.HASH_OUTPUT_SIZE] macKey = okm[self.MAC_KEYS_OFFSET:self.MAC_KEYS_OFFSET + self.HASH_OUTPUT_SIZE] return (cipherKey, macKey)
def encrypt(self, public_key, plain_text): """Ecies encrypt plain text. First create a ephemeral ecdsa key pair, then serialize the public key for part of result. Then derived a shared key based ecdh, using the key based hkdf to generate aes key and hmac key, using aes-256-cfb to generate the part of result. Last using hmac-sha3 and the part of previous step to generate last part of result. :param public_key: public key :param plain_text: plain text :Returns: cipher text """ ephemeral_private_key = self.generate_private_key() rb = ephemeral_private_key.public_key().public_numbers().encode_point() z = ephemeral_private_key.exchange(ec.ECDH(), public_key) hkdf_output = Hkdf(salt=None, input_key_material=z, hash=self.hash) \ .expand(length=AES_KEY_LENGTH + HMAC_KEY_LENGTH) aes_key = hkdf_output[:AES_KEY_LENGTH] hmac_key = hkdf_output[AES_KEY_LENGTH:AES_KEY_LENGTH + HMAC_KEY_LENGTH] aes_cipher = AES.new(aes_key, AES.MODE_CFB) em = aes_cipher.iv + aes_cipher.encrypt(plain_text) mac = hmac.new(hmac_key, em, self.hash) d = mac.digest() return rb + em + d
def test_kat(self): for (salt, context, skm, expected_hexout) in KAT: expected_out = unhexlify(expected_hexout) for outlen in range(0, len(expected_out)): out = Hkdf(salt.encode("ascii"), skm.encode("ascii")).expand( context.encode("ascii"), outlen) self.assertEqual(out, expected_out[:outlen])
def _get_nacl_secret_box(secret, hmac_secret): if isinstance(secret, text_type): secret = secret.encode("utf-8") if isinstance(hmac_secret, text_type): hmac_secret = hmac_secret.encode("utf-8") secret_key = Hkdf(b"", hmac_secret).expand(secret) box = nacl.secret.SecretBox(secret_key) return box
def decrypt(self, private_key, cipher_text): """Ecies decrypt cipher text. First restore the ephemeral public key from bytes(97 bytes for 384, 65 bytes for 256). Then derived a shared key based ecdh, using the key based hkdf to generate aes key and hmac key, using hmac-sha3 to verify the hmac bytes. Last using aes-256-cfb to decrypt the bytes. :param private_key: private key :param cipher_text: cipher text :Returns: plain text """ key_len = private_key.curve.key_size if key_len != self.curve.key_size: raise ValueError( "Invalid key. Input security level {} does not " "match the current security level {}".format( key_len, self.curve.key_size)) d_len = key_len >> 3 rb_len = ((key_len + 7) // 8) * 2 + 1 ct_len = len(cipher_text) if ct_len <= rb_len + d_len: raise ValueError( "Illegal cipherText length: cipher text length {} " "must be > rb length plus d_len {}".format(ct_len, rb_len + d_len) ) rb = cipher_text[:rb_len] em = cipher_text[rb_len:ct_len - d_len] d = cipher_text[ct_len - d_len:ct_len] ephemeral_public_key = EllipticCurvePublicNumbers \ .from_encoded_point(self.curve(), rb) \ .public_key(default_backend()) z = private_key.exchange(ec.ECDH(), ephemeral_public_key) hkdf_output = Hkdf(salt=None, input_key_material=z, hash=self._hash) \ .expand(length=AES_KEY_LENGTH + HMAC_KEY_LENGTH) aes_key = hkdf_output[:AES_KEY_LENGTH] hmac_key = hkdf_output[AES_KEY_LENGTH:AES_KEY_LENGTH + HMAC_KEY_LENGTH] mac = hmac.new(hmac_key, em, self._hash) recovered_d = mac.digest() if not constant_time.bytes_eq(recovered_d, d): raise ValueError("Hmac verify failed.") iv = em[:IV_LENGTH] aes_cipher = AES.new(key=aes_key, mode=AES.MODE_CFB, iv=iv) return aes_cipher.decrypt(em[IV_LENGTH:len(em)])
def kdf( ecpoint: Point, key_length: int, salt: Optional[bytes] = None, info: Optional[bytes] = None, ) -> bytes: data = ecpoint.to_bytes(is_compressed=True) salt = salt or b'' info = info or b'' return Hkdf( salt, data, hash=blake2b, ).expand(info=info, length=key_length)
def derive_privkey_by_label( self, label: bytes, salt: Optional[bytes] = None, params: Optional[UmbralParameters] = None) -> UmbralPrivateKey: """ Derives an UmbralPrivateKey using a KDF from this instance of UmbralKeyingMaterial, a label, and an optional salt. """ params = params if params is not None else default_params() key_material = Hkdf( salt, self.__keying_material, hash=blake2b, ).expand(info=b"NuCypher/KeyDerivation/" + label, length=64) bn_key = hash_to_curvebn(key_material, params=params) return UmbralPrivateKey(bn_key, params)
def get_priv_key(address): # read master secret from hsm_secret hsm_secret = open(expanduser('~/.lightning/bitcoin/hsm_secret'), 'rb').read() # derive the bip32_seed salt = bytes([0]) or b'\x00' bip32_seed = Hkdf(salt, hsm_secret, hash=hashlib.sha256).expand(b'bip32 seed') master = network.keys.bip32_seed(bip32_seed) index = 0 while True: # derive an index subkey = master.subkey_for_path('0/0/' + str(index)) setup('mainnet') # create segwit address segwit = PrivateKey.from_wif( subkey.wif()).get_public_key().get_segwit_address() # wrap in P2SH address wrapped_p2sh = P2shAddress.from_script(segwit.to_script_pub_key()) if wrapped_p2sh.to_string() == address: break index += 1 plugin.log('found the address at index {}'.format(index), level="info") return master.subkey_for_path('0/0/' + str(index))
def expand_password(data, num_bytes): h = Hkdf(salt=b"", input_key_material=data, hash=hashlib.sha256) info = b"SPAKE2 pw" return h.expand(info, num_bytes)
def expand_arbitrary_element_seed(data, num_bytes): h = Hkdf(salt=b"", input_key_material=data, hash=hashlib.sha256) info = b"SPAKE2 arbitrary element" return h.expand(info, num_bytes)
def HKDF(skm, outlen, salt=None, CTXinfo=b""): return Hkdf(salt, skm).expand(CTXinfo, outlen)