Windows Hello 浅尝(2)

接着探索

上一篇讲了一个微软官方的Demo,这个Demo基本上已经把我们要做的事情做完了。

那么基于这个Demo,我说下我的思路。

1.首先是要在界面程序中枚举出蓝牙设备

2.为使用蓝牙设备的相关信息创建解锁用的Windows Hello设备

3.当task收到解锁事件的时候再次枚举蓝牙设备,然后判断每个枚举到的蓝牙设备有没有对应Windows Hello设备

4. 有就使用使用这个Windows Hello设备解锁电脑

那这样我先使用我的小米手环的信息创建对应的解锁设备,当我的手环在附近的时候Task就能枚举到它从而解锁,当手环不在附近的时候Task自然就枚举不到它,于是就不能使用Windows Hello解锁。

开始实践

关于枚举蓝牙设备,我又在微软的官方例子中找到了Demo

Demo地址:https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing

这个Demo就展示了使用DeviceWatch去枚举设备

DeviceWatcher m_deviceWatcher;
string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" };
m_deviceWatcher = DeviceInformation.CreateWatcher("(System.Devices.Aep.ProtocolId:=\"{bb7bb05e-5972-42b5-94fc-76eaa7084d49}\")",
//m_deviceWatcher = DeviceInformation.CreateWatcher("(System.Devices.Aep.ProtocolId:=\"{e0cbf06c-cd8b-4647-bb8a-263b43f0f974}\")",
                                                  requestedProperties,
                                                  DeviceInformationKind.AssociationEndpoint);

m_deviceWatcher.Added += DeviceWatcher_Added;
m_deviceWatcher.Updated += DeviceWatcher_Updated;
m_deviceWatcher.Removed += DeviceWatcher_Removed;
m_deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;
m_deviceWatcher.Stopped += DeviceWatcher_Stopped;
m_deviceWatcher.Start();

这个代码应该是一目了然的, 其中的关键就在于CreateWatcher时候使用的参数 {bb7bb05e-5972-42b5-94fc-76eaa7084d49} 能枚举到小米手环,但是枚举不到手机 {e0cbf06c-cd8b-4647-bb8a-263b43f0f974} 则相反,能枚举到手机但是枚举不到小米手环。

这个类还能枚举到其他很多的设备,就靠CreateWatcher的参数具体可以看官方的Demo。

下面是接口的定义,其中 DeviceInformation 和 DeviceInformationUpdate 就包含了设备的信息

private void DeviceWatcher_Added(DeviceWatcher Sender, DeviceInformation DeviceInfo)
{

}

private void DeviceWatcher_Updated(DeviceWatcher Sender, DeviceInformationUpdate DeviceInfoUpdate)
{

}

private void DeviceWatcher_Removed(DeviceWatcher Sender, DeviceInformationUpdate DeviceInfoUpdate)
{

}

private void DeviceWatcher_EnumerationCompleted(DeviceWatcher Sender, object e)
{

}

private void DeviceWatcher_Stopped(DeviceWatcher Sender, object e)
{

}

基本属性都有对应的变量,而我在CreateWatcher的时候附加的属性  string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" }; 会以键值对的形式保存在 DeviceInformation 和 DeviceInformationUpdate 的 Properties中

我首先在界面程序中使用这套接口枚举到了我的手环,基本信息是这样的

DeviceID: BluetoothLE#BluetoothLExx:xx:xx:xx:xx:xx-xx:xx:xx:xx:xx:xx

Name: MI Band 2

一开始我是想直接使用 BluetoothLE#BluetoothLExx:xx:xx:xx:xx:xx-xx:xx:xx:xx:xx:xx 这个ID去创建解锁设备的,但是发现都失败,实验下来可能是只能使用GUID去创建解锁设备。于是我就需要把 BluetoothLE#BluetoothLExx:xx:xx:xx:xx:xx-xx:xx:xx:xx:xx:xx 也存储起来,存储的思路

其实例子中也给出了就是存在解锁设备的  DeviceConfigurationData  中,因为 我还要在 DeviceConfigurationData 中还要存储解锁用的两个密码,所以我干脆就将在 DeviceConfigurationData  中存储JSON格式的数据,专门写了个序列化很反序列化的类。

public class JsonData
{

    public string Sign { get; set; }

    public string DeviceID { get; set; }

    public string DeviceKey { get; set; }

    public string AuthKey { get; set; }

    public bool CanUnLock { get; set; }
}

public class CMyHelloWinJson
{

    public static JsonData ParesToData(string js)
    {
        JsonData rv = null;
        try
        {
            JsonObject schoolObject = JsonObject.Parse(js);
            if (schoolObject != null)
            {
                rv = new JsonData();
                rv.Sign = schoolObject.GetNamedString("Sign");
                rv.DeviceID = schoolObject.GetNamedString("DeviceID");
                rv.DeviceKey = schoolObject.GetNamedString("DeviceKey");
                rv.AuthKey = schoolObject.GetNamedString("AuthKey");
                rv.CanUnLock = schoolObject.GetNamedBoolean("CanUnLock");
            }
        }catch(Exception e)
        {
            return rv;
        }

        return rv;
    }

