开发自有App一键配网时,如果您不希望终端用户在添加设备时选择设备型号,可以采用本文档介绍的固定密钥加密WiFi热点的方案。

背景信息

一键配网方案默认从云端获取加密密钥,对热点信息加密后传输给设备。其中每个产品使用的加密密钥不同,因此终端用户在添加设备时需要选择设备的产品型号(如下图中标注2所示)。

流程

使用一键配网固定密钥方案后,终端用户选择品类后直接显示连接WiFi的界面(即省掉了图中标注2所示)。一键配网固定密钥方案的原理如下。

  1. 自定义加密WiFi热点的密码。
  2. 将加密后的热点信息发送给设备(设备上需要预置相应的解密密钥)。
  3. 设备收到手机发送的数据后,将热点信息解密后使用。
重要 固定密钥存在安全风险,您需要避免配网加密密钥泄露。一旦密钥泄露,攻击者可以在用户配网时获取到用户家庭WiFi的密码。

设备端开发

设备端开发主要需基于生活物联网平台SDK(V1.1.0及以上版本)的源码进行修改。

  1. 下载生活物联网平台SDK(V1.1.0及以上版本),请参见获取SDK
  2. 按照示例代码修改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);
    }
  3. 按照示例代码分别修改以下文件中的函数。

    待修改的函数如下:

    • 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端开发

  1. 在生活物联网平台的控制台上创建自有App,并依次完成集成安全图片、下载App SDK、SDK初始化等操作。
  2. 按照示例代码修改配网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);