概述
腾讯物联网云平台 密钥 MQTT参数生成及密码加密算法实现
- 腾讯云三元组
腾讯云三元组
首先在腾讯物联网云平台创建好项目、产品、设备,然后获取该设备的三元组。下面通过我的创建的产品作为示例:
ProductID:IAYFFH3EO2
DeviceName:dev3
DeviceSecret: xjOShbtCetQmvEaJ75RJ1g==
#获取clinetID、Username、Password
clientID:IAYFFH3EO2dev3(ProductID+DeviceName)
Username:IAYFFH3EO2dev3;12010126;HD3CI;1635759071(
c
l
i
e
n
t
i
d
;
{clientid};
clientid;{sdkappid};
c
o
n
n
i
d
;
{connid};
connid;{expiry})
sdkappid、connid可随机生成,但注意字符个数sdkappid为8个字符,connid为5个字符。expiry为失效时间戳,即超过该时间戳后该密钥失效。Username可通过后面的加密算法自动生成,不需要自行生成。
Password:password 是由Username和DeviceSecret进行hmacSha1或者hmacSha256生成的,而且DeviceSecret是通过base64加密生成的,在生成Password前需要DeviceSecret解密base64,再进行hmacSha1或者hmacSha256加密生成。
腾讯云也提供了几种语言的算法实现,目前试过python的脚本是hmacsha256算法脚本且能正常生成参数但是我们是进行C开发的所以不适合通过调用python脚本来生成。其提供的C是hmacsha1算法但是工程不完整的而且是HAL平台的。本人通过下载腾讯云的sdk将一部分代码提取了出来,实现c通过hmacsha1算法生成clientID、Username、Password。
test.c
#include "limits.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "utils_base64.h"
#include "utils_hmac.h"
#include <time.h>
#include <string.h>
/* Max size of base64 encoded PSK = 64, after decode: 64/4*3 = 48*/
#define DECODE_PSK_LENGTH 48
/* MAX valid time when connect to MQTT server. 0: always valid */
/* Use this only if the device has accurate UTC time. Otherwise, set to 0 */
#define MAX_ACCESS_EXPIRE_TIMEOUT (60 * 1000)
//过期时间我这里设置的是1分钟,只要每次连接前都生成一次这里可以设置为0
/* Max size of conn Id
*/
#define MAX_CONN_ID_LEN (6)
/* IoT C-SDK APPID */
#define QCLOUD_IOT_DEVICE_SDK_APPID
"12010126"
//sdkappid设置的固定值
#define QCLOUD_IOT_DEVICE_SDK_APPID_LEN (sizeof(QCLOUD_IOT_DEVICE_SDK_APPID) - 1)
static void HexDump(uint8_t *pData, uint16_t len)
{
int i;
for (i = 0; i < len; i++) {
if (i % 32 == 0) {
printf("n");
}
printf(" %02X", pData[i]);
}
printf("n");
}
int main(int argc, char **argv)
{
char *product_id
= NULL;
char *device_name
= NULL;
char *device_secret = NULL;
char *username
= NULL;
int
username_len = 0;
char
conn_id[MAX_CONN_ID_LEN];
char password[51]
= {0};
char username_sign[41] = {0};
char
psk_base64decode[DECODE_PSK_LENGTH];
size_t psk_base64decode_len = 0;
long cur_timestamp = 0;
if (argc != 4) {
printf("please ./qcloud-mqtt-sign product_id device_name device_secretrn");
return -1;
}
product_id
= argv[1];
device_name
= argv[2];
device_secret = argv[3];
/* first device_secret base64 decode */
qcloud_iot_utils_base64decode((unsigned char *)psk_base64decode, DECODE_PSK_LENGTH, &psk_base64decode_len,(unsigned char *)device_secret, strlen(device_secret));
//base64_decode(device_secret, psk_base64decode);
printf("device_secret base64 decode:");
HexDump(psk_base64decode, psk_base64decode_len);
/* second create mqtt username
* [productdevicename;appid;randomconnid;timestamp] */
cur_timestamp = time(NULL) + MAX_ACCESS_EXPIRE_TIMEOUT / 1000;
if (cur_timestamp <= 0 || MAX_ACCESS_EXPIRE_TIMEOUT <= 0) {
cur_timestamp = LONG_MAX;
}
// 20 for timestampe length & delimiter
username_len = strlen(product_id) + strlen(device_name) + QCLOUD_IOT_DEVICE_SDK_APPID_LEN + MAX_CONN_ID_LEN + 20;
username
= (char *)malloc(username_len);
if (username == NULL) {
printf("malloc username failed!rn");
return -1;
}
snprintf(username, username_len, "%s%s;%s;%s;%ld", product_id, device_name, QCLOUD_IOT_DEVICE_SDK_APPID,"HD3CI", cur_timestamp);
//connid设置的固定值HD3CI
/* third use psk_base64decode hamc_sha1 calc mqtt username sign crate mqtt
* password */
utils_hmac_sha1(username, strlen(username), username_sign, psk_base64decode, psk_base64decode_len);
//Hmacsha256_enc(psk_base64decode,psk_base64decode_len,username,strlen(username),username_sign);
printf("username sign: %srn", username_sign);
snprintf(password, 51, "%s;hmacsha1", username_sign);
printf("Client ID: %s%srn", product_id, device_name);
printf("username : %srn", username);
printf("password : %srn", password);
free(username);
return 0;
}
utils_base64.c
/*
* Tencent is pleased to support the open source community by making IoT Hub
available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file
except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software
distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND,
* either express or implied. See the License for the specific language
governing permissions and
* limitations under the License.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "utils_base64.h"
#include <stdint.h>
#include <stdlib.h>
static const unsigned char base64_enc_map[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
static const unsigned char base64_dec_map[128] = {
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 62,
127, 127, 127, 63,
52,
53,
54,
55,
56,
57,
58,
59,
60,
61,
127, 127, 127, 64,
127, 127, 127, 0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
127, 127, 127, 127, 127, 127, 26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36,
37,
38,
39,
40,
41,
42,
43,
44,
45,
46,
47,
48,
49,
50,
51,
127, 127, 127, 127, 127};
#define BASE64_SIZE_T_MAX ((size_t)-1) /* SIZE_T_MAX is not standard */
int qcloud_iot_utils_base64encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen)
{
size_t
i, n;
unsigned char *p;
if (slen == 0) {
*olen = 0;
return (0);
}
n = slen / 3 + (slen % 3 != 0);
if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
*olen = BASE64_SIZE_T_MAX;
return (QCLOUD_ERR_FAILURE);
}
n *= 4;
if ((dlen < n + 1) || (NULL == dst)) {
*olen = n + 1;
return (QCLOUD_ERR_FAILURE);
}
n = (slen / 3) * 3;
int C1, C2, C3;
for (i = 0, p = dst; i < n; i += 3) {
C1 = *src++;
C2 = *src++;
C3 = *src++;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
*p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
*p++ = base64_enc_map[C3 & 0x3F];
}
if (i < slen) {
C1 = *src++;
C2 = ((i + 1) < slen) ? *src++ : 0;
*p++ = base64_enc_map[(C1 >> 2) & 0x3F];
*p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
if ((i + 1) < slen)
*p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
else
*p++ = '=';
*p++ = '=';
}
*olen = p - dst;
*p
= 0;
return (0);
}
int qcloud_iot_utils_base64decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen)
{
size_t
i, n;
uint32_t
j, x;
unsigned char *p;
/* First pass: check for validity and get output length */
for (i = n = j = 0; i < slen; i++) {
/* Skip spaces before checking for EOL */
x = 0;
while (i < slen && src[i] == ' ') {
++i;
++x;
}
/* Spaces at end of buffer are OK */
if (i == slen)
break;
if ((slen - i) >= 2 && src[i] == 'r' && src[i + 1] == 'n')
continue;
if (src[i] == 'n')
continue;
/* Space inside a line is an error */
if (x != 0)
return (QCLOUD_ERR_FAILURE);
if (src[i] == '=' && ++j > 2)
return (QCLOUD_ERR_FAILURE);
if (src[i] > 127 || base64_dec_map[src[i]] == 127)
return (QCLOUD_ERR_FAILURE);
if (base64_dec_map[src[i]] < 64 && j != 0)
return (QCLOUD_ERR_FAILURE);
n++;
}
if (n == 0) {
*olen = 0;
return (0);
}
n = ((n * 6) + 7) >> 3;
n -= j;
if (dst == NULL || dlen < n) {
*olen = n;
return (QCLOUD_ERR_FAILURE);
}
for (j = 3, n = x = 0, p = dst; i > 0; i--, src++) {
if (*src == 'r' || *src == 'n' || *src == ' ')
continue;
j -= (base64_dec_map[*src] == 64);
x = (x << 6) | (base64_dec_map[*src] & 0x3F);
if (++n == 4) {
n = 0;
if (j > 0)
*p++ = (unsigned char)(x >> 16);
if (j > 1)
*p++ = (unsigned char)(x >> 8);
if (j > 2)
*p++ = (unsigned char)(x);
}
}
*olen = p - dst;
return (0);
}
#ifdef __cplusplus
}
#endif
utils_base64.h
/*
* Tencent is pleased to support the open source community by making IoT Hub
available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file
except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software
distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND,
* either express or implied. See the License for the specific language
governing permissions and
* limitations under the License.
*
*/
#ifndef QCLOUD_IOT_UTILS_BASE64_H_
#define QCLOUD_IOT_UTILS_BASE64_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include "qcloud_iot_export_error.h"
int qcloud_iot_utils_base64encode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
int qcloud_iot_utils_base64decode(unsigned char *dst, size_t dlen, size_t *olen, const unsigned char *src, size_t slen);
#ifdef __cplusplus
}
#endif
#endif /* QCLOUD_IOT_UTILS_BASE64_H_ */
qcloud_iot_export_error.h
/*
* Tencent is pleased to support the open source community by making IoT Hub
available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file
except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software
distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND,
* either express or implied. See the License for the specific language
governing permissions and
* limitations under the License.
*
*/
#ifndef QCLOUD_IOT_EXPORT_ERROR_H_
#define QCLOUD_IOT_EXPORT_ERROR_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* IOT SDK return/error code
* Enumeration of return code in QCloud IoT C-SDK.
* Values less than 0 are specific error codes
* Value of 0 is successful return
* Values greater than 0 are specific non-error return codes
*/
typedef enum {
QCLOUD_RET_MQTT_ALREADY_CONNECTED
= 4,
// Already connected with MQTT server
QCLOUD_RET_MQTT_CONNACK_CONNECTION_ACCEPTED = 3,
// MQTT connection accepted by server
QCLOUD_RET_MQTT_MANUALLY_DISCONNECTED
= 2,
// Manually disconnected with MQTT server
QCLOUD_RET_MQTT_RECONNECTED
= 1,
// Reconnected with MQTT server successfully
QCLOUD_RET_SUCCESS = 0,
// Successful return
QCLOUD_ERR_FAILURE
= -1001,
// Generic failure return
QCLOUD_ERR_INVAL
= -1002,
// Invalid parameter
QCLOUD_ERR_DEV_INFO = -1003,
// Fail to get device info
QCLOUD_ERR_MALLOC
= -1004,
// Fail to malloc memory
QCLOUD_ERR_HTTP_CLOSED
= -3,
// HTTP server close the connection
QCLOUD_ERR_HTTP
= -4,
// HTTP unknown error
QCLOUD_ERR_HTTP_PRTCL
= -5,
// HTTP protocol error
QCLOUD_ERR_HTTP_UNRESOLVED_DNS = -6,
// HTTP DNS resolve failed
QCLOUD_ERR_HTTP_PARSE
= -7,
// HTTP URL parse failed
QCLOUD_ERR_HTTP_CONN
= -8,
// HTTP connect failed
QCLOUD_ERR_HTTP_AUTH
= -9,
// HTTP auth failed
QCLOUD_ERR_HTTP_NOT_FOUND
= -10,
// HTTP 404
QCLOUD_ERR_HTTP_TIMEOUT
= -11,
// HTTP timeout
QCLOUD_ERR_MQTT_PUSH_TO_LIST_FAILED
= -102,
// Fail to push node to MQTT waiting list
QCLOUD_ERR_MQTT_NO_CONN
= -103,
// Not connected with MQTT server
QCLOUD_ERR_MQTT_UNKNOWN
= -104,
// MQTT unknown error
QCLOUD_ERR_MQTT_ATTEMPTING_RECONNECT
= -105,
// Reconnecting with MQTT server
QCLOUD_ERR_MQTT_RECONNECT_TIMEOUT
= -106,
// MQTT reconnect timeout
QCLOUD_ERR_MQTT_MAX_SUBSCRIPTIONS
= -107,
// MQTT topic subscription out of range
QCLOUD_ERR_MQTT_SUB
= -108,
// MQTT topic subscription fail
QCLOUD_ERR_MQTT_NOTHING_TO_READ
= -109,
// MQTT nothing to read
QCLOUD_ERR_MQTT_PACKET_READ
= -110,
// Something wrong when reading MQTT packet
QCLOUD_ERR_MQTT_REQUEST_TIMEOUT
= -111,
// MQTT request timeout
QCLOUD_ERR_MQTT_CONNACK_UNKNOWN
= -112,
// MQTT connection refused: unknown error
QCLOUD_ERR_MQTT_CONNACK_UNACCEPTABLE_PROTOCOL_VERSION = -113,
// MQTT connection refused: protocol version invalid
QCLOUD_ERR_MQTT_CONNACK_IDENTIFIER_REJECTED
= -114,
// MQTT connection refused: identifier rejected
QCLOUD_ERR_MQTT_CONNACK_SERVER_UNAVAILABLE
= -115,
// MQTT connection refused: service not available
QCLOUD_ERR_MQTT_CONNACK_BAD_USERDATA
= -116,
// MQTT connection refused: bad user name or password
QCLOUD_ERR_MQTT_CONNACK_NOT_AUTHORIZED
= -117,
// MQTT connection refused: not authorized
QCLOUD_ERR_RX_MESSAGE_INVAL
= -118,
// MQTT received invalid msg
QCLOUD_ERR_BUF_TOO_SHORT
= -119,
// MQTT recv buffer not enough
QCLOUD_ERR_MQTT_QOS_NOT_SUPPORT
= -120,
// MQTT QoS level not supported
QCLOUD_ERR_MQTT_UNSUB_FAIL
= -121,
// MQTT unsubscribe failed
QCLOUD_ERR_JSON_PARSE
= -132,
// JSON parsing error
QCLOUD_ERR_JSON_BUFFER_TRUNCATED = -133,
// JSON buffer truncated
QCLOUD_ERR_JSON_BUFFER_TOO_SMALL = -134,
// JSON parsing buffer not enough
QCLOUD_ERR_JSON
= -135,
// JSON generation error
QCLOUD_ERR_MAX_JSON_TOKEN
= -136,
// JSON token out of range
QCLOUD_ERR_MAX_APPENDING_REQUEST = -137,
// appending request out of range
QCLOUD_ERR_MAX_TOPIC_LENGTH
= -138,
// Topic length oversize
QCLOUD_ERR_COAP_NULL
= -150,
// COAP null pointer
QCLOUD_ERR_COAP_DATA_SIZE
= -151,
// COAP data size out of range
QCLOUD_ERR_COAP_INTERNAL
= -152,
// COAP interval error
QCLOUD_ERR_COAP_BADMSG
= -153,
// COAP bad msg
QCLOUD_ERR_DTLS_PEER_CLOSE_NOTIFY = -160,
// DTLS connection is closed
QCLOUD_ERR_PROPERTY_EXIST
= -201,
// property already exist
QCLOUD_ERR_NOT_PROPERTY_EXIST = -202,
// property not exist
QCLOUD_ERR_REPORT_TIMEOUT
= -203,
// update timeout
QCLOUD_ERR_REPORT_REJECTED
= -204,
// update rejected by server
QCLOUD_ERR_GET_TIMEOUT
= -205,
// get timeout
QCLOUD_ERR_GET_REJECTED
= -206,
// get rejected by server
QCLOUD_ERR_ACTION_EXIST
= -210,
// acion already exist
QCLOUD_ERR_NOT_ACTION_EXIST = -211,
// acion not exist
QCLOUD_ERR_GATEWAY_CREATE_SESSION_FAIL = -221,
// Gateway fail to create sub-device session
QCLOUD_ERR_GATEWAY_SESSION_NO_EXIST
= -222,
// Gateway sub-device session not exist
QCLOUD_ERR_GATEWAY_SESSION_TIMEOUT
= -223,
// Gateway sub-device session timeout
QCLOUD_ERR_GATEWAY_SUBDEV_ONLINE
= -224,
// Gateway sub-device online
QCLOUD_ERR_GATEWAY_SUBDEV_OFFLINE
= -225,
// Gateway sub-device offline
QCLOUD_ERR_TCP_SOCKET_FAILED
= -601,
// TLS TCP socket connect fail
QCLOUD_ERR_TCP_UNKNOWN_HOST
= -602,
// TCP unknown host (DNS fail)
QCLOUD_ERR_TCP_CONNECT
= -603,
// TCP/UDP socket connect fail
QCLOUD_ERR_TCP_READ_TIMEOUT
= -604,
// TCP read timeout
QCLOUD_ERR_TCP_WRITE_TIMEOUT
= -605,
// TCP write timeout
QCLOUD_ERR_TCP_READ_FAIL
= -606,
// TCP read error
QCLOUD_ERR_TCP_WRITE_FAIL
= -607,
// TCP write error
QCLOUD_ERR_TCP_PEER_SHUTDOWN
= -608,
// TCP server close connection
QCLOUD_ERR_TCP_NOTHING_TO_READ = -609,
// TCP socket nothing to read
QCLOUD_ERR_SSL_INIT
= -701,
// TLS/SSL init fail
QCLOUD_ERR_SSL_CERT
= -702,
// TLS/SSL certificate issue
QCLOUD_ERR_SSL_CONNECT
= -703,
// TLS/SSL connect fail
QCLOUD_ERR_SSL_CONNECT_TIMEOUT = -704,
// TLS/SSL connect timeout
QCLOUD_ERR_SSL_WRITE_TIMEOUT
= -705,
// TLS/SSL write timeout
QCLOUD_ERR_SSL_WRITE
= -706,
// TLS/SSL write error
QCLOUD_ERR_SSL_READ_TIMEOUT
= -707,
// TLS/SSL read timeout
QCLOUD_ERR_SSL_READ
= -708,
// TLS/SSL read error
QCLOUD_ERR_SSL_NOTHING_TO_READ = -709,
// TLS/SSL nothing to read
QCLOUD_ERR_BIND_PARA_ERR
= -801,
// bind sub device param error
QCLOUD_ERR_BIND_SUBDEV_ERR
= -802,
// sub device not exist or illegal
QCLOUD_ERR_BIND_SIGN_ERR
= -803,
// signature check err
QCLOUD_ERR_BIND_SIGN_METHOD_RRR = -804,
// signmethod not supporte
QCLOUD_ERR_BIND_SIGN_EXPIRED
= -805,
// signature expired
QCLOUD_ERR_BIND_BEEN_BINDED
= -806,
// sub device has been binded by other gateway
QCLOUD_ERR_BIND_SUBDEV_FORBID
= -807,
// sub device not allow to bind
QCLOUD_ERR_BIND_OP_FORBID
= -808,
// operation not permit
QCLOUD_ERR_BIND_REPEATED_REQ
= -809,
// repeated bind request,has been binded
} IoT_Return_Code;
#ifdef __cplusplus
}
#endif
#endif /* QCLOUD_IOT_EXPORT_ERROR_H_ */
utils_hmac.c
/*
* Tencent is pleased to support the open source community by making IoT Hub
available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file
except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software
distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND,
* either express or implied. See the License for the specific language
governing permissions and
* limitations under the License.
*
*/
#include <stdint.h>
#include "utils_hmac.h"
#include <string.h>
#include "utils_md5.h"
#include "utils_sha1.h"
#define KEY_IOPAD_SIZE 64
#define MD5_DIGEST_SIZE
16
#define SHA1_DIGEST_SIZE 20
void utils_hmac_md5(const char *msg, int msg_len, char *digest, const char *key, int key_len)
{
if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
//Log_e("parameter is Null,failed!");
return;
}
if (key_len > KEY_IOPAD_SIZE) {
//Log_e("key_len > size(%d) of array", KEY_IOPAD_SIZE);
return;
}
iot_md5_context context;
unsigned char
k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
unsigned char
k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
unsigned char
out[MD5_DIGEST_SIZE];
int
i;
/* start out by storing key in pads */
memset(k_ipad, 0, sizeof(k_ipad));
memset(k_opad, 0, sizeof(k_opad));
memcpy(k_ipad, key, key_len);
memcpy(k_opad, key, key_len);
/* XOR key with ipad and opad values */
for (i = 0; i < KEY_IOPAD_SIZE; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/* perform inner MD5 */
utils_md5_init(&context);
/* init context for 1st pass */
utils_md5_starts(&context);
/* setup context for 1st pass */
utils_md5_update(&context, k_ipad, KEY_IOPAD_SIZE);
/* start with inner pad */
utils_md5_update(&context, (unsigned char *)msg, msg_len); /* then text of datagram */
utils_md5_finish(&context, out);
/* finish up 1st pass */
/* perform outer MD5 */
utils_md5_init(&context);
/* init context for 2nd pass */
utils_md5_starts(&context);
/* setup context for 2nd pass */
utils_md5_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */
utils_md5_update(&context, out, MD5_DIGEST_SIZE);
/* then results of 1st hash */
utils_md5_finish(&context, out);
/* finish up 2nd pass */
for (i = 0; i < MD5_DIGEST_SIZE; ++i) {
digest[i * 2]
= utils_hb2hex(out[i] >> 4);
digest[i * 2 + 1] = utils_hb2hex(out[i]);
}
}
void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len)
{
if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
//Log_e("parameter is Null,failed!");
return;
}
if (key_len > KEY_IOPAD_SIZE) {
//Log_e("key_len > size(%d) of array", KEY_IOPAD_SIZE);
return;
}
iot_sha1_context context;
unsigned char
k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
unsigned char
k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
unsigned char
out[SHA1_DIGEST_SIZE];
int
i;
/* start out by storing key in pads */
memset(k_ipad, 0, sizeof(k_ipad));
memset(k_opad, 0, sizeof(k_opad));
memcpy(k_ipad, key, key_len);
memcpy(k_opad, key, key_len);
/* XOR key with ipad and opad values */
for (i = 0; i < KEY_IOPAD_SIZE; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/* perform inner SHA */
utils_sha1_init(&context);
/* init context for 1st pass */
utils_sha1_starts(&context);
/* setup context for 1st pass */
utils_sha1_update(&context, k_ipad, KEY_IOPAD_SIZE);
/* start with inner pad */
utils_sha1_update(&context, (unsigned char *)msg, msg_len); /* then text of datagram */
utils_sha1_finish(&context, out);
/* finish up 1st pass */
/* perform outer SHA */
utils_sha1_init(&context);
/* init context for 2nd pass */
utils_sha1_starts(&context);
/* setup context for 2nd pass */
utils_sha1_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */
utils_sha1_update(&context, out, SHA1_DIGEST_SIZE);
/* then results of 1st hash */
utils_sha1_finish(&context, out);
/* finish up 2nd pass */
for (i = 0; i < SHA1_DIGEST_SIZE; ++i) {
digest[i * 2]
= utils_hb2hex(out[i] >> 4);
digest[i * 2 + 1] = utils_hb2hex(out[i]);
}
}
int utils_hmac_sha1_hex(const char *msg, int msg_len, char *digest, const char *key, int key_len)
{
if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
//Log_e("parameter is Null,failed!");
return 0;
}
if (key_len > KEY_IOPAD_SIZE) {
//Log_e("key_len > size(%d) of array", KEY_IOPAD_SIZE);
return 0;
}
iot_sha1_context context;
unsigned char
k_ipad[KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
unsigned char
k_opad[KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
unsigned char
out[SHA1_DIGEST_SIZE];
int
i;
/* start out by storing key in pads */
memset(k_ipad, 0, sizeof(k_ipad));
memset(k_opad, 0, sizeof(k_opad));
memcpy(k_ipad, key, key_len);
memcpy(k_opad, key, key_len);
/* XOR key with ipad and opad values */
for (i = 0; i < KEY_IOPAD_SIZE; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/* perform inner SHA */
utils_sha1_init(&context);
/* init context for 1st pass */
utils_sha1_starts(&context);
/* setup context for 1st pass */
utils_sha1_update(&context, k_ipad, KEY_IOPAD_SIZE);
/* start with inner pad */
utils_sha1_update(&context, (unsigned char *)msg, msg_len); /* then text of datagram */
utils_sha1_finish(&context, out);
/* finish up 1st pass */
/* perform outer SHA */
utils_sha1_init(&context);
/* init context for 2nd pass */
utils_sha1_starts(&context);
/* setup context for 2nd pass */
utils_sha1_update(&context, k_opad, KEY_IOPAD_SIZE); /* start with outer pad */
utils_sha1_update(&context, out, SHA1_DIGEST_SIZE);
/* then results of 1st hash */
utils_sha1_finish(&context, out);
/* finish up 2nd pass */
memcpy(digest, out, SHA1_DIGEST_SIZE);
return SHA1_DIGEST_SIZE;
}
utils_hmac.h
/*
* Tencent is pleased to support the open source community by making IoT Hub
available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file
except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software
distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND,
* either express or implied. See the License for the specific language
governing permissions and
* limitations under the License.
*
*/
#ifndef QCLOUD_IOT_UTILS_HMAC_H_
#define QCLOUD_IOT_UTILS_HMAC_H_
#include <string.h>
void utils_hmac_md5(const char *msg, int msg_len, char *digest, const char *key, int key_len);
void utils_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len);
int utils_hmac_sha1_hex(const char *msg, int msg_len, char *digest, const char *key, int key_len);
#endif
utils_md5.c
/*
* Tencent is pleased to support the open source community by making IoT Hub
available.
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file
except in
* compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software
distributed under the License is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND,
* either express or implied. See the License for the specific language
governing permissions and
* limitations under the License.
*
*/
#ifdef __cplusplus
extern "C" {
#endif
#include "utils_md5.h"
#include <stdlib.h>
#include <string.h>
#define MD5_DIGEST_SIZE 16
/* Implementation that should never be optimized out by the compiler */
static void _utils_md5_zeroize(void *v, size_t n)
{
volatile unsigned char *p = v;
while (n--) *p++ = 0;
}
/*
* 32-bit integer manipulation macros (little endian)
*/
#ifndef IOT_MD5_GET_UINT32_LE
#define IOT_MD5_GET_UINT32_LE(n, b, i)
{
(n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) | ((uint32_t)(b)[(i) + 2] << 16) |
((uint32_t)(b)[(i) + 3] << 24);
}
#endif
#ifndef IOT_MD5_PUT_UINT32_LE
#define IOT_MD5_PUT_UINT32_LE(n, b, i)
{
(b)[(i)]
= (unsigned char)(((n)) & 0xFF);
(b)[(i) + 1] = (unsigned char)(((n) >> 8) & 0xFF);
(b)[(i) + 2] = (unsigned char)(((n) >> 16) & 0xFF);
(b)[(i) + 3] = (unsigned char)(((n) >> 24) & 0xFF);
}
#endif
void utils_md5_init(iot_md5_context *ctx)
{
memset(ctx, 0, sizeof(iot_md5_context));
}
void utils_md5_free(iot_md5_context *ctx)
{
if (ctx == NULL) {
return;
}
_utils_md5_zeroize(ctx, sizeof(iot_md5_context));
}
void utils_md5_clone(iot_md5_context *dst, const iot_md5_context *src)
{
*dst = *src;
}
/*
* MD5 context setup
*/
void utils_md5_starts(iot_md5_context *ctx)
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
}
void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64])
{
uint32_t X[16], A, B, C, D;
IOT_MD5_GET_UINT32_LE(X[0], data, 0);
IOT_MD5_GET_UINT32_LE(X[1], data, 4);
IOT_MD5_GET_UINT32_LE(X[2], data, 8);
IOT_MD5_GET_UINT32_LE(X[3], data, 12);
IOT_MD5_GET_UINT32_LE(X[4], data, 16);
IOT_MD5_GET_UINT32_LE(X[5], data, 20);
IOT_MD5_GET_UINT32_LE(X[6], data, 24);
IOT_MD5_GET_UINT32_LE(X[7], data, 28);
IOT_MD5_GET_UINT32_LE(X[8], data, 32);
IOT_MD5_GET_UINT32_LE(X[9], data, 36);
IOT_MD5_GET_UINT32_LE(X[10], data, 40);
IOT_MD5_GET_UINT32_LE(X[11], data, 44);
IOT_MD5_GET_UINT32_LE(X[12], data, 48);
IOT_MD5_GET_UINT32_LE(X[13], data, 52);
IOT_MD5_GET_UINT32_LE(X[14], data, 56);
IOT_MD5_GET_UINT32_LE(X[15], data, 60);
#define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define P(a, b, c, d, k, s, t)
{
a += F(b, c, d) + X[k] + t;
a = S(a, s) + b;
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
#define F(x, y, z) (z ^ (x & (y ^ z)))
P(A, B, C, D, 0, 7, 0xD76AA478);
P(D, A, B, C, 1, 12, 0xE8C7B756);
P(C, D, A, B, 2, 17, 0x242070DB);
P(B, C, D, A, 3, 22, 0xC1BDCEEE);
P(A, B, C, D, 4, 7, 0xF57C0FAF);
P(D, A, B, C, 5, 12, 0x4787C62A);
P(C, D, A, B, 6, 17, 0xA8304613);
P(B, C, D, A, 7, 22, 0xFD469501);
P(A, B, C, D, 8, 7, 0x698098D8);
P(D, A, B, C, 9, 12, 0x8B44F7AF);
P(C, D, A, B, 10, 17, 0xFFFF5BB1);
P(B, C, D, A, 11, 22, 0x895CD7BE);
P(A, B, C, D, 12, 7, 0x6B901122);
P(D, A, B, C, 13, 12, 0xFD987193);
P(C, D, A, B, 14, 17, 0xA679438E);
P(B, C, D, A, 15, 22, 0x49B40821);
#undef F
#define F(x, y, z) (y ^ (z & (x ^ y)))
P(A, B, C, D, 1, 5, 0xF61E2562);
P(D, A, B, C, 6, 9, 0xC040B340);
P(C, D, A, B, 11, 14, 0x265E5A51);
P(B, C, D, A, 0, 20, 0xE9B6C7AA);
P(A, B, C, D, 5, 5, 0xD62F105D);
P(D, A, B, C, 10, 9, 0x02441453);
P(C, D, A, B, 15, 14, 0xD8A1E681);
P(B, C, D, A, 4, 20, 0xE7D3FBC8);
P(A, B, C, D, 9, 5, 0x21E1CDE6);
P(D, A, B, C, 14, 9, 0xC33707D6);
P(C, D, A, B, 3, 14, 0xF4D50D87);
P(B, C, D, A, 8, 20, 0x455A14ED);
P(A, B, C, D, 13, 5, 0xA9E3E905);
P(D, A, B, C, 2, 9, 0xFCEFA3F8);
P(C, D, A, B, 7, 14, 0x676F02D9);
P(B, C, D, A, 12, 20, 0x8D2A4C8A);
#undef F
#define F(x, y, z) (x ^ y ^ z)
P(A, B, C, D, 5, 4, 0xFFFA3942);
P(D, A, B, C, 8, 11, 0x8771F681);
P(C, D, A, B, 11, 16, 0x6D9D6122);
P(B, C, D, A, 14, 23, 0xFDE5380C);
P(A, B, C, D, 1, 4, 0xA4BEEA44);
P(D, A, B, C, 4, 11, 0x4BDECFA9);
P(C, D, A, B, 7, 16, 0xF6BB4B60);
P(B, C, D, A, 10, 23, 0xBEBFBC70);
P(A, B, C, D, 13, 4, 0x289B7EC6);
P(D, A, B, C, 0, 11, 0xEAA127FA);
P(C, D, A, B, 3, 16, 0xD4EF3085);
P(B, C, D, A, 6, 23, 0x04881D05);
P(A, B, C, D, 9, 4, 0xD9D4D039);
P(D, A, B, C, 12, 11, 0xE6DB99E5);
P(C, D, A, B, 15, 16, 0x1FA27CF8);
P(B, C, D, A, 2, 23, 0xC4AC5665);
#undef F
#define F(x, y, z) (y ^ (x | ~z))
P(A, B, C, D, 0, 6, 0xF4292244);
P(D, A, B, C, 7, 10, 0x432AFF97);
P(C, D, A, B, 14, 15, 0xAB9423A7);
P(B, C, D, A, 5, 21, 0xFC93A039);
P(A, B, C, D, 12, 6, 0x655B59C3);
P(D, A, B, C, 3, 10, 0x8F0CCC92);
P(C, D, A, B, 10, 15, 0xFFEFF47D);
P(B, C, D, A, 1, 21, 0x85845DD1);
P(A, B, C, D, 8, 6, 0x6FA87E4F);
P(D, A, B, C, 15, 10, 0xFE2CE6E0);
P(C, D, A, B, 6, 15, 0xA3014314);
P(B, C, D, A, 13, 21, 0x4E0811A1);
P(A, B, C, D, 4, 6, 0xF7537E82);
P(D, A, B, C, 11, 10, 0xBD3AF235);
P(C, D, A, B, 2, 15, 0x2AD7D2BB);
P(B, C, D, A, 9, 21, 0xEB86D391);
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
}
/*
* MD5 process buffer
*/
void utils_md5_update(iot_md5_context *ctx, const unsigned char *input, size_t ilen)
{
size_t
fill;
uint32_t left;
if (ilen == 0) {
return;
}
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += (uint32_t)ilen;
ctx->total[0] &= 0xFFFFFFFF;
if (ctx->total[0] < (uint32_t)ilen) {
ctx->total[1]++;
}
if (left && ilen >= fill) {
memcpy((void *)(ctx->buffer + left), input, fill);
utils_md5_process(ctx, ctx->buffer);
input += fill;
ilen -= fill;
left = 0;
}
while (ilen >= 64) {
utils_md5_process(ctx, input);
input += 64;
ilen -= 64;
}
if (ilen > 0) {
memcpy((void *)(ctx->buffer + left), input, ilen);
}
}
static const unsigned char iot_md5_padding[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/*
* MD5 final digest
*/
void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16])
{
uint32_t
last, padn;
uint32_t
high, low;
unsigned char msglen[8];
high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
low
= (ctx->total[0] << 3);
IOT_MD5_PUT_UINT32_LE(low, msglen, 0);
IOT_MD5_PUT_UINT32_LE(high, msglen, 4);
last = ctx->total[0] & 0x3F;
padn = (last < 56) ? (56 - last) : (120 - last);
utils_md5_update(ctx, iot_md5_padding, padn);
utils_md5_update(ctx, msglen, 8);
IOT_MD5_PUT_UINT32_LE(ctx->state[0], output, 0);
IOT_MD5_PUT_UINT32_LE(ctx->state[1], output, 4);
IOT_MD5_PUT_UINT32_LE(ctx->state[2], output, 8);
IOT_MD5_PUT_UINT32_LE(ctx->state[3], output, 12);
}
/*
* output = MD5( input buffer )
*/
void utils_md5(const unsigned char *input, size_t ilen, unsigned char output[16])
{
iot_md5_context ctx;
utils_md5_init(&ctx);
utils_md5_starts(&ctx);
utils_md5_update(&ctx, input, ilen);
utils_md5_finish(&ctx, output);
utils_md5_free(&ctx);
}
int8_t utils_hb2hex(uint8_t hb)
{
hb = hb & 0xF;
return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a');
}
void utils_md5_str(const unsigned char *input, size_t ilen, unsigned char *output)
{
int
i;
unsigned char buf_out[16];
utils_md5(input, ilen, buf_out);
// hex to string
for (i = 0; i < 16; ++i) {
output[i * 2]
= utils_hb2hex(buf_out[i] >> 4);
output[i * 2 + 1] = utils_hb2hex(buf_out[i]);
}
output[32] = '