async public Task HkdfExpand_Success(string expectedKey, HkdfAlgorithm algorithm, string prkString, int outputByteSize, string info, PclCryptoFunctionService sut) { var prk = Convert.FromBase64String(prkString); var key = await sut.HkdfExpandAsync(prk, info, outputByteSize, algorithm); Assert.Equal(expectedKey, Convert.ToBase64String(key)); var keyFromByteArray = await sut.HkdfExpandAsync(prk, Encoding.UTF8.GetBytes(info), outputByteSize, algorithm); Assert.Equal(key, keyFromByteArray); }
async public Task Hkdf_Success(string expectedKey, HkdfAlgorithm algorithm, string ikmString, string salt, string info, PclCryptoFunctionService sut) { byte[] ikm = Convert.FromBase64String(ikmString); var key = await sut.HkdfAsync(ikm, salt, info, 32, algorithm); Assert.Equal(expectedKey, Convert.ToBase64String(key)); var keyFromByteArray = await sut.HkdfAsync(ikm, Encoding.UTF8.GetBytes(salt), Encoding.UTF8.GetBytes(info), 32, algorithm); Assert.Equal(key, keyFromByteArray); }
private CryptoHashAlgorithm HkdfAlgorithmToCryptoHashAlgorithm(HkdfAlgorithm hkdfAlgorithm) { switch (hkdfAlgorithm) { case HkdfAlgorithm.Sha256: return(CryptoHashAlgorithm.Sha256); case HkdfAlgorithm.Sha512: return(CryptoHashAlgorithm.Sha512); default: throw new ArgumentException($"Invalid hkdf algorithm type, {hkdfAlgorithm}"); } }
// ref: https://tools.ietf.org/html/rfc5869 public async Task <byte[]> HkdfExpandAsync(byte[] prk, byte[] info, int outputByteSize, HkdfAlgorithm algorithm) { var hashLen = algorithm == HkdfAlgorithm.Sha256 ? 32 : 64; var maxOutputByteSize = 255 * hashLen; if (outputByteSize > maxOutputByteSize) { throw new ArgumentException($"{nameof(outputByteSize)} is too large. Max is {maxOutputByteSize}, received {outputByteSize}"); } if (prk.Length < hashLen) { throw new ArgumentException($"{nameof(prk)} length is too small. Must be at least {hashLen} for {algorithm}"); } var cryptoHashAlgorithm = HkdfAlgorithmToCryptoHashAlgorithm(algorithm); var previousT = new byte[0]; var runningOkmLength = 0; var n = (int)Math.Ceiling((double)outputByteSize / hashLen); var okm = new byte[n * hashLen]; for (var i = 0; i < n; i++) { var t = new byte[previousT.Length + info.Length + 1]; previousT.CopyTo(t, 0); info.CopyTo(t, previousT.Length); t[t.Length - 1] = (byte)(i + 1); previousT = await HmacAsync(t, prk, cryptoHashAlgorithm); previousT.CopyTo(okm, runningOkmLength); runningOkmLength = previousT.Length; if (runningOkmLength >= outputByteSize) { break; } } return(okm.Take(outputByteSize).ToArray()); }
public async Task <byte[]> HkdfExpandAsync(byte[] prk, string info, int outputByteSize, HkdfAlgorithm algorithm) => await HkdfExpandAsync(prk, Encoding.UTF8.GetBytes(info), outputByteSize, algorithm);
public async Task <byte[]> HkdfAsync(byte[] ikm, byte[] salt, byte[] info, int outputByteSize, HkdfAlgorithm algorithm) { var prk = await HmacAsync(ikm, salt, HkdfAlgorithmToCryptoHashAlgorithm(algorithm)); return(await HkdfExpandAsync(prk, info, outputByteSize, algorithm)); }
public async Task <byte[]> HkdfAsync(byte[] ikm, string salt, byte[] info, int outputByteSize, HkdfAlgorithm algorithm) => await HkdfAsync(ikm, Encoding.UTF8.GetBytes(salt), info, outputByteSize, algorithm);