1 /*
2 * Copyright (C) 2015-2019 Alibaba Group Holding Limited
3 */
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8
9 #define PRODUCTKEY_MAXLEN (20)
10 #define DEVICENAME_MAXLEN (32)
11 #define DEVICESECRET_MAXLEN (64)
12
13 #define SIGN_SOURCE_MAXLEN (200)
14 #define CLIENTID_MAXLEN (150)
15 #define USERNAME_MAXLEN (64)
16 #define PASSWORD_MAXLEN (65)
17
18 #define TIMESTAMP_VALUE "2524608000000"
19 #define MQTT_CLINETID_KV "|timestamp=2524608000000,_v=paho-c-1.0.0,securemode=3,signmethod=hmacsha256,lan=C|"
20
21 static void utils_hmac_sha256(const unsigned char *msg, unsigned long int msg_len, const unsigned char *key, unsigned long int key_len, unsigned char output[32]);
22
_hex2str(unsigned char * input,unsigned int input_len,char * output)23 static void _hex2str(unsigned char *input, unsigned int input_len, char *output)
24 {
25 char *zEncode = "0123456789ABCDEF";
26 int i = 0, j = 0;
27
28 for (i = 0; i < input_len; i++) {
29 output[j++] = zEncode[(input[i] >> 4) & 0xf];
30 output[j++] = zEncode[(input[i]) & 0xf];
31 }
32 }
33
aiotMqttSign(const char * productKey,const char * deviceName,const char * deviceSecret,char clientId[150],char username[64],char password[65])34 int aiotMqttSign(const char *productKey, const char *deviceName, const char *deviceSecret,
35 char clientId[150], char username[64], char password[65])
36 {
37 char deviceId[PRODUCTKEY_MAXLEN + DEVICENAME_MAXLEN + 2] = {0};
38 char macSrc[SIGN_SOURCE_MAXLEN] = {0};
39 unsigned char macRes[32] = {0};
40 int res;
41
42 /* check parameters */
43 if (productKey == NULL || deviceName == NULL || deviceSecret == NULL ||
44 clientId == NULL || username == NULL || password == NULL) {
45 return -1;
46 }
47 if ((strlen(productKey) > PRODUCTKEY_MAXLEN) || (strlen(deviceName) > DEVICENAME_MAXLEN) ||
48 (strlen(deviceSecret) > DEVICESECRET_MAXLEN)) {
49 return -1;
50 }
51
52 /* setup deviceId */
53 memcpy(deviceId, deviceName, strlen(deviceName));
54 memcpy(deviceId + strlen(deviceId), "&", strlen("&"));
55 memcpy(deviceId + strlen(deviceId), productKey, strlen(productKey));
56
57 /* setup clientid */
58 memcpy(clientId, deviceId, strlen(deviceId));
59 memcpy(clientId + strlen(deviceId), MQTT_CLINETID_KV, strlen(MQTT_CLINETID_KV));
60 memset(clientId + strlen(deviceId) + strlen(MQTT_CLINETID_KV), 0, 1);
61
62 /* setup username */
63 memcpy(username, deviceId, strlen(deviceId));
64 memset(username + strlen(deviceId), 0, 1);
65
66 /* setup password */
67 memcpy(macSrc, "clientId", strlen("clientId"));
68 memcpy(macSrc + strlen(macSrc), deviceId, strlen(deviceId));
69 memcpy(macSrc + strlen(macSrc), "deviceName", strlen("deviceName"));
70 memcpy(macSrc + strlen(macSrc), deviceName, strlen(deviceName));
71 memcpy(macSrc + strlen(macSrc), "productKey", strlen("productKey"));
72 memcpy(macSrc + strlen(macSrc), productKey, strlen(productKey));
73 memcpy(macSrc + strlen(macSrc), "timestamp", strlen("timestamp"));
74 memcpy(macSrc + strlen(macSrc), TIMESTAMP_VALUE, strlen(TIMESTAMP_VALUE));
75
76 utils_hmac_sha256((unsigned char *)macSrc, strlen(macSrc), (unsigned char *)deviceSecret,
77 strlen(deviceSecret), macRes);
78
79 memset(password, 0, PASSWORD_MAXLEN);
80 _hex2str(macRes, sizeof(macRes), password);
81
82 return 0;
83 }
84
85 /******************************
86 * hmac-sha256 implement below
87 ******************************/
88 #define SHA256_KEY_IOPAD_SIZE (64)
89 #define SHA256_DIGEST_SIZE (32)
90
91 /**
92 * \brief SHA-256 context structure
93 */
94 typedef struct {
95 unsigned long int total[2]; /*!< number of bytes processed */
96 unsigned long int state[8]; /*!< intermediate digest state */
97 unsigned char buffer[64]; /*!< data block being processed */
98 int is224; /*!< 0 => SHA-256, else SHA-224 */
99 } iot_sha256_context;
100
101 typedef union {
102 char sptr[8];
103 unsigned long long int lint;
104 } u_retLen;
105
106 /*
107 * 32-bit integer manipulation macros (big endian)
108 */
109 #ifndef GET_UINT32_BE
110 #define GET_UINT32_BE(n,b,i) \
111 do { \
112 (n) = ( (unsigned long int) (b)[(i) ] << 24 ) \
113 | ( (unsigned long int) (b)[(i) + 1] << 16 ) \
114 | ( (unsigned long int) (b)[(i) + 2] << 8 ) \
115 | ( (unsigned long int) (b)[(i) + 3] ); \
116 } while( 0 )
117 #endif
118
119 #ifndef PUT_UINT32_BE
120 #define PUT_UINT32_BE(n,b,i) \
121 do { \
122 (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
123 (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
124 (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
125 (b)[(i) + 3] = (unsigned char) ( (n) ); \
126 } while( 0 )
127 #endif
128
129
utils_sha256_zeroize(void * v,unsigned long int n)130 static void utils_sha256_zeroize(void *v, unsigned long int n)
131 {
132 volatile unsigned char *p = v;
133 while (n--) {
134 *p++ = 0;
135 }
136 }
137
utils_sha256_init(iot_sha256_context * ctx)138 void utils_sha256_init(iot_sha256_context *ctx)
139 {
140 memset(ctx, 0, sizeof(iot_sha256_context));
141 }
142
utils_sha256_free(iot_sha256_context * ctx)143 void utils_sha256_free(iot_sha256_context *ctx)
144 {
145 if (NULL == ctx) {
146 return;
147 }
148
149 utils_sha256_zeroize(ctx, sizeof(iot_sha256_context));
150 }
151
utils_sha256_starts(iot_sha256_context * ctx)152 void utils_sha256_starts(iot_sha256_context *ctx)
153 {
154 int is224 = 0;
155 ctx->total[0] = 0;
156 ctx->total[1] = 0;
157
158 if (is224 == 0) {
159 /* SHA-256 */
160 ctx->state[0] = 0x6A09E667;
161 ctx->state[1] = 0xBB67AE85;
162 ctx->state[2] = 0x3C6EF372;
163 ctx->state[3] = 0xA54FF53A;
164 ctx->state[4] = 0x510E527F;
165 ctx->state[5] = 0x9B05688C;
166 ctx->state[6] = 0x1F83D9AB;
167 ctx->state[7] = 0x5BE0CD19;
168 }
169
170 ctx->is224 = is224;
171 }
172
173 static const unsigned long int K[] = {
174 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
175 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
176 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
177 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
178 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
179 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
180 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
181 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
182 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
183 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
184 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
185 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
186 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
187 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
188 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
189 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
190 };
191
192 #define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
193 #define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
194
195 #define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
196 #define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
197
198 #define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
199 #define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
200
201 #define F0(x,y,z) ((x & y) | (z & (x | y)))
202 #define F1(x,y,z) (z ^ (x & (y ^ z)))
203
204 #define R(t) \
205 ( \
206 W[t] = S1(W[t - 2]) + W[t - 7] + \
207 S0(W[t - 15]) + W[t - 16] \
208 )
209
210 #define P(a,b,c,d,e,f,g,h,x,K) \
211 { \
212 temp1 = h + S3(e) + F1(e,f,g) + K + x; \
213 temp2 = S2(a) + F0(a,b,c); \
214 d += temp1; h = temp1 + temp2; \
215 }
216
utils_sha256_process(iot_sha256_context * ctx,const unsigned char data[64])217 void utils_sha256_process(iot_sha256_context *ctx, const unsigned char data[64])
218 {
219 unsigned long int temp1, temp2, W[64];
220 unsigned long int A[8];
221 unsigned int i;
222
223 for (i = 0; i < 8; i++) {
224 A[i] = ctx->state[i];
225 }
226
227 for (i = 0; i < 64; i++) {
228 if (i < 16) {
229 GET_UINT32_BE(W[i], data, 4 * i);
230 } else {
231 R(i);
232 }
233
234 P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i]);
235
236 temp1 = A[7];
237 A[7] = A[6];
238 A[6] = A[5];
239 A[5] = A[4];
240 A[4] = A[3];
241 A[3] = A[2];
242 A[2] = A[1];
243 A[1] = A[0];
244 A[0] = temp1;
245 }
246
247 for (i = 0; i < 8; i++) {
248 ctx->state[i] += A[i];
249 }
250 }
utils_sha256_update(iot_sha256_context * ctx,const unsigned char * input,unsigned long int ilen)251 void utils_sha256_update(iot_sha256_context *ctx, const unsigned char *input, unsigned long int ilen)
252 {
253 size_t fill;
254 unsigned long int left;
255
256 if (ilen == 0) {
257 return;
258 }
259
260 left = ctx->total[0] & 0x3F;
261 fill = 64 - left;
262
263 ctx->total[0] += (unsigned long int) ilen;
264 ctx->total[0] &= 0xFFFFFFFF;
265
266 if (ctx->total[0] < (unsigned long int) ilen) {
267 ctx->total[1]++;
268 }
269
270 if (left && ilen >= fill) {
271 memcpy((void *)(ctx->buffer + left), input, fill);
272 utils_sha256_process(ctx, ctx->buffer);
273 input += fill;
274 ilen -= fill;
275 left = 0;
276 }
277
278 while (ilen >= 64) {
279 utils_sha256_process(ctx, input);
280 input += 64;
281 ilen -= 64;
282 }
283
284 if (ilen > 0) {
285 memcpy((void *)(ctx->buffer + left), input, ilen);
286 }
287 }
288
289 static const unsigned char sha256_padding[64] = {
290 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
291 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
292 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
293 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
294 };
295
utils_sha256_finish(iot_sha256_context * ctx,unsigned char output[32])296 void utils_sha256_finish(iot_sha256_context *ctx, unsigned char output[32])
297 {
298 unsigned long int last, padn;
299 unsigned long int high, low;
300 unsigned char msglen[8];
301
302 high = (ctx->total[0] >> 29)
303 | (ctx->total[1] << 3);
304 low = (ctx->total[0] << 3);
305
306 PUT_UINT32_BE(high, msglen, 0);
307 PUT_UINT32_BE(low, msglen, 4);
308
309 last = ctx->total[0] & 0x3F;
310 padn = (last < 56) ? (56 - last) : (120 - last);
311
312 utils_sha256_update(ctx, sha256_padding, padn);
313 utils_sha256_update(ctx, msglen, 8);
314
315 PUT_UINT32_BE(ctx->state[0], output, 0);
316 PUT_UINT32_BE(ctx->state[1], output, 4);
317 PUT_UINT32_BE(ctx->state[2], output, 8);
318 PUT_UINT32_BE(ctx->state[3], output, 12);
319 PUT_UINT32_BE(ctx->state[4], output, 16);
320 PUT_UINT32_BE(ctx->state[5], output, 20);
321 PUT_UINT32_BE(ctx->state[6], output, 24);
322
323 if (ctx->is224 == 0) {
324 PUT_UINT32_BE(ctx->state[7], output, 28);
325 }
326 }
327
utils_sha256(const unsigned char * input,unsigned long int ilen,unsigned char output[32])328 void utils_sha256(const unsigned char *input, unsigned long int ilen, unsigned char output[32])
329 {
330 iot_sha256_context ctx;
331
332 utils_sha256_init(&ctx);
333 utils_sha256_starts(&ctx);
334 utils_sha256_update(&ctx, input, ilen);
335 utils_sha256_finish(&ctx, output);
336 utils_sha256_free(&ctx);
337 }
338
utils_hmac_sha256(const unsigned char * msg,unsigned long int msg_len,const unsigned char * key,unsigned long int key_len,unsigned char output[32])339 static void utils_hmac_sha256(const unsigned char *msg, unsigned long int msg_len, const unsigned char *key, unsigned long int key_len, unsigned char output[32])
340 {
341 iot_sha256_context context;
342 unsigned char k_ipad[SHA256_KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
343 unsigned char k_opad[SHA256_KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
344 int32_t i;
345
346 if ((NULL == msg) || (NULL == key) || (NULL == output)) {
347 return;
348 }
349
350 if (key_len > SHA256_KEY_IOPAD_SIZE) {
351 return;
352 }
353
354 /* start out by storing key in pads */
355 memset(k_ipad, 0, sizeof(k_ipad));
356 memset(k_opad, 0, sizeof(k_opad));
357 memcpy(k_ipad, key, key_len);
358 memcpy(k_opad, key, key_len);
359
360 /* XOR key with ipad and opad values */
361 for (i = 0; i < SHA256_KEY_IOPAD_SIZE; i++) {
362 k_ipad[i] ^= 0x36;
363 k_opad[i] ^= 0x5c;
364 }
365
366 /* perform inner SHA */
367 utils_sha256_init(&context); /* init context for 1st pass */
368 utils_sha256_starts(&context); /* setup context for 1st pass */
369 utils_sha256_update(&context, k_ipad, SHA256_KEY_IOPAD_SIZE); /* start with inner pad */
370 utils_sha256_update(&context, msg, msg_len); /* then text of datagram */
371 utils_sha256_finish(&context, output); /* finish up 1st pass */
372
373 /* perform outer SHA */
374 utils_sha256_init(&context); /* init context for 2nd pass */
375 utils_sha256_starts(&context); /* setup context for 2nd pass */
376 utils_sha256_update(&context, k_opad, SHA256_KEY_IOPAD_SIZE); /* start with outer pad */
377 utils_sha256_update(&context, output, SHA256_DIGEST_SIZE); /* then results of 1st hash */
378 utils_sha256_finish(&context, output); /* finish up 2nd pass */
379 }