private static void DeriveKeyCore(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 = GetTotalByteLengthIncludingNullTerminator(hashAlgorithm);

                // 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");
            }
        }
        private uint GetCbcEncryptedOutputSizeWithPadding(BCryptKeyHandle symmetricKeyHandle, byte* pbInput, uint cbInput)
        {
            // ok for this memory to remain uninitialized since nobody depends on it
            byte* pbIV = stackalloc byte[checked((int)_symmetricAlgorithmBlockSizeInBytes)];

            // Calling BCryptEncrypt with a null output pointer will cause it to return the total number
            // of bytes required for the output buffer.
            uint dwResult;
            int ntstatus = UnsafeNativeMethods.BCryptEncrypt(
                hKey: symmetricKeyHandle,
                pbInput: pbInput,
                cbInput: cbInput,
                pPaddingInfo: null,
                pbIV: pbIV,
                cbIV: _symmetricAlgorithmBlockSizeInBytes,
                pbOutput: null,
                cbOutput: 0,
                pcbResult: out dwResult,
                dwFlags: BCryptEncryptFlags.BCRYPT_BLOCK_PADDING);
            UnsafeNativeMethods.ThrowExceptionForBCryptStatus(ntstatus);

            return dwResult;
        }
        // 'pbIV' must be a pointer to a buffer equal in length to the symmetric algorithm block size.
        private byte[] DoCbcDecrypt(BCryptKeyHandle symmetricKeyHandle, byte* pbIV, byte* pbInput, uint cbInput)
        {
            // BCryptDecrypt mutates the provided IV; we need to clone it to prevent mutation of the original value
            byte* pbClonedIV = stackalloc byte[checked((int)_symmetricAlgorithmBlockSizeInBytes)];
            UnsafeBufferUtil.BlockCopy(from: pbIV, to: pbClonedIV, byteCount: _symmetricAlgorithmBlockSizeInBytes);

            // First, figure out how large an output buffer we require.
            // Ideally we'd be able to transform the last block ourselves and strip
            // off the padding before creating the return value array, but we don't
            // know the actual padding scheme being used under the covers (we can't
            // assume PKCS#7). So unfortunately we're stuck with the temporary buffer.
            // (Querying the output size won't mutate the IV.)
            uint dwEstimatedDecryptedByteCount;
            int ntstatus = UnsafeNativeMethods.BCryptDecrypt(
                hKey: symmetricKeyHandle,
                pbInput: pbInput,
                cbInput: cbInput,
                pPaddingInfo: null,
                pbIV: pbClonedIV,
                cbIV: _symmetricAlgorithmBlockSizeInBytes,
                pbOutput: null,
                cbOutput: 0,
                pcbResult: out dwEstimatedDecryptedByteCount,
                dwFlags: BCryptEncryptFlags.BCRYPT_BLOCK_PADDING);
            UnsafeNativeMethods.ThrowExceptionForBCryptStatus(ntstatus);

            byte[] decryptedPayload = new byte[dwEstimatedDecryptedByteCount];
            uint dwActualDecryptedByteCount;
            fixed (byte* pbDecryptedPayload = decryptedPayload)
            {
                byte dummy;

                // Perform the actual decryption.
                ntstatus = UnsafeNativeMethods.BCryptDecrypt(
                    hKey: symmetricKeyHandle,
                    pbInput: pbInput,
                    cbInput: cbInput,
                    pPaddingInfo: null,
                    pbIV: pbClonedIV,
                    cbIV: _symmetricAlgorithmBlockSizeInBytes,
                    pbOutput: (pbDecryptedPayload != null) ? pbDecryptedPayload : &dummy, // CLR won't pin zero-length arrays
                    cbOutput: dwEstimatedDecryptedByteCount,
                    pcbResult: out dwActualDecryptedByteCount,
                    dwFlags: BCryptEncryptFlags.BCRYPT_BLOCK_PADDING);
                UnsafeNativeMethods.ThrowExceptionForBCryptStatus(ntstatus);
            }

            // Decryption finished!
            CryptoUtil.Assert(dwActualDecryptedByteCount <= dwEstimatedDecryptedByteCount, "dwActualDecryptedByteCount <= dwEstimatedDecryptedByteCount");
            if (dwActualDecryptedByteCount == dwEstimatedDecryptedByteCount)
            {
                // payload takes up the entire buffer
                return decryptedPayload;
            }
            else
            {
                // payload takes up only a partial buffer
                byte[] resizedDecryptedPayload = new byte[dwActualDecryptedByteCount];
                Buffer.BlockCopy(decryptedPayload, 0, resizedDecryptedPayload, 0, resizedDecryptedPayload.Length);
                return resizedDecryptedPayload;
            }
        }
        // 'pbIV' must be a pointer to a buffer equal in length to the symmetric algorithm block size.
        private void DoCbcEncrypt(BCryptKeyHandle symmetricKeyHandle, byte* pbIV, byte* pbInput, uint cbInput, byte* pbOutput, uint cbOutput)
        {
            // BCryptEncrypt mutates the provided IV; we need to clone it to prevent mutation of the original value
            byte* pbClonedIV = stackalloc byte[checked((int)_symmetricAlgorithmBlockSizeInBytes)];
            UnsafeBufferUtil.BlockCopy(from: pbIV, to: pbClonedIV, byteCount: _symmetricAlgorithmBlockSizeInBytes);

            uint dwEncryptedBytes;
            int ntstatus = UnsafeNativeMethods.BCryptEncrypt(
                hKey: symmetricKeyHandle,
                pbInput: pbInput,
                cbInput: cbInput,
                pPaddingInfo: null,
                pbIV: pbClonedIV,
                cbIV: _symmetricAlgorithmBlockSizeInBytes,
                pbOutput: pbOutput,
                cbOutput: cbOutput,
                pcbResult: out dwEncryptedBytes,
                dwFlags: BCryptEncryptFlags.BCRYPT_BLOCK_PADDING);
            UnsafeNativeMethods.ThrowExceptionForBCryptStatus(ntstatus);

            // Need to make sure we didn't underrun the buffer - means caller passed a bad value
            CryptoUtil.Assert(dwEncryptedBytes == cbOutput, "dwEncryptedBytes == cbOutput");
        }
 public Win8SP800_108_CTR_HMACSHA512Provider(byte* pbKdk, uint cbKdk)
 {
     _keyHandle = ImportKey(pbKdk, cbKdk);
 }