物联网通信 签名方法

设备向平台发起 HTTP/HTTPS 请求时,请求报文中需包含签名信息(X-TC-Signature)以验证请求者身份。

相关产品
物联网通信 产品页,含版本规格、价格与购买入口。

一、签名步骤

设备请求报文示例:

curl -X POST https://ap-guangzhou.gateway.tencentdevices.com/device/register \\-H "Content-Type: application/json; charset=utf-8" \\-H "X-TC-Algorithm: hmacsha256" \\-H "X-TC-Timestamp: 155****065" \\-H "X-TC-Nonce: 5456" \\-H "X-TC-Signature: 2230eefd229f582d8b1b891af****b91597240707d778ab3738f756258d7652c" \\-d '{"ProductId":"ASJ****GX","DeviceName":"xyz"}'

二、1. 拼接签名字符串

StringToSign = HTTPRequestMethod + \\n + CanonicalHost + \\n + CanonicalURI + \\n + CanonicalQueryString + \\n + Algorithm + \\n + RequestTimestamp + \\n + Nonce + \\n + HashedCanonicalRequest

参数名称 描述
HTTPRequestMethod HTTP 请求方式, 支持 POST。
CanonicalHost HTTP 请求的 Host 地址。
CanonicalURI HTTP 请求 URI 。例如 https://ap-guangzhou.gateway.tencentdevices.com/device/register 的 URI 为 /device/register。
CanonicalQueryString 发起 HTTP 请求 URL 中的查询字符串,对于 POST 请求,固定为空字符串""。
Algorithm 签名方法。目前支持 hmacsha256 和 hmacsha1。
RequestTimestamp 请求时间戳,单位:秒。
Nonce 随机数。
HashedCanonicalRequest 请求正文 Hash 值。HTTP 请求正文做 SHA256 哈希,然后十六进制编码,最后编码串转换成小写字母。

根据以上的规则,示例中的规范签名串如下:

POSTap-guangzhou.gateway.tencentdevices.com/device/registerhmacsha256155****065545635e9c5b0e3ae67532d3c9f17ead6c902226****b1ff7f6e89887f1398934f064

三、2. 计算签名

·使用密钥签名,包括产品级密钥和设备级密钥,伪代码如下:

Signature = Base64_Encode(HMAC_SHA256(SignSecret, StringToSign))

参数名称 描述
SignSecret 签名密钥,如动态注册使用 ProductSecret,设备发布消息或上报日志则使用 psk。
StringToSign 待签名的字符串。

·使用证书签名,伪代码如下:

Signature = Base64_Encode(RSA_SHA256(PrivateKey, StringToSign))

参数名称 描述
PrivateKey 证书私钥,如设备发布消息或上报日志则使用设备的 X509 私钥证书。
StringToSign 待签名的字符串。

四、3. 组装请求报文

根据上述得到的签名串,最终完整的请求如下:

POST https://ap-guangzhou.gateway.tencentdevices.com/devregisterContent-Type: application/jsonHost: ap-guangzhou.gateway.tencentdevices.comX-TC-Algorithm: hmacsha256X-TC-Timestamp: 155****065X-TC-Nonce: 5456X-TC-Signature: 2230eefd229f582d8b1b891af71****1597240707d778ab3738f756258d7652c{"ProductId":"ASJ****GX","DeviceName":"xyz"}

五、C 语言示例代码

工程下载 后,在 Linux 环境进行编译,编译指令:

./cmake_build.sh

编译成功后,按如下指令执行签名示例:

./out/bin/qcloud-dynreg-sign product_id product_secretkey device_name

六、Python3 示例代码

import hashlibimport randomimport timeimport hmacimport base64if __name__ == '__main__': sign_format = '%s\\n%s\\n%s\\n%s\\n%s\\n%d\\n%d\\n%s' url_format = '%s://ap-guangzhou.gateway.tencentdevices.com/device/register' request_format = "{\\"ProductId\\":\\"%s\\",\\"DeviceName\\":\\"%s\\"}"device_name = 'dev***'product_id = 'JCZ****KXS'product_secret = 'X42fPqw********94cY5sQ1Y'request_text = request_format % (product_id, device_name)request_hash = hashlib.sha256(request_text.encode("utf-8")).hexdigest()nonce = random.randrange(2147483647)timestamp = int(time.time())sign_content = sign_format % ( "POST", "ap-guangzhou.gateway.tencentdevices.com", "/device/register", "", "hmacsha256", timestamp, nonce, request_hash)print("\\nsign_content: \\n" + sign_content)sign_base64 = base64.b64encode(hmac.new(product_secret.encode("utf-8"), sign_content.encode("utf-8"), hashlib.sha256).digest())print("sign_base64: " + str(sign_base64))

七、Java 示例代码

package com.tencent.iot.hub.device.java.core.sign;import org.json.JSONException;import org.json.JSONObject;import org.junit.Test;import java.nio.charset.Charset;import java.security.InvalidKeyException;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.util.Base64;import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import static junit.framework.TestCase.assertTrue;import static junit.framework.TestCase.fail;public class SignForHttpTest {private static final String HMAC_ALGO = "hmacsha256";@Testpublic void testSign() { try { JSONObject yourPayload = new JSONObject(); String signature = getSignature("YourProductId", "YourDeviceName", "YourDevicePsk", "YourTopicName", yourPayload, 0); System.out.println(signature); assertTrue(true); } catch (Exception e) { e.printStackTrace(); fail(); }}public static String getSignature(String productID, String deviceName, String devicePsk, String topicName, JSONObject payload, Integer qos) { int randNum = (int) (Math.random() * ((1 << 31) – 1)); int timestamp = (int) (System.currentTimeMillis() / 1000); final JSONObject obj = new JSONObject(); try { obj.put("ProductId", productID); obj.put("DeviceName", deviceName); obj.put("TopicName", topicName); obj.put("Payload", payload.toString()); obj.put("Qos", qos); } catch (JSONException e) { e.printStackTrace(); } String originRequest = obj.toString(); String hashedRequest = ""; try { MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] encodedhash = digest.digest(originRequest.getBytes(Charset.forName("UTF-8"))); hashedRequest = HMACSHA256.bytesToHexString(encodedhash); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } @SuppressWarnings("DefaultLocale") String signSourceStr = String.format("%s\\n%s\\n%s\\n%s\\n%s\\n%d\\n%d\\n%s", "POST", "ap-guangzhou.gateway.tencentdevices.com", "/device/publish", "", HMAC_ALGO, timestamp, randNum, hashedRequest ); return HMACSHA256.getSignature(signSourceStr.getBytes(), devicePsk.getBytes());}public static class HMACSHA256 { /** * 生成签名数据 * * @param data 待加密的数据 * @param key 加密使用的key * @return 生成16进制编码的字符串 */ public static String getSignature(byte[] data, byte[] key) { Mac mac; SecretKeySpec signKey = new SecretKeySpec(key, HMAC_ALGO); try { mac = Mac.getInstance(HMAC_ALGO); mac.init(signKey); byte[] rawHmac = mac.doFinal(data); return Base64.getEncoder().encodeToString(rawHmac); } catch (InvalidKeyException | NoSuchAlgorithmException e) { e.printStackTrace(); } return null; } /** * byte[]数组转换为16进制的字符串 * * @param bytes 要转换的字节数组 * @return 转换后的结果 */ private static String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(0xFF & bytes[i]); if (hex.length() == 1) { sb.append('0'); } sb.append(hex); } return sb.toString(); }}}

赞 (0)
上一篇 4天前
下一篇 4天前