开发自有App一键配网时,如果您不希望终端用户在添加设备时选择设备型号,可以采用本文档介绍的固定密钥加密WiFi热点的方案。
背景信息
一键配网方案默认从云端获取加密密钥,对热点信息加密后传输给设备。其中每个产品使用的加密密钥不同,因此终端用户在添加设备时需要选择设备的产品型号(如下图中标注2所示)。
使用一键配网固定密钥方案后,终端用户选择品类后直接显示连接WiFi的界面(即省掉了图中标注2所示)。一键配网固定密钥方案的原理如下。
- 自定义加密WiFi热点的密码。
- 将加密后的热点信息发送给设备(设备上需要预置相应的解密密钥)。
- 设备收到手机发送的数据后,将热点信息解密后使用。
重要 固定密钥存在安全风险,您需要避免配网加密密钥泄露。一旦密钥泄露,攻击者可以在用户配网时获取到用户家庭WiFi的密码。
设备端开发
设备端开发主要需基于生活物联网平台SDK(V1.1.0及以上版本)的源码进行修改。
- 下载生活物联网平台SDK(V1.1.0及以上版本),请参见获取SDK。
- 按照示例代码修改sdk/src/services/awss/awss_crypt.c文件中的aes_decrypt_string函数。
switch (sec_lvl) { case SEC_LVL_AES128_PRODUCT: { // 一型一密的密钥方案,即通过ProductKey,Random生成可以解码PassWord的key char product_sec[OS_PRODUCT_SECRET_LEN + 1] = {0}; os_product_get_secret(product_sec); cal_passwd(product_sec, random, key); memcpy(iv, random, sizeof(random)); break; } /************************需要您自行实现的部分(开始)****************************/ case SEC_LVL_AES128_FIXKEY: // SEC_LVL_AES128_FIXKEY = 6 { // 以下修改为您自定义固定密钥方案 memcpy(key, your_key, AES128_KEY_LEN); // 您将自定义安全存储的your_key,直接替换作为key的内容 cal_passwd(product_sec, random, key); memcpy(iv, random, sizeof(random)); break; } /************************需要您自行实现的部分(结束)****************************/ } if (decrypt) { // 使用生成的AES Key,解密出连接AP的PassWord p_aes128_t aes = os_aes128_init(key, iv, PLATFORM_AES_DECRYPTION); if (cbc == 1) { // 设置AP os_aes128_cbc_decrypt(aes, decoded, len / AES128_KEY_LEN / 2, plain); } else { // 设置smart config os_aes128_cfb_decrypt(aes, decoded, len, plain); } os_aes128_destroy(aes); }
- 按照示例代码分别修改以下文件中的函数。
待修改的函数如下:
- sdk/src/services/awss/awss_smartconfig.c文件中的zconfig_get_ssid_passwd函数
- sdk/src/services/awss/awss_smartconfig_mcast.c文件中的decode_passwd函数
- sdk/src/services/awss/awss_wps.c文件中的get_ssid_passwd_from_w函数
函数的修改示例如下。
/* CAN'T use snprintf here, because of SPACE char */ if (passwd_encrypt > PASSWD_ENCRYPT_CIPHER) { //使用aes128-cfb解密 decode_chinese(pbuf, passwd_len, tmp, &passwd_cipher_len, 6); passwd_len = passwd_cipher_len; memset(zc_passwd, 0, ZC_MAX_PASSWD_LEN); /************************需要您自行实现的部分(开始)*************************/ aes_decrypt_string((char *)tmp, (char *)zc_passwd, passwd_len, SEC_LVL_AES128_FIXKEY, 0); if (is_utf8((const char *)zc_passwd, passwd_len) == 0) { // 如果第一种方式解密的PassWord有乱码,则尝试用以下一型一密的方式再次解密 aes_decrypt_string((char *)tmp, (char *)zc_passwd, passwd_len, os_get_encrypt_type(), 0); if (is_utf8((const char *)zc_passwd, passwd_len) == 0) { void *tmp_mutex = zc_mutex; awss_trace("passwd err\r\n"); memset(zconfig_data, 0, sizeof(*zconfig_data)); zc_mutex = tmp_mutex; awss_event_post(AWSS_PASSWD_ERR); ret = -1; goto exit; } } /**********************需要您自行实现的部分(结束)**************************/ else ... }
App端开发
- 在生活物联网平台的控制台上创建自有App,并依次完成集成安全图片、下载App SDK、SDK初始化等操作。
- 创建自有App,请参见创建自有App。
- 集成安全图片,请参见集成安全图片。
- 下载App SDK,并确保已勾选配网套餐项,请参见下载并集成SDK。
- SDK初始化,请参见SDK初始化(Android)与SDK初始化(iOS)。
- 按照示例代码修改配网SDK。
- iOS SDK
IMLCandDeviceModel *model = [[IMLCandDeviceModel alloc] init]; ... model.productEncryptKey = xxx; // 设置固定密钥 ... [kLkAddDevBiz setDevice:model]; // 设置待添加设备信息
- Android SDK
DeviceInfo info = new DeviceInfo(); // 32位hex string info.productEncryptKey = "xxx"; // 设置smart config info.linkType = LinkType.ALI_BROADCAST.getName(); AddDeviceBiz.getInstance().setDevice(info); AddDeviceBiz.getInstance().startAddDevice(context, callback);
- iOS SDK