一、签名步骤
设备请求报文示例:
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(); }}}