    public static string ParesToJson(JsonData Dat)
    {
        JsonObject schoolObject = new JsonObject();
        schoolObject.SetNamedValue("Sign", JsonValue.CreateStringValue(Dat.Sign));
        schoolObject.SetNamedValue("DeviceID", JsonValue.CreateStringValue(Dat.DeviceID));
        schoolObject.SetNamedValue("DeviceKey", JsonValue.CreateStringValue(Dat.DeviceKey));
        schoolObject.SetNamedValue("AuthKey", JsonValue.CreateStringValue(Dat.AuthKey));
        schoolObject.SetNamedValue("CanUnLock", JsonValue.CreateBooleanValue(Dat.CanUnLock));
        return schoolObject.ToString();
    }
}

所以在界面中创建解锁设备的代码就变成了这样

string modelnumber = "MyHelloWin";

// 随机数转 string 可能会丢失信息的
byte[] deviceKeyArray = new byte[32];
byte[] authKeyArray = new byte[32];

IBuffer deviceKey = CryptographicBuffer.CreateFromByteArray(deviceKeyArray);
IBuffer authKey = CryptographicBuffer.CreateFromByteArray(authKeyArray);

JsonData Dat = new JsonData();
Dat.Sign = "MyHellowin";

Dat.DeviceKey = System.Text.Encoding.UTF8.GetString(deviceKeyArray);

Dat.AuthKey = System.Text.Encoding.UTF8.GetString(authKeyArray);

Dat.DeviceID = DeviceID;

Dat.CanUnLock = false;

string js = CMyHelloWinJson.ParesToJson(Dat);
byte[] signArry = System.Text.Encoding.UTF8.GetBytes(js);
IBuffer deviceConfigData = CryptographicBuffer.CreateFromByteArray(signArry);
String deviceGUId = System.Guid.NewGuid().ToString();
int state = await WinHello.RegisterDeviceAsync(deviceGUId, bleDeviceDisplay.DeviceName, modelnumber, deviceConfigData, deviceKey, authKey);

// 注册
SecondaryAuthenticationFactorDeviceCapabilities Capabilities = SecondaryAuthenticationFactorDeviceCapabilities.SecureStorage;
SecondaryAuthenticationFactorRegistrationResult RegistrationResult = await SecondaryAuthenticationFactorRegistration.RequestStartRegisteringDeviceAsync(DervicesID,
        Capabilities,
        FriendlyName,
        ModelNumber,
        deviceKey,
        authKey);
if (RegistrationResult.Status == SecondaryAuthenticationFactorRegistrationStatus.Started) {
    await RegistrationResult.Registration.FinishRegisteringDeviceAsync(DerviceContext);
}

return (int)RegistrationResult.Status;

界面写好了,那么解锁的时候思路大致就是这样的

先是枚举出所有的蓝牙设备,使用和上面相同的方法。

