HMAC Key Derivation function (HKDF) is used to derive an encryption key from a pass phrase. Initially HKDF creates a pseudorandom key (PRK) using a pass phrase and a salt value (and any other random functions which are relavent), in order to produce an HMAC hash function (such as HMAC-SHA256), andalong with a salt value. Next the PRK output is used to produce a key of the required length. If we generate a 16-byte output (32 hex characters), we have a 128-bit key, and a 32-byte output (64 hex characters) will generate a 256-bit key. HKDF is used in TLS 1.3 for generating encryption keys [RFC 5869][article]:
HKDF - HMAC Key Derivation functionSample runA sample run is Hashing type: SHA-256 Message: hello Hex: 68656c6c6f Salt: 8e94ef805b93e683ff18 Info: =================== PRK: 1e133888e9fed8f9ceb210f88af26fa8f62f4190dd230f6317bf9f61ee07a690 OKM: 13485067e21af17c0900f70d885f0259 Key (Hex): 13485067e21af17c0900f70d885f0259 Key (Base-64): E0hQZ+Ia8XwJAPcNiF8CWQ== If we try Test Case 1: Hashing type: SHA-256 Message: Hex: 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b Salt: 000102030405060708090a0b0c Info: f0f1f2f3f4f5f6f7f8f9 =================== PRK: 077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5 OKM: 3cb25f25faacd57a90434f64d0362f2a Key (Hex): 3cb25f25faacd57a90434f64d0362f2a Key (Base-64): PLJfJfqs1XqQQ09k0DYvKg== Here is the test vector: In this case we have a hash of "3cb25f25faacd57a90434f64d0362f2a" which is 32 hex characters, and is thus 128-bits (16 bytes) [here]. CodeAn outline of the code is: import sys from binascii import unhexlify,hexlify,b2a_base64 import hashlib import hmac import math import binascii def hmac_hash(key, data): return hmac.new(key, data, hash).digest() def hkdf(length: int, ikm, salt: bytes = b"", info: bytes = b"") -> bytes: hash_len = hash().digest_size prk = hmac_hash(salt, ikm) t = b"" okm = b"" for i in range(math.ceil(length / hash_len)): t = hmac_hash(prk, t + info + bytes([1+i])) okm += t return okm[:length] hash=hashlib.sha256 password='hello' salt="8e94ef805b93e683ff18" info="" length=16 type=5 ## Uncomment out to run validation test # Test 1 https://tools.ietf.org/html/rfc5869 #hash=hashlib.sha256 # type=3 #password=unhexlify('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b').decode() #salt="000102030405060708090a0b0c" #info="f0f1f2f3f4f5f6f7f8f9" # PRK = 077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5 # OKM = 0x3cb25f25faacd57a90434f64d0362f2a.. if (len(sys.argv)>1): password=str(sys.argv[1]) if (len(sys.argv)>2): salt=str(sys.argv[2]) if (len(sys.argv)>3): length=int(sys.argv[3]) if (len(sys.argv)>4): type=int(sys.argv[4]) if (len(sys.argv)>5): info=str(sys.argv[5]) if (password.startswith("0x")): password=unhexlify(password.replace('0x','')).decode() if (type==0): hash=hashlib.md5 print ("Hashing type:\tMD5") if (type==1): hash=hashlib.sha1 print ("Hashing type:\tSHA-1") if (type==2): hash=hashlib.sha224 print ("Hashing type:\tSHA-224") if (type==3): hash=hashlib.sha256 print ("Hashing type:\tSHA-256") if (type==4): hash=hashlib.sha384 print ("Hashing type:\tSHA-384") if (type==5): hash=hashlib.sha512 print ("Hashing type:\tSHA-512") prk = hmac_hash(unhexlify(salt), password.encode()) okm= hkdf(length, password.encode(), unhexlify(salt), unhexlify(info)) print("Message:\t",password) print("Salt:\t\t",salt) print("Info:\t\t",info) print("===================") print ("PRK:",binascii.hexlify(bytearray(prk)).decode()) print ("OKM:",binascii.hexlify(bytearray(okm)).decode()) print ("\nKey (Hex):\t",binascii.hexlify(bytearray(okm)).decode()) print ("Key (Base-64):\t",b2a_base64(bytearray(okm)).decode()) For the hashing function we could use md5(), sha1(), sha224(), sha256(), sha384(), or sha512(). |