/// <summary> /// Setup the key properties specified in the key creation parameters /// </summary> private static void InitializeKeyProperties(SafeNCryptKeyHandle keyHandle, CngKeyCreationParameters creationParameters) { unsafe { if (creationParameters.ExportPolicy.HasValue) { CngExportPolicies exportPolicy = creationParameters.ExportPolicy.Value; keyHandle.SetExportPolicy(exportPolicy); } if (creationParameters.KeyUsage.HasValue) { CngKeyUsages keyUsage = creationParameters.KeyUsage.Value; ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty(keyHandle, KeyPropertyName.KeyUsage, &keyUsage, sizeof(CngKeyUsages), CngPropertyOptions.Persist); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } if (creationParameters.ParentWindowHandle != IntPtr.Zero) { IntPtr parentWindowHandle = creationParameters.ParentWindowHandle; ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty(keyHandle, KeyPropertyName.ParentWindowHandle, &parentWindowHandle, sizeof(IntPtr), CngPropertyOptions.None); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } CngUIPolicy uiPolicy = creationParameters.UIPolicy; if (uiPolicy != null) { InitializeKeyUiPolicyProperties(keyHandle, uiPolicy); } // Iterate over the custom properties, setting those as well. foreach (CngProperty property in creationParameters.Parameters) { byte[] value = property.GetValueWithoutCopying(); int valueLength = (value == null) ? 0 : value.Length; fixed(byte *pValue = value.MapZeroLengthArrayToNonNullPointer()) { ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty(keyHandle, property.Name, pValue, valueLength, property.Options); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } } } }
internal static unsafe CngKey ImportEncryptedPkcs8( ReadOnlySpan <byte> keyBlob, ReadOnlySpan <char> password, CngProvider provider) { SafeNCryptProviderHandle providerHandle = provider.OpenStorageProvider(); SafeNCryptKeyHandle keyHandle; using (SafeUnicodeStringHandle passwordHandle = new SafeUnicodeStringHandle(password)) { Interop.NCrypt.NCryptBuffer *buffers = stackalloc Interop.NCrypt.NCryptBuffer[1]; buffers[0] = new Interop.NCrypt.NCryptBuffer { BufferType = Interop.NCrypt.BufferType.PkcsSecret, cbBuffer = checked (2 * (password.Length + 1)), pvBuffer = passwordHandle.DangerousGetHandle(), }; if (buffers[0].pvBuffer == IntPtr.Zero) { buffers[0].cbBuffer = 0; } Interop.NCrypt.NCryptBufferDesc desc = new Interop.NCrypt.NCryptBufferDesc { cBuffers = 1, pBuffers = (IntPtr)buffers, ulVersion = 0, }; ErrorCode errorCode = Interop.NCrypt.NCryptImportKey( providerHandle, IntPtr.Zero, Interop.NCrypt.NCRYPT_PKCS8_PRIVATE_KEY_BLOB, ref desc, out keyHandle, ref MemoryMarshal.GetReference(keyBlob), keyBlob.Length, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { keyHandle.Dispose(); throw errorCode.ToCryptographicException(); } } CngKey key = new CngKey(providerHandle, keyHandle); key.IsEphemeral = true; return(key); }
public static SafeNCryptProviderHandle OpenStorageProvider(this CngProvider provider) { string providerName = provider.Provider; SafeNCryptProviderHandle providerHandle; ErrorCode errorCode = Interop.NCrypt.NCryptOpenStorageProvider(out providerHandle, providerName, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } return(providerHandle); }
private static SafeNCryptProviderHandle OpenNCryptProvider(string providerName) { SafeNCryptProviderHandle providerHandle; ErrorCode errorCode = Interop.NCrypt.NCryptOpenStorageProvider(out providerHandle, providerName, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } Debug.Assert(!providerHandle.IsInvalid); return(providerHandle); }
protected sealed override bool ReleaseHandle() { if (_isNcrypt) { ErrorCode errorCode = Interop.NCrypt.NCryptFreeObject(handle); return(errorCode == ErrorCode.ERROR_SUCCESS); } else { bool success = Interop.Crypt32.CryptReleaseContext(handle, 0); return(success); } }
/// <summary> /// Delete this key /// </summary> public void Delete() { ErrorCode errorCode = Interop.NCrypt.NCryptDeleteKey(_keyHandle, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } _keyHandle.SetHandleAsInvalid(); // Once the key is deleted, the handles are no longer valid so dispose of this instance Dispose(); }
/// <summary> /// Returns a CNG key property. /// </summary> /// <returns> /// null - if property not defined on key. /// throws - for any other type of error. /// </returns> internal static byte[]? GetProperty(this SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options) { Debug.Assert(!ncryptHandle.IsInvalid); unsafe { ErrorCode errorCode = Interop.NCrypt.NCryptGetProperty( ncryptHandle, propertyName, null, 0, out int numBytesNeeded, options); if (errorCode == ErrorCode.NTE_NOT_FOUND) { return(null); } if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } byte[] propertyValue = new byte[numBytesNeeded]; fixed(byte *pPropertyValue = propertyValue) { errorCode = Interop.NCrypt.NCryptGetProperty( ncryptHandle, propertyName, pPropertyValue, propertyValue.Length, out numBytesNeeded, options); } if (errorCode == ErrorCode.NTE_NOT_FOUND) { return(null); } if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } Array.Resize(ref propertyValue, numBytesNeeded); return(propertyValue); } }
// Now that the padding mode and information have been marshaled to their native counterparts, perform the encryption or decryption. private unsafe byte[] EncryptOrDecrypt(SafeNCryptKeyHandle key, ReadOnlySpan <byte> input, AsymmetricPaddingMode paddingMode, void *paddingInfo, bool encrypt) { int estimatedSize = KeySize / 8; #if DEBUG estimatedSize = 2; // Make sure the NTE_BUFFER_TOO_SMALL scenario gets exercised. #endif byte[] output = new byte[estimatedSize]; int numBytesNeeded = 0; ErrorCode errorCode = 0; for (int i = 0; i <= StatusUnsuccessfulRetryCount; i++) { errorCode = EncryptOrDecrypt(key, input, output, paddingMode, paddingInfo, encrypt, out numBytesNeeded); if (errorCode != ErrorCode.STATUS_UNSUCCESSFUL) { break; } } if (errorCode == ErrorCode.NTE_BUFFER_TOO_SMALL) { output = new byte[numBytesNeeded]; for (int i = 0; i <= StatusUnsuccessfulRetryCount; i++) { errorCode = EncryptOrDecrypt(key, input, output, paddingMode, paddingInfo, encrypt, out numBytesNeeded); if (errorCode != ErrorCode.STATUS_UNSUCCESSFUL) { break; } } } if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } Array.Resize(ref output, numBytesNeeded); return(output); }
public static CngKey Open(string keyName, CngProvider provider, CngKeyOpenOptions openOptions) { ArgumentNullException.ThrowIfNull(keyName); ArgumentNullException.ThrowIfNull(provider); SafeNCryptProviderHandle providerHandle = provider.OpenStorageProvider(); SafeNCryptKeyHandle keyHandle; ErrorCode errorCode = Interop.NCrypt.NCryptOpenKey(providerHandle, out keyHandle, keyName, 0, openOptions); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } return(new CngKey(providerHandle, keyHandle)); }
internal bool TryExportKeyBlob( string blobType, Span <byte> destination, out int bytesWritten) { // Sanity check the current bounds Span <byte> empty = default; ErrorCode errorCode = Interop.NCrypt.NCryptExportKey( _keyHandle, IntPtr.Zero, blobType, IntPtr.Zero, ref MemoryMarshal.GetReference(empty), empty.Length, out int written, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } if (written > destination.Length) { bytesWritten = 0; return(false); } errorCode = Interop.NCrypt.NCryptExportKey( _keyHandle, IntPtr.Zero, blobType, IntPtr.Zero, ref MemoryMarshal.GetReference(destination), destination.Length, out written, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } bytesWritten = written; return(true); }
public static void SetExportPolicy(this SafeNCryptKeyHandle keyHandle, CngExportPolicies exportPolicy) { unsafe { ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty( keyHandle, KeyPropertyName.ExportPolicy, &exportPolicy, sizeof(CngExportPolicies), CngPropertyOptions.Persist); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } }
/// <summary> /// Retrieve a well-known CNG pointer property. (Note: .NET Framework compat: this helper likes to return special values rather than throw exceptions for missing /// or ill-formatted property values. Only use it for well-known properties that are unlikely to be ill-formatted.) /// </summary> public static IntPtr GetPropertyAsIntPtr(this SafeNCryptHandle ncryptHandle, string propertyName, CngPropertyOptions options) { unsafe { IntPtr value; ErrorCode errorCode = Interop.NCrypt.NCryptGetProperty(ncryptHandle, propertyName, &value, IntPtr.Size, out _, options); if (errorCode == ErrorCode.NTE_NOT_FOUND) { return(IntPtr.Zero); } if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } return(value); } }
private static void SetKeyLength(SafeNCryptKeyHandle keyHandle, int keySize) { unsafe { ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty( keyHandle, KeyPropertyName.Length, &keySize, sizeof(int), CngPropertyOptions.Persist); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } }
/// <summary> /// Determine if a property exists on the key /// </summary> public bool HasProperty(string name, CngPropertyOptions options) { ArgumentNullException.ThrowIfNull(name); unsafe { ErrorCode errorCode = Interop.NCrypt.NCryptGetProperty(_keyHandle, name, null, 0, out _, options); if (errorCode == ErrorCode.NTE_NOT_FOUND) { return(false); } if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } return(true); } }
public static unsafe bool TrySignHash(this SafeNCryptKeyHandle keyHandle, ReadOnlySpan <byte> hash, Span <byte> signature, AsymmetricPaddingMode paddingMode, void *pPaddingInfo, out int bytesWritten) { ErrorCode error = Interop.NCrypt.NCryptSignHash(keyHandle, pPaddingInfo, hash, hash.Length, signature, signature.Length, out int numBytesNeeded, paddingMode); switch (error) { case ErrorCode.ERROR_SUCCESS: bytesWritten = numBytesNeeded; return(true); case ErrorCode.NTE_BUFFER_TOO_SMALL: bytesWritten = 0; return(false); default: throw error.ToCryptographicException(); } }
public static CngKey Create(CngAlgorithm algorithm, string?keyName, CngKeyCreationParameters?creationParameters) { ArgumentNullException.ThrowIfNull(algorithm); creationParameters ??= new CngKeyCreationParameters(); SafeNCryptProviderHandle providerHandle = creationParameters.Provider !.OpenStorageProvider(); SafeNCryptKeyHandle? keyHandle = null; try { ErrorCode errorCode = Interop.NCrypt.NCryptCreatePersistedKey(providerHandle, out keyHandle, algorithm.Algorithm, keyName, 0, creationParameters.KeyCreationOptions); if (errorCode != ErrorCode.ERROR_SUCCESS) { // For ecc, the exception may be caught and re-thrown as PlatformNotSupportedException throw errorCode.ToCryptographicException(); } InitializeKeyProperties(keyHandle, creationParameters); errorCode = Interop.NCrypt.NCryptFinalizeKey(keyHandle, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { // For ecc, the exception may be caught and re-thrown as PlatformNotSupportedException throw errorCode.ToCryptographicException(); } CngKey key = new CngKey(providerHandle, keyHandle); // No name translates to an ephemeral key if (keyName == null) { key.IsEphemeral = true; } return(key); } catch { keyHandle?.Dispose(); providerHandle.Dispose(); throw; } }
private static void SetExportable(SafeNCryptKeyHandle keyHandle) { CngExportPolicies exportPolicy = CngExportPolicies.AllowPlaintextExport; unsafe { ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty( keyHandle, KeyPropertyName.ExportPolicy, &exportPolicy, sizeof(CngExportPolicies), CngPropertyOptions.Persist); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } }
// // Now that the padding mode and information have been marshaled to their native counterparts, perform the encryption or decryption. // private static unsafe byte[] EncryptOrDecrypt(SafeNCryptKeyHandle key, byte[] input, AsymmetricPaddingMode paddingMode, void *paddingInfo, EncryptOrDecryptAction encryptOrDecrypt) { int numBytesNeeded; ErrorCode errorCode = encryptOrDecrypt(key, input, input.Length, paddingInfo, null, 0, out numBytesNeeded, paddingMode); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } byte[] output = new byte[numBytesNeeded]; errorCode = encryptOrDecrypt(key, input, input.Length, paddingInfo, output, numBytesNeeded, out numBytesNeeded, paddingMode); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } return(output); }
/// <summary> /// Setup the UIPolicy key properties specified in the key creation parameters /// </summary> private static void InitializeKeyUiPolicyProperties(SafeNCryptKeyHandle keyHandle, CngUIPolicy uiPolicy) { unsafe { fixed(char *pinnedCreationTitle = uiPolicy.CreationTitle, pinnedFriendlyName = uiPolicy.FriendlyName, pinnedDescription = uiPolicy.Description) { NCRYPT_UI_POLICY ncryptUiPolicy = new NCRYPT_UI_POLICY() { dwVersion = 1, dwFlags = uiPolicy.ProtectionLevel, pszCreationTitle = new IntPtr(pinnedCreationTitle), pszFriendlyName = new IntPtr(pinnedFriendlyName), pszDescription = new IntPtr(pinnedDescription), }; ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty(keyHandle, KeyPropertyName.UIPolicy, &ncryptUiPolicy, sizeof(NCRYPT_UI_POLICY), CngPropertyOptions.Persist); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } string useContext = uiPolicy.UseContext; if (useContext != null) { int useContextByteLength = checked ((useContext.Length + 1) * sizeof(char)); fixed(char *pinnedUseContext = useContext) { ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty(keyHandle, KeyPropertyName.UseContext, pinnedUseContext, useContextByteLength, CngPropertyOptions.Persist); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } } } }
// Now that the padding mode and information have been marshaled to their native counterparts, perform the encryption or decryption. private unsafe bool TryEncryptOrDecrypt(SafeNCryptKeyHandle key, ReadOnlySpan <byte> input, Span <byte> output, AsymmetricPaddingMode paddingMode, void *paddingInfo, bool encrypt, out int bytesWritten) { int numBytesNeeded; ErrorCode errorCode = EncryptOrDecrypt(key, input, output, paddingMode, paddingInfo, encrypt, out numBytesNeeded); switch (errorCode) { case ErrorCode.ERROR_SUCCESS: bytesWritten = numBytesNeeded; return(true); case ErrorCode.NTE_BUFFER_TOO_SMALL: bytesWritten = 0; return(false); default: throw errorCode.ToCryptographicException(); } }
protected sealed override bool ReleaseHandle() { if (_parentHandle != null) { _parentHandle.DangerousRelease(); _parentHandle = null; SetHandle(IntPtr.Zero); return(true); } else if (_isNcrypt) { ErrorCode errorCode = Interop.NCrypt.NCryptFreeObject(handle); return(errorCode == ErrorCode.ERROR_SUCCESS); } else { bool success = Interop.Advapi32.CryptReleaseContext(handle, 0); return(success); } }
internal static byte[] ExportKeyBlob(SafeNCryptKeyHandle keyHandle, string blobType) { Debug.Assert(!keyHandle.IsInvalid); int numBytesNeeded; ErrorCode errorCode = Interop.NCrypt.NCryptExportKey( keyHandle, IntPtr.Zero, blobType, IntPtr.Zero, null, 0, out numBytesNeeded, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } byte[] buffer = new byte[numBytesNeeded]; errorCode = Interop.NCrypt.NCryptExportKey( keyHandle, IntPtr.Zero, blobType, IntPtr.Zero, buffer, buffer.Length, out numBytesNeeded, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } Array.Resize(ref buffer, numBytesNeeded); return(buffer); }
private static void SetProperty(SafeNCryptHandle ncryptHandle, string propertyName, byte[] value) { Debug.Assert(!ncryptHandle.IsInvalid); unsafe { fixed(byte *pBlob = value) { ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty( ncryptHandle, propertyName, pBlob, value.Length, CngPropertyOptions.None); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } } }
/// <summary> /// Set an arbitrary property on the key /// </summary> public void SetProperty(CngProperty property) { unsafe { byte[] propertyValue = property.GetValueWithoutCopying(); // .NET Framework compat. It would have nicer to throw an ArgumentNull exception or something... if (propertyValue == null) throw ErrorCode.NTE_INVALID_PARAMETER.ToCryptographicException(); fixed(byte *pinnedPropertyValue = propertyValue.MapZeroLengthArrayToNonNullPointer()) { ErrorCode errorCode = Interop.NCrypt.NCryptSetProperty(_keyHandle, property.Name, pinnedPropertyValue, propertyValue.Length, property.Options); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } } } }
private static unsafe ErrorCode EncryptOrDecrypt( SafeNCryptKeyHandle key, ReadOnlySpan <byte> input, Span <byte> output, AsymmetricPaddingMode paddingMode, void *paddingInfo, bool encrypt, out int bytesNeeded) { ErrorCode errorCode = encrypt ? Interop.NCrypt.NCryptEncrypt(key, input, input.Length, paddingInfo, output, output.Length, out bytesNeeded, paddingMode) : Interop.NCrypt.NCryptDecrypt(key, input, input.Length, paddingInfo, output, output.Length, out bytesNeeded, paddingMode); // Windows 10.1903 can return success when it meant NTE_BUFFER_TOO_SMALL. if (errorCode == ErrorCode.ERROR_SUCCESS && bytesNeeded > output.Length) { errorCode = ErrorCode.NTE_BUFFER_TOO_SMALL; } return(errorCode); }
internal static unsafe int GetKeyLength(SafeNCryptKeyHandle keyHandle) { int keySize = 0; int bytesWritten; ErrorCode errorCode = Interop.NCrypt.NCryptGetProperty( keyHandle, KeyPropertyName.Length, &keySize, sizeof(int), out bytesWritten, CngPropertyOptions.None); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } Debug.Assert(bytesWritten == sizeof(int)); return(keySize); }
public static unsafe byte[] SignHash(this SafeNCryptKeyHandle keyHandle, byte[] hash, AsymmetricPaddingMode paddingMode, void *pPaddingInfo, int estimatedSize) { #if DEBUG estimatedSize = 2; // Make sure the NTE_BUFFER_TOO_SMALL scenario gets exercised. #endif byte[] signature = new byte[estimatedSize]; int numBytesNeeded; ErrorCode errorCode = Interop.NCrypt.NCryptSignHash(keyHandle, pPaddingInfo, hash, hash.Length, signature, signature.Length, out numBytesNeeded, paddingMode); if (errorCode == ErrorCode.NTE_BUFFER_TOO_SMALL) { signature = new byte[numBytesNeeded]; errorCode = Interop.NCrypt.NCryptSignHash(keyHandle, pPaddingInfo, hash, hash.Length, signature, signature.Length, out numBytesNeeded, paddingMode); } if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } Array.Resize(ref signature, numBytesNeeded); return(signature); }
public static CngKey Create(CngAlgorithm algorithm, string keyName, CngKeyCreationParameters creationParameters) { if (algorithm == null) { throw new ArgumentNullException(nameof(algorithm)); } if (creationParameters == null) { creationParameters = new CngKeyCreationParameters(); } SafeNCryptProviderHandle providerHandle = creationParameters.Provider.OpenStorageProvider(); SafeNCryptKeyHandle keyHandle; ErrorCode errorCode = Interop.NCrypt.NCryptCreatePersistedKey(providerHandle, out keyHandle, algorithm.Algorithm, keyName, 0, creationParameters.KeyCreationOptions); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } InitializeKeyProperties(keyHandle, creationParameters); errorCode = Interop.NCrypt.NCryptFinalizeKey(keyHandle, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } CngKey key = new CngKey(providerHandle, keyHandle); // No name translates to an ephemeral key if (keyName == null) { key.IsEphemeral = true; } return(key); }
/// <summary> /// Export the key out of the KSP /// </summary> public byte[] Export(CngKeyBlobFormat format) { ArgumentNullException.ThrowIfNull(format); int numBytesNeeded; ErrorCode errorCode = Interop.NCrypt.NCryptExportKey(_keyHandle, IntPtr.Zero, format.Format, IntPtr.Zero, null, 0, out numBytesNeeded, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } byte[] buffer = new byte[numBytesNeeded]; errorCode = Interop.NCrypt.NCryptExportKey(_keyHandle, IntPtr.Zero, format.Format, IntPtr.Zero, buffer, buffer.Length, out numBytesNeeded, 0); if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } Array.Resize(ref buffer, numBytesNeeded); return(buffer); }
/// <summary> /// Determine if a property exists on the key /// </summary> public bool HasProperty(string name, CngPropertyOptions options) { if (name == null) { throw new ArgumentNullException(nameof(name)); } unsafe { int numBytesNeeded; ErrorCode errorCode = Interop.NCrypt.NCryptGetProperty(_keyHandle, name, null, 0, out numBytesNeeded, options); if (errorCode == ErrorCode.NTE_NOT_FOUND) { return(false); } if (errorCode != ErrorCode.ERROR_SUCCESS) { throw errorCode.ToCryptographicException(); } return(true); } }