private void DeviceWatcher_Added(DeviceWatcher Sender, DeviceInformation DeviceInfo)
{

  IReadOnlyList<SecondaryAuthenticationFactorInfo> deviceList = await SecondaryAuthenticationFactorRegistration.FindAllRegisteredDeviceInfoAsync(SecondaryAuthenticationFactorDeviceFindScope.AllUsers);
  for (int i = 0; i < deviceList.Count; i++)
  {
      SecondaryAuthenticationFactorInfo deviceInfo = deviceList.ElementAt(i);

      byte[] combinedDataArray;
      CryptographicBuffer.CopyToByteArray(deviceInfo.DeviceConfigurationData, out combinedDataArray);
      string JS = System.Text.Encoding.UTF8.GetString(combinedDataArray);
      JsonData Dat = CMyHelloWinJson.ParesToData(JS);

      if (Dat == null)
      {
          continue;
      }

      if (String.Equals(Dat.DeviceID, DeviceInfo.DeviceID)) { // 使用这个设备进行解锁  }   }}

具体解锁的方法,上面一篇文章中有相应的介绍。或者你直接看我写的Demo: http://git.oschina.net/alwaysking/MyHelloWin

然而,当我天真的这样就搞定的时候,来了个晴天霹雳,因为在Task中使用DeviceWatcher枚举设备的时候他的回调函数根本不会被触发。注意我的蓝牙设备是配对的设备。

解决方法也是有的,我们下一篇再讲

时间: 2024-11-09 04:37:52

Windows Hello 浅尝(2)的相关文章

浅尝MongoDB

浅尝MongoDB NoSQL Mongo 数据库 安装mongoDB Linux 以linux环境为例,安装mongodb,最简单的方式就是 利用自带的包管理器 我的环境是 linux deepin 15.4 (基于debian 8) sudo apt install mongodb ~$ mongo -version MongoDB shell version: 3.2.11 当你看到这个说明你的mogodb已经安装完成. Windows 略 windows很容易 去官网下个包,无脑下一步即

Python图形界面开发编程:wxPython(浅尝篇)

Python 提供了多个图形开发界面的库,几个常用 Python GUI 库如下: Tkinter: Tkinter 模块(Tk 接口)是 Python 的标准 Tk GUI 工具包的接口 .Tk 和 Tkinter 可以在大多数的 Unix 平台下使用,同样可以应用在 Windows 和 Macintosh 系统里.Tk8.0 的后续版本可以实现本地窗口风格,并良好地运行在绝大多数平台中. wxPython:wxPython 是一款开源软件,是 Python 语言的一套优秀的 GUI 图形库,

浅尝awk

前几天写了sed,这次来继续学习一下它的好兄弟,awk,用了两者,一个这样的感觉,两者都可以用来处理匹配,如果想对文本做处理,sed的删除,匹配,替换要用的频繁一些,如果要深入文本的每一行,对每一行进行一些列处理,例如,统计,然后格式化输出,awk就可以派上用场了 查看自己ubuntu当前的awk which awk,其实用的是/usr/bin/mawk 在学习sed篇中,我们知道,sed是读取文本的每一行到一个模式空间,然后对模式空间的内容进行处理,其实awk差不多,它也是对模式空间进行处理,

浅尝key-value数据库(二)——MongoDB的优与劣

浅尝key-value数据库(二)——MongoDB的优与劣 MongoDB的名字取自英文单词"humongous"的中间五个字母,是一个C++开发的基于分布式文件存储的数据库开源项目.他的文件存储格式是BSON(Binary JSON),因此可以高效存储二进制数据,例如图像.视频等大对象. 由于我是CentOS x86_64的系统,于是安装MongoDB非常简单: vi /etc/yum.repos.d/mongo.repo [10gen] name=10gen Repository

浅尝key-value数据库(一)——一览NoSQL

浅尝key-value数据库(一)——一览NoSQL 最近由于一个项目的关系,研究了一下key-value数据库这个最近很火的概念.本系列从项目需求的角度分析并测试了几个key-value数据库的性能. key-value数据库,又称作NoSQL数据库,他的最基本的基础原理就是CAP. CAP是2000年PODC上Eric Brewer提出的一个概念,即 C -> Consistency; A -> Availability; P -> Tolerance to network Part

浅尝key-value数据库(三)——MongoDB的分布式

浅尝key-value数据库(三)——MongoDB的分布式 测试了单机MongoDB的随机读和写入性能,这一节来讲一讲MongoDB的分布式. MongoDB的分布式分成两种,一种是Replication,一种是Sharding.我们主要来看一下Sharding. 先贴一张结构示意图: MongoDB Auto-Sharding的配置非常简单,在不同的机器分别开启shard, config server, mongos的进程即可.(假设config serevr的IP为192.168.1.11

浅尝ECMAScript6

浅尝ECMAScript6 简介 ECMAScript6 是最新的ECMAScript标准,于2015年6月正式推出(所以也称为ECMAScript 2015),相比于2009年推出的es5, es6定义了更加丰富的语言特性,基于该标准的Javascript语言也迎来了语法上的重大变革.本文列举了部分es6新特性,希望之前没接触es6的小伙伴读完本文能对下一代js编程有一个初步的认识. 箭头函数 箭头函数用 "=>"简化函数定义,类似于C#, Java8中的Lambda表达式,支

浅尝CKRule规则引擎

最近在参与一家材料公司的ERP系统开发,主要负责仓储系统.由于该公司的业务流程相对复杂且多变,做得那是万般痛苦,成天沉浸在业务变更代码大改的死循环里,久而久之,有种遥遥无期的绝望. 怎样才能很好或者说比较轻松的去适应这样的复杂业务变化?最近真没少在园里看大神们的贴子,但是收获甚微,也许是我个人理解的深度不够.前两天无聊的时候,把心里的唠叨在圈子里发了下,后来有人给我推荐了个叫“CKRule”的规则引擎.规则引擎?小弟孤陋寡闻还是第一次听,一番百度后找到了CKRule的官网,果断下载了试用版.文件

来自后端的突袭? --开包即食的教程带你浅尝最新开源的C# Web引擎 Blazor

来自后端的突袭? --开包即食的教程带你浅尝最新开源的C# Web引擎 Blazor 在今年年初, 恰逢新春佳节临近的时候. 微软给全球的C#开发者们, 着实的送上了一分惊喜. 微软正式开源Blazor ,将.NET带回到浏览器. 这个小惊喜, 迅速的在dotnet开发者中间传开了. 而就在昨天(2018年3月22日) Blazor发布了它的第一次Release. Blazor到底是个什么样的东西呢?我们是否真的可以携着C#语言进入前端的市场中? 不如现在就跟我一起体验dotnet blazor