# 辅助工具

为了方便验证设备接入的流程，我们提供了一些工具来帮助开发者生成密钥和设备签名，包括 shell 和 Java 两个版本。

**注意：这里的工具仅用于协助开发者验证流程和演示相关算法，只适合调试使用和开发参考，不推荐用于生产环境。建议开发者根据自己的使用场景进行二次开发。**

## 1. 获取工具

- **建议在 Linux 或 Mac OS 环境下使用。请先确认你的本机环境有 OpenSSL，建议使用 v1.1.1 版本。**
- **设备签名应在设备出厂前内置到设备中的安全区域，或是服务端签名完成后下发到设备使用。请不要在设备端进行签名流程。**

### shell 脚本示例代码

[Shell 脚本下载地址](https://github.com/wmpf/wmpf_demo_external/blob/master/assets/mmiot_ecdsa_sign.sh)

### Java 示例代码

可以通过下列方式集成

- jar 包：下载 [wmpf-signup-device-multi-platform-util-jvm-0.0.1.jar](https://github.com/wmpf/wmpf_demo_external/blob/master/assets/wmpf-signup-device-multi-platform-util-jvm-0.0.1.jar?raw=true)，并集成到你的 Java 项目中。
- 源码：你也可以根据下方的地址和命令自己编译该工具。
  - [源码地址](https://github.com/wmpf/wmpf_demo_external/tree/master/wmpf-activate-util)
  - 编译发布到 maven local：`./gradlew publishtomavenlocal`
  - [source jar](https://github.com/wmpf/wmpf_demo_external/blob/master/assets/wmpf-signup-device-multi-platform-util-jvm-0.0.1-sources.jar?raw=true)

此外，还需要在你的项目中添加下列依赖

- `org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72`
- `com.squareup.okhttp3:okhttp:4.7.2`
- `com.google.code.gson:gson:2.8.6`
- `org.jetbrains.kotlin:kotlin-stdlib-common:1.3.72`

## 2. 密钥生成

生成的公钥需[上传到微信终端合作平台](reg-device-info#_3-设置公钥)换取 `KeyVersion` ，私钥将用于生成设备签名。

### shell

```bash
sudo bash ./mmiot_ecdsa_sign.sh gen_ecdsa_key prikey_filepath pubkey_filepath
```

例如：
![](https://res8.wxqcloud.qq.com.cn/wxdoc/ac36ea9f-4e13-40a7-937f-15a79726d3cb.png)

执行成功后，终端输出 `gen_ecdsa_key succ prikey_path:prikey_filepaht pubkey_path:pubkey_filepath`，且在对应目录已生成两个文件，分别保存公钥与私钥。

### Java

```java
  // 设置该脚本的工作目录
  WmpfDeviceSignUpUtil.workingDir = System.getProperty("java.io.tmpdir")
  // 生成公私钥
  // 如果你已经有一对公私钥，分别将公私钥的文件名命名为 wmpfPublicKeyPath.key 和 wmpfPrivateKeyPath.key，放在 workingDir 下面即可，脚本会自动读取
  // 如果 workingDir 下没有找到公私钥，脚本会自动生成一组
  val (privateKey, publicKey) = WmpfDeviceSignUpUtil.getPrivateKeyPublicKeyPair()
  println("private key = [$privateKey]")
  println("public key = [$publicKey]")
```

## 3. 生成设备签名

### shell

调用 `mmiot_ecdsa_sign` 工具，输入 ProductId、deviceId、私钥文件，生成每个设备的签名 Signature 。

```bash
sudo bash ./mmiot_ecdsa_sign.sh gen_ecdsa_sign ProductId my_deivice_id prikey_filepath sign_filepath
```

`sign_filepath` 是你想要输出 Signature 的路径，比如 `/Users/mine/Desktop/sign/sign_file`。**路径是输出到文件，而不是文件夹**。

例如：

![](https://res8.wxqcloud.qq.com.cn/wxdoc/723e4d63-0fe8-48f8-af40-6dca7e0fd4d7.png)

可以看到，执行工具后，终端输出`gen_ecdsa_sign succ sign_file_path:sign_filepath`，且在对应路径下生成了该设备的签名文件。

**校验设备签名**

```bash
sudo bash ./mmiot_ecdsa_sign.sh verify_ecdsa_sign ProductId my_device_id pubkey_filepath sign_filepath
```

例如：
![](https://res8.wxqcloud.qq.com.cn/wxdoc/3c4223d4-2b48-4dcb-804b-040168ac8ecf.png)

### Java

```java
  val productId = "your-product-id-from-we-cooper"
  val deviceId = "your-customized-device-id"
  // TODO 上传公钥到「微信终端合作平台」
  // 获取Signature
  val signature = WmpfDeviceSignUpUtil.getSignature(
  productId,
  deviceId,
  privateKey
)
  println("signature = [$signature]")
  // 校验签名
  if (
    WmpfDeviceSignUpUtil.verifySignature(
      productId,
      deviceId,
      publicKey,
      signature
    )
  ) {
    println("verifySignature success")
  } else {
    println("verifySignature fail")
  }
```

## 4. 注册设备

Java 示例代码还提供了通过微信后台[注册设备](hardware-register)的参考实现。

### Java

```java
  val deviceInfo = DeviceInfo()
  deviceInfo.model_name = "your-model-name"
  deviceInfo.product_id = productId
  deviceInfo.device_id_list = Array(1) { deviceId }.toList()
  // 获取 accessToken
  // 入参：微信开放平台注册的移动应用 appId，移动应用 appSecret
  val accessTokenResp =
  WmpfDeviceSignUpUtil.getAccessToken("your-app-id", "your-app-secret")
  if (accessTokenResp.errcode == 0) {
    println("access token [${accessTokenResp.access_token}] expires = " + accessTokenResp.expires_in)
      // 添加设备信息到微信后台
      val resp = WmpfDeviceSignUpUtil.addDevicesToWeChatServer(
      accessToken = accessTokenResp.access_token,
      deviceInfo = deviceInfo
    )
    if (resp.errcode == 0) {
      println("addDevicesToWeChatServer resp success")
    }
  } else {
    println("get access token fail code = ${accessTokenResp.errcode}, msg = ${accessTokenResp.errmsg}")
  }
```
