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