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]. In this case we will use SHA-256. Normally, for the derivation of a key from a password, the input to the HKDF method would be from an KDF, such as with PBKDF2, Argon2 or scrypt. In this case we will use the HKDF class in .NET, and which was introduced in .NET 5.
HKDF with C# |
Method
The following shows how an encryption key can be generated using HKDF, and where we need a secret and a salt value. Both Bob and Alice have the same secret and salt. Normally, for the derivation of a key from a password, the input to the HKDF method would be from an KDF, such as with PBKDF2, Argon2 or scrypt.
Coding
First we create a folder named "hkdf", and then go into that folder.We can create a Dotnet console project for .NET 7.0 with:
dotnet new console --framework net7.0
This produces a Csproject file of:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> </Project>
Next we can add the code of:
namespace HelloWorld { class Program { static void Main(string[] args) { var salt="8e94ef805b93e683ff18"; var password="Test2"; var length=16; try { if (args.Length >0) password=args[0]; if (args.Length >1) salt=args[1]; if (args.Length >2) length=System.Convert.ToInt32(args[2]); var ikm = System.Text.Encoding.UTF8.GetBytes(password); var s=System.Convert.FromHexString(salt); var info=System.Convert.FromHexString(""); var hash1=System.Security.Cryptography.HKDF.DeriveKey(System.Security.Cryptography.HashAlgorithmName.MD5,ikm,length,s,info); var hash2=System.Security.Cryptography.HKDF.DeriveKey(System.Security.Cryptography.HashAlgorithmName.SHA1,ikm,length,s,info); var hash3=System.Security.Cryptography.HKDF.DeriveKey(System.Security.Cryptography.HashAlgorithmName.SHA256,ikm,length,s,info); var hash4=System.Security.Cryptography.HKDF.DeriveKey(System.Security.Cryptography.HashAlgorithmName.SHA384,ikm,length,s,info); var hash5=System.Security.Cryptography.HKDF.DeriveKey(System.Security.Cryptography.HashAlgorithmName.SHA512,ikm,length,s,info); Console.WriteLine("Password: {0}",password); Console.WriteLine("Salt: {0}",salt); Console.WriteLine("Length: {0}",length); Console.WriteLine("\nKey (MD5): {0} [{1}]",Convert.ToBase64String(hash1),Convert.ToHexString(hash1)); Console.WriteLine("\nKey (SHA1): {0} [{1}]",Convert.ToBase64String(hash2),Convert.ToHexString(hash2)); Console.WriteLine("\nKey (SHA256): {0} [{1}]",Convert.ToBase64String(hash3),Convert.ToHexString(hash3)); Console.WriteLine("\nKey (SHA384): {0} [{1}]",Convert.ToBase64String(hash4),Convert.ToHexString(hash4)); Console.WriteLine("\nKey (SHA512): {0} [{1}]",Convert.ToBase64String(hash5),Convert.ToHexString(hash5)); } catch (Exception e) { Console.WriteLine("Error: {0}",e.Message); } } } }
A sample run is:
Password: Hello Salt: 8e94ef805b93e683ff18 Length: 64 Key (MD5): sgpqiORAZVn6cTGv9SwA3+cFzha70pC7wEwNT1KpYsb4DOSbddt1BEN3qPVmXa6N1W0Z3KJImYV8ZXPPEJ7twQ== [B20A6A88E4406559FA7131AFF52C00DFE705CE16BBD290BBC04C0D4F52A962C6F80CE49B75DB75044377A8F5665DAE8DD56D19DCA24899857C6573CF109EEDC1] Key (SHA1): 0IK6zDQztpsWQXVNxgjhd3xfBMVwlTSrYFNpG7NLscg2IskUOdjts0MjlMNqtuXcTCkkji2Z+ijMfn7ABYvuCQ== [D082BACC3433B69B1641754DC608E1777C5F04C5709534AB6053691BB34BB1C83622C91439D8EDB3432394C36AB6E5DC4C29248E2D99FA28CC7E7EC0058BEE09] Key (SHA256): fkl6DakxPFGaN8nCFPQ23CtgWqkP7EXGeu+xYmQAf6LLvlfvhZCEchUrZVwxLuKuc4m4oqALUf5UxvvkVIDJzw== [7E497A0DA9313C519A37C9C214F436DC2B605AA90FEC45C67AEFB16264007FA2CBBE57EF85908472152B655C312EE2AE7389B8A2A00B51FE54C6FBE45480C9CF] Key (SHA384): mLYgulce0/DNndZlVgQ+uTi7PyAhduYNPWhNsPYByVLpxqvxRtxE0rrcrzljdx9M2HyPMXaNbhTolAXrV1fDDw== [98B620BA571ED3F0CD9DD66556043EB938BB3F202176E60D3D684DB0F601C952E9C6ABF146DC44D2BADCAF3963771F4CD87C8F31768D6E14E89405EB5757C30F] Key (SHA512): U/HZEl864zHDocYh2TfLHxqGHN8fPCrwIbns/dX657ePV0Rp+tnY8+qjz1W+8jfeUWzBbRIlwY6qML30DqCyeA== [53F1D9125F3AE331C3A1C621D937CB1F1A861CDF1F3C2AF021B9ECFDD5FAE7B78F574469FAD9D8F3EAA3CF55BEF237DE516CC16D1225C18EAA30BDF40EA0B278]