internal static byte[] DeriveKeyMaterialTls(
            SafeNCryptSecretHandle secretAgreement,
            byte[] label,
            byte[] seed,
            SecretAgreementFlags flags)
        {
            Span <NCryptBuffer> buffers = stackalloc NCryptBuffer[2];

            unsafe
            {
                fixed(byte *pLabel = label, pSeed = seed)
                {
                    NCryptBuffer labelBuffer = default;

                    labelBuffer.cbBuffer   = label.Length;
                    labelBuffer.BufferType = BufferType.KdfTlsLabel;
                    labelBuffer.pvBuffer   = new IntPtr(pLabel);
                    buffers[0]             = labelBuffer;

                    NCryptBuffer seedBuffer = default;

                    seedBuffer.cbBuffer   = seed.Length;
                    seedBuffer.BufferType = BufferType.KdfTlsSeed;
                    seedBuffer.pvBuffer   = new IntPtr(pSeed);
                    buffers[1]            = seedBuffer;

                    return(DeriveKeyMaterial(
                               secretAgreement,
                               BCryptNative.KeyDerivationFunction.Tls,
                               buffers,
                               flags));
                }
            }
        }
 private static extern ErrorCode NCryptDeriveKey(
     SafeNCryptSecretHandle hSharedSecret,
     string pwszKDF,
     [In] ref NCryptBufferDesc pParameterList,
     [Out, MarshalAs(UnmanagedType.LPArray)] byte[]?pbDerivedKey,
     int cbDerivedKey,
     [Out] out int pcbResult,
     SecretAgreementFlags dwFlags);
        private static unsafe byte[] DeriveKeyMaterial(
            SafeNCryptSecretHandle secretAgreement,
            string kdf,
            ReadOnlySpan <NCryptBuffer> parameters,
            SecretAgreementFlags flags)
        {
            fixed(NCryptBuffer *pParameters = &MemoryMarshal.GetReference(parameters))
            {
                NCryptBufferDesc parameterDesc = default;

                parameterDesc.ulVersion = 0;
                parameterDesc.cBuffers  = parameters.Length;
                parameterDesc.pBuffers  = new IntPtr(pParameters);

                // Figure out how big the key material is
                ErrorCode error = NCryptDeriveKey(
                    secretAgreement,
                    kdf,
                    ref parameterDesc,
                    null,
                    0,
                    out int keySize,
                    flags);

                if (error != ErrorCode.ERROR_SUCCESS && error != ErrorCode.NTE_BUFFER_TOO_SMALL)
                {
                    throw error.ToCryptographicException();
                }

                // Allocate memory for the key material and generate it
                byte[] keyMaterial = new byte[keySize];

                error = NCryptDeriveKey(
                    secretAgreement,
                    kdf,
                    ref parameterDesc,
                    keyMaterial,
                    keyMaterial.Length,
                    out keySize,
                    flags);

                if (error != ErrorCode.ERROR_SUCCESS)
                {
                    throw error.ToCryptographicException();
                }

                // Just in case it shrank the answer once it had a buffer.
                Array.Resize(ref keyMaterial, Math.Min(keySize, keyMaterial.Length));
                return(keyMaterial);
            }
        }
 internal static byte[] DeriveKeyMaterialHash(
     SafeNCryptSecretHandle secretAgreement,
     string hashAlgorithm,
     byte[]?secretPrepend,
     byte[]?secretAppend,
     SecretAgreementFlags flags)
 {
     return(DeriveKeyMaterial(
                secretAgreement,
                BCryptNative.KeyDerivationFunction.Hash,
                hashAlgorithm,
                null,
                secretPrepend,
                secretAppend,
                flags));
 }
        private static byte[] DeriveKeyMaterial(
            SafeNCryptSecretHandle secretAgreement,
            string kdf,
            string hashAlgorithm,
            byte[]?hmacKey,
            byte[]?secretPrepend,
            byte[]?secretAppend,
            SecretAgreementFlags flags)
        {
            // First marshal the hash algoritm
            IntPtr hashAlgorithmString = IntPtr.Zero;

            try
            {
                hashAlgorithmString = Marshal.StringToCoTaskMemUni(hashAlgorithm);

                Span <NCryptBuffer> parameters = stackalloc NCryptBuffer[4];
                int parameterCount             = 0;
                // We always need to marshal the hashing function
                NCryptBuffer hashAlgorithmBuffer = default;
                hashAlgorithmBuffer.cbBuffer   = (hashAlgorithm.Length + 1) * sizeof(char);
                hashAlgorithmBuffer.BufferType = BufferType.KdfHashAlgorithm;
                hashAlgorithmBuffer.pvBuffer   = hashAlgorithmString;

                parameters[parameterCount] = hashAlgorithmBuffer;
                parameterCount++;

                unsafe
                {
                    fixed(byte *pHmacKey = hmacKey, pSecretPrepend = secretPrepend, pSecretAppend = secretAppend)
                    {
                        //
                        // Now marshal the other parameters
                        //

                        if (pHmacKey != null)
                        {
                            NCryptBuffer hmacKeyBuffer = default;
                            hmacKeyBuffer.cbBuffer   = hmacKey !.Length;
                            hmacKeyBuffer.BufferType = BufferType.KdfHmacKey;
                            hmacKeyBuffer.pvBuffer   = new IntPtr(pHmacKey);

                            parameters[parameterCount] = hmacKeyBuffer;
                            parameterCount++;
                        }

                        if (pSecretPrepend != null)
                        {
                            NCryptBuffer secretPrependBuffer = default;
                            secretPrependBuffer.cbBuffer   = secretPrepend !.Length;
                            secretPrependBuffer.BufferType = BufferType.KdfSecretPrepend;
                            secretPrependBuffer.pvBuffer   = new IntPtr(pSecretPrepend);

                            parameters[parameterCount] = secretPrependBuffer;
                            parameterCount++;
                        }

                        if (pSecretAppend != null)
                        {
                            NCryptBuffer secretAppendBuffer = default;
                            secretAppendBuffer.cbBuffer   = secretAppend !.Length;
                            secretAppendBuffer.BufferType = BufferType.KdfSecretAppend;
                            secretAppendBuffer.pvBuffer   = new IntPtr(pSecretAppend);

                            parameters[parameterCount] = secretAppendBuffer;
                            parameterCount++;
                        }

                        return(DeriveKeyMaterial(
                                   secretAgreement,
                                   kdf,
                                   parameters.Slice(0, parameterCount),
                                   flags));
                    }
                }
            }
            finally
            {
                if (hashAlgorithmString != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(hashAlgorithmString);
                }
            }
        }
        private static unsafe byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement, string kdf, string hashAlgorithm, byte[] hmacKey, byte[] secretPrepend, byte[] secretAppend, SecretAgreementFlags flags)
        {
            byte[] buffer5;
            List <NCryptBuffer> list = new List <NCryptBuffer>();
            IntPtr zero = IntPtr.Zero;

            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                RuntimeHelpers.PrepareConstrainedRegions();
                try
                {
                }
                finally
                {
                    zero = Marshal.StringToCoTaskMemUni(hashAlgorithm);
                }
                NCryptBuffer item = new NCryptBuffer {
                    cbBuffer   = (hashAlgorithm.Length + 1) * 2,
                    BufferType = BufferType.KdfHashAlgorithm,
                    pvBuffer   = zero
                };
                list.Add(item);
                try
                {
                    fixed(byte *numRef = hmacKey)
                    {
                        fixed(byte *numRef2 = secretPrepend)
                        {
                            fixed(byte *numRef3 = secretAppend)
                            {
                                if (numRef != IntPtr.Zero)
                                {
                                    NCryptBuffer buffer2 = new NCryptBuffer {
                                        cbBuffer   = hmacKey.Length,
                                        BufferType = BufferType.KdfHmacKey,
                                        pvBuffer   = new IntPtr((void *)numRef)
                                    };
                                    list.Add(buffer2);
                                }
                                if (numRef2 != IntPtr.Zero)
                                {
                                    NCryptBuffer buffer3 = new NCryptBuffer {
                                        cbBuffer   = secretPrepend.Length,
                                        BufferType = BufferType.KdfSecretPrepend,
                                        pvBuffer   = new IntPtr((void *)numRef2)
                                    };
                                    list.Add(buffer3);
                                }
                                if (numRef3 != IntPtr.Zero)
                                {
                                    NCryptBuffer buffer4 = new NCryptBuffer {
                                        cbBuffer   = secretAppend.Length,
                                        BufferType = BufferType.KdfSecretAppend,
                                        pvBuffer   = new IntPtr((void *)numRef3)
                                    };
                                    list.Add(buffer4);
                                }
                                return(DeriveKeyMaterial(secretAgreement, kdf, list.ToArray(), flags));
                            }
                        }
                    }
                }
                finally
                {
                    numRef  = null;
                    numRef2 = null;
                    numRef3 = null;
                }
            }
            finally
            {
                if (zero != IntPtr.Zero)
                {
                    Marshal.FreeCoTaskMem(zero);
                }
            }
            return(buffer5);
        }
        private static unsafe byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement, string kdf, NCryptBuffer[] parameters, SecretAgreementFlags flags)
        {
            fixed(NCryptBuffer *bufferRef = parameters)
            {
                NCryptBufferDesc pParameterList = new NCryptBufferDesc {
                    ulVersion = 0,
                    cBuffers  = parameters.Length,
                    pBuffers  = new IntPtr((void *)bufferRef)
                };
                int       pcbResult = 0;
                ErrorCode code      = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement, kdf, ref pParameterList, null, 0, out pcbResult, flags);

                if ((code != ErrorCode.Success) && (code != ErrorCode.BufferTooSmall))
                {
                    throw new CryptographicException((int)code);
                }
                byte[] pbDerivedKey = new byte[pcbResult];
                code = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement, kdf, ref pParameterList, pbDerivedKey, pbDerivedKey.Length, out pcbResult, flags);
                if (code != ErrorCode.Success)
                {
                    throw new CryptographicException((int)code);
                }
                return(pbDerivedKey);
            }
        }
        internal static unsafe byte[] DeriveKeyMaterialTls(SafeNCryptSecretHandle secretAgreement, byte[] label, byte[] seed, SecretAgreementFlags flags)
        {
            NCryptBuffer[] parameters = new NCryptBuffer[2];
            fixed(byte *numRef = label)
            {
                fixed(byte *numRef2 = seed)
                {
                    NCryptBuffer buffer = new NCryptBuffer {
                        cbBuffer   = label.Length,
                        BufferType = BufferType.KdfTlsLabel,
                        pvBuffer   = new IntPtr((void *)numRef)
                    };

                    parameters[0] = buffer;
                    NCryptBuffer buffer2 = new NCryptBuffer {
                        cbBuffer   = seed.Length,
                        BufferType = BufferType.KdfTlsSeed,
                        pvBuffer   = new IntPtr((void *)numRef2)
                    };

                    parameters[1] = buffer2;
                    return(DeriveKeyMaterial(secretAgreement, "TLS_PRF", parameters, flags));
                }
            }
        }
 internal static byte[] DeriveKeyMaterialHmac(SafeNCryptSecretHandle secretAgreement, string hashAlgorithm, byte[] hmacKey, byte[] secretPrepend, byte[] secretAppend, SecretAgreementFlags flags)
 {
     return(DeriveKeyMaterial(secretAgreement, "HMAC", hashAlgorithm, hmacKey, secretPrepend, secretAppend, flags));
 }
 internal static byte[] DeriveKeyMaterialHash(SafeNCryptSecretHandle secretAgreement, string hashAlgorithm, byte[] secretPrepend, byte[] secretAppend, SecretAgreementFlags flags)
 {
     return(DeriveKeyMaterial(secretAgreement, "HASH", hashAlgorithm, null, secretPrepend, secretAppend, flags));
 }