| File: SP800_108\Win7SP800_108_CTR_HMACSHA512Provider.cs | Web Access |
| Project: src\aspnetcore\src\DataProtection\DataProtection\src\Microsoft.AspNetCore.DataProtection.csproj (Microsoft.AspNetCore.DataProtection) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using Microsoft.AspNetCore.Cryptography; using Microsoft.AspNetCore.Cryptography.Cng; using Microsoft.AspNetCore.Cryptography.SafeHandles; namespace Microsoft.AspNetCore.DataProtection.SP800_108; internal sealed unsafe class Win7SP800_108_CTR_HMACSHA512Provider : ISP800_108_CTR_HMACSHA512Provider { private readonly BCryptHashHandle _hashHandle; public Win7SP800_108_CTR_HMACSHA512Provider(byte* pbKdk, uint cbKdk) { _hashHandle = CachedAlgorithmHandles.HMAC_SHA512.CreateHmac(pbKdk, cbKdk); } public void DeriveKey(byte* pbLabel, uint cbLabel, byte* pbContext, uint cbContext, byte* pbDerivedKey, uint cbDerivedKey) { const uint SHA512_DIGEST_SIZE_IN_BYTES = 512 / 8; byte* pbHashDigest = stackalloc byte[(int)SHA512_DIGEST_SIZE_IN_BYTES]; // NOTE: pbDerivedKey and cbDerivedKey are modified as data is copied to the output buffer. // this will be zero-inited var tempInputBuffer = new byte[checked( sizeof(int) /* [i] */ + cbLabel /* Label */ + 1 /* 0x00 */ + cbContext /* Context */ + sizeof(int) /* [L] */)]; fixed (byte* pbTempInputBuffer = tempInputBuffer) { // Step 1: Calculate all necessary offsets into the temp input & output buffer. byte* pbTempInputCounter = pbTempInputBuffer; byte* pbTempInputLabel = &pbTempInputCounter[sizeof(int)]; byte* pbTempInputContext = &pbTempInputLabel[cbLabel + 1 /* 0x00 */]; byte* pbTempInputBitlengthIndicator = &pbTempInputContext[cbContext]; // Step 2: Copy Label and Context into the temp input buffer. UnsafeBufferUtil.BlockCopy(from: pbLabel, to: pbTempInputLabel, byteCount: cbLabel); UnsafeBufferUtil.BlockCopy(from: pbContext, to: pbTempInputContext, byteCount: cbContext); // Step 3: copy [L] into last part of data to be hashed, big-endian BitHelpers.WriteTo(pbTempInputBitlengthIndicator, checked(cbDerivedKey * 8)); // Step 4: iterate until all desired bytes have been generated for (uint i = 1; cbDerivedKey > 0; i++) { // Step 4a: Copy [i] into the first part of data to be hashed, big-endian BitHelpers.WriteTo(pbTempInputCounter, i); // Step 4b: Hash. Win7 doesn't allow reusing hash algorithm objects after the final hash // has been computed, so we'll just keep calling DuplicateHash on the original // hash handle. This offers a slight performance increase over allocating a new hash // handle for each iteration. We don't need to mess with any of this on Win8 since on // that platform we use BCryptKeyDerivation directly, which offers superior performance. using (var hashHandle = _hashHandle.DuplicateHash()) { hashHandle.HashData(pbTempInputBuffer, (uint)tempInputBuffer.Length, pbHashDigest, SHA512_DIGEST_SIZE_IN_BYTES); } // Step 4c: Copy bytes from the temporary buffer to the output buffer. uint numBytesToCopy = Math.Min(cbDerivedKey, SHA512_DIGEST_SIZE_IN_BYTES); UnsafeBufferUtil.BlockCopy(from: pbHashDigest, to: pbDerivedKey, byteCount: numBytesToCopy); pbDerivedKey += numBytesToCopy; cbDerivedKey -= numBytesToCopy; } } } public void Dispose() { _hashHandle.Dispose(); } }