NCryptNative.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Core / System / Security / Cryptography / NCryptNative.cs / 1305376 / NCryptNative.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

using System; 
using System.Collections.Generic; 
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; 
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; 
using System.Security.Permissions;
using System.Text; 
using System.Diagnostics.Contracts; 
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles; 

namespace System.Security.Cryptography {

    // 
    // Public facing enumerations
    // 
 
    /// 
    ///     Flags to control how often and in which format a key is allowed to be exported 
    /// 
    [Flags]
    public enum CngExportPolicies {
        None = 0x00000000, 
        AllowExport = 0x00000001,                       // NCRYPT_ALLOW_EXPORT_FLAG
        AllowPlaintextExport = 0x00000002,              // NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG 
        AllowArchiving = 0x00000004,                    // NCRYPT_ALLOW_ARCHIVING_FLAG 
        AllowPlaintextArchiving = 0x00000008            // NCRYPT_ALLOW_PLAINTEXT_ARCHIVING_FLAG
    } 

    /// 
    ///     Flags controlling how the key is created
    ///  
    [Flags]
    public enum CngKeyCreationOptions { 
        None = 0x00000000, 
        MachineKey = 0x00000020,                        // NCRYPT_MACHINE_KEY_FLAG
        OverwriteExistingKey = 0x00000080               // NCRYPT_OVERWRITE_KEY_FLAG 
    }

