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 }