/// <summary>
        /// Applies the UI context.
        /// </summary>
        /// <param name="ngcKeyHandle">The NGC key handle.</param>
        /// <param name="uiContext">The UI context.</param>
        private static void ApplyUiContext(SafeNCryptHandle ngcKeyHandle, AuthProviderUiContext uiContext)
        {
            if (uiContext == null)
            {
                return;
            }
            var parentWindowHandle = uiContext.ParentWindowHandle;

            if (parentWindowHandle != IntPtr.Zero)
            {
                var handle = BitConverter.GetBytes(IntPtr.Size == 8
                    ? parentWindowHandle.ToInt64()
                    : parentWindowHandle.ToInt32());
                NCryptSetProperty(
                    ngcKeyHandle,
                    NCRYPT_WINDOW_HANDLE_PROPERTY,
                    handle,
                    handle.Length,
                    CngPropertyOptions.None)
                .CheckStatus("NCRYPT_WINDOW_HANDLE_PROPERTY");
            }

            var message = uiContext.Message;

            if (!string.IsNullOrEmpty(message))
            {
                NCryptSetProperty(
                    ngcKeyHandle,
                    NCRYPT_USE_CONTEXT_PROPERTY,
                    message,
                    (message.Length + 1) * 2,
                    CngPropertyOptions.None)
                .CheckStatus("NCRYPT_USE_CONTEXT_PROPERTY");
            }
        }
        /// <summary>
        /// Creates a new instance of the <see cref="WinHelloProvider"/> class.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="windowHandle">The window handle.</param>
        /// <returns>A new instance of the <see cref="WinHelloProvider"/> class.</returns>
        // ReSharper disable once UnusedMember.Global
        public static WinHelloProvider CreateInstance(string message, IntPtr windowHandle)
        {
            if (!IsAvailable())
            {
                throw new AuthProviderIsUnavailableException("Windows Hello is not available.");
            }

            lock (Mutex)
            {
                if (!TryOpenPersistentKey(out var ngcKeyHandle))
                {
                    CreatePersistentKey(true, AuthProviderUiContext.With(message, windowHandle)).Dispose();
                }

                ngcKeyHandle.Dispose();
                var winHelloProvider = new WinHelloProvider(AuthProviderUiContext.With(message, windowHandle));
                return(_instance ?? (_instance = winHelloProvider));
            }
        }
        private WinHelloProvider(AuthProviderUiContext uIContext)
        {
            if (!TryOpenPersistentKey(out var ngcKeyHandle))
            {
                throw new AuthProviderInvalidKeyException("Persistent key does not exist.");
            }

            using (ngcKeyHandle)
            {
                if (!VerifyPersistentKeyIntegrity(ngcKeyHandle))
                {
                    ngcKeyHandle.Close();
                    DeletePersistentKey();
                    throw new AuthProviderInvalidKeyException(InvalidatedKeyMessage);
                }
            }

            _uiContext      = uIContext;
            _currentKeyName = _persistentKeyName.Value;
        }
        private static SafeNCryptKeyHandle CreatePersistentKey(bool overwriteExisting, AuthProviderUiContext uIContext)
        {
            NCryptOpenStorageProvider(
                out var ngcProviderHandle,
                MS_NGC_KEY_STORAGE_PROVIDER,
                0).CheckStatus("NCryptOpenStorageProvider");

            SafeNCryptKeyHandle ngcKeyHandle;

            using (ngcProviderHandle)
            {
                NCryptCreatePersistedKey(
                    ngcProviderHandle,
                    out ngcKeyHandle,
                    BCRYPT_RSA_ALGORITHM,
                    _persistentKeyName.Value,
                    0,
                    overwriteExisting ? CngKeyCreationOptions.OverwriteExistingKey : CngKeyCreationOptions.None)
                .CheckStatus("NCryptCreatePersistedKey");

                var lengthProp = BitConverter.GetBytes(2048);
                NCryptSetProperty(
                    ngcKeyHandle,
                    NCRYPT_LENGTH_PROPERTY,
                    lengthProp,
                    lengthProp.Length,
                    CngPropertyOptions.None)
                .CheckStatus("NCRYPT_LENGTH_PROPERTY");

                var keyUsage = BitConverter.GetBytes(NCRYPT_ALLOW_DECRYPT_FLAG | NCRYPT_ALLOW_SIGNING_FLAG);
                NCryptSetProperty(
                    ngcKeyHandle,
                    NCRYPT_KEY_USAGE_PROPERTY,
                    keyUsage,
                    keyUsage.Length,
                    CngPropertyOptions.None)
                .CheckStatus("NCRYPT_KEY_USAGE_PROPERTY");

                var cacheType = BitConverter.GetBytes(NCRYPT_NGC_CACHE_TYPE_PROPERTY_AUTH_MANDATORY_FLAG);
                try
                {
                    NCryptSetProperty(
                        ngcKeyHandle,
                        NCRYPT_NGC_CACHE_TYPE_PROPERTY,
                        cacheType,
                        cacheType.Length,
                        CngPropertyOptions.None)
                    .CheckStatus("NCRYPT_NGC_CACHE_TYPE_PROPERTY");
                }
                catch
                {
                    NCryptSetProperty(
                        ngcKeyHandle,
                        NCRYPT_NGC_CACHE_TYPE_PROPERTY_DEPRECATED,
                        cacheType,
                        cacheType.Length,
                        CngPropertyOptions.None)
                    .CheckStatus("NCRYPT_NGC_CACHE_TYPE_PROPERTY_DEPRECATED");
                }

                ApplyUiContext(ngcKeyHandle, uIContext);

                NCryptFinalizeKey(ngcKeyHandle, 0).CheckStatus("NCryptFinalizeKey");
            }

            return(ngcKeyHandle);
        }