/// <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); }