    /// 
    ///     Flags controlling how a key is opened 
    /// 
    [Flags] 
    [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "Approved API exception to have an easy way to express user keys")] 
    public enum CngKeyOpenOptions {
        None = 0x00000000, 
        UserKey = 0x00000000,
        MachineKey = 0x00000020,                        // NCRYPT_MACHINE_KEY_FLAG
        Silent = 0x00000040                             // NCRYPT_SILENT_FLAG
    } 

    ///  
    ///     Flags indicating the type of key 
    /// 
    [Flags] 
    internal enum CngKeyTypes {
        None = 0x00000000,
        MachineKey = 0x00000020                         // NCRYPT_MACHINE_KEY_FLAG
    } 

    ///  
    ///     Bits defining what operations are valid to use a key with 
    /// 
    [Flags] 
    [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Justification = "Flags are defined by the native ncrypt API")]
    public enum CngKeyUsages {
        None = 0x00000000,
        Decryption = 0x00000001,                        // NCRYPT_ALLOW_DECRYPT_FLAG 
        Signing = 0x00000002,                           // NCRYPT_ALLOW_SIGNING_FLAG
        KeyAgreement = 0x00000004,                      // NCRYPT_ALLOW_KEY_AGREEMENT_FLAG 
        AllUsages = 0x00ffffff                          // NCRYPT_ALLOW_ALL_USAGES 
    }
 
    /// 
    ///     Options affecting how a property is interpreted by CNG
    /// 
    [Flags] 
    [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Justification = "Flags are defined by the native ncrypt API")]
    public enum CngPropertyOptions { 
        None = 0x00000000, 
        CustomProperty = 0x40000000,                    // NCRYPT_PERSIST_ONLY_FLAG
        Persist = unchecked((int)0x80000000)            // NCRYPT_PERSIST_FLAG 
    }

    /// 
    ///     Levels of UI protection available for a key 
    /// 
    [Flags] 
    public enum CngUIProtectionLevels { 
        None = 0x00000000,
        ProtectKey = 0x00000001,                        // NCRYPT_UI_PROTECT_KEY_FLAG 
        ForceHighProtection = 0x00000002                // NCRYPT_UI_FORCE_HIGH_PROTECTION_FLAG
    }

    ///  
    ///     Native interop with CNG's NCrypt layer. Native definitions are in ncrypt.h
    ///  
    internal static class NCryptNative { 
        //
        // Enumerations 
        //

        /// 
        ///     Types of NCryptBuffers 
        /// 
        internal enum BufferType { 
            KdfHashAlgorithm = 0x00000000,              // KDF_HASH_ALGORITHM 
            KdfSecretPrepend = 0x00000001,              // KDF_SECRET_PREPEND
            KdfSecretAppend = 0x00000002,               // KDF_SECRET_APPEND 
            KdfHmacKey = 0x00000003,                    // KDF_HMAC_KEY
            KdfTlsLabel = 0x00000004,                   // KDF_TLS_PRF_LABEL
            KdfTlsSeed = 0x00000005                     // KDF_TLS_PRF_SEED
        } 

        ///  
        ///     Result codes from NCrypt APIs 
        /// 
        internal enum ErrorCode { 
            Success = 0,                                            // ERROR_SUCCESS
            BadSignature = unchecked((int)0x80090006),              // NTE_BAD_SIGNATURE
            NotFound = unchecked((int)0x80090011),                  // NTE_NOT_FOUND
            KeyDoesNotExist = unchecked((int)0x80090016),           // NTE_BAD_KEYSET 
            BufferTooSmall = unchecked((int)0x80090028)             // NTE_BUFFER_TOO_SMALL
        } 
 
        /// 
        ///     Well known names of key properties 
        /// 
        internal static class KeyPropertyName {
            internal const string Algorithm = "Algorithm Name";                 // NCRYPT_ALGORITHM_PROPERTY
            internal const string AlgorithmGroup = "Algorithm Group";           // NCRYPT_ALGORITHM_GROUP_PROPERTY 
            internal const string ExportPolicy = "Export Policy";               // NCRYPT_EXPORT_POLICY_PROPERTY
            internal const string KeyType = "Key Type";                         // NCRYPT_KEY_TYPE_PROPERTY 
            internal const string KeyUsage = "Key Usage";                       // NCRYPT_KEY_USAGE_PROPERTY 
            internal const string Length = "Length";                            // NCRYPT_LENGTH_PROPERTY
            internal const string Name = "Name";                                // NCRYPT_NAME_PROPERTY 
            internal const string ParentWindowHandle = "HWND Handle";           // NCRYPT_WINDOW_HANDLE_PROPERTY
            internal const string ProviderHandle = "Provider Handle";           // NCRYPT_PROVIDER_HANDLE_PROPERTY
            internal const string UIPolicy = "UI Policy";                       // NCRYPT_UI_POLICY_PROPERTY
            internal const string UniqueName = "Unique Name";                   // NCRYPT_UNIQUE_NAME_PROPERTY 
            internal const string UseContext = "Use Context";                   // NCRYPT_USE_CONTEXT_PROPERTY
 
            // 
            // Properties defined by the CLR
            // 

            /// 
            ///     Is the key a CLR created ephemeral key, it will contain a single byte with value 1 if the
            ///     key was created by the CLR as an ephemeral key. 
            /// 
            internal const string ClrIsEphemeral = "CLR IsEphemeral"; 
        } 

        ///  
        ///     Well known names of provider properties
        /// 
        internal static class ProviderPropertyName {
            internal const string Name = "Name";        // NCRYPT_NAME_PROPERTY 
        }
 
        ///  
        ///     Flags for code:System.Security.Cryptography.NCryptNative.UnsafeNativeMethods.NCryptSecretAgreement
        ///  
        [Flags]
        internal enum SecretAgreementFlags {
            None = 0x00000000,
            UseSecretAsHmacKey = 0x00000001             // KDF_USE_SECRET_AS_HMAC_KEY_FLAG 
        }
 
        // 
        // Structures
        // 

        [StructLayout(LayoutKind.Sequential)]
        internal struct NCRYPT_UI_POLICY {
            public int dwVersion; 
            public CngUIProtectionLevels dwFlags;
 
            [MarshalAs(UnmanagedType.LPWStr)] 
            public string pszCreationTitle;
 
            [MarshalAs(UnmanagedType.LPWStr)]
            public string pszFriendlyName;

            [MarshalAs(UnmanagedType.LPWStr)] 
            public string pszDescription;
        } 
 
        [StructLayout(LayoutKind.Sequential)]
        internal struct NCryptBuffer { 
            public int cbBuffer;
            public BufferType BufferType;
            public IntPtr pvBuffer;
        } 

        [StructLayout(LayoutKind.Sequential)] 
        internal struct NCryptBufferDesc { 
            public int ulVersion;
            public int cBuffers; 
            public IntPtr pBuffers;         // NCryptBuffer[cBuffers]
        }

        [SuppressUnmanagedCodeSecurity] 
        internal static class UnsafeNativeMethods {
            ///  
            ///     Create an NCrypt key 
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)] 
            internal static extern ErrorCode NCryptCreatePersistedKey(SafeNCryptProviderHandle hProvider,
                                                                      [Out] out SafeNCryptKeyHandle phKey,
                                                                      string pszAlgId,
                                                                      string pszKeyName, 
                                                                      int dwLegacyKeySpec,
                                                                      CngKeyCreationOptions dwFlags); 
 
            /// 
            ///     Delete a key 
            /// 
            [DllImport("ncrypt.dll")]
            internal static extern ErrorCode NCryptDeleteKey(SafeNCryptKeyHandle hKey, int flags);
 
            /// 
            ///     Generate a key from a secret agreement 
            ///  
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal 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); 
 
            /// 
            ///     Export a key from the KSP 
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal static extern ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey,
                                                             IntPtr hExportKey,               // NCRYPT_KEY_HANDLE 
                                                             string pszBlobType,
                                                             IntPtr pParameterList,           // NCryptBufferDesc * 
                                                             [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput, 
                                                             int cbOutput,
                                                             [Out] out int pcbResult, 
                                                             int dwFlags);

            /// 
            ///     Finalize a key to prepare it for use 
            /// 
            [DllImport("ncrypt.dll")] 
            internal static extern ErrorCode NCryptFinalizeKey(SafeNCryptKeyHandle hKey, int dwFlags); 

            ///  
            ///     Get the value of a property of an NCrypt object
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal static extern ErrorCode NCryptGetProperty(SafeNCryptHandle hObject, 
                                                               string pszProperty,
                                                               [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput, 
                                                               int cbOutput, 
                                                               [Out] out int pcbResult,
                                                               CngPropertyOptions dwFlags); 

            /// 
            ///     Get the value of a pointer property of an NCrypt object
            ///  
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] 
            internal static extern ErrorCode NCryptGetProperty(SafeNCryptHandle hObject, 
                                                               string pszProperty,
                                                               [Out] out IntPtr pbOutput, 
                                                               int cbOutput,
                                                               [Out] out int pcbResult,
                                                               CngPropertyOptions dwFlags);
 
            /// 
            ///     Import a key into the KSP 
            ///  
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal static extern ErrorCode NCryptImportKey(SafeNCryptProviderHandle hProvider, 
                                                             IntPtr hImportKey,     // NCRYPT_KEY_HANDLE
                                                             string pszBlobType,
                                                             IntPtr pParameterList, // NCryptBufferDesc *
                                                             [Out] out SafeNCryptKeyHandle phKey, 
                                                             [MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
                                                             int cbData, 
                                                             int dwFlags); 

            ///  
            ///     Open an existing key
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal static extern ErrorCode NCryptOpenKey(SafeNCryptProviderHandle hProvider, 
                                                           [Out] out SafeNCryptKeyHandle phKey,
                                                           string pszKeyName, 
                                                           int dwLegacyKeySpec, 
                                                           CngKeyOpenOptions dwFlags);
 
            /// 
            ///     Acquire a handle to a key storage provider
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)] 
            internal static extern ErrorCode NCryptOpenStorageProvider([Out] out SafeNCryptProviderHandle phProvider,
                                                                       string pszProviderName, 
                                                                       int dwFlags); 

            ///  
            ///     Generate a secret agreement for generating shared key material
            /// 
            [DllImport("ncrypt.dll")]
            internal static extern ErrorCode NCryptSecretAgreement(SafeNCryptKeyHandle hPrivKey, 
                                                                   SafeNCryptKeyHandle hPubKey,
                                                                   [Out] out SafeNCryptSecretHandle phSecret, 
                                                                   int dwFlags); 

            ///  
            ///     Set a property value on an NCrypt object
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject, 
                                                               string pszProperty,
                                                               [MarshalAs(UnmanagedType.LPArray)] byte[] pbInput, 
                                                               int cbInput, 
                                                               CngPropertyOptions dwFlags);
 
            /// 
            ///     Set a string property value on an NCrypt object
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)] 
            internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
                                                               string pszProperty, 
                                                               string pbInput, 
                                                               int cbInput,
                                                               CngPropertyOptions dwFlags); 

            /// 
            ///     Set a property value on an NCrypt object when a pointer to the buffer already exists in
            ///     managed code. To set a pointer valued property, use the ref IntPtr overload. 
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)] 
            internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject, 
                                                               string pszProperty,
                                                               IntPtr pbInput, 
                                                               int cbInput,
                                                               CngPropertyOptions dwFlags);

            ///  
            ///     Create a signature for a hash value
            ///  
            [DllImport("ncrypt.dll")] 
            internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
                                                            IntPtr pPaddingInfo, 
                                                            [MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
                                                            int cbHashValue,
                                                            [MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
                                                            int cbSignature, 
                                                            [Out] out int pcbResult,
                                                            int dwFlags); 
 
            /// 
            ///     Verify a signature over a hash value 
            /// 
            [DllImport("ncrypt.dll")]
            internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
                                                                   IntPtr pPaddingInfo, 
                                                                   [MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
                                                                   int cbHashValue, 
                                                                   [MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature, 
                                                                   int cbSignature,
                                                                   int dwFlags); 
        }

        //
        // Utility and wrapper functions 
        //
 
        private static bool? s_ncryptSupported; 

        ///  
        ///     Determine if NCrypt is supported on the current machine
        /// 
        internal static bool NCryptSupported {
            //  
            // 
            //  
            //  
            // 
            [System.Security.SecurityCritical] 
            [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
            get {
                if (!s_ncryptSupported.HasValue) {
                    // Attempt to load ncrypt.dll to see if the NCrypt CNG APIs are available on the machine 
                    using (SafeLibraryHandle ncrypt = Microsoft.Win32.UnsafeNativeMethods.LoadLibraryEx("ncrypt", IntPtr.Zero, 0)) {
                        s_ncryptSupported = !ncrypt.IsInvalid; 
                    } 
                }
 
                return s_ncryptSupported.Value;
            }
        }
 
        /// 
        ///     Build an ECC public key blob to represent the given parameters 
        ///  
        internal static byte[] BuildEccPublicBlob(string algorithm, BigInteger x, BigInteger y) {
            Contract.Requires(!String.IsNullOrEmpty(algorithm)); 
            Contract.Ensures(Contract.Result() != null);

            //
            // #ECCPublicBlobFormat 
            // The ECC public key blob format is as follows:
            // 
            // DWORD dwMagic 
            // DWORD cbKey
            // X parameter (cbKey bytes long, byte-reversed) 
            // Y parameter (cbKey bytes long, byte-reversed)
            //

            // First map the algorithm name to its magic number and key size 
            BCryptNative.KeyBlobMagicNumber algorithmMagic;
            int keySize; 
            BCryptNative.MapAlgorithmIdToMagic(algorithm, out algorithmMagic, out keySize); 

            // Next generate the public key parameters 
            byte[] xBytes = ReverseBytes(FillKeyParameter(x.ToByteArray(), keySize));
            byte[] yBytes = ReverseBytes(FillKeyParameter(y.ToByteArray(), keySize));

            // Finally, lay out the structure itself 
            byte[] blob = new byte[2 * sizeof(int) + xBytes.Length + yBytes.Length];
            Buffer.BlockCopy(BitConverter.GetBytes((int)algorithmMagic), 0, blob, 0, sizeof(int)); 
            Buffer.BlockCopy(BitConverter.GetBytes(xBytes.Length), 0, blob, sizeof(int), sizeof(int)); 
            Buffer.BlockCopy(xBytes, 0, blob, 2 * sizeof(int), xBytes.Length);
            Buffer.BlockCopy(yBytes, 0, blob, 2 * sizeof(int) + xBytes.Length, yBytes.Length); 

            return blob;
        }
 
        /// 
        ///     Create a random CNG key 
        ///  
        // 
        //  
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        internal static SafeNCryptKeyHandle CreatePersistedKey(SafeNCryptProviderHandle provider,
                                                               string algorithm, 
                                                               string name, 
                                                               CngKeyCreationOptions options) {
            Contract.Requires(provider != null && !provider.IsInvalid && !provider.IsClosed); 
            Contract.Requires(!String.IsNullOrEmpty(algorithm));
            Contract.Ensures(Contract.Result() != null &&
                             !Contract.Result().IsInvalid &&
                             !Contract.Result().IsClosed); 

            SafeNCryptKeyHandle keyHandle = null; 
            ErrorCode error = UnsafeNativeMethods.NCryptCreatePersistedKey(provider, 
                                                                           out keyHandle,
                                                                           algorithm, 
                                                                           name,
                                                                           0,
                                                                           options);
            if (error != ErrorCode.Success) { 
                throw new CryptographicException((int)error);
            } 
 
            return keyHandle;
        } 

        /// 
        ///     Delete a key
        ///  
        // 
        //  
        //  
        // 
        [System.Security.SecurityCritical] 
        internal static void DeleteKey(SafeNCryptKeyHandle key) {
            Contract.Requires(key != null);

            ErrorCode error = UnsafeNativeMethods.NCryptDeleteKey(key, 0); 
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error); 
            } 

            // Key handles are no longer valid after deleting 
            key.Dispose();
        }

        ///  
        ///     Derive key material from a hash or HMAC KDF
        ///  
        ///  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        [System.Security.SecurityCritical]
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] 
        private static byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement,
                                                string kdf,
                                                string hashAlgorithm,
                                                byte[] hmacKey, 
                                                byte[] secretPrepend,
                                                byte[] secretAppend, 
                                                SecretAgreementFlags flags) { 
            Contract.Requires(secretAgreement != null);
            Contract.Requires(!String.IsNullOrEmpty(kdf)); 
            Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm));
            Contract.Requires(hmacKey == null || kdf == BCryptNative.KeyDerivationFunction.Hmac);
            Contract.Ensures(Contract.Result() != null);
 
            List parameters = new List();
 
            // First marshal the hash algoritm 
            IntPtr hashAlgorithmString = IntPtr.Zero;
 
            // Run in a CER so that we know we'll free the memory for the marshaled string
            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                // Assign in a CER so we don't fail between allocating the memory and assigning the result 
                // back to the string variable.
                RuntimeHelpers.PrepareConstrainedRegions(); 
                try { } 
                finally {
                    hashAlgorithmString = Marshal.StringToCoTaskMemUni(hashAlgorithm); 
                }

                // We always need to marshal the hashing function
                NCryptBuffer hashAlgorithmBuffer = new NCryptBuffer(); 
                hashAlgorithmBuffer.cbBuffer = (hashAlgorithm.Length + 1) * sizeof(char);
                hashAlgorithmBuffer.BufferType = BufferType.KdfHashAlgorithm; 
                hashAlgorithmBuffer.pvBuffer = hashAlgorithmString; 
                parameters.Add(hashAlgorithmBuffer);
 
                unsafe {
                    fixed (byte* pHmacKey = hmacKey, pSecretPrepend = secretPrepend, pSecretAppend = secretAppend) {
                        //
                        // Now marshal the other parameters 
                        //
 
                        if (pHmacKey != null) { 
                            NCryptBuffer hmacKeyBuffer = new NCryptBuffer();
                            hmacKeyBuffer.cbBuffer = hmacKey.Length; 
                            hmacKeyBuffer.BufferType = BufferType.KdfHmacKey;
                            hmacKeyBuffer.pvBuffer = new IntPtr(pHmacKey);
                            parameters.Add(hmacKeyBuffer);
                        } 

                        if (pSecretPrepend != null) { 
                            NCryptBuffer secretPrependBuffer = new NCryptBuffer(); 
                            secretPrependBuffer.cbBuffer = secretPrepend.Length;
                            secretPrependBuffer.BufferType = BufferType.KdfSecretPrepend; 
                            secretPrependBuffer.pvBuffer = new IntPtr(pSecretPrepend);
                            parameters.Add(secretPrependBuffer);
                        }
 
                        if (pSecretAppend != null) {
                            NCryptBuffer secretAppendBuffer = new NCryptBuffer(); 
                            secretAppendBuffer.cbBuffer = secretAppend.Length; 
                            secretAppendBuffer.BufferType = BufferType.KdfSecretAppend;
                            secretAppendBuffer.pvBuffer = new IntPtr(pSecretAppend); 
                            parameters.Add(secretAppendBuffer);
                        }

                        return DeriveKeyMaterial(secretAgreement, 
                                                 kdf,
                                                 parameters.ToArray(), 
                                                 flags); 
                    }
                } 
            }
            finally {
                if (hashAlgorithmString != IntPtr.Zero) {
                    Marshal.FreeCoTaskMem(hashAlgorithmString); 
                }
            } 
        } 

        ///  
        ///     Derive key material using a given KDF and secret agreement
        /// 
        // 
        //  
        // 
        //  
        [System.Security.SecurityCritical] 
        private static byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement,
                                                string kdf, 
                                                NCryptBuffer[] parameters,
                                                SecretAgreementFlags flags) {
            Contract.Requires(secretAgreement != null);
            Contract.Requires(!String.IsNullOrEmpty(kdf)); 
            Contract.Requires(parameters != null);
            Contract.Ensures(Contract.Result() != null); 
 
            unsafe {
                fixed (NCryptBuffer* pParameters = parameters) { 
                    NCryptBufferDesc parameterDesc = new NCryptBufferDesc();
                    parameterDesc.ulVersion = 0;
                    parameterDesc.cBuffers = parameters.Length;
                    parameterDesc.pBuffers = new IntPtr(pParameters); 

                    // Figure out how big the key material is 
                    int keySize = 0; 
                    ErrorCode error = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement,
                                                                          kdf, 
                                                                          ref parameterDesc,
                                                                          null,
                                                                          0,
                                                                          out keySize, 
                                                                          flags);
                    if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) { 
                        throw new CryptographicException((int)error); 
                    }
 
                    // Allocate memory for the key material and generate it
                    byte[] keyMaterial = new byte[keySize];
                    error = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement,
                                                                kdf, 
                                                                ref parameterDesc,
                                                                keyMaterial, 
                                                                keyMaterial.Length, 
                                                                out keySize,
                                                                flags); 

                    if (error != ErrorCode.Success) {
                        throw new CryptographicException((int)error);
                    } 

                    return keyMaterial; 
                } 
            }
        } 

        /// 
        ///     Derive key material from a secret agreement using a hash KDF
        ///  
        // 
        //  
        //  
        [System.Security.SecurityCritical]
        internal static byte[] DeriveKeyMaterialHash(SafeNCryptSecretHandle secretAgreement, 
                                                     string hashAlgorithm,
                                                     byte[] secretPrepend,
                                                     byte[] secretAppend,
                                                     SecretAgreementFlags flags) { 
            Contract.Requires(secretAgreement != null);
            Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm)); 
            Contract.Ensures(Contract.Result() != null); 

            return DeriveKeyMaterial(secretAgreement, 
                                     BCryptNative.KeyDerivationFunction.Hash,
                                     hashAlgorithm,
                                     null,
                                     secretPrepend, 
                                     secretAppend,
                                     flags); 
        } 

        ///  
        ///     Derive key material from a secret agreement using a HMAC KDF
        /// 
        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        internal static byte[] DeriveKeyMaterialHmac(SafeNCryptSecretHandle secretAgreement, 
                                                     string hashAlgorithm,
                                                     byte[] hmacKey, 
                                                     byte[] secretPrepend,
                                                     byte[] secretAppend,
                                                     SecretAgreementFlags flags) {
            Contract.Requires(secretAgreement != null); 
            Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm));
            Contract.Ensures(Contract.Result() != null); 
 
            return DeriveKeyMaterial(secretAgreement,
                                     BCryptNative.KeyDerivationFunction.Hmac, 
                                     hashAlgorithm,
                                     hmacKey,
                                     secretPrepend,
                                     secretAppend, 
                                     flags);
        } 
 
        /// 
        ///     Derive key material from a secret agreeement using the TLS KDF 
        /// 
        // 
        // 
        //  
        // 
        //  
        [System.Security.SecurityCritical] 
        internal static byte[] DeriveKeyMaterialTls(SafeNCryptSecretHandle secretAgreement,
                                                    byte[] label, 
                                                    byte[] seed,
                                                    SecretAgreementFlags flags) {
            Contract.Requires(secretAgreement != null);
            Contract.Requires(label != null && seed != null); 
            Contract.Ensures(Contract.Result() != null);
 
            NCryptBuffer[] buffers = new NCryptBuffer[2]; 

            unsafe { 
                fixed (byte* pLabel = label, pSeed = seed) {
                    NCryptBuffer labelBuffer = new NCryptBuffer();
                    labelBuffer.cbBuffer = label.Length;
                    labelBuffer.BufferType = BufferType.KdfTlsLabel; 
                    labelBuffer.pvBuffer = new IntPtr(pLabel);
                    buffers[0] = labelBuffer; 
 
                    NCryptBuffer seedBuffer = new NCryptBuffer();
                    seedBuffer.cbBuffer = seed.Length; 
                    seedBuffer.BufferType = BufferType.KdfTlsSeed;
                    seedBuffer.pvBuffer = new IntPtr(pSeed);
                    buffers[1] = seedBuffer;
 
                    return DeriveKeyMaterial(secretAgreement,
                                             BCryptNative.KeyDerivationFunction.Tls, 
                                             buffers, 
                                             flags);
                } 
            }
        }

        ///  
        ///     Generate a secret agreement value for between two parties
        ///  
        //  
        // 
        //  
        // 
        // 
        [System.Security.SecurityCritical]
        internal static SafeNCryptSecretHandle DeriveSecretAgreement(SafeNCryptKeyHandle privateKey, 
                                                                     SafeNCryptKeyHandle otherPartyPublicKey) {
            Contract.Requires(privateKey != null); 
            Contract.Requires(otherPartyPublicKey != null); 
            Contract.Ensures(Contract.Result() != null &&
                             !Contract.Result().IsClosed && 
                             !Contract.Result().IsInvalid);

            SafeNCryptSecretHandle secretAgreement;
            ErrorCode error = UnsafeNativeMethods.NCryptSecretAgreement(privateKey, 
                                                                        otherPartyPublicKey,
                                                                        out secretAgreement, 
                                                                        0); 

            if (error != ErrorCode.Success) { 
                throw new CryptographicException((int)error);
            }

            return secretAgreement; 
        }
 
        ///  
        ///     Export a key from the KSP
        ///  
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        internal static byte[] ExportKey(SafeNCryptKeyHandle key, string format) {
            Contract.Requires(key != null); 
            Contract.Requires(!String.IsNullOrEmpty(format)); 
            Contract.Ensures(Contract.Result() != null);
 
            // Figure out how big of a buffer we need to export into
            int bufferSize = 0;
            ErrorCode error = UnsafeNativeMethods.NCryptExportKey(key,
                                                                  IntPtr.Zero, 
                                                                  format,
                                                                  IntPtr.Zero, 
                                                                  null, 
                                                                  0,
                                                                  out bufferSize, 
                                                                  0);

            if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
                throw new CryptographicException((int)error); 
            }
 
            // Export the key 
            Debug.Assert(bufferSize > 0, "bufferSize > 0");
            byte[] keyBlob = new byte[bufferSize]; 
            error = UnsafeNativeMethods.NCryptExportKey(key,
                                                        IntPtr.Zero,
                                                        format,
                                                        IntPtr.Zero, 
                                                        keyBlob,
                                                        keyBlob.Length, 
                                                        out bufferSize, 
                                                        0);
 
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error);
            }
 
            return keyBlob;
        } 
 
        /// 
        ///     Make sure that a key is padded out to be its full size 
        /// 
        private static byte[] FillKeyParameter(byte[] key, int keySize) {
            Contract.Requires(key != null);
            Contract.Requires(keySize > 0); 
            Contract.Ensures(Contract.Result() != null && Contract.Result().Length >= keySize / 8);
 
            int bytesRequired = (keySize / 8) + (keySize % 8 == 0 ? 0 : 1); 
            if (key.Length == bytesRequired) {
                return key; 
            }

#if DEBUG
            // If the key is longer than required, it should have been padded out with zeros 
            if (key.Length > bytesRequired) {
                for (int i = bytesRequired; i < key.Length; i++) { 
                    Debug.Assert(key[i] == 0, "key[i] == 0"); 
                }
            } 
#endif
            byte[] fullKey = new byte[bytesRequired];
            Buffer.BlockCopy(key, 0, fullKey, 0, Math.Min(key.Length, fullKey.Length));
            return fullKey; 
        }
 
        ///  
        ///     Finalize a key and prepare it for use
        ///  
        // 
        // 
        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        internal static void FinalizeKey(SafeNCryptKeyHandle key) { 
            Contract.Requires(key != null && !key.IsInvalid && !key.IsClosed);
 
            ErrorCode error = UnsafeNativeMethods.NCryptFinalizeKey(key, 0);
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error);
            } 
        }
 
        ///  
        ///     Get the value of an NCrypt property
        ///  
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        internal static byte[] GetProperty(SafeNCryptHandle ncryptObject,
                                           string propertyName, 
                                           CngPropertyOptions propertyOptions, 
                                           out bool foundProperty) {
            Contract.Requires(ncryptObject != null); 
            Contract.Requires(propertyName != null);

            // Find out how big of a buffer we need to store the property in
            int bufferSize = 0; 
            ErrorCode error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
                                                                    propertyName, 
                                                                    null, 
                                                                    0,
                                                                    out bufferSize, 
                                                                    propertyOptions);

            //
            // NTE_NOT_FOUND means this property does not exist, any other error besides NTE_BUFFER_TOO_SMALL 
            // indicates a real problem.
            // 
 
            if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall && error != ErrorCode.NotFound) {
                    throw new CryptographicException((int)error); 
            }

            foundProperty = error != ErrorCode.NotFound;
 
            // Pull back the property value
            byte[] value = null; 
            if (error != ErrorCode.NotFound && bufferSize > 0) { 
                value = new byte[bufferSize];
                error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject, 
                                                              propertyName,
                                                              value,
                                                              value.Length,
                                                              out bufferSize, 
                                                              propertyOptions);
                if (error != ErrorCode.Success) { 
                    throw new CryptographicException((int)error); 
                }
 
                foundProperty = true;
            }

            return value; 
        }
 
        ///  
        ///     Get the value of a DWORD NCrypt property
        ///  
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        internal static int GetPropertyAsDWord(SafeNCryptHandle ncryptObject,
                                               string propertyName, 
                                               CngPropertyOptions propertyOptions) { 
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null); 

            bool foundProperty;
            byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
 
            if (!foundProperty || valueBytes == null) {
                return 0; 
            } 
            else {
                return BitConverter.ToInt32(valueBytes, 0); 
            }
        }

        ///  
        ///     Get the value of a pointer NCrypt property
        ///  
        //  
        // 
        //  
        [System.Security.SecurityCritical]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        internal static IntPtr GetPropertyAsIntPtr(SafeNCryptHandle ncryptObject,
                                                   string propertyName, 
                                                   CngPropertyOptions propertyOptions) {
            Contract.Requires(ncryptObject != null); 
            Contract.Requires(propertyName != null); 

            // Find out how big of a buffer we need to store the property in 
            int bufferSize = IntPtr.Size;
            IntPtr value = IntPtr.Zero;
            ErrorCode error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
                                                                    propertyName, 
                                                                    out value,
                                                                    IntPtr.Size, 
                                                                    out bufferSize, 
                                                                    propertyOptions);
 
            // NTE_NOT_FOUND means this property was not set, so return a NULL pointer
            if (error == ErrorCode.NotFound) {
                return IntPtr.Zero;
            } 

            if (error != ErrorCode.Success) { 
                throw new CryptographicException((int)error); 
            }
 
            return value;
        }

        ///  
        ///     Get the value of a string NCrypt property
        ///  
        //  
        // 
        //  
        // 
        // 
        [System.Security.SecurityCritical]
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] 
        internal static string GetPropertyAsString(SafeNCryptHandle ncryptObject,
                                                   string propertyName, 
                                                   CngPropertyOptions propertyOptions) { 
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null); 

            bool foundProperty;
            byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
 
            if (!foundProperty || valueBytes == null) {
                return null; 
            } 
            else if (valueBytes.Length == 0) {
                return String.Empty; 
            }
            else {
                unsafe {
                    fixed (byte* pValueBytes = valueBytes) { 
                        return Marshal.PtrToStringUni(new IntPtr(pValueBytes));
                    } 
                } 
            }
        } 

        /// 
        ///     Get the value of an NCrypt structure property -- this will return an empty structure if the
        ///     property does not exist. 
        /// 
        //  
        //  
        // 
        //  
        // 
        [System.Security.SecurityCritical]
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
        internal static T GetPropertyAsStruct(SafeNCryptHandle ncryptObject, 
                                                 string propertyName,
                                                 CngPropertyOptions propertyOptions) where T : struct { 
            Contract.Requires(ncryptObject != null); 
            Contract.Requires(propertyName != null);
 
            bool foundProperty;
            byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);

            if (!foundProperty || valueBytes == null) { 
                return new T();
            } 
 
            unsafe {
                fixed (byte *pValue = valueBytes) { 
                    return (T)Marshal.PtrToStructure(new IntPtr(pValue), typeof(T));
                }
            }
        } 

        ///  
        ///     Import a key into the KSP 
        /// 
        //  
        // 
        // 
        // 
        //  
        [System.Security.SecurityCritical]
        internal static SafeNCryptKeyHandle ImportKey(SafeNCryptProviderHandle provider, 
                                                      byte[] keyBlob, 
                                                      string format) {
            Contract.Requires(provider != null); 
            Contract.Requires(keyBlob != null);
            Contract.Requires(!String.IsNullOrEmpty(format));
            Contract.Ensures(Contract.Result() != null &&
                             !Contract.Result().IsInvalid && 
                             !Contract.Result().IsClosed);
 
            SafeNCryptKeyHandle keyHandle = null; 
            ErrorCode error = UnsafeNativeMethods.NCryptImportKey(provider,
                                                                  IntPtr.Zero, 
                                                                  format,
                                                                  IntPtr.Zero,
                                                                  out keyHandle,
                                                                  keyBlob, 
                                                                  keyBlob.Length,
                                                                  0); 
 
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error); 
            }

            return keyHandle;
        } 

        ///  
        ///     Open an existing key 
        /// 
        //  
        // 
        // 
        // 
        //  
        [System.Security.SecurityCritical]
        internal static SafeNCryptKeyHandle OpenKey(SafeNCryptProviderHandle provider, 
                                                    string name, 
                                                    CngKeyOpenOptions options) {
            Contract.Requires(provider != null && !provider.IsInvalid && !provider.IsClosed); 
            Contract.Requires(name != null);

            SafeNCryptKeyHandle key = null;
            ErrorCode error = UnsafeNativeMethods.NCryptOpenKey(provider, out key, name, 0, options); 

            if (error != ErrorCode.Success) { 
                throw new CryptographicException((int)error); 
            }
 
            return key;
        }

        ///  
        ///     Open the specified key storage provider
        ///  
        //  
        // 
        //  
        // 
        // 
        [System.Security.SecurityCritical]
        internal static SafeNCryptProviderHandle OpenStorageProvider(string providerName) { 
            Contract.Requires(!String.IsNullOrEmpty(providerName));
            Contract.Ensures(Contract.Result() != null && 
                             !Contract.Result().IsInvalid && 
                             !Contract.Result().IsClosed);
 
            SafeNCryptProviderHandle providerHandle = null;
            ErrorCode error = UnsafeNativeMethods.NCryptOpenStorageProvider(out providerHandle,
                                                                            providerName,
                                                                            0); 

            if (error != ErrorCode.Success) { 
                throw new CryptographicException((int)error); 
            }
 
            return providerHandle;
        }

        ///  
        ///     Reverse the bytes in a buffer
        ///  
        private static byte[] ReverseBytes(byte[] buffer) { 
            Contract.Requires(buffer != null);
            Contract.Ensures(Contract.Result() != null && Contract.Result().Length == buffer.Length); 
            return ReverseBytes(buffer, 0, buffer.Length, false);
        }

        ///  
        ///     Reverse a section of bytes within a buffer
        ///  
        private static byte[] ReverseBytes(byte[] buffer, int offset, int count) { 
            return ReverseBytes(buffer, offset, count, false);
        } 

        private static byte[] ReverseBytes(byte[] buffer, int offset, int count, bool padWithZeroByte) {
            Contract.Requires(buffer != null);
            Contract.Requires(offset >= 0 && offset < buffer.Length); 
            Contract.Requires(count >= 0 && buffer.Length - count >= offset);
            Contract.Ensures(Contract.Result() != null); 
            Contract.Ensures(Contract.Result().Length == (padWithZeroByte ? count + 1 : count)); 
            Contract.Ensures(padWithZeroByte ? Contract.Result()[count] == 0 : true);
 
            byte[] reversed;
            if(padWithZeroByte)
            {
                reversed = new byte[count+1]; // the last (most-significant) byte will be left as 0x00 
            }
            else 
            { 
                reversed = new byte[count];
            } 

            int lastByte = offset + count - 1;
            for (int i = 0; i < count; i++) {
                reversed[i] = buffer[lastByte - i]; 
            }
 
            return reversed; 
        }
 
        /// 
        ///     Set a DWORD property on an NCrypt object
        /// 
        //  
        // 
        //  
        [System.Security.SecurityCritical] 
        internal static void SetProperty(SafeNCryptHandle ncryptObject,
                                         string propertyName, 
                                         int value,
                                         CngPropertyOptions propertyOptions) {
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null); 

            SetProperty(ncryptObject, propertyName, BitConverter.GetBytes(value), propertyOptions); 
        } 

        ///  
        ///     Set a string property
        /// 
        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        internal static void SetProperty(SafeNCryptHandle ncryptObject, 
                                         string propertyName,
                                         string value, 
                                         CngPropertyOptions propertyOptions) {
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null);
 
            ErrorCode error = UnsafeNativeMethods.NCryptSetProperty(ncryptObject,
                                                                    propertyName, 
                                                                    value, 
                                                                    (value.Length + 1) * sizeof(char),
                                                                    propertyOptions); 

            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error);
            } 
        }
 
        ///  
        ///     Set a structure property
        ///  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        [System.Security.SecurityCritical] 
        internal static void SetProperty(SafeNCryptHandle ncryptObject,
                                            string propertyName,
                                            T value,
                                            CngPropertyOptions propertyOptions) where T : struct { 
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null); 
 
            byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
 
            unsafe {
                fixed (byte *pBuffer = buffer) {

                    bool marshaledStructure = false; 
                    RuntimeHelpers.PrepareConstrainedRegions();
                    try { 
                        // If we successfully marshal into the buffer, make sure to destroy the buffer when we're done 
                        RuntimeHelpers.PrepareConstrainedRegions();
                        try { } 
                        finally {
                            Marshal.StructureToPtr(value, new IntPtr(pBuffer), false);
                            marshaledStructure = true;
                        } 

                        SetProperty(ncryptObject, propertyName, buffer, propertyOptions); 
                    } 
                    finally {
                        if (marshaledStructure) { 
                            Marshal.DestroyStructure(new IntPtr(pBuffer), typeof(T));
                        }
                    }
                } 
            }
        } 
 
        /// 
        ///     Set a property on an NCrypt object 
        /// 
        // 
        // 
        //  
        [System.Security.SecurityCritical]
        internal static void SetProperty(SafeNCryptHandle ncryptObject, 
                                         string propertyName, 
                                         byte[] value,
                                         CngPropertyOptions propertyOptions) { 
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null);

            ErrorCode error = UnsafeNativeMethods.NCryptSetProperty(ncryptObject, 
                                                                    propertyName,
                                                                    value, 
                                                                    value != null ? value.Length : 0, 
                                                                    propertyOptions);
 
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error);
            }
        } 

        ///  
        ///     Sign a hash using no padding 
        /// 
        //  
        // 
        // 
        [System.Security.SecurityCritical]
        internal static byte[] SignHash(SafeNCryptKeyHandle key, byte[] hash) { 
            Contract.Requires(key != null);
            Contract.Requires(hash != null); 
            Contract.Ensures(Contract.Result() != null); 

            // Figure out how big the signature is 
            int signatureSize = 0;
            ErrorCode error = UnsafeNativeMethods.NCryptSignHash(key,
                                                                 IntPtr.Zero,
                                                                 hash, 
                                                                 hash.Length,
                                                                 null, 
                                                                 0, 
                                                                 out signatureSize,
                                                                 0); 

            if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
                throw new CryptographicException((int)error);
            } 

            // Sign the data 
            Debug.Assert(signatureSize > 0, "signatureSize > 0"); 
            byte[] signature = new byte[signatureSize];
 
            error = UnsafeNativeMethods.NCryptSignHash(key,
                                                       IntPtr.Zero,
                                                       hash,
                                                       hash.Length, 
                                                       signature,
                                                       signature.Length, 
                                                       out signatureSize, 
                                                       0);
 
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error);
            }
 
            return signature;
        } 
 
        /// 
        ///     Unpack a key blob in ECC public blob format into its X and Y parameters 
        ///
        ///     This method expects that the blob be in the correct format -- blobs accepted from partially
        ///     trusted code need to be validated before being unpacked.
        ///  
        internal static void UnpackEccPublicBlob(byte[] blob, out BigInteger x, out BigInteger y) {
            Contract.Requires(blob != null && blob.Length > 2 * sizeof(int)); 
 
            //
            // See code:System.Security.Cryptography.NCryptNative#ECCPublicBlobFormat  for details about the 
            // format of the ECC public key blob.
            //

            // read the size of each parameter 
            int parameterSize = BitConverter.ToInt32(blob, sizeof(int));
            Debug.Assert(parameterSize > 0, "parameterSize > 0"); 
            Debug.Assert(blob.Length >= 2 * sizeof(int) + 2 * parameterSize, "blob.Length >= 2 * sizeof(int) + 2 * parameterSize"); 

            // read out the X and Y parameters, in memory reversed form 
            // add 0x00 padding to force BigInteger to interpret these as positive numbers
            x = new BigInteger(ReverseBytes(blob, 2 * sizeof(int), parameterSize, true));
            y = new BigInteger(ReverseBytes(blob, 2 * sizeof(int) + parameterSize, parameterSize, true));
        } 

        ///  
        ///     Verify a signature created with no padding 
        /// 
        //  
        // 
        // 
        [System.Security.SecurityCritical]
        internal static bool VerifySignature(SafeNCryptKeyHandle key, byte[] hash, byte[] signature) { 
            Contract.Requires(key != null);
            Contract.Requires(hash != null); 
            Contract.Requires(signature != null); 

            ErrorCode error = UnsafeNativeMethods.NCryptVerifySignature(key, 
                                                                        IntPtr.Zero,
                                                                        hash,
                                                                        hash.Length,
                                                                        signature, 
                                                                        signature.Length,
                                                                        0); 
 
            if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
                throw new CryptographicException((int)error); 
            }

            return error == ErrorCode.Success;
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

