сохранить пароль с помощью Windows Hello

Я хочу сохранить и получить пароль с помощью Windows Hello. Пользователь может выбрать во время входа в систему, хочет ли он ввести свой пароль вручную, или если он хочет использовать Windows Hello для разблокировки (который затем извлекает последний использованный пароль и заполняет его для пользователя).

Если Windows Hello настроен правильно, в документе есть два варианта использования.
Один нужно просто разблокировать:

UserConsentVerificationResult consentResult = await UserConsentVerifier.RequestVerificationAsync("userMessage");
if (consentResult.Equals(UserConsentVerificationResult.Verified))
{
   // continue
}

и один для подписи сообщения с сервера:

var openKeyResult = await KeyCredentialManager.OpenAsync(AccountId);
if (openKeyResult.Status == KeyCredentialStatus.Success)
{
    var userKey = openKeyResult.Credential;
    var publicKey = userKey.RetrievePublicKey();
    //the message is the challenge from the server
    var signResult = await userKey.RequestSignAsync(message);

    if (signResult.Status == KeyCredentialStatus.Success)
    {
        //the with the private key of the user signed message        
        return signResult.Result;
    }
}

Оба не очень полезны для моего варианта использования: мне нужен симметричный способ хранения и извлечения пароля.

Коротко о моем вопросе:
Есть ли способ симметрично хранить данные с помощью Windows Hello?

соответствующие документы:
https://docs.microsoft.com/en-us/windows/uwp/security/microsoft-passport


person Florian Moser    schedule 21.05.2017    source источник
comment
Не могли бы вы объяснить, что вы имеете в виду? Мне нужен симметричный способ хранения и извлечения моего пароля. Очевидно, что это не обязательно должен быть тот же пароль, который использовался для входа в систему, но он должен быть одним и тем же при каждом получении. Насколько я знаю, Windows Hello больше похожа на двухфакторную аутентификацию, она не используется для хранения и извлечения пароля.   -  person Scavenger    schedule 25.05.2017
comment
Словом, странно сформулированную фразу я убрал; Я хочу хранить данные симметрично. Windows Hello больше похожа на двухфакторную аутентификацию: к сожалению, это было и мое впечатление, поэтому мой вопрос, есть ли способ использовать ее в качестве безопасного симметричного хранилища.   -  person Florian Moser    schedule 25.05.2017


Ответы (2)


Я решил эту проблему, зашифровав/расшифровав секрет, который я хотел сохранить, используя пароль, сгенерированный с помощью Windows Hello. Пароль был подписью над фиксированным сообщением.

Полный пример кода (непроверенный), чтобы проиллюстрировать мою точку зрения:

const accountId = "A ID for this key";
const challenge = "sign this challenge using Windows Hello to get a secure string";

public async Task<byte[]> GetSecureEncryptionKey() {
    // if first time; we first need to create a key
    if (firstTime) {
        if (!await this.CreateKeyAsync()) {
            return null;
        }
    }

    // get the key using Windows Hellp
    return await this.GetKeyAsync();
}

private async Task<bool> CreateKeyAsync() {
    if (!await KeyCredentialManager.IsSupportedAsync()) {
        return false;
    }

    // if app opened for the first time, we need to create an account first
    var keyCreationResult = await KeyCredentialManager.RequestCreateAsync(AccountId, KeyCredentialCreationOption.ReplaceExisting);
    return keyCreationResult.Status == KeyCredentialStatus.Success);
}

private async Task<byte[]> GetKeyAsync() {
    var openKeyResult = await KeyCredentialManager.OpenAsync(AccountId);

    if (openKeyResult.Status == KeyCredentialStatus.Success)
    {
        // convert our string challenge to be able to sign it 
        var buffer = CryptographicBuffer.ConvertStringToBinary(
            challenge, BinaryStringEncoding.Utf8
        );

        // request a sign from the user
        var signResult = await openKeyResult.Credential.RequestSignAsync(buffer);

        // if successful, we can use that signature as a key
        if (signResult.Status == KeyCredentialStatus.Success)
        {
            return signResult.Result.ToArray();
        }
    }

    return null;
}

полный источник на github и показывает, как я интегрировал эти концепции в приложение.

person Florian Moser    schedule 22.01.2019

Вы можете использовать PasswordVault для установки пароля следующим образом:

    private void SetPassword(string password, string userName)
    {
        PasswordVault myVault = new PasswordVault();
        myVault.Add(new PasswordCredential("Your App ID", userName, password));
    }

для удаления пароля:

    private void RemovePassword(string userName)
    {
        PasswordVault myVault = new PasswordVault();

        var password = myVault.Retrieve("Your App ID", userName);
        if (password != null)
            myVault.Remove(password);
    }

если вы хотите использовать его с Windows Hello:

    public async Task<string> SignInAsync(string userName)
    {
        var result = await UserConsentVerifier.RequestVerificationAsync(requestMessage);
        if (result != UserConsentVerificationResult.Verified)
            return null;

        var vault = new PasswordVault();
        var credentials = vault.Retrieve("Your App ID", userName);

        return credentials?.Password;
    }

это проверит Windows Hello перед доступом к значению пароля

person fs_dm    schedule 18.01.2019
comment
Я не уверен, что это решает проблему, с которой я столкнулся: я хотел надежно сохранить секрет, который можно было бы снова получить, используя либо пароль (вы отвечаете, решает эту проблему), либо Windows Hello (с которым ваш ответ не может справиться) - person Florian Moser; 18.01.2019
comment
Если я правильно помню, я решил это, используя определенную подпись (аналогично примеру 2 из вопроса): после входа в систему Windows Hello я подписывал определенное сообщение (которое никогда не менялось). Затем я использовал эту подпись в качестве ключа шифрования и, следовательно, мог симметрично шифровать. - person Florian Moser; 18.01.2019
comment
@FlorianMoser, я только что обновил свой ответ, пожалуйста, проверьте - person fs_dm; 18.01.2019
comment
Опубликованный пример не может обеспечить тот же уровень безопасности, что и подход, который я описал выше (шифрование/дешифрование пароля с использованием подписи над фиксированным сообщением): с решением из вашего ответа, если удалить вызов Windows Hello (например, в обновлении с ошибками) вход в систему завершится успешно! Это невозможно при использовании подписи, поскольку расшифровка невозможна без подписи Windows Hello. Я сформулирую, как я решил вопрос, именно как ответ, как только найду время. Ваш ответ по-прежнему правильный; и я мог бы сделать это таким образом. - person Florian Moser; 20.01.2019
comment
@FlorianMoser Использовали ли вы «KeyCredentialManager» в своем подходе? - person fs_dm; 21.01.2019