1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 #include "linkkit/infra/infra_config.h"
5 
6 #ifdef INFRA_MD5
7 
8 #include <stdlib.h>
9 #include <string.h>
10 
11 #include "linkkit/infra/infra_md5.h"
12 
13 #define MD5_KEY_IOPAD_SIZE (64)
14 #define MD5_DIGEST_SIZE    (16)
15 
16 /* Implementation that should never be optimized out by the compiler */
utils_md5_zeroize(void * v,size_t n)17 static void utils_md5_zeroize(void *v, size_t n)
18 {
19     volatile unsigned char *p = v; // avoid be optimized by the compiler
20     while (n--) {
21         *p++ = 0;
22     }
23 }
24 
25 /*
26  * 32-bit integer manipulation macros (little endian)
27  */
28 #ifndef IOT_MD5_GET_UINT32_LE
29 #define IOT_MD5_GET_UINT32_LE(n, b, i)                                         \
30     {                                                                          \
31         (n) = ((uint32_t)(b)[(i)]) | ((uint32_t)(b)[(i) + 1] << 8) |           \
32               ((uint32_t)(b)[(i) + 2] << 16) | ((uint32_t)(b)[(i) + 3] << 24); \
33     }
34 #endif
35 
36 #ifndef IOT_MD5_PUT_UINT32_LE
37 #define IOT_MD5_PUT_UINT32_LE(n, b, i)                      \
38     {                                                       \
39         (b)[(i)] = (unsigned char)(((n)) & 0xFF);           \
40         (b)[(i) + 1] = (unsigned char)(((n) >> 8) & 0xFF);  \
41         (b)[(i) + 2] = (unsigned char)(((n) >> 16) & 0xFF); \
42         (b)[(i) + 3] = (unsigned char)(((n) >> 24) & 0xFF); \
43     }
44 #endif
45 
utils_md5_init(iot_md5_context * ctx)46 void utils_md5_init(iot_md5_context *ctx)
47 {
48     memset(ctx, 0, sizeof(iot_md5_context));
49 }
50 
utils_md5_free(iot_md5_context * ctx)51 void utils_md5_free(iot_md5_context *ctx)
52 {
53     if (ctx == NULL) {
54         return;
55     }
56 
57     utils_md5_zeroize(ctx, sizeof(iot_md5_context));
58 }
59 
utils_md5_clone(iot_md5_context * dst,const iot_md5_context * src)60 void utils_md5_clone(iot_md5_context *dst, const iot_md5_context *src)
61 {
62     *dst = *src;
63 }
64 
65 /*
66  * MD5 context setup
67  */
utils_md5_starts(iot_md5_context * ctx)68 void utils_md5_starts(iot_md5_context *ctx)
69 {
70     ctx->total[0] = 0;
71     ctx->total[1] = 0;
72 
73     ctx->state[0] = 0x67452301;
74     ctx->state[1] = 0xEFCDAB89;
75     ctx->state[2] = 0x98BADCFE;
76     ctx->state[3] = 0x10325476;
77 }
78 
utils_md5_process(iot_md5_context * ctx,const unsigned char data[64])79 void utils_md5_process(iot_md5_context *ctx, const unsigned char data[64])
80 {
81     uint32_t X[16], A, B, C, D;
82 
83     IOT_MD5_GET_UINT32_LE(X[0], data, 0);
84     IOT_MD5_GET_UINT32_LE(X[1], data, 4);
85     IOT_MD5_GET_UINT32_LE(X[2], data, 8);
86     IOT_MD5_GET_UINT32_LE(X[3], data, 12);
87     IOT_MD5_GET_UINT32_LE(X[4], data, 16);
88     IOT_MD5_GET_UINT32_LE(X[5], data, 20);
89     IOT_MD5_GET_UINT32_LE(X[6], data, 24);
90     IOT_MD5_GET_UINT32_LE(X[7], data, 28);
91     IOT_MD5_GET_UINT32_LE(X[8], data, 32);
92     IOT_MD5_GET_UINT32_LE(X[9], data, 36);
93     IOT_MD5_GET_UINT32_LE(X[10], data, 40);
94     IOT_MD5_GET_UINT32_LE(X[11], data, 44);
95     IOT_MD5_GET_UINT32_LE(X[12], data, 48);
96     IOT_MD5_GET_UINT32_LE(X[13], data, 52);
97     IOT_MD5_GET_UINT32_LE(X[14], data, 56);
98     IOT_MD5_GET_UINT32_LE(X[15], data, 60);
99 
100 #define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
101 
102 #define P(a, b, c, d, k, s, t)      \
103     {                               \
104         a += F(b, c, d) + X[k] + t; \
105         a = S(a, s) + b;            \
106     }
107 
108     A = ctx->state[0];
109     B = ctx->state[1];
110     C = ctx->state[2];
111     D = ctx->state[3];
112 
113 #define F(x, y, z) (z ^ (x & (y ^ z)))
114 
115     P(A, B, C, D, 0, 7, 0xD76AA478);
116     P(D, A, B, C, 1, 12, 0xE8C7B756);
117     P(C, D, A, B, 2, 17, 0x242070DB);
118     P(B, C, D, A, 3, 22, 0xC1BDCEEE);
119     P(A, B, C, D, 4, 7, 0xF57C0FAF);
120     P(D, A, B, C, 5, 12, 0x4787C62A);
121     P(C, D, A, B, 6, 17, 0xA8304613);
122     P(B, C, D, A, 7, 22, 0xFD469501);
123     P(A, B, C, D, 8, 7, 0x698098D8);
124     P(D, A, B, C, 9, 12, 0x8B44F7AF);
125     P(C, D, A, B, 10, 17, 0xFFFF5BB1);
126     P(B, C, D, A, 11, 22, 0x895CD7BE);
127     P(A, B, C, D, 12, 7, 0x6B901122);
128     P(D, A, B, C, 13, 12, 0xFD987193);
129     P(C, D, A, B, 14, 17, 0xA679438E);
130     P(B, C, D, A, 15, 22, 0x49B40821);
131 
132 #undef F
133 
134 #define F(x, y, z) (y ^ (z & (x ^ y)))
135 
136     P(A, B, C, D, 1, 5, 0xF61E2562);
137     P(D, A, B, C, 6, 9, 0xC040B340);
138     P(C, D, A, B, 11, 14, 0x265E5A51);
139     P(B, C, D, A, 0, 20, 0xE9B6C7AA);
140     P(A, B, C, D, 5, 5, 0xD62F105D);
141     P(D, A, B, C, 10, 9, 0x02441453);
142     P(C, D, A, B, 15, 14, 0xD8A1E681);
143     P(B, C, D, A, 4, 20, 0xE7D3FBC8);
144     P(A, B, C, D, 9, 5, 0x21E1CDE6);
145     P(D, A, B, C, 14, 9, 0xC33707D6);
146     P(C, D, A, B, 3, 14, 0xF4D50D87);
147     P(B, C, D, A, 8, 20, 0x455A14ED);
148     P(A, B, C, D, 13, 5, 0xA9E3E905);
149     P(D, A, B, C, 2, 9, 0xFCEFA3F8);
150     P(C, D, A, B, 7, 14, 0x676F02D9);
151     P(B, C, D, A, 12, 20, 0x8D2A4C8A);
152 
153 #undef F
154 
155 #define F(x, y, z) (x ^ y ^ z)
156 
157     P(A, B, C, D, 5, 4, 0xFFFA3942);
158     P(D, A, B, C, 8, 11, 0x8771F681);
159     P(C, D, A, B, 11, 16, 0x6D9D6122);
160     P(B, C, D, A, 14, 23, 0xFDE5380C);
161     P(A, B, C, D, 1, 4, 0xA4BEEA44);
162     P(D, A, B, C, 4, 11, 0x4BDECFA9);
163     P(C, D, A, B, 7, 16, 0xF6BB4B60);
164     P(B, C, D, A, 10, 23, 0xBEBFBC70);
165     P(A, B, C, D, 13, 4, 0x289B7EC6);
166     P(D, A, B, C, 0, 11, 0xEAA127FA);
167     P(C, D, A, B, 3, 16, 0xD4EF3085);
168     P(B, C, D, A, 6, 23, 0x04881D05);
169     P(A, B, C, D, 9, 4, 0xD9D4D039);
170     P(D, A, B, C, 12, 11, 0xE6DB99E5);
171     P(C, D, A, B, 15, 16, 0x1FA27CF8);
172     P(B, C, D, A, 2, 23, 0xC4AC5665);
173 
174 #undef F
175 
176 #define F(x, y, z) (y ^ (x | ~z))
177 
178     P(A, B, C, D, 0, 6, 0xF4292244);
179     P(D, A, B, C, 7, 10, 0x432AFF97);
180     P(C, D, A, B, 14, 15, 0xAB9423A7);
181     P(B, C, D, A, 5, 21, 0xFC93A039);
182     P(A, B, C, D, 12, 6, 0x655B59C3);
183     P(D, A, B, C, 3, 10, 0x8F0CCC92);
184     P(C, D, A, B, 10, 15, 0xFFEFF47D);
185     P(B, C, D, A, 1, 21, 0x85845DD1);
186     P(A, B, C, D, 8, 6, 0x6FA87E4F);
187     P(D, A, B, C, 15, 10, 0xFE2CE6E0);
188     P(C, D, A, B, 6, 15, 0xA3014314);
189     P(B, C, D, A, 13, 21, 0x4E0811A1);
190     P(A, B, C, D, 4, 6, 0xF7537E82);
191     P(D, A, B, C, 11, 10, 0xBD3AF235);
192     P(C, D, A, B, 2, 15, 0x2AD7D2BB);
193     P(B, C, D, A, 9, 21, 0xEB86D391);
194 
195 #undef F
196 
197     ctx->state[0] += A;
198     ctx->state[1] += B;
199     ctx->state[2] += C;
200     ctx->state[3] += D;
201 }
202 
203 /*
204  * MD5 process buffer
205  */
utils_md5_update(iot_md5_context * ctx,const unsigned char * input,uint32_t ilen)206 void utils_md5_update(iot_md5_context *ctx, const unsigned char *input,
207                       uint32_t ilen)
208 {
209     uint32_t fill;
210     uint32_t left;
211 
212     if (ilen == 0) {
213         return;
214     }
215 
216     left = ctx->total[0] & 0x3F;
217     fill = 64 - left;
218 
219     ctx->total[0] += (uint32_t)ilen;
220     ctx->total[0] &= 0xFFFFFFFF;
221 
222     if (ctx->total[0] < (uint32_t)ilen) {
223         ctx->total[1]++;
224     }
225 
226     if (left && ilen >= fill) {
227         memcpy((void *)(ctx->buffer + left), input, fill);
228         utils_md5_process(ctx, ctx->buffer);
229         input += fill;
230         ilen -= fill;
231         left = 0;
232     }
233 
234     while (ilen >= 64) {
235         utils_md5_process(ctx, input);
236         input += 64;
237         ilen -= 64;
238     }
239 
240     if (ilen > 0) {
241         memcpy((void *)(ctx->buffer + left), input, ilen);
242     }
243 }
244 
245 static const unsigned char iot_md5_padding[64] = {
246     0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
247     0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
248     0,    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
249 };
250 
251 /*
252  * MD5 final digest
253  */
utils_md5_finish(iot_md5_context * ctx,unsigned char output[16])254 void utils_md5_finish(iot_md5_context *ctx, unsigned char output[16])
255 {
256     uint32_t last, padn;
257     uint32_t high, low;
258     unsigned char msglen[8];
259 
260     high = (ctx->total[0] >> 29) | (ctx->total[1] << 3);
261     low = (ctx->total[0] << 3);
262 
263     IOT_MD5_PUT_UINT32_LE(low, msglen, 0);
264     IOT_MD5_PUT_UINT32_LE(high, msglen, 4);
265 
266     last = ctx->total[0] & 0x3F;
267     padn = (last < 56) ? (56 - last) : (120 - last);
268 
269     utils_md5_update(ctx, iot_md5_padding, padn);
270     utils_md5_update(ctx, msglen, 8);
271 
272     IOT_MD5_PUT_UINT32_LE(ctx->state[0], output, 0);
273     IOT_MD5_PUT_UINT32_LE(ctx->state[1], output, 4);
274     IOT_MD5_PUT_UINT32_LE(ctx->state[2], output, 8);
275     IOT_MD5_PUT_UINT32_LE(ctx->state[3], output, 12);
276 }
277 
278 /*
279  * output = MD5( input buffer )
280  */
utils_md5(const unsigned char * input,uint32_t ilen,unsigned char output[16])281 void utils_md5(const unsigned char *input, uint32_t ilen,
282                unsigned char output[16])
283 {
284     iot_md5_context ctx;
285 
286     utils_md5_init(&ctx);
287     utils_md5_starts(&ctx);
288     utils_md5_update(&ctx, input, ilen);
289     utils_md5_finish(&ctx, output);
290     utils_md5_free(&ctx);
291 }
292 
utils_hb2hex(uint8_t hb)293 static int8_t utils_hb2hex(uint8_t hb)
294 {
295     hb = hb & 0xF;
296     return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a');
297 }
298 
utils_hmac_md5(const char * msg,int msg_len,char * digest,const char * key,int key_len)299 void utils_hmac_md5(const char *msg, int msg_len, char *digest, const char *key,
300                     int key_len)
301 {
302     iot_md5_context context;
303     unsigned char
304         k_ipad[MD5_KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad  */
305     unsigned char
306         k_opad[MD5_KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
307     unsigned char out[MD5_DIGEST_SIZE];
308     int i;
309 
310     if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
311         return;
312     }
313 
314     if (key_len > MD5_KEY_IOPAD_SIZE) {
315         return;
316     }
317 
318     /* start out by storing key in pads */
319     memset(k_ipad, 0, sizeof(k_ipad));
320     memset(k_opad, 0, sizeof(k_opad));
321     memcpy(k_ipad, key, key_len);
322     memcpy(k_opad, key, key_len);
323 
324     /* XOR key with ipad and opad values */
325     for (i = 0; i < MD5_KEY_IOPAD_SIZE; i++) {
326         k_ipad[i] ^= 0x36;
327         k_opad[i] ^= 0x5c;
328     }
329 
330     /* perform inner MD5 */
331     utils_md5_init(&context);   /* init context for 1st pass */
332     utils_md5_starts(&context); /* setup context for 1st pass */
333     utils_md5_update(&context, k_ipad,
334                      MD5_KEY_IOPAD_SIZE); /* start with inner pad */
335     utils_md5_update(&context, (unsigned char *)msg,
336                      msg_len);       /* then text of datagram */
337     utils_md5_finish(&context, out); /* finish up 1st pass */
338 
339     /* perform outer MD5 */
340     utils_md5_init(&context);   /* init context for 2nd pass */
341     utils_md5_starts(&context); /* setup context for 2nd pass */
342     utils_md5_update(&context, k_opad,
343                      MD5_KEY_IOPAD_SIZE); /* start with outer pad */
344     utils_md5_update(&context, out,
345                      MD5_DIGEST_SIZE); /* then results of 1st hash */
346     utils_md5_finish(&context, out);   /* finish up 2nd pass */
347 
348     for (i = 0; i < MD5_DIGEST_SIZE; ++i) {
349         digest[i * 2] = utils_hb2hex(out[i] >> 4);
350         digest[i * 2 + 1] = utils_hb2hex(out[i]);
351     }
352 }
353 
354 #endif
355