public void DeriveKey(byte *pbLabel, uint cbLabel, byte *pbContext, uint cbContext, byte *pbDerivedKey, uint cbDerivedKey) { const int SHA512_ALG_CHAR_COUNT = 7; char * pszHashAlgorithm = stackalloc char[SHA512_ALG_CHAR_COUNT /* includes terminating null */]; pszHashAlgorithm[0] = 'S'; pszHashAlgorithm[1] = 'H'; pszHashAlgorithm[2] = 'A'; pszHashAlgorithm[3] = '5'; pszHashAlgorithm[4] = '1'; pszHashAlgorithm[5] = '2'; pszHashAlgorithm[6] = (char)0; // First, build the buffers necessary to pass (label, context, PRF algorithm) into the KDF BCryptBuffer *pBuffers = stackalloc BCryptBuffer[3]; pBuffers[0].BufferType = BCryptKeyDerivationBufferType.KDF_LABEL; pBuffers[0].pvBuffer = (IntPtr)pbLabel; pBuffers[0].cbBuffer = cbLabel; pBuffers[1].BufferType = BCryptKeyDerivationBufferType.KDF_CONTEXT; pBuffers[1].pvBuffer = (IntPtr)pbContext; pBuffers[1].cbBuffer = cbContext; pBuffers[2].BufferType = BCryptKeyDerivationBufferType.KDF_HASH_ALGORITHM; pBuffers[2].pvBuffer = (IntPtr)pszHashAlgorithm; pBuffers[2].cbBuffer = checked (SHA512_ALG_CHAR_COUNT * sizeof(char)); // Add the header which points to the buffers var bufferDesc = default(BCryptBufferDesc); BCryptBufferDesc.Initialize(ref bufferDesc); bufferDesc.cBuffers = 3; bufferDesc.pBuffers = pBuffers; // Finally, invoke the KDF uint numBytesDerived; var ntstatus = UnsafeNativeMethods.BCryptKeyDerivation( hKey: _keyHandle, pParameterList: &bufferDesc, pbDerivedKey: pbDerivedKey, cbDerivedKey: cbDerivedKey, pcbResult: out numBytesDerived, dwFlags: 0); UnsafeNativeMethods.ThrowExceptionForBCryptStatus(ntstatus); // Final sanity checks before returning control to caller. CryptoUtil.Assert(numBytesDerived == cbDerivedKey, "numBytesDerived == cbDerivedKey"); }
private static void Pbkdf2Win8ImplStep2(BCryptKeyHandle pbkdf2KeyHandle, string hashAlgorithm, byte *pbSalt, uint cbSalt, ulong iterCount, byte *pbDerivedBytes, uint cbDerivedBytes) { // First, build the buffers necessary to pass (hash alg, salt, iter count) into the KDF BCryptBuffer *pBuffers = stackalloc BCryptBuffer[3]; pBuffers[0].BufferType = BCryptKeyDerivationBufferType.KDF_ITERATION_COUNT; pBuffers[0].pvBuffer = (IntPtr)(&iterCount); pBuffers[0].cbBuffer = sizeof(ulong); pBuffers[1].BufferType = BCryptKeyDerivationBufferType.KDF_SALT; pBuffers[1].pvBuffer = (IntPtr)pbSalt; pBuffers[1].cbBuffer = cbSalt; fixed(char *pszHashAlgorithm = hashAlgorithm) { pBuffers[2].BufferType = BCryptKeyDerivationBufferType.KDF_HASH_ALGORITHM; pBuffers[2].pvBuffer = (IntPtr)pszHashAlgorithm; pBuffers[2].cbBuffer = hashAlgorithm.GetTotalByteLengthIncludingNullTerminator(); // Add the header which points to the buffers BCryptBufferDesc bufferDesc = default(BCryptBufferDesc); BCryptBufferDesc.Initialize(ref bufferDesc); bufferDesc.cBuffers = 3; bufferDesc.pBuffers = pBuffers; // Finally, import the KDK into the KDF algorithm, then invoke the KDF uint numBytesDerived; int ntstatus = UnsafeNativeMethods.BCryptKeyDerivation( hKey: pbkdf2KeyHandle, pParameterList: &bufferDesc, pbDerivedKey: pbDerivedBytes, cbDerivedKey: cbDerivedBytes, pcbResult: out numBytesDerived, dwFlags: 0); UnsafeNativeMethods.ThrowExceptionForBCryptStatus(ntstatus); // Final sanity checks before returning control to caller. CryptoUtil.Assert(numBytesDerived == cbDerivedBytes, "numBytesDerived == cbDerivedBytes"); } }