using System; 
using System.Collections.Generic; 
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; 
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices; 
using System.Security.Permissions;
using System.Text; 
using System.Diagnostics.Contracts; 
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles; 

namespace System.Security.Cryptography {

    // 
    // Public facing enumerations
    // 
 
    /// 
    ///     Flags to control how often and in which format a key is allowed to be exported 
    /// 
    [Flags]
    public enum CngExportPolicies {
        None = 0x00000000, 
        AllowExport = 0x00000001,                       // NCRYPT_ALLOW_EXPORT_FLAG
        AllowPlaintextExport = 0x00000002,              // NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG 
        AllowArchiving = 0x00000004,                    // NCRYPT_ALLOW_ARCHIVING_FLAG 
        AllowPlaintextArchiving = 0x00000008            // NCRYPT_ALLOW_PLAINTEXT_ARCHIVING_FLAG
    } 

    /// 
    ///     Flags controlling how the key is created
    ///  
    [Flags]
    public enum CngKeyCreationOptions { 
        None = 0x00000000, 
        MachineKey = 0x00000020,                        // NCRYPT_MACHINE_KEY_FLAG
        OverwriteExistingKey = 0x00000080               // NCRYPT_OVERWRITE_KEY_FLAG 
    }

    /// 
    ///     Flags controlling how a key is opened 
    /// 
    [Flags] 
    [SuppressMessage("Microsoft.Design", "CA1008:EnumsShouldHaveZeroValue", Justification = "Approved API exception to have an easy way to express user keys")] 
    public enum CngKeyOpenOptions {
        None = 0x00000000, 
        UserKey = 0x00000000,
        MachineKey = 0x00000020,                        // NCRYPT_MACHINE_KEY_FLAG
        Silent = 0x00000040                             // NCRYPT_SILENT_FLAG
    } 

