//https://tools.ietf.org/html/rfc5869 public static void HkdfExtract(this IHashProvider provider, HashType hashType, ReadOnlySpan <byte> salt, ReadOnlySpan <byte> ikm, Span <byte> output) { if (salt.Length == 0) { salt = Empty.Slice(0, provider.HashSize(hashType)); } if (ikm.Length == 0) { ikm = Empty.Slice(0, provider.HashSize(hashType)); } provider.HmacData(hashType, salt, ikm, output); }
public static unsafe void HkdfExtract(IHashProvider provider, HashType hashType, void *salt, int saltLength, void *ikm, int ikmLength, void *output, int outputLength) { if (saltLength == 0) { salt = (byte *)s_zeroArray; saltLength = provider.HashSize(hashType); } if (ikmLength == 0) { ikm = (byte *)s_zeroArray; ikmLength = provider.HashSize(hashType); } provider.HmacData(hashType, salt, saltLength, ikm, ikmLength, output, outputLength); }
//https://tools.ietf.org/html/rfc5869 public static void HkdfExpand(this IHashProvider provider, HashType hashType, ReadOnlySpan <byte> prk, ReadOnlySpan <byte> info, Span <byte> output) { var hashLength = provider.HashSize(hashType); var tLength = hashLength + info.Length + sizeof(byte); var t = new Span <byte>(new byte[tLength]); info.CopyTo(t.Slice(hashLength)); byte counter = 1; var counterSpan = t.Slice(t.Length - 1); counterSpan.Write(counter); provider.HmacData(hashType, prk, t.Slice(hashLength), t.Slice(0, hashLength)); while (true) { var amountToCopy = Math.Min(hashLength, output.Length); t.Slice(0, amountToCopy).CopyTo(output); output = output.Slice(amountToCopy); if (output.Length == 0) { return; } counter++; counterSpan.Write(counter); provider.HmacData(hashType, prk, t, t.Slice(0, hashLength)); } }
public static unsafe void HkdfExpand(IHashProvider provider, HashType hashType, void *prk, int prkLength, Span <byte> info, Span <byte> output) { int hashLength = provider.HashSize(hashType); var tLength = hashLength + info.Length + sizeof(byte); var t = stackalloc byte[tLength]; var tSpan = new Span <byte>(t, tLength); info.CopyTo(tSpan.Slice(hashLength)); byte counter = 1; var counterSpan = tSpan.Slice(tSpan.Length - 1); counterSpan.Write(counter); provider.HmacData(hashType, prk, prkLength, t + hashLength, tLength - hashLength, t, hashLength); while (true) { int amountToCopy = Math.Min(hashLength, output.Length); tSpan.Slice(0, amountToCopy).CopyTo(output); output = output.Slice(amountToCopy); if (output.Length == 0) { break; } counter++; counterSpan.Write(counter); provider.HmacData(hashType, prk, prkLength, t, tLength, t, hashLength); } }
public unsafe static byte[] FinishedKey(IHashProvider provider, HashType hashType, byte *handshakeTrafficSecret) { var output = new byte[provider.HashSize(hashType)]; HkdfExpandLabel(provider, hashType, handshakeTrafficSecret, output.Length, Tls1_3Consts.ServerFinishedKey, new Span <byte>(), output); return(output); }
public static unsafe void P_Hash12(IHashProvider hash, HashType hashType, Span <byte> keyMaterial, void *secret, int secretLength, Span <byte> seed) { var hashSize = hash.HashSize(hashType); var a1Length = hashSize + seed.Length; var a1 = stackalloc byte[a1Length]; Span <byte> a1Span = new Span <byte>(a1, a1Length); seed.CopyTo(a1Span.Slice(hashSize)); var seedPtr = a1 + hashSize; hash.HmacData(hashType, secret, secretLength, seedPtr, seed.Length, a1, hashSize); var currentKeyData = stackalloc byte[hashSize]; int keyMaterialIndex = 0; while (true) { hash.HmacData(hashType, secret, secretLength, a1, a1Length, currentKeyData, hashSize); for (int i = 0; i < hashSize; i++) { keyMaterial[keyMaterialIndex] = currentKeyData[i]; keyMaterialIndex++; if (keyMaterialIndex == keyMaterial.Length) { return; } } hash.HmacData(hashType, secret, secretLength, a1, hashSize, a1, hashSize); } }
public static void HkdfFact(string input, IHashProvider provider) { var lines = input.Split('\n').Select(l => l.Trim().Split('=')).ToDictionary(val => val[0], val => val[1]); var hashType = (HashType)Enum.Parse(typeof(HashType), lines["Hash"], true); var ikm = lines["IKM"].HexToByteArray(); var salt = string.IsNullOrEmpty(lines["salt"]) ? new byte[0] : lines["salt"].HexToByteArray(); var info = string.IsNullOrEmpty(lines["info"]) ? new byte[0] : lines["info"].HexToByteArray(); var prk = lines["PRK"].HexToByteArray(); var okm = lines["OKM"].HexToByteArray(); var prkResult = new byte[provider.HashSize(hashType)]; var okmResult = new byte[okm.Length]; provider.HkdfExtract(hashType, salt, ikm, prkResult); provider.HkdfExpand(hashType, prkResult, info, okmResult); Assert.Equal(prk, prkResult); Assert.Equal(okm, okmResult); }
//https://tools.ietf.org/html/rfc5246#section-4.7 //TLS 1.2 Secret Expansion into an n length run of bytes // P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + // HMAC_hash(secret, A(2) + seed) + // A() is defined as: // A(0) = seed // A(i) = HMAC_hash(secret, A(i-1)) public static void Tls12Prf(this IHashProvider hashProvider, HashType hashType, ReadOnlySpan <byte> secret, ReadOnlySpan <byte> label, ReadOnlySpan <byte> seed, Span <byte> keyMaterial) { var hashSize = hashProvider.HashSize(hashType); var aLength = hashSize + seed.Length + label.Length; var a1 = new Span <byte>(new byte[aLength]); label.CopyTo(a1.Slice(hashSize)); seed.CopyTo(a1.Slice(hashSize + label.Length)); hashProvider.HmacData(hashType, secret, a1.Slice(hashSize), a1.Slice(0, hashSize)); var currentKeyData = new Span <byte>(new byte[hashSize]); while (keyMaterial.Length > 0) { //HMAC_hash(secret, A(n) + seed) hashProvider.HmacData(hashType, secret, a1, currentKeyData); //Copy required bytes into the output keymaterial and reduce size remaining var amountToCopy = Math.Min(keyMaterial.Length, currentKeyData.Length); currentKeyData.Slice(0, amountToCopy).CopyTo(keyMaterial); keyMaterial = keyMaterial.Slice(amountToCopy); //A(n) = HMAC_hash(secret, A(n-1)) hashProvider.HmacData(hashType, secret, a1.Slice(0, hashSize), a1.Slice(0, hashSize)); } }