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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SecurityStandardsManager.cs
- WmiInstallComponent.cs
- StreamAsIStream.cs
- ObjectDataSourceView.cs
- LineGeometry.cs
- XPathPatternBuilder.cs
- CheckBoxList.cs
- CleanUpVirtualizedItemEventArgs.cs
- XmlSchemaComplexType.cs
- formatter.cs
- PolygonHotSpot.cs
- StrongNameUtility.cs
- ChannelParameterCollection.cs
- CommentEmitter.cs
- SafeReadContext.cs
- Privilege.cs
- WebScriptMetadataFormatter.cs
- HttpAsyncResult.cs
- QueryParameter.cs
- ApplicationDirectoryMembershipCondition.cs
- ObjectResult.cs
- MatrixTransform.cs
- MatrixTransform.cs
- XmlDsigSep2000.cs
- TraceLog.cs
- EdmSchemaAttribute.cs
- WebBrowserProgressChangedEventHandler.cs
- RealizationDrawingContextWalker.cs
- FieldToken.cs
- DataGridViewRowDividerDoubleClickEventArgs.cs
- AesCryptoServiceProvider.cs
- Property.cs
- MdImport.cs
- XmlCountingReader.cs
- EllipseGeometry.cs
- ProfileBuildProvider.cs
- DataReaderContainer.cs
- CommonGetThemePartSize.cs
- RoleManagerModule.cs
- CachedPathData.cs
- ChannelDispatcherBase.cs
- StateMachine.cs
- SiteMapNode.cs
- SafeNativeMethodsOther.cs
- SiteMapSection.cs
- ParseNumbers.cs
- GetWinFXPath.cs
- HtmlTableRow.cs
- XamlStream.cs
- RuntimeEnvironment.cs
- ParallelLoopState.cs
- PropertyGeneratedEventArgs.cs
- ProfileSettings.cs
- SupportingTokenDuplexChannel.cs
- ThicknessAnimationUsingKeyFrames.cs
- MenuAutomationPeer.cs
- XmlTypeMapping.cs
- StateWorkerRequest.cs
- XPathEmptyIterator.cs
- DataGridState.cs
- TargetPerspective.cs
- SqlDataReader.cs
- QilStrConcatenator.cs
- Quaternion.cs
- RegexCompilationInfo.cs
- MatrixKeyFrameCollection.cs
- Splitter.cs
- ExtentCqlBlock.cs
- DesignerLinkAdapter.cs
- FlowchartDesignerCommands.cs
- XmlNavigatorStack.cs
- FontUnitConverter.cs
- EntityCommandExecutionException.cs
- NativeMethods.cs
- AnchoredBlock.cs
- TreeViewCancelEvent.cs
- TextParaClient.cs
- RtfFormatStack.cs
- CompilerError.cs
- CodeEntryPointMethod.cs
- TimeStampChecker.cs
- SpanIndex.cs
- XslAst.cs
- SchemaComplexType.cs
- UndirectedGraph.cs
- FreezableOperations.cs
- LayoutManager.cs
- MatrixAnimationBase.cs
- DBNull.cs
- CompiledQueryCacheKey.cs
- DataGridViewColumnDesignTimeVisibleAttribute.cs
- Calendar.cs
- SizeFConverter.cs
- LinqDataSourceContextEventArgs.cs
- EntityDataSourceEntityTypeFilterConverter.cs
- StringComparer.cs
- SoapTransportImporter.cs
- RelationshipWrapper.cs
- ExtendedPropertiesHandler.cs
- Canvas.cs