    ///  
    ///     Flags indicating the type of key 
    /// 
    [Flags] 
    internal enum CngKeyTypes {
        None = 0x00000000,
        MachineKey = 0x00000020                         // NCRYPT_MACHINE_KEY_FLAG
    } 

    ///  
    ///     Bits defining what operations are valid to use a key with 
    /// 
    [Flags] 
    [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Justification = "Flags are defined by the native ncrypt API")]
    public enum CngKeyUsages {
        None = 0x00000000,
        Decryption = 0x00000001,                        // NCRYPT_ALLOW_DECRYPT_FLAG 
        Signing = 0x00000002,                           // NCRYPT_ALLOW_SIGNING_FLAG
        KeyAgreement = 0x00000004,                      // NCRYPT_ALLOW_KEY_AGREEMENT_FLAG 
        AllUsages = 0x00ffffff                          // NCRYPT_ALLOW_ALL_USAGES 
    }
 
    /// 
    ///     Options affecting how a property is interpreted by CNG
    /// 
    [Flags] 
    [SuppressMessage("Microsoft.Usage", "CA2217:DoNotMarkEnumsWithFlags", Justification = "Flags are defined by the native ncrypt API")]
    public enum CngPropertyOptions { 
        None = 0x00000000, 
        CustomProperty = 0x40000000,                    // NCRYPT_PERSIST_ONLY_FLAG
        Persist = unchecked((int)0x80000000)            // NCRYPT_PERSIST_FLAG 
    }

    /// 
    ///     Levels of UI protection available for a key 
    /// 
    [Flags] 
    public enum CngUIProtectionLevels { 
        None = 0x00000000,
        ProtectKey = 0x00000001,                        // NCRYPT_UI_PROTECT_KEY_FLAG 
        ForceHighProtection = 0x00000002                // NCRYPT_UI_FORCE_HIGH_PROTECTION_FLAG
    }

    ///  
    ///     Native interop with CNG's NCrypt layer. Native definitions are in ncrypt.h
    ///  
    internal static class NCryptNative { 
        //
        // Enumerations 
        //

        /// 
        ///     Types of NCryptBuffers 
        /// 
        internal enum BufferType { 
            KdfHashAlgorithm = 0x00000000,              // KDF_HASH_ALGORITHM 
            KdfSecretPrepend = 0x00000001,              // KDF_SECRET_PREPEND
            KdfSecretAppend = 0x00000002,               // KDF_SECRET_APPEND 
            KdfHmacKey = 0x00000003,                    // KDF_HMAC_KEY
            KdfTlsLabel = 0x00000004,                   // KDF_TLS_PRF_LABEL
            KdfTlsSeed = 0x00000005                     // KDF_TLS_PRF_SEED
        } 

        ///  
        ///     Result codes from NCrypt APIs 
        /// 
        internal enum ErrorCode { 
            Success = 0,                                            // ERROR_SUCCESS
            BadSignature = unchecked((int)0x80090006),              // NTE_BAD_SIGNATURE
            NotFound = unchecked((int)0x80090011),                  // NTE_NOT_FOUND
            KeyDoesNotExist = unchecked((int)0x80090016),           // NTE_BAD_KEYSET 
            BufferTooSmall = unchecked((int)0x80090028)             // NTE_BUFFER_TOO_SMALL
        } 
 
        /// 
        ///     Well known names of key properties 
        /// 
        internal static class KeyPropertyName {
            internal const string Algorithm = "Algorithm Name";                 // NCRYPT_ALGORITHM_PROPERTY
            internal const string AlgorithmGroup = "Algorithm Group";           // NCRYPT_ALGORITHM_GROUP_PROPERTY 
            internal const string ExportPolicy = "Export Policy";               // NCRYPT_EXPORT_POLICY_PROPERTY
            internal const string KeyType = "Key Type";                         // NCRYPT_KEY_TYPE_PROPERTY 
            internal const string KeyUsage = "Key Usage";                       // NCRYPT_KEY_USAGE_PROPERTY 
            internal const string Length = "Length";                            // NCRYPT_LENGTH_PROPERTY
            internal const string Name = "Name";                                // NCRYPT_NAME_PROPERTY 
            internal const string ParentWindowHandle = "HWND Handle";           // NCRYPT_WINDOW_HANDLE_PROPERTY
            internal const string ProviderHandle = "Provider Handle";           // NCRYPT_PROVIDER_HANDLE_PROPERTY
            internal const string UIPolicy = "UI Policy";                       // NCRYPT_UI_POLICY_PROPERTY
            internal const string UniqueName = "Unique Name";                   // NCRYPT_UNIQUE_NAME_PROPERTY 
            internal const string UseContext = "Use Context";                   // NCRYPT_USE_CONTEXT_PROPERTY
 
            // 
            // Properties defined by the CLR
            // 

            /// 
            ///     Is the key a CLR created ephemeral key, it will contain a single byte with value 1 if the
            ///     key was created by the CLR as an ephemeral key. 
            /// 
            internal const string ClrIsEphemeral = "CLR IsEphemeral"; 
        } 

        ///  
        ///     Well known names of provider properties
        /// 
        internal static class ProviderPropertyName {
            internal const string Name = "Name";        // NCRYPT_NAME_PROPERTY 
        }
 
        ///  
        ///     Flags for code:System.Security.Cryptography.NCryptNative.UnsafeNativeMethods.NCryptSecretAgreement
        ///  
        [Flags]
        internal enum SecretAgreementFlags {
            None = 0x00000000,
            UseSecretAsHmacKey = 0x00000001             // KDF_USE_SECRET_AS_HMAC_KEY_FLAG 
        }
 
        // 
        // Structures
        // 

        [StructLayout(LayoutKind.Sequential)]
        internal struct NCRYPT_UI_POLICY {
            public int dwVersion; 
            public CngUIProtectionLevels dwFlags;
 
            [MarshalAs(UnmanagedType.LPWStr)] 
            public string pszCreationTitle;
 
            [MarshalAs(UnmanagedType.LPWStr)]
            public string pszFriendlyName;

            [MarshalAs(UnmanagedType.LPWStr)] 
            public string pszDescription;
        } 
 
        [StructLayout(LayoutKind.Sequential)]
        internal struct NCryptBuffer { 
            public int cbBuffer;
            public BufferType BufferType;
            public IntPtr pvBuffer;
        } 

        [StructLayout(LayoutKind.Sequential)] 
        internal struct NCryptBufferDesc { 
            public int ulVersion;
            public int cBuffers; 
            public IntPtr pBuffers;         // NCryptBuffer[cBuffers]
        }

        [SuppressUnmanagedCodeSecurity] 
        internal static class UnsafeNativeMethods {
            ///  
            ///     Create an NCrypt key 
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)] 
            internal static extern ErrorCode NCryptCreatePersistedKey(SafeNCryptProviderHandle hProvider,
                                                                      [Out] out SafeNCryptKeyHandle phKey,
                                                                      string pszAlgId,
                                                                      string pszKeyName, 
                                                                      int dwLegacyKeySpec,
                                                                      CngKeyCreationOptions dwFlags); 
 
            /// 
            ///     Delete a key 
            /// 
            [DllImport("ncrypt.dll")]
            internal static extern ErrorCode NCryptDeleteKey(SafeNCryptKeyHandle hKey, int flags);
 
            /// 
            ///     Generate a key from a secret agreement 
            ///  
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal 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); 
 
            /// 
            ///     Export a key from the KSP 
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal static extern ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey,
                                                             IntPtr hExportKey,               // NCRYPT_KEY_HANDLE 
                                                             string pszBlobType,
                                                             IntPtr pParameterList,           // NCryptBufferDesc * 
                                                             [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput, 
                                                             int cbOutput,
                                                             [Out] out int pcbResult, 
                                                             int dwFlags);

            /// 
            ///     Finalize a key to prepare it for use 
            /// 
            [DllImport("ncrypt.dll")] 
            internal static extern ErrorCode NCryptFinalizeKey(SafeNCryptKeyHandle hKey, int dwFlags); 

            ///  
            ///     Get the value of a property of an NCrypt object
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal static extern ErrorCode NCryptGetProperty(SafeNCryptHandle hObject, 
                                                               string pszProperty,
                                                               [Out, MarshalAs(UnmanagedType.LPArray)] byte[] pbOutput, 
                                                               int cbOutput, 
                                                               [Out] out int pcbResult,
                                                               CngPropertyOptions dwFlags); 

            /// 
            ///     Get the value of a pointer property of an NCrypt object
            ///  
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] 
            internal static extern ErrorCode NCryptGetProperty(SafeNCryptHandle hObject, 
                                                               string pszProperty,
                                                               [Out] out IntPtr pbOutput, 
                                                               int cbOutput,
                                                               [Out] out int pcbResult,
                                                               CngPropertyOptions dwFlags);
 
            /// 
            ///     Import a key into the KSP 
            ///  
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal static extern ErrorCode NCryptImportKey(SafeNCryptProviderHandle hProvider, 
                                                             IntPtr hImportKey,     // NCRYPT_KEY_HANDLE
                                                             string pszBlobType,
                                                             IntPtr pParameterList, // NCryptBufferDesc *
                                                             [Out] out SafeNCryptKeyHandle phKey, 
                                                             [MarshalAs(UnmanagedType.LPArray)] byte[] pbData,
                                                             int cbData, 
                                                             int dwFlags); 

            ///  
            ///     Open an existing key
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal static extern ErrorCode NCryptOpenKey(SafeNCryptProviderHandle hProvider, 
                                                           [Out] out SafeNCryptKeyHandle phKey,
                                                           string pszKeyName, 
                                                           int dwLegacyKeySpec, 
                                                           CngKeyOpenOptions dwFlags);
 
            /// 
            ///     Acquire a handle to a key storage provider
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)] 
            internal static extern ErrorCode NCryptOpenStorageProvider([Out] out SafeNCryptProviderHandle phProvider,
                                                                       string pszProviderName, 
                                                                       int dwFlags); 

            ///  
            ///     Generate a secret agreement for generating shared key material
            /// 
            [DllImport("ncrypt.dll")]
            internal static extern ErrorCode NCryptSecretAgreement(SafeNCryptKeyHandle hPrivKey, 
                                                                   SafeNCryptKeyHandle hPubKey,
                                                                   [Out] out SafeNCryptSecretHandle phSecret, 
                                                                   int dwFlags); 

            ///  
            ///     Set a property value on an NCrypt object
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)]
            internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject, 
                                                               string pszProperty,
                                                               [MarshalAs(UnmanagedType.LPArray)] byte[] pbInput, 
                                                               int cbInput, 
                                                               CngPropertyOptions dwFlags);
 
            /// 
            ///     Set a string property value on an NCrypt object
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)] 
            internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject,
                                                               string pszProperty, 
                                                               string pbInput, 
                                                               int cbInput,
                                                               CngPropertyOptions dwFlags); 

            /// 
            ///     Set a property value on an NCrypt object when a pointer to the buffer already exists in
            ///     managed code. To set a pointer valued property, use the ref IntPtr overload. 
            /// 
            [DllImport("ncrypt.dll", CharSet = CharSet.Unicode)] 
            internal static extern ErrorCode NCryptSetProperty(SafeNCryptHandle hObject, 
                                                               string pszProperty,
                                                               IntPtr pbInput, 
                                                               int cbInput,
                                                               CngPropertyOptions dwFlags);

            ///  
            ///     Create a signature for a hash value
            ///  
            [DllImport("ncrypt.dll")] 
            internal static extern ErrorCode NCryptSignHash(SafeNCryptKeyHandle hKey,
                                                            IntPtr pPaddingInfo, 
                                                            [MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
                                                            int cbHashValue,
                                                            [MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature,
                                                            int cbSignature, 
                                                            [Out] out int pcbResult,
                                                            int dwFlags); 
 
            /// 
            ///     Verify a signature over a hash value 
            /// 
            [DllImport("ncrypt.dll")]
            internal static extern ErrorCode NCryptVerifySignature(SafeNCryptKeyHandle hKey,
                                                                   IntPtr pPaddingInfo, 
                                                                   [MarshalAs(UnmanagedType.LPArray)] byte[] pbHashValue,
                                                                   int cbHashValue, 
                                                                   [MarshalAs(UnmanagedType.LPArray)] byte[] pbSignature, 
                                                                   int cbSignature,
                                                                   int dwFlags); 
        }

        //
        // Utility and wrapper functions 
        //
 
        private static bool? s_ncryptSupported; 

        ///  
        ///     Determine if NCrypt is supported on the current machine
        /// 
        internal static bool NCryptSupported {
            //  
            // 
            //  
            //  
            // 
            [System.Security.SecurityCritical] 
            [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
            get {
                if (!s_ncryptSupported.HasValue) {
                    // Attempt to load ncrypt.dll to see if the NCrypt CNG APIs are available on the machine 
                    using (SafeLibraryHandle ncrypt = Microsoft.Win32.UnsafeNativeMethods.LoadLibraryEx("ncrypt", IntPtr.Zero, 0)) {
                        s_ncryptSupported = !ncrypt.IsInvalid; 
                    } 
                }
 
                return s_ncryptSupported.Value;
            }
        }
 
        /// 
        ///     Build an ECC public key blob to represent the given parameters 
        ///  
        internal static byte[] BuildEccPublicBlob(string algorithm, BigInteger x, BigInteger y) {
            Contract.Requires(!String.IsNullOrEmpty(algorithm)); 
            Contract.Ensures(Contract.Result() != null);

            //
            // #ECCPublicBlobFormat 
            // The ECC public key blob format is as follows:
            // 
            // DWORD dwMagic 
            // DWORD cbKey
            // X parameter (cbKey bytes long, byte-reversed) 
            // Y parameter (cbKey bytes long, byte-reversed)
            //

            // First map the algorithm name to its magic number and key size 
            BCryptNative.KeyBlobMagicNumber algorithmMagic;
            int keySize; 
            BCryptNative.MapAlgorithmIdToMagic(algorithm, out algorithmMagic, out keySize); 

            // Next generate the public key parameters 
            byte[] xBytes = ReverseBytes(FillKeyParameter(x.ToByteArray(), keySize));
            byte[] yBytes = ReverseBytes(FillKeyParameter(y.ToByteArray(), keySize));

            // Finally, lay out the structure itself 
            byte[] blob = new byte[2 * sizeof(int) + xBytes.Length + yBytes.Length];
            Buffer.BlockCopy(BitConverter.GetBytes((int)algorithmMagic), 0, blob, 0, sizeof(int)); 
            Buffer.BlockCopy(BitConverter.GetBytes(xBytes.Length), 0, blob, sizeof(int), sizeof(int)); 
            Buffer.BlockCopy(xBytes, 0, blob, 2 * sizeof(int), xBytes.Length);
            Buffer.BlockCopy(yBytes, 0, blob, 2 * sizeof(int) + xBytes.Length, yBytes.Length); 

            return blob;
        }
 
        /// 
        ///     Create a random CNG key 
        ///  
        // 
        //  
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        internal static SafeNCryptKeyHandle CreatePersistedKey(SafeNCryptProviderHandle provider,
                                                               string algorithm, 
                                                               string name, 
                                                               CngKeyCreationOptions options) {
            Contract.Requires(provider != null && !provider.IsInvalid && !provider.IsClosed); 
            Contract.Requires(!String.IsNullOrEmpty(algorithm));
            Contract.Ensures(Contract.Result() != null &&
                             !Contract.Result().IsInvalid &&
                             !Contract.Result().IsClosed); 

            SafeNCryptKeyHandle keyHandle = null; 
            ErrorCode error = UnsafeNativeMethods.NCryptCreatePersistedKey(provider, 
                                                                           out keyHandle,
                                                                           algorithm, 
                                                                           name,
                                                                           0,
                                                                           options);
            if (error != ErrorCode.Success) { 
                throw new CryptographicException((int)error);
            } 
 
            return keyHandle;
        } 

        /// 
        ///     Delete a key
        ///  
        // 
        //  
        //  
        // 
        [System.Security.SecurityCritical] 
        internal static void DeleteKey(SafeNCryptKeyHandle key) {
            Contract.Requires(key != null);

            ErrorCode error = UnsafeNativeMethods.NCryptDeleteKey(key, 0); 
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error); 
            } 

            // Key handles are no longer valid after deleting 
            key.Dispose();
        }

        ///  
        ///     Derive key material from a hash or HMAC KDF
        ///  
        ///  
        // 
        //  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        [System.Security.SecurityCritical]
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] 
        private static byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement,
                                                string kdf,
                                                string hashAlgorithm,
                                                byte[] hmacKey, 
                                                byte[] secretPrepend,
                                                byte[] secretAppend, 
                                                SecretAgreementFlags flags) { 
            Contract.Requires(secretAgreement != null);
            Contract.Requires(!String.IsNullOrEmpty(kdf)); 
            Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm));
            Contract.Requires(hmacKey == null || kdf == BCryptNative.KeyDerivationFunction.Hmac);
            Contract.Ensures(Contract.Result() != null);
 
            List parameters = new List();
 
            // First marshal the hash algoritm 
            IntPtr hashAlgorithmString = IntPtr.Zero;
 
            // Run in a CER so that we know we'll free the memory for the marshaled string
            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                // Assign in a CER so we don't fail between allocating the memory and assigning the result 
                // back to the string variable.
                RuntimeHelpers.PrepareConstrainedRegions(); 
                try { } 
                finally {
                    hashAlgorithmString = Marshal.StringToCoTaskMemUni(hashAlgorithm); 
                }

                // We always need to marshal the hashing function
                NCryptBuffer hashAlgorithmBuffer = new NCryptBuffer(); 
                hashAlgorithmBuffer.cbBuffer = (hashAlgorithm.Length + 1) * sizeof(char);
                hashAlgorithmBuffer.BufferType = BufferType.KdfHashAlgorithm; 
                hashAlgorithmBuffer.pvBuffer = hashAlgorithmString; 
                parameters.Add(hashAlgorithmBuffer);
 
                unsafe {
                    fixed (byte* pHmacKey = hmacKey, pSecretPrepend = secretPrepend, pSecretAppend = secretAppend) {
                        //
                        // Now marshal the other parameters 
                        //
 
                        if (pHmacKey != null) { 
                            NCryptBuffer hmacKeyBuffer = new NCryptBuffer();
                            hmacKeyBuffer.cbBuffer = hmacKey.Length; 
                            hmacKeyBuffer.BufferType = BufferType.KdfHmacKey;
                            hmacKeyBuffer.pvBuffer = new IntPtr(pHmacKey);
                            parameters.Add(hmacKeyBuffer);
                        } 

                        if (pSecretPrepend != null) { 
                            NCryptBuffer secretPrependBuffer = new NCryptBuffer(); 
                            secretPrependBuffer.cbBuffer = secretPrepend.Length;
                            secretPrependBuffer.BufferType = BufferType.KdfSecretPrepend; 
                            secretPrependBuffer.pvBuffer = new IntPtr(pSecretPrepend);
                            parameters.Add(secretPrependBuffer);
                        }
 
                        if (pSecretAppend != null) {
                            NCryptBuffer secretAppendBuffer = new NCryptBuffer(); 
                            secretAppendBuffer.cbBuffer = secretAppend.Length; 
                            secretAppendBuffer.BufferType = BufferType.KdfSecretAppend;
                            secretAppendBuffer.pvBuffer = new IntPtr(pSecretAppend); 
                            parameters.Add(secretAppendBuffer);
                        }

                        return DeriveKeyMaterial(secretAgreement, 
                                                 kdf,
                                                 parameters.ToArray(), 
                                                 flags); 
                    }
                } 
            }
            finally {
                if (hashAlgorithmString != IntPtr.Zero) {
                    Marshal.FreeCoTaskMem(hashAlgorithmString); 
                }
            } 
        } 

        ///  
        ///     Derive key material using a given KDF and secret agreement
        /// 
        // 
        //  
        // 
        //  
        [System.Security.SecurityCritical] 
        private static byte[] DeriveKeyMaterial(SafeNCryptSecretHandle secretAgreement,
                                                string kdf, 
                                                NCryptBuffer[] parameters,
                                                SecretAgreementFlags flags) {
            Contract.Requires(secretAgreement != null);
            Contract.Requires(!String.IsNullOrEmpty(kdf)); 
            Contract.Requires(parameters != null);
            Contract.Ensures(Contract.Result() != null); 
 
            unsafe {
                fixed (NCryptBuffer* pParameters = parameters) { 
                    NCryptBufferDesc parameterDesc = new NCryptBufferDesc();
                    parameterDesc.ulVersion = 0;
                    parameterDesc.cBuffers = parameters.Length;
                    parameterDesc.pBuffers = new IntPtr(pParameters); 

                    // Figure out how big the key material is 
                    int keySize = 0; 
                    ErrorCode error = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement,
                                                                          kdf, 
                                                                          ref parameterDesc,
                                                                          null,
                                                                          0,
                                                                          out keySize, 
                                                                          flags);
                    if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) { 
                        throw new CryptographicException((int)error); 
                    }
 
                    // Allocate memory for the key material and generate it
                    byte[] keyMaterial = new byte[keySize];
                    error = UnsafeNativeMethods.NCryptDeriveKey(secretAgreement,
                                                                kdf, 
                                                                ref parameterDesc,
                                                                keyMaterial, 
                                                                keyMaterial.Length, 
                                                                out keySize,
                                                                flags); 

                    if (error != ErrorCode.Success) {
                        throw new CryptographicException((int)error);
                    } 

                    return keyMaterial; 
                } 
            }
        } 

        /// 
        ///     Derive key material from a secret agreement using a hash KDF
        ///  
        // 
        //  
        //  
        [System.Security.SecurityCritical]
        internal static byte[] DeriveKeyMaterialHash(SafeNCryptSecretHandle secretAgreement, 
                                                     string hashAlgorithm,
                                                     byte[] secretPrepend,
                                                     byte[] secretAppend,
                                                     SecretAgreementFlags flags) { 
            Contract.Requires(secretAgreement != null);
            Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm)); 
            Contract.Ensures(Contract.Result() != null); 

            return DeriveKeyMaterial(secretAgreement, 
                                     BCryptNative.KeyDerivationFunction.Hash,
                                     hashAlgorithm,
                                     null,
                                     secretPrepend, 
                                     secretAppend,
                                     flags); 
        } 

        ///  
        ///     Derive key material from a secret agreement using a HMAC KDF
        /// 
        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        internal static byte[] DeriveKeyMaterialHmac(SafeNCryptSecretHandle secretAgreement, 
                                                     string hashAlgorithm,
                                                     byte[] hmacKey, 
                                                     byte[] secretPrepend,
                                                     byte[] secretAppend,
                                                     SecretAgreementFlags flags) {
            Contract.Requires(secretAgreement != null); 
            Contract.Requires(!String.IsNullOrEmpty(hashAlgorithm));
            Contract.Ensures(Contract.Result() != null); 
 
            return DeriveKeyMaterial(secretAgreement,
                                     BCryptNative.KeyDerivationFunction.Hmac, 
                                     hashAlgorithm,
                                     hmacKey,
                                     secretPrepend,
                                     secretAppend, 
                                     flags);
        } 
 
        /// 
        ///     Derive key material from a secret agreeement using the TLS KDF 
        /// 
        // 
        // 
        //  
        // 
        //  
        [System.Security.SecurityCritical] 
        internal static byte[] DeriveKeyMaterialTls(SafeNCryptSecretHandle secretAgreement,
                                                    byte[] label, 
                                                    byte[] seed,
                                                    SecretAgreementFlags flags) {
            Contract.Requires(secretAgreement != null);
            Contract.Requires(label != null && seed != null); 
            Contract.Ensures(Contract.Result() != null);
 
            NCryptBuffer[] buffers = new NCryptBuffer[2]; 

            unsafe { 
                fixed (byte* pLabel = label, pSeed = seed) {
                    NCryptBuffer labelBuffer = new NCryptBuffer();
                    labelBuffer.cbBuffer = label.Length;
                    labelBuffer.BufferType = BufferType.KdfTlsLabel; 
                    labelBuffer.pvBuffer = new IntPtr(pLabel);
                    buffers[0] = labelBuffer; 
 
                    NCryptBuffer seedBuffer = new NCryptBuffer();
                    seedBuffer.cbBuffer = seed.Length; 
                    seedBuffer.BufferType = BufferType.KdfTlsSeed;
                    seedBuffer.pvBuffer = new IntPtr(pSeed);
                    buffers[1] = seedBuffer;
 
                    return DeriveKeyMaterial(secretAgreement,
                                             BCryptNative.KeyDerivationFunction.Tls, 
                                             buffers, 
                                             flags);
                } 
            }
        }

        ///  
        ///     Generate a secret agreement value for between two parties
        ///  
        //  
        // 
        //  
        // 
        // 
        [System.Security.SecurityCritical]
        internal static SafeNCryptSecretHandle DeriveSecretAgreement(SafeNCryptKeyHandle privateKey, 
                                                                     SafeNCryptKeyHandle otherPartyPublicKey) {
            Contract.Requires(privateKey != null); 
            Contract.Requires(otherPartyPublicKey != null); 
            Contract.Ensures(Contract.Result() != null &&
                             !Contract.Result().IsClosed && 
                             !Contract.Result().IsInvalid);

            SafeNCryptSecretHandle secretAgreement;
            ErrorCode error = UnsafeNativeMethods.NCryptSecretAgreement(privateKey, 
                                                                        otherPartyPublicKey,
                                                                        out secretAgreement, 
                                                                        0); 

            if (error != ErrorCode.Success) { 
                throw new CryptographicException((int)error);
            }

            return secretAgreement; 
        }
 
        ///  
        ///     Export a key from the KSP
        ///  
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        internal static byte[] ExportKey(SafeNCryptKeyHandle key, string format) {
            Contract.Requires(key != null); 
            Contract.Requires(!String.IsNullOrEmpty(format)); 
            Contract.Ensures(Contract.Result() != null);
 
            // Figure out how big of a buffer we need to export into
            int bufferSize = 0;
            ErrorCode error = UnsafeNativeMethods.NCryptExportKey(key,
                                                                  IntPtr.Zero, 
                                                                  format,
                                                                  IntPtr.Zero, 
                                                                  null, 
                                                                  0,
                                                                  out bufferSize, 
                                                                  0);

            if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
                throw new CryptographicException((int)error); 
            }
 
            // Export the key 
            Debug.Assert(bufferSize > 0, "bufferSize > 0");
            byte[] keyBlob = new byte[bufferSize]; 
            error = UnsafeNativeMethods.NCryptExportKey(key,
                                                        IntPtr.Zero,
                                                        format,
                                                        IntPtr.Zero, 
                                                        keyBlob,
                                                        keyBlob.Length, 
                                                        out bufferSize, 
                                                        0);
 
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error);
            }
 
            return keyBlob;
        } 
 
        /// 
        ///     Make sure that a key is padded out to be its full size 
        /// 
        private static byte[] FillKeyParameter(byte[] key, int keySize) {
            Contract.Requires(key != null);
            Contract.Requires(keySize > 0); 
            Contract.Ensures(Contract.Result() != null && Contract.Result().Length >= keySize / 8);
 
            int bytesRequired = (keySize / 8) + (keySize % 8 == 0 ? 0 : 1); 
            if (key.Length == bytesRequired) {
                return key; 
            }

#if DEBUG
            // If the key is longer than required, it should have been padded out with zeros 
            if (key.Length > bytesRequired) {
                for (int i = bytesRequired; i < key.Length; i++) { 
                    Debug.Assert(key[i] == 0, "key[i] == 0"); 
                }
            } 
#endif
            byte[] fullKey = new byte[bytesRequired];
            Buffer.BlockCopy(key, 0, fullKey, 0, Math.Min(key.Length, fullKey.Length));
            return fullKey; 
        }
 
        ///  
        ///     Finalize a key and prepare it for use
        ///  
        // 
        // 
        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        internal static void FinalizeKey(SafeNCryptKeyHandle key) { 
            Contract.Requires(key != null && !key.IsInvalid && !key.IsClosed);
 
            ErrorCode error = UnsafeNativeMethods.NCryptFinalizeKey(key, 0);
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error);
            } 
        }
 
        ///  
        ///     Get the value of an NCrypt property
        ///  
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        internal static byte[] GetProperty(SafeNCryptHandle ncryptObject,
                                           string propertyName, 
                                           CngPropertyOptions propertyOptions, 
                                           out bool foundProperty) {
            Contract.Requires(ncryptObject != null); 
            Contract.Requires(propertyName != null);

            // Find out how big of a buffer we need to store the property in
            int bufferSize = 0; 
            ErrorCode error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
                                                                    propertyName, 
                                                                    null, 
                                                                    0,
                                                                    out bufferSize, 
                                                                    propertyOptions);

            //
            // NTE_NOT_FOUND means this property does not exist, any other error besides NTE_BUFFER_TOO_SMALL 
            // indicates a real problem.
            // 
 
            if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall && error != ErrorCode.NotFound) {
                    throw new CryptographicException((int)error); 
            }

            foundProperty = error != ErrorCode.NotFound;
 
            // Pull back the property value
            byte[] value = null; 
            if (error != ErrorCode.NotFound && bufferSize > 0) { 
                value = new byte[bufferSize];
                error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject, 
                                                              propertyName,
                                                              value,
                                                              value.Length,
                                                              out bufferSize, 
                                                              propertyOptions);
                if (error != ErrorCode.Success) { 
                    throw new CryptographicException((int)error); 
                }
 
                foundProperty = true;
            }

            return value; 
        }
 
        ///  
        ///     Get the value of a DWORD NCrypt property
        ///  
        // 
        // 
        // 
        [System.Security.SecurityCritical] 
        internal static int GetPropertyAsDWord(SafeNCryptHandle ncryptObject,
                                               string propertyName, 
                                               CngPropertyOptions propertyOptions) { 
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null); 

            bool foundProperty;
            byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
 
            if (!foundProperty || valueBytes == null) {
                return 0; 
            } 
            else {
                return BitConverter.ToInt32(valueBytes, 0); 
            }
        }

        ///  
        ///     Get the value of a pointer NCrypt property
        ///  
        //  
        // 
        //  
        [System.Security.SecurityCritical]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        internal static IntPtr GetPropertyAsIntPtr(SafeNCryptHandle ncryptObject,
                                                   string propertyName, 
                                                   CngPropertyOptions propertyOptions) {
            Contract.Requires(ncryptObject != null); 
            Contract.Requires(propertyName != null); 

            // Find out how big of a buffer we need to store the property in 
            int bufferSize = IntPtr.Size;
            IntPtr value = IntPtr.Zero;
            ErrorCode error = UnsafeNativeMethods.NCryptGetProperty(ncryptObject,
                                                                    propertyName, 
                                                                    out value,
                                                                    IntPtr.Size, 
                                                                    out bufferSize, 
                                                                    propertyOptions);
 
            // NTE_NOT_FOUND means this property was not set, so return a NULL pointer
            if (error == ErrorCode.NotFound) {
                return IntPtr.Zero;
            } 

            if (error != ErrorCode.Success) { 
                throw new CryptographicException((int)error); 
            }
 
            return value;
        }

        ///  
        ///     Get the value of a string NCrypt property
        ///  
        //  
        // 
        //  
        // 
        // 
        [System.Security.SecurityCritical]
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")] 
        internal static string GetPropertyAsString(SafeNCryptHandle ncryptObject,
                                                   string propertyName, 
                                                   CngPropertyOptions propertyOptions) { 
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null); 

            bool foundProperty;
            byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);
 
            if (!foundProperty || valueBytes == null) {
                return null; 
            } 
            else if (valueBytes.Length == 0) {
                return String.Empty; 
            }
            else {
                unsafe {
                    fixed (byte* pValueBytes = valueBytes) { 
                        return Marshal.PtrToStringUni(new IntPtr(pValueBytes));
                    } 
                } 
            }
        } 

        /// 
        ///     Get the value of an NCrypt structure property -- this will return an empty structure if the
        ///     property does not exist. 
        /// 
        //  
        //  
        // 
        //  
        // 
        [System.Security.SecurityCritical]
        [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "Reviewed")]
        internal static T GetPropertyAsStruct(SafeNCryptHandle ncryptObject, 
                                                 string propertyName,
                                                 CngPropertyOptions propertyOptions) where T : struct { 
            Contract.Requires(ncryptObject != null); 
            Contract.Requires(propertyName != null);
 
            bool foundProperty;
            byte[] valueBytes = GetProperty(ncryptObject, propertyName, propertyOptions, out foundProperty);

            if (!foundProperty || valueBytes == null) { 
                return new T();
            } 
 
            unsafe {
                fixed (byte *pValue = valueBytes) { 
                    return (T)Marshal.PtrToStructure(new IntPtr(pValue), typeof(T));
                }
            }
        } 

        ///  
        ///     Import a key into the KSP 
        /// 
        //  
        // 
        // 
        // 
        //  
        [System.Security.SecurityCritical]
        internal static SafeNCryptKeyHandle ImportKey(SafeNCryptProviderHandle provider, 
                                                      byte[] keyBlob, 
                                                      string format) {
            Contract.Requires(provider != null); 
            Contract.Requires(keyBlob != null);
            Contract.Requires(!String.IsNullOrEmpty(format));
            Contract.Ensures(Contract.Result() != null &&
                             !Contract.Result().IsInvalid && 
                             !Contract.Result().IsClosed);
 
            SafeNCryptKeyHandle keyHandle = null; 
            ErrorCode error = UnsafeNativeMethods.NCryptImportKey(provider,
                                                                  IntPtr.Zero, 
                                                                  format,
                                                                  IntPtr.Zero,
                                                                  out keyHandle,
                                                                  keyBlob, 
                                                                  keyBlob.Length,
                                                                  0); 
 
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error); 
            }

            return keyHandle;
        } 

        ///  
        ///     Open an existing key 
        /// 
        //  
        // 
        // 
        // 
        //  
        [System.Security.SecurityCritical]
        internal static SafeNCryptKeyHandle OpenKey(SafeNCryptProviderHandle provider, 
                                                    string name, 
                                                    CngKeyOpenOptions options) {
            Contract.Requires(provider != null && !provider.IsInvalid && !provider.IsClosed); 
            Contract.Requires(name != null);

            SafeNCryptKeyHandle key = null;
            ErrorCode error = UnsafeNativeMethods.NCryptOpenKey(provider, out key, name, 0, options); 

            if (error != ErrorCode.Success) { 
                throw new CryptographicException((int)error); 
            }
 
            return key;
        }

        ///  
        ///     Open the specified key storage provider
        ///  
        //  
        // 
        //  
        // 
        // 
        [System.Security.SecurityCritical]
        internal static SafeNCryptProviderHandle OpenStorageProvider(string providerName) { 
            Contract.Requires(!String.IsNullOrEmpty(providerName));
            Contract.Ensures(Contract.Result() != null && 
                             !Contract.Result().IsInvalid && 
                             !Contract.Result().IsClosed);
 
            SafeNCryptProviderHandle providerHandle = null;
            ErrorCode error = UnsafeNativeMethods.NCryptOpenStorageProvider(out providerHandle,
                                                                            providerName,
                                                                            0); 

            if (error != ErrorCode.Success) { 
                throw new CryptographicException((int)error); 
            }
 
            return providerHandle;
        }

        ///  
        ///     Reverse the bytes in a buffer
        ///  
        private static byte[] ReverseBytes(byte[] buffer) { 
            Contract.Requires(buffer != null);
            Contract.Ensures(Contract.Result() != null && Contract.Result().Length == buffer.Length); 
            return ReverseBytes(buffer, 0, buffer.Length, false);
        }

        ///  
        ///     Reverse a section of bytes within a buffer
        ///  
        private static byte[] ReverseBytes(byte[] buffer, int offset, int count) { 
            return ReverseBytes(buffer, offset, count, false);
        } 

        private static byte[] ReverseBytes(byte[] buffer, int offset, int count, bool padWithZeroByte) {
            Contract.Requires(buffer != null);
            Contract.Requires(offset >= 0 && offset < buffer.Length); 
            Contract.Requires(count >= 0 && buffer.Length - count >= offset);
            Contract.Ensures(Contract.Result() != null); 
            Contract.Ensures(Contract.Result().Length == (padWithZeroByte ? count + 1 : count)); 
            Contract.Ensures(padWithZeroByte ? Contract.Result()[count] == 0 : true);
 
            byte[] reversed;
            if(padWithZeroByte)
            {
                reversed = new byte[count+1]; // the last (most-significant) byte will be left as 0x00 
            }
            else 
            { 
                reversed = new byte[count];
            } 

            int lastByte = offset + count - 1;
            for (int i = 0; i < count; i++) {
                reversed[i] = buffer[lastByte - i]; 
            }
 
            return reversed; 
        }
 
        /// 
        ///     Set a DWORD property on an NCrypt object
        /// 
        //  
        // 
        //  
        [System.Security.SecurityCritical] 
        internal static void SetProperty(SafeNCryptHandle ncryptObject,
                                         string propertyName, 
                                         int value,
                                         CngPropertyOptions propertyOptions) {
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null); 

            SetProperty(ncryptObject, propertyName, BitConverter.GetBytes(value), propertyOptions); 
        } 

        ///  
        ///     Set a string property
        /// 
        // 
        //  
        // 
        [System.Security.SecurityCritical] 
        internal static void SetProperty(SafeNCryptHandle ncryptObject, 
                                         string propertyName,
                                         string value, 
                                         CngPropertyOptions propertyOptions) {
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null);
 
            ErrorCode error = UnsafeNativeMethods.NCryptSetProperty(ncryptObject,
                                                                    propertyName, 
                                                                    value, 
                                                                    (value.Length + 1) * sizeof(char),
                                                                    propertyOptions); 

            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error);
            } 
        }
 
        ///  
        ///     Set a structure property
        ///  
        // 
        // 
        // 
        //  
        // 
        //  
        //  
        // 
        [System.Security.SecurityCritical] 
        internal static void SetProperty(SafeNCryptHandle ncryptObject,
                                            string propertyName,
                                            T value,
                                            CngPropertyOptions propertyOptions) where T : struct { 
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null); 
 
            byte[] buffer = new byte[Marshal.SizeOf(typeof(T))];
 
            unsafe {
                fixed (byte *pBuffer = buffer) {

                    bool marshaledStructure = false; 
                    RuntimeHelpers.PrepareConstrainedRegions();
                    try { 
                        // If we successfully marshal into the buffer, make sure to destroy the buffer when we're done 
                        RuntimeHelpers.PrepareConstrainedRegions();
                        try { } 
                        finally {
                            Marshal.StructureToPtr(value, new IntPtr(pBuffer), false);
                            marshaledStructure = true;
                        } 

                        SetProperty(ncryptObject, propertyName, buffer, propertyOptions); 
                    } 
                    finally {
                        if (marshaledStructure) { 
                            Marshal.DestroyStructure(new IntPtr(pBuffer), typeof(T));
                        }
                    }
                } 
            }
        } 
 
        /// 
        ///     Set a property on an NCrypt object 
        /// 
        // 
        // 
        //  
        [System.Security.SecurityCritical]
        internal static void SetProperty(SafeNCryptHandle ncryptObject, 
                                         string propertyName, 
                                         byte[] value,
                                         CngPropertyOptions propertyOptions) { 
            Contract.Requires(ncryptObject != null);
            Contract.Requires(propertyName != null);

            ErrorCode error = UnsafeNativeMethods.NCryptSetProperty(ncryptObject, 
                                                                    propertyName,
                                                                    value, 
                                                                    value != null ? value.Length : 0, 
                                                                    propertyOptions);
 
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error);
            }
        } 

        ///  
        ///     Sign a hash using no padding 
        /// 
        //  
        // 
        // 
        [System.Security.SecurityCritical]
        internal static byte[] SignHash(SafeNCryptKeyHandle key, byte[] hash) { 
            Contract.Requires(key != null);
            Contract.Requires(hash != null); 
            Contract.Ensures(Contract.Result() != null); 

            // Figure out how big the signature is 
            int signatureSize = 0;
            ErrorCode error = UnsafeNativeMethods.NCryptSignHash(key,
                                                                 IntPtr.Zero,
                                                                 hash, 
                                                                 hash.Length,
                                                                 null, 
                                                                 0, 
                                                                 out signatureSize,
                                                                 0); 

            if (error != ErrorCode.Success && error != ErrorCode.BufferTooSmall) {
                throw new CryptographicException((int)error);
            } 

            // Sign the data 
            Debug.Assert(signatureSize > 0, "signatureSize > 0"); 
            byte[] signature = new byte[signatureSize];
 
            error = UnsafeNativeMethods.NCryptSignHash(key,
                                                       IntPtr.Zero,
                                                       hash,
                                                       hash.Length, 
                                                       signature,
                                                       signature.Length, 
                                                       out signatureSize, 
                                                       0);
 
            if (error != ErrorCode.Success) {
                throw new CryptographicException((int)error);
            }
 
            return signature;
        } 
 
        /// 
        ///     Unpack a key blob in ECC public blob format into its X and Y parameters 
        ///
        ///     This method expects that the blob be in the correct format -- blobs accepted from partially
        ///     trusted code need to be validated before being unpacked.
        ///  
        internal static void UnpackEccPublicBlob(byte[] blob, out BigInteger x, out BigInteger y) {
            Contract.Requires(blob != null && blob.Length > 2 * sizeof(int)); 
 
            //
            // See code:System.Security.Cryptography.NCryptNative#ECCPublicBlobFormat  for details about the 
            // format of the ECC public key blob.
            //

            // read the size of each parameter 
            int parameterSize = BitConverter.ToInt32(blob, sizeof(int));
            Debug.Assert(parameterSize > 0, "parameterSize > 0"); 
            Debug.Assert(blob.Length >= 2 * sizeof(int) + 2 * parameterSize, "blob.Length >= 2 * sizeof(int) + 2 * parameterSize"); 

            // read out the X and Y parameters, in memory reversed form 
            // add 0x00 padding to force BigInteger to interpret these as positive numbers
            x = new BigInteger(ReverseBytes(blob, 2 * sizeof(int), parameterSize, true));
            y = new BigInteger(ReverseBytes(blob, 2 * sizeof(int) + parameterSize, parameterSize, true));
        } 

        ///  
        ///     Verify a signature created with no padding 
        /// 
        //  
        // 
        // 
        [System.Security.SecurityCritical]
        internal static bool VerifySignature(SafeNCryptKeyHandle key, byte[] hash, byte[] signature) { 
            Contract.Requires(key != null);
            Contract.Requires(hash != null); 
            Contract.Requires(signature != null); 

            ErrorCode error = UnsafeNativeMethods.NCryptVerifySignature(key, 
                                                                        IntPtr.Zero,
                                                                        hash,
                                                                        hash.Length,
                                                                        signature, 
                                                                        signature.Length,
                                                                        0); 
 
            if (error != ErrorCode.Success && error != ErrorCode.BadSignature) {
                throw new CryptographicException((int)error); 
            }

            return error == ErrorCode.Success;
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK