def _set_ciphers(self): """Generate out/inbound encryption keys and initialise respective ciphers.""" prk = hkdf.hkdf_extract(self.CIPHER_SALT, self.shared_key) self.outgoing_key = hkdf.hkdf_expand(prk, self.OUT_CIPHER_INFO, 32) prk = hkdf.hkdf_extract(self.CIPHER_SALT, self.shared_key) self.incoming_key = hkdf.hkdf_expand(prk, self.IN_CIPHER_INFO, 32)
def decrypt_keys(cls, encryption_key: bytes, user_key: Union[str, CipherString]) -> Tuple[bytes, bytes]: # stretch / expand the encryption key tmp_key_enc = hkdf_expand(encryption_key, b'enc', 32, sha256) tmp_key_mac = hkdf_expand(encryption_key, b'mac', 32, sha256) # 'decrypt' the user_key to produce the actual keys plaintext = cls.decrypt_generic(tmp_key_enc, tmp_key_mac, user_key) assert(len(plaintext) == 64) # split out the real keys key_enc = plaintext[:32] key_mac = plaintext[32:] return key_enc, key_mac
def _makeRelayCrypto(self, secret_input): '''Derive shared key material using HKDF from secret_input. :returns: **oppy.crypto.relaycrypto.RelayCrypto** initialized with shared key data ''' prk = hkdf.hkdf_extract(salt=T_KEY, input_key_material=secret_input, hash=hashlib.sha256) km = hkdf.hkdf_expand(pseudo_random_key=prk, info=M_EXPAND, length=72, hash=hashlib.sha256) df = km[:DIGEST_LEN] db = km[DIGEST_LEN:DIGEST_LEN * 2] kf = km[DIGEST_LEN * 2:DIGEST_LEN * 2 + KEY_LEN] kb = km[DIGEST_LEN * 2 + KEY_LEN:DIGEST_LEN * 2 + KEY_LEN * 2] f_digest = hashlib.sha1(df) b_digest = hashlib.sha1(db) f_cipher = util.makeAES128CTRCipher(kf) b_cipher = util.makeAES128CTRCipher(kb) return RelayCrypto(forward_digest=f_digest, backward_digest=b_digest, forward_cipher=f_cipher, backward_cipher=b_cipher)
def pair_verify_m1_m2(self, client_public): self.client_curve_public = client_public self.accessory_curve = x25519.X25519PrivateKey.generate() self.accessory_curve_public = self.accessory_curve.public_key( ).public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) self.accessory_shared_key = self.accessory_curve.exchange( x25519.X25519PublicKey.from_public_bytes(client_public)) accessory_info = self.accessory_curve_public + self.accessory_id + client_public accessory_signed = self.accessory_ltsk.sign(accessory_info) accessory_sig = accessory_signed.signature sub_tlv = Tlv8.encode([ Tlv8.Tag.IDENTIFIER, self.accessory_id, Tlv8.Tag.SIGNATURE, accessory_sig ]) prk = hkdf.hkdf_extract(b"Pair-Verify-Encrypt-Salt", self.accessory_shared_key) session_key = hkdf.hkdf_expand(prk, b"Pair-Verify-Encrypt-Info", 32) c = ChaCha20_Poly1305.new(key=session_key, nonce=b"PV-Msg02") enc_tlv, tag = c.encrypt_and_digest(sub_tlv) return [ Tlv8.Tag.STATE, PairingState.M2, Tlv8.Tag.PUBLICKEY, self.accessory_curve_public, Tlv8.Tag.ENCRYPTEDDATA, enc_tlv + tag ]
def _makeRelayCrypto(self, secret_input): '''Derive shared key material using HKDF from secret_input. :returns: **oppy.crypto.relaycrypto.RelayCrypto** initialized with shared key data ''' prk = hkdf.hkdf_extract(salt=T_KEY, input_key_material=secret_input, hash=hashlib.sha256) km = hkdf.hkdf_expand(pseudo_random_key=prk, info=M_EXPAND, length=72, hash=hashlib.sha256) df = km[: DIGEST_LEN] db = km[DIGEST_LEN : DIGEST_LEN * 2] kf = km[DIGEST_LEN * 2 : DIGEST_LEN * 2 + KEY_LEN] kb = km[DIGEST_LEN * 2 + KEY_LEN : DIGEST_LEN * 2 + KEY_LEN * 2] f_digest = hashlib.sha1(df) b_digest = hashlib.sha1(db) f_cipher = util.makeAES128CTRCipher(kf) b_cipher = util.makeAES128CTRCipher(kb) return RelayCrypto(forward_digest=f_digest, backward_digest=b_digest, forward_cipher=f_cipher, backward_cipher=b_cipher)
def pair_verify_m3_m4(self, encrypted): prk = hkdf.hkdf_extract(b"Pair-Verify-Encrypt-Salt", self.accessory_shared_key) session_key = hkdf.hkdf_expand(prk, b"Pair-Verify-Encrypt-Info", 32) c = ChaCha20_Poly1305.new(key=session_key, nonce=b"PV-Msg03") enc_tlv = encrypted[:-16] tag = encrypted[-16:] dec_tlv = c.decrypt_and_verify(enc_tlv, tag) sub_tlv = Tlv8.decode(dec_tlv) device_id = sub_tlv[Tlv8.Tag.IDENTIFIER] device_sig = sub_tlv[Tlv8.Tag.SIGNATURE] device_info = self.client_curve_public + device_id + self.accessory_curve_public device_pairing_filepath = "./pairings/" + device_id.decode( "utf-8") + ".pub" if path.exists(device_pairing_filepath): with open(device_pairing_filepath, "rb") as device_pairing_file: self.device_ltpk = device_pairing_file.read() verify_key = nacl.signing.VerifyKey(self.device_ltpk) verify_key.verify(device_info, device_sig) return True, [Tlv8.Tag.STATE, PairingState.M4] else: return False, [Tlv8.Tag.ERROR, PairingErrors.AUTHENTICATION]
def hkdf(self, ecdhSecret): prk = hkdf_extract(salt=b"54686579206c6976696e272069742075702061742074686520486f74656c2043616c69666f726e69610a576861742061206e6963652073757270726973652028776861742061206e696365207375727072697365290a4272696e6720796f757220616c69626973", hash=hashlib.sha256, input_key_material=ecdhSecret) return hkdf_expand(pseudo_random_key=prk, info=b"knock", length=16)
def compute_ik(shared_secret, service_public_key, beacon_public_key): salt = service_public_key + beacon_public_key prk = hkdf.hkdf_extract(salt, shared_secret, hash=hashlib.sha256) ik = hkdf.hkdf_expand(prk, b"", 32, hash=hashlib.sha256)[:16] print(b'shared: ' + binascii.hexlify(shared_secret)) print(b'service: ' + binascii.hexlify(service_public_key)) print(b'beacon: ' + binascii.hexlify(beacon_public_key)) print(b'ik: ' + binascii.hexlify(ik)) return ik
def pair_setup_m5_m6_1(self, encrypted): prk = hkdf.hkdf_extract(b"Pair-Setup-Encrypt-Salt", self.ctx.session_key) session_key = hkdf.hkdf_expand(prk, b"Pair-Setup-Encrypt-Info", 32) c = ChaCha20_Poly1305.new(key=session_key, nonce=b"PS-Msg05") enc_tlv = encrypted[:-16] tag = encrypted[-16:] dec_tlv = c.decrypt_and_verify(enc_tlv, tag) return Tlv8.decode(dec_tlv), session_key
def GetAndPrintIdentityKey(shared_secret, service_public_key, beacon_public_key): """Compute the identity key from a Curve25519 shared secret.""" salt = service_public_key + beacon_public_key PrintBinary("Salt", salt) prk = hkdf.hkdf_extract(salt, shared_secret, hash=hashlib.sha256) PrintBinary("Prk (extracted bytes)", prk) ik = hkdf.hkdf_expand(prk, "", 32, hash=hashlib.sha256)[:16] PrintBinary("Identity key", ik) return ik
def main(): parser = argparse.ArgumentParser( description='Generates pseudorandom key usin HKDF method described in ' 'RFC 5869. Hash function used for HMAC is SHA256.') parser.add_argument( '-i', '--info', default='', help='optional context and application specific information, defaults ' 'to empty string') parser.add_argument( '-k', '--key', default='-', help='path to pseudorandom key, use "-" for reading from standard' ' input') parser.add_argument( '-l', '--length', default=32, type=int, help='desired length of output material, defaults to 32') parser.add_argument( '-L', '--append-length', default=False, action='store_true', help='if set, to info requested length is appended, encoded as ' 'big-endian binary; using this flag prevents shorter keys being ' 'prefixes to longer keys') args = parser.parse_args() info = args.info if args.append_length: # Binding length to info is described in RFC 5869 in section # "3.2. The 'info' Input to HKDF". Thanks to that, shorter derived # keys wont be prefixes of longer derived keys. info = info + struct.pack('>I', args.length) key_file = sys.stdin if args.key != '-': key_file = open(args.key, 'r') key_data = key_file.read() output = hkdf_expand(pseudo_random_key=key_data, info=info, length=args.length, hash_object=hashlib.sha256) sys.stdout.write(output) if args.key != '-': key_file.close()
def get_subkey(keyname, salt = None): b64_pairing_key = get_from_datadir("pairingkey") if b64_pairing_key is None: pairing_key = random(32) save_to_datadir("pairingkey", standard_b64encode(pairing_key).decode('ascii')) else: pairing_key = standard_b64decode(b64_pairing_key) if type(keyname) == str: keyname = keyname.encode() return hkdf_expand(hkdf_extract(salt, pairing_key), keyname, 32)
def _hkdfDeriveParameter(self, hashFunction, masterSecret, masterSalt, id, algorithm, type, length): info = cbor.dumps([ id, algorithm, unicode(type), # encode as text string length ]) extract = hkdf.hkdf_extract(salt=masterSalt, input_key_material=masterSecret, hash=hashFunction) expand = hkdf.hkdf_expand(pseudo_random_key=extract, info=info, length=length, hash=hashFunction) return expand
def prng_sample(prng_seed, info): hashinput = hkdf.hkdf_expand(prng_seed, info, 64) # Riad: # "The issue is that the Python interface is slightly different than the # Rust one. In particular, the Python hash_to_field function does not # automatically inject a ciphersuite string, whereas the Rust interface # you're using does." # Inject \0 for ciphersuite so that the Hr function matches rust's # hash_to_field r = OS2IP(hashinput) % q return r
def pair_setup_m5_m6_2(self, dec_tlv): self.device_id = dec_tlv[Tlv8.Tag.IDENTIFIER] self.device_ltpk = dec_tlv[Tlv8.Tag.PUBLICKEY] device_sig = dec_tlv[Tlv8.Tag.SIGNATURE] prk = hkdf.hkdf_extract(b"Pair-Setup-Controller-Sign-Salt", self.ctx.session_key) device_x = hkdf.hkdf_expand(prk, b"Pair-Setup-Controller-Sign-Info", 32) device_info = device_x + self.device_id + self.device_ltpk verify_key = nacl.signing.VerifyKey(self.device_ltpk) verify_key.verify(device_info, device_sig)
def _kdf(self, master_salt, master_secret, role_id, out_type): out_bytes = {'Key': self.algorithm.key_bytes, 'IV': self.algorithm.iv_bytes}[out_type] info = cbor.dumps([ role_id, self.id_context, self.algorithm.value, out_type, out_bytes ]) extracted = hkdf.hkdf_extract(master_salt, master_secret, hash=self.hashfun) expanded = hkdf.hkdf_expand(extracted, info=info, hash=self.hashfun, length=out_bytes) return expanded
def _kdf(self, master_secret, master_salt, role_id, out_type): out_bytes = { 'Key': self.algorithm.key_bytes, 'IV': self.algorithm.iv_bytes }[out_type] info = cbor.dumps([role_id, self.algorithm.value, out_type, out_bytes]) extracted = hkdf.hkdf_extract(master_salt, master_secret, hash=self.hashfun) expanded = hkdf.hkdf_expand(extracted, info=info, hash=self.hashfun, length=out_bytes) return expanded
def solicitar_diffie_hellman(p, g, sock): mensagem = str(p) + '/' + str(g) # mensagem = valor p/valor g mensagem = adicionar_padding(mensagem) # Preenche a mensagem até atingir o tamanho do payload sock.send(bytes(mensagem, 'utf-8')) # Envia os parâmetros iniciais p e g para o servidor A = random.randint(1, 10000) a = g ** A % p resposta = sock.recv(TAM_PAYLOAD) resposta = remover_padding(resposta) b = int(resposta) # Armazena o valor 'b' recebido do servidor mensagem = str(a) # mensagem = valor a mensagem = adicionar_padding(mensagem) sock.send(bytes(mensagem, 'utf-8')) # Compartilha o valor gerado 'a' com o servidor chave_compartilhada = str(b ** A % p) print("[+] Chave compartilhada gerada: {}".format(chave_compartilhada)) # Deriva uma chave que possa ser usada pelo algoritmo de criptografia chave_compartilhada = derivar_chave(bytes(chave_compartilhada, 'utf-8')) print(f"[+] Chave derivada: {chave_compartilhada.decode()}") k = hkdf.hkdf_extract(None, chave_compartilhada) nova_chave = hkdf.hkdf_expand(k) # Expande a chave utilizando hkdf nova_chave = derivar_chave(nova_chave) mensagem = str(nova_chave) mensagem = criptografar(mensagem, chave_compartilhada).decode() mensagem += gerar_hmac(chave_compartilhada, mensagem) mensagem = adicionar_padding(mensagem) sock.send(bytes(mensagem, 'utf-8')) chave_compartilhada = nova_chave # Atualiza a chave para a nova chave gerada print("[+] Nova chave gerada: {}\n".format(chave_compartilhada.decode())) resposta = sock.recv(TAM_PAYLOAD) if verificar_hmac(resposta, chave_compartilhada) == 'NOK': print("[+] O HMAC da mensagem recebida não corresponde aos dados.") raise SystemExit resposta = remover_padding(resposta) resposta = resposta[:-64] # Retira os últimos 64 bytes da mensagem (HMAC) resposta = decodificar(resposta, chave_compartilhada) print(resposta) return chave_compartilhada
def derive_key(key_material, salt, info): """ Derive a fixed-size (64-byte) key for use in cryptographic operations. The key is derived using HKDF with the SHA-512 hash function. See https://tools.ietf.org/html/rfc5869. :type key_material: str or bytes :type salt: bytes :type info: bytes """ if not isinstance(key_material, bytes): key_material = key_material.encode() pseudorandom_key = hkdf_extract(salt, key_material, hash=hashlib.sha512) return hkdf_expand(pseudorandom_key, info, length=64, hash=hashlib.sha512)
def compute_identity_key(shared_secret, service_public_key, beacon_public_key): logger.debug('service_public_key: {}'.format( binascii.hexlify(service_public_key))) logger.debug('beacon_public_key: {}'.format( binascii.hexlify(beacon_public_key))) salt = service_public_key + beacon_public_key logger.debug('salt: {}'.format(binascii.hexlify(salt))) prk = hkdf.hkdf_extract(salt, shared_secret, hash=hashlib.sha256) logger.debug('prk: {}'.format(binascii.hexlify(prk))) identity_key = hkdf.hkdf_expand(prk, b"", 32, hash=hashlib.sha256)[:16] logger.debug('identity_key: {}'.format(binascii.hexlify(identity_key))) return identity_key
def pair_setup_m5_m6_2(self, dec_tlv): self.device_id = dec_tlv[Tlv8.Tag.IDENTIFIER] self.device_ltpk = dec_tlv[Tlv8.Tag.PUBLICKEY] device_sig = dec_tlv[Tlv8.Tag.SIGNATURE] prk = hkdf.hkdf_extract(b"Pair-Setup-Controller-Sign-Salt", self.ctx.session_key) device_x = hkdf.hkdf_expand(prk, b"Pair-Setup-Controller-Sign-Info", 32) device_info = device_x + self.device_id + self.device_ltpk verify_key = nacl.signing.VerifyKey(self.device_ltpk) verify_key.verify(device_info, device_sig) with open("./pairings/" + self.device_id.decode("utf-8") + ".pub", "wb") as device_pairing_file: device_pairing_file.write(self.device_ltpk)
def check_fun_tv(tv): ''' Generate and check HKDF pseudorandom key and output key material for a specific test vector PRK = HKDF-Extract([test vector values]) OKM = HKDF-Expand(PRK, [test vector values]) ''' test_prk = hkdf.hkdf_extract(tv["salt"], tv["IKM"], tv["hash"]) test_okm = hkdf.hkdf_expand(test_prk, tv["info"], tv["L"], tv["hash"]) print "%s" % tv print "PRK: %s" % ("match" if test_prk == tv["PRK"] else "FAIL") print "OKM: %s" % ("match" if test_okm == tv["OKM"] else "FAIL") print assert_equals(test_prk, tv["PRK"]) assert_equals(test_okm, tv["OKM"])
def pair_verify_m3_m4(self, encrypted): prk = hkdf.hkdf_extract(b"Pair-Verify-Encrypt-Salt", self.accessory_shared_key) session_key = hkdf.hkdf_expand(prk, b"Pair-Verify-Encrypt-Info", 32) c = ChaCha20_Poly1305.new(key=session_key, nonce=b"PV-Msg03") enc_tlv = encrypted[:-16] tag = encrypted[-16:] dec_tlv = c.decrypt_and_verify(enc_tlv, tag) sub_tlv = Tlv8.decode(dec_tlv) device_id = sub_tlv[Tlv8.Tag.IDENTIFIER] device_sig = sub_tlv[Tlv8.Tag.SIGNATURE] device_info = self.client_curve_public + device_id + self.accessory_curve_public verify_key = nacl.signing.VerifyKey(self.device_ltpk) verify_key.verify(device_info, device_sig) return [Tlv8.Tag.STATE, PairingState.M4]
def pair_setup_m5_m6_3(self, session_key): prk = hkdf.hkdf_extract(b"Pair-Setup-Accessory-Sign-Salt", self.ctx.session_key) accessory_x = hkdf.hkdf_expand(prk, b"Pair-Setup-Accessory-Sign-Info", 32) # self.accessory_ltsk = nacl.signing.SigningKey.generate() # self.accessory_ltpk = bytes(self.accessory_ltsk.verify_key) accessory_info = accessory_x + self.accessory_id + self.accessory_ltpk accessory_signed = self.accessory_ltsk.sign(accessory_info) accessory_sig = accessory_signed.signature dec_tlv = Tlv8.encode([ Tlv8.Tag.IDENTIFIER, self.accessory_id, Tlv8.Tag.PUBLICKEY, self.accessory_ltpk, Tlv8.Tag.SIGNATURE, accessory_sig ]) c = ChaCha20_Poly1305.new(key=session_key, nonce=b"PS-Msg06") enc_tlv, tag = c.encrypt_and_digest(dec_tlv) return enc_tlv, tag
def get_enc_mac_keys(encoded_secret, privateKey): secret = b64decode(encoded_secret) if len(secret) != 144: raise ValueError('Invalid secret size') sharedSecret = privateKey.get_shared_key(curve25519.Public(secret[:32]), lambda a: a) key_material = Hmac(b'\0' * 32).hash(sharedSecret) sharedSecretExpanded = hkdf_expand(key_material, length=80, hash=hashlib.sha256) if not Hmac(sharedSecretExpanded[32:64]).is_valid( secret[:32] + secret[64:], expected=secret[32:64]): raise ValueError('Hmac validation failed') keysEncrypted = sharedSecretExpanded[64:] + secret[64:] keysDecrypted = Aes(sharedSecretExpanded[:32]).decrypt(keysEncrypted) encKey = keysDecrypted[:32] macKey = keysDecrypted[32:64] return encKey, macKey
def keys_for_site(self, name): # build a 64-byte string specific for this site name. keys = hkdf_expand(sha256, self.master, name.encode('utf8'), 64) # first half is conf key, second half is auth return keys[:32], keys[32:]
def prng_rerandomize(prng_seed, newseed, info): m1 = hkdf.hkdf_expand(prng_seed, info, 128) return hkdf.hkdf_extract(m1[64:], input_key_material=(m1[:64] + newseed), hash=hashlib.sha512)
def tv_expand(tv_number): tv = test_vectors[tv_number] test_prk = hkdf.hkdf_extract(tv["salt"], tv["IKM"], tv["hash"]) return hkdf.hkdf_expand(test_prk, tv["info"], tv["L"], tv["hash"])
def derive_key(self, key, length=96): return hkdf.hkdf_expand(key, self.proto_id, length)
import hkdf prk = hkdf.hkdf_extract(bytes.fromhex("8e94ef805b93e683ff18"), b"asecretpassword") key = hkdf.hkdf_expand(prk, b"context1", 32) print (key)
def hkdf_expand_label(self, secret: bytes, label: bytes, context: bytes, length: int) -> bytes: hkdf_label = self.hkdf_label(label, context, length) return hkdf.hkdf_expand(secret, hkdf_label, length, self.hashmod)
def hkdf_expand_label(self, secret, label, context, length): import hkdf hkdf_label = self.hkdf_label(label, context, length) return hkdf.hkdf_expand(secret, hkdf_label, length, hashlib.sha256)
def hkdf_expand_label(self, secret, label, context, length): hkdf_label = self.hkdf_label(label, context, length) return hkdf.hkdf_expand(secret, hkdf_label, length, self.hashmod)
0x79, ]) ciphersuite = b"\0" d = 32 # extract the secret m m = hkdf.hkdf_extract(salt=DOM_SEP_PARAM_GEN, input_key_material=seed, hash=hashlib.sha512) # generate h using hash_to_group info = bytes("H2G_h", "ascii") # expand the secret key = hkdf.hkdf_expand(pseudo_random_key=m, info=info, length=32, hash=hashlib.sha512) # hash to G2 h = map2curve_osswu2(key, ciphersuite) # generate hlistusing hash_to_group hlist = [] for i in range(d + 1): info = b"H2G_h" + I2OSP(i, 1) # expand the secret key = hkdf.hkdf_expand(pseudo_random_key=m, info=info, length=32, hash=hashlib.sha512) # hash to G2 hi = map2curve_osswu2(key, ciphersuite)