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 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 _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 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 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 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 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 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 _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 _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 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 prng_init(seed, salt): # extract the secret m return hkdf.hkdf_extract(salt, input_key_material=seed, 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 tv_extract(tv_number): tv = test_vectors[tv_number] return hkdf.hkdf_extract(tv["salt"], tv["IKM"], tv["hash"])
import hkdf prk = hkdf.hkdf_extract(bytes.fromhex("8e94ef805b93e683ff18"), b"asecretpassword") key = hkdf.hkdf_expand(prk, b"context1", 32) print (key)
def hkdf_extract(self, salt: bytes, input_key_material: bytes) -> bytes: if input_key_material is None: input_key_material = b"\x00" * self.hash_len return hkdf.hkdf_extract(salt, input_key_material, self.hashmod)
def hkdf_extract(self, salt, input_key_material): import hkdf if input_key_material is None: input_key_material = b"\x00" * hashlib.sha256().digest_size return hkdf.hkdf_extract(salt, input_key_material, hashlib.sha256)
def get_subkey(keyname, salt = None): if type(keyname) == str: keyname = keyname.encode() return hkdf_expand(hkdf_extract(salt, pairing_key), keyname, 32)
0x5b, 0xe0, 0xcd, 0x19, 0x13, 0x7e, 0x21, 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):