1 /*
2 md5.hpp is a reformulation of the md5.h and md5.c code from
3 http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to
4 function as a component of a header only library. This conversion was done by
5 Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The
6 changes are released under the same license as the original (listed below)
7 */
8 /*
9 Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved.
10
11 This software is provided 'as-is', without any express or implied
12 warranty. In no event will the authors be held liable for any damages
13 arising from the use of this software.
14
15 Permission is granted to anyone to use this software for any purpose,
16 including commercial applications, and to alter it and redistribute it
17 freely, subject to the following restrictions:
18
19 1. The origin of this software must not be misrepresented; you must not
20 claim that you wrote the original software. If you use this software
21 in a product, an acknowledgment in the product documentation would be
22 appreciated but is not required.
23 2. Altered source versions must be plainly marked as such, and must not be
24 misrepresented as being the original software.
25 3. This notice may not be removed or altered from any source distribution.
26
27 L. Peter Deutsch
28 ghost@aladdin.com
29
30 */
31 /* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */
32 /*
33 Independent implementation of MD5 (RFC 1321).
34
35 This code implements the MD5 Algorithm defined in RFC 1321, whose
36 text is available at
37 http://www.ietf.org/rfc/rfc1321.txt
38 The code is derived from the text of the RFC, including the test suite
39 (section A.5) but excluding the rest of Appendix A. It does not include
40 any code or documentation that is identified in the RFC as being
41 copyrighted.
42
43 The original and principal author of md5.h is L. Peter Deutsch
44 <ghost@aladdin.com>. Other authors are noted in the change history
45 that follows (in reverse chronological order):
46
47 2002-04-13 lpd Removed support for non-ANSI compilers; removed
48 references to Ghostscript; clarified derivation from RFC 1321;
49 now handles byte order either statically or dynamically.
50 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
51 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);
52 added conditionalization for C++ compilation from Martin
53 Purschke <purschke@bnl.gov>.
54 1999-05-03 lpd Original version.
55 */
56
57 #ifndef WEBSOCKETPP_COMMON_MD5_HPP
58 #define WEBSOCKETPP_COMMON_MD5_HPP
59
60 /*
61 * This package supports both compile-time and run-time determination of CPU
62 * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
63 * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
64 * defined as non-zero, the code will be compiled to run only on big-endian
65 * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
66 * run on either big- or little-endian CPUs, but will run slightly less
67 * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
68 */
69
70 #include <stddef.h>
71 #include <string>
72 #include <cstring>
73
74 namespace websocketpp {
75 /// Provides MD5 hashing functionality
76 namespace md5 {
77
78 typedef unsigned char md5_byte_t; /* 8-bit byte */
79 typedef unsigned int md5_word_t; /* 32-bit word */
80
81 /* Define the state of the MD5 Algorithm. */
82 typedef struct md5_state_s {
83 md5_word_t count[2]; /* message length in bits, lsw first */
84 md5_word_t abcd[4]; /* digest buffer */
85 md5_byte_t buf[64]; /* accumulate block */
86 } md5_state_t;
87
88 /* Initialize the algorithm. */
89 inline void md5_init(md5_state_t *pms);
90
91 /* Append a string to the message. */
92 inline void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes);
93
94 /* Finish the message and return the digest. */
95 inline void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);
96
97 #undef ZSW_MD5_BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
98 #ifdef ARCH_IS_BIG_ENDIAN
99 # define ZSW_MD5_BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
100 #else
101 # define ZSW_MD5_BYTE_ORDER 0
102 #endif
103
104 #define ZSW_MD5_T_MASK ((md5_word_t)~0)
105 #define ZSW_MD5_T1 /* 0xd76aa478 */ (ZSW_MD5_T_MASK ^ 0x28955b87)
106 #define ZSW_MD5_T2 /* 0xe8c7b756 */ (ZSW_MD5_T_MASK ^ 0x173848a9)
107 #define ZSW_MD5_T3 0x242070db
108 #define ZSW_MD5_T4 /* 0xc1bdceee */ (ZSW_MD5_T_MASK ^ 0x3e423111)
109 #define ZSW_MD5_T5 /* 0xf57c0faf */ (ZSW_MD5_T_MASK ^ 0x0a83f050)
110 #define ZSW_MD5_T6 0x4787c62a
111 #define ZSW_MD5_T7 /* 0xa8304613 */ (ZSW_MD5_T_MASK ^ 0x57cfb9ec)
112 #define ZSW_MD5_T8 /* 0xfd469501 */ (ZSW_MD5_T_MASK ^ 0x02b96afe)
113 #define ZSW_MD5_T9 0x698098d8
114 #define ZSW_MD5_T10 /* 0x8b44f7af */ (ZSW_MD5_T_MASK ^ 0x74bb0850)
115 #define ZSW_MD5_T11 /* 0xffff5bb1 */ (ZSW_MD5_T_MASK ^ 0x0000a44e)
116 #define ZSW_MD5_T12 /* 0x895cd7be */ (ZSW_MD5_T_MASK ^ 0x76a32841)
117 #define ZSW_MD5_T13 0x6b901122
118 #define ZSW_MD5_T14 /* 0xfd987193 */ (ZSW_MD5_T_MASK ^ 0x02678e6c)
119 #define ZSW_MD5_T15 /* 0xa679438e */ (ZSW_MD5_T_MASK ^ 0x5986bc71)
120 #define ZSW_MD5_T16 0x49b40821
121 #define ZSW_MD5_T17 /* 0xf61e2562 */ (ZSW_MD5_T_MASK ^ 0x09e1da9d)
122 #define ZSW_MD5_T18 /* 0xc040b340 */ (ZSW_MD5_T_MASK ^ 0x3fbf4cbf)
123 #define ZSW_MD5_T19 0x265e5a51
124 #define ZSW_MD5_T20 /* 0xe9b6c7aa */ (ZSW_MD5_T_MASK ^ 0x16493855)
125 #define ZSW_MD5_T21 /* 0xd62f105d */ (ZSW_MD5_T_MASK ^ 0x29d0efa2)
126 #define ZSW_MD5_T22 0x02441453
127 #define ZSW_MD5_T23 /* 0xd8a1e681 */ (ZSW_MD5_T_MASK ^ 0x275e197e)
128 #define ZSW_MD5_T24 /* 0xe7d3fbc8 */ (ZSW_MD5_T_MASK ^ 0x182c0437)
129 #define ZSW_MD5_T25 0x21e1cde6
130 #define ZSW_MD5_T26 /* 0xc33707d6 */ (ZSW_MD5_T_MASK ^ 0x3cc8f829)
131 #define ZSW_MD5_T27 /* 0xf4d50d87 */ (ZSW_MD5_T_MASK ^ 0x0b2af278)
132 #define ZSW_MD5_T28 0x455a14ed
133 #define ZSW_MD5_T29 /* 0xa9e3e905 */ (ZSW_MD5_T_MASK ^ 0x561c16fa)
134 #define ZSW_MD5_T30 /* 0xfcefa3f8 */ (ZSW_MD5_T_MASK ^ 0x03105c07)
135 #define ZSW_MD5_T31 0x676f02d9
136 #define ZSW_MD5_T32 /* 0x8d2a4c8a */ (ZSW_MD5_T_MASK ^ 0x72d5b375)
137 #define ZSW_MD5_T33 /* 0xfffa3942 */ (ZSW_MD5_T_MASK ^ 0x0005c6bd)
138 #define ZSW_MD5_T34 /* 0x8771f681 */ (ZSW_MD5_T_MASK ^ 0x788e097e)
139 #define ZSW_MD5_T35 0x6d9d6122
140 #define ZSW_MD5_T36 /* 0xfde5380c */ (ZSW_MD5_T_MASK ^ 0x021ac7f3)
141 #define ZSW_MD5_T37 /* 0xa4beea44 */ (ZSW_MD5_T_MASK ^ 0x5b4115bb)
142 #define ZSW_MD5_T38 0x4bdecfa9
143 #define ZSW_MD5_T39 /* 0xf6bb4b60 */ (ZSW_MD5_T_MASK ^ 0x0944b49f)
144 #define ZSW_MD5_T40 /* 0xbebfbc70 */ (ZSW_MD5_T_MASK ^ 0x4140438f)
145 #define ZSW_MD5_T41 0x289b7ec6
146 #define ZSW_MD5_T42 /* 0xeaa127fa */ (ZSW_MD5_T_MASK ^ 0x155ed805)
147 #define ZSW_MD5_T43 /* 0xd4ef3085 */ (ZSW_MD5_T_MASK ^ 0x2b10cf7a)
148 #define ZSW_MD5_T44 0x04881d05
149 #define ZSW_MD5_T45 /* 0xd9d4d039 */ (ZSW_MD5_T_MASK ^ 0x262b2fc6)
150 #define ZSW_MD5_T46 /* 0xe6db99e5 */ (ZSW_MD5_T_MASK ^ 0x1924661a)
151 #define ZSW_MD5_T47 0x1fa27cf8
152 #define ZSW_MD5_T48 /* 0xc4ac5665 */ (ZSW_MD5_T_MASK ^ 0x3b53a99a)
153 #define ZSW_MD5_T49 /* 0xf4292244 */ (ZSW_MD5_T_MASK ^ 0x0bd6ddbb)
154 #define ZSW_MD5_T50 0x432aff97
155 #define ZSW_MD5_T51 /* 0xab9423a7 */ (ZSW_MD5_T_MASK ^ 0x546bdc58)
156 #define ZSW_MD5_T52 /* 0xfc93a039 */ (ZSW_MD5_T_MASK ^ 0x036c5fc6)
157 #define ZSW_MD5_T53 0x655b59c3
158 #define ZSW_MD5_T54 /* 0x8f0ccc92 */ (ZSW_MD5_T_MASK ^ 0x70f3336d)
159 #define ZSW_MD5_T55 /* 0xffeff47d */ (ZSW_MD5_T_MASK ^ 0x00100b82)
160 #define ZSW_MD5_T56 /* 0x85845dd1 */ (ZSW_MD5_T_MASK ^ 0x7a7ba22e)
161 #define ZSW_MD5_T57 0x6fa87e4f
162 #define ZSW_MD5_T58 /* 0xfe2ce6e0 */ (ZSW_MD5_T_MASK ^ 0x01d3191f)
163 #define ZSW_MD5_T59 /* 0xa3014314 */ (ZSW_MD5_T_MASK ^ 0x5cfebceb)
164 #define ZSW_MD5_T60 0x4e0811a1
165 #define ZSW_MD5_T61 /* 0xf7537e82 */ (ZSW_MD5_T_MASK ^ 0x08ac817d)
166 #define ZSW_MD5_T62 /* 0xbd3af235 */ (ZSW_MD5_T_MASK ^ 0x42c50dca)
167 #define ZSW_MD5_T63 0x2ad7d2bb
168 #define ZSW_MD5_T64 /* 0xeb86d391 */ (ZSW_MD5_T_MASK ^ 0x14792c6e)
169
md5_process(md5_state_t * pms,md5_byte_t const * data)170 static void md5_process(md5_state_t *pms, md5_byte_t const * data /*[64]*/) {
171 md5_word_t
172 a = pms->abcd[0], b = pms->abcd[1],
173 c = pms->abcd[2], d = pms->abcd[3];
174 md5_word_t t;
175 #if ZSW_MD5_BYTE_ORDER > 0
176 /* Define storage only for big-endian CPUs. */
177 md5_word_t X[16];
178 #else
179 /* Define storage for little-endian or both types of CPUs. */
180 md5_word_t xbuf[16];
181 md5_word_t const * X;
182 #endif
183
184 {
185 #if ZSW_MD5_BYTE_ORDER == 0
186 /*
187 * Determine dynamically whether this is a big-endian or
188 * little-endian machine, since we can use a more efficient
189 * algorithm on the latter.
190 */
191 static int const w = 1;
192
193 if (*((md5_byte_t const *)&w)) /* dynamic little-endian */
194 #endif
195 #if ZSW_MD5_BYTE_ORDER <= 0 /* little-endian */
196 {
197 /*
198 * On little-endian machines, we can process properly aligned
199 * data without copying it.
200 */
201 if (!((data - (md5_byte_t const *)0) & 3)) {
202 /* data are properly aligned */
203 X = (md5_word_t const *)data;
204 } else {
205 /* not aligned */
206 std::memcpy(xbuf, data, 64);
207 X = xbuf;
208 }
209 }
210 #endif
211 #if ZSW_MD5_BYTE_ORDER == 0
212 else /* dynamic big-endian */
213 #endif
214 #if ZSW_MD5_BYTE_ORDER >= 0 /* big-endian */
215 {
216 /*
217 * On big-endian machines, we must arrange the bytes in the
218 * right order.
219 */
220 const md5_byte_t *xp = data;
221 int i;
222
223 # if ZSW_MD5_BYTE_ORDER == 0
224 X = xbuf; /* (dynamic only) */
225 # else
226 # define xbuf X /* (static only) */
227 # endif
228 for (i = 0; i < 16; ++i, xp += 4)
229 xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
230 }
231 #endif
232 }
233
234 #define ZSW_MD5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
235
236 /* Round 1. */
237 /* Let [abcd k s i] denote the operation
238 a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
239 #define ZSW_MD5_F(x, y, z) (((x) & (y)) | (~(x) & (z)))
240 #define SET(a, b, c, d, k, s, Ti)\
241 t = a + ZSW_MD5_F(b,c,d) + X[k] + Ti;\
242 a = ZSW_MD5_ROTATE_LEFT(t, s) + b
243 /* Do the following 16 operations. */
244 SET(a, b, c, d, 0, 7, ZSW_MD5_T1);
245 SET(d, a, b, c, 1, 12, ZSW_MD5_T2);
246 SET(c, d, a, b, 2, 17, ZSW_MD5_T3);
247 SET(b, c, d, a, 3, 22, ZSW_MD5_T4);
248 SET(a, b, c, d, 4, 7, ZSW_MD5_T5);
249 SET(d, a, b, c, 5, 12, ZSW_MD5_T6);
250 SET(c, d, a, b, 6, 17, ZSW_MD5_T7);
251 SET(b, c, d, a, 7, 22, ZSW_MD5_T8);
252 SET(a, b, c, d, 8, 7, ZSW_MD5_T9);
253 SET(d, a, b, c, 9, 12, ZSW_MD5_T10);
254 SET(c, d, a, b, 10, 17, ZSW_MD5_T11);
255 SET(b, c, d, a, 11, 22, ZSW_MD5_T12);
256 SET(a, b, c, d, 12, 7, ZSW_MD5_T13);
257 SET(d, a, b, c, 13, 12, ZSW_MD5_T14);
258 SET(c, d, a, b, 14, 17, ZSW_MD5_T15);
259 SET(b, c, d, a, 15, 22, ZSW_MD5_T16);
260 #undef SET
261
262 /* Round 2. */
263 /* Let [abcd k s i] denote the operation
264 a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
265 #define ZSW_MD5_G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
266 #define SET(a, b, c, d, k, s, Ti)\
267 t = a + ZSW_MD5_G(b,c,d) + X[k] + Ti;\
268 a = ZSW_MD5_ROTATE_LEFT(t, s) + b
269 /* Do the following 16 operations. */
270 SET(a, b, c, d, 1, 5, ZSW_MD5_T17);
271 SET(d, a, b, c, 6, 9, ZSW_MD5_T18);
272 SET(c, d, a, b, 11, 14, ZSW_MD5_T19);
273 SET(b, c, d, a, 0, 20, ZSW_MD5_T20);
274 SET(a, b, c, d, 5, 5, ZSW_MD5_T21);
275 SET(d, a, b, c, 10, 9, ZSW_MD5_T22);
276 SET(c, d, a, b, 15, 14, ZSW_MD5_T23);
277 SET(b, c, d, a, 4, 20, ZSW_MD5_T24);
278 SET(a, b, c, d, 9, 5, ZSW_MD5_T25);
279 SET(d, a, b, c, 14, 9, ZSW_MD5_T26);
280 SET(c, d, a, b, 3, 14, ZSW_MD5_T27);
281 SET(b, c, d, a, 8, 20, ZSW_MD5_T28);
282 SET(a, b, c, d, 13, 5, ZSW_MD5_T29);
283 SET(d, a, b, c, 2, 9, ZSW_MD5_T30);
284 SET(c, d, a, b, 7, 14, ZSW_MD5_T31);
285 SET(b, c, d, a, 12, 20, ZSW_MD5_T32);
286 #undef SET
287
288 /* Round 3. */
289 /* Let [abcd k s t] denote the operation
290 a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
291 #define ZSW_MD5_H(x, y, z) ((x) ^ (y) ^ (z))
292 #define SET(a, b, c, d, k, s, Ti)\
293 t = a + ZSW_MD5_H(b,c,d) + X[k] + Ti;\
294 a = ZSW_MD5_ROTATE_LEFT(t, s) + b
295 /* Do the following 16 operations. */
296 SET(a, b, c, d, 5, 4, ZSW_MD5_T33);
297 SET(d, a, b, c, 8, 11, ZSW_MD5_T34);
298 SET(c, d, a, b, 11, 16, ZSW_MD5_T35);
299 SET(b, c, d, a, 14, 23, ZSW_MD5_T36);
300 SET(a, b, c, d, 1, 4, ZSW_MD5_T37);
301 SET(d, a, b, c, 4, 11, ZSW_MD5_T38);
302 SET(c, d, a, b, 7, 16, ZSW_MD5_T39);
303 SET(b, c, d, a, 10, 23, ZSW_MD5_T40);
304 SET(a, b, c, d, 13, 4, ZSW_MD5_T41);
305 SET(d, a, b, c, 0, 11, ZSW_MD5_T42);
306 SET(c, d, a, b, 3, 16, ZSW_MD5_T43);
307 SET(b, c, d, a, 6, 23, ZSW_MD5_T44);
308 SET(a, b, c, d, 9, 4, ZSW_MD5_T45);
309 SET(d, a, b, c, 12, 11, ZSW_MD5_T46);
310 SET(c, d, a, b, 15, 16, ZSW_MD5_T47);
311 SET(b, c, d, a, 2, 23, ZSW_MD5_T48);
312 #undef SET
313
314 /* Round 4. */
315 /* Let [abcd k s t] denote the operation
316 a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
317 #define ZSW_MD5_I(x, y, z) ((y) ^ ((x) | ~(z)))
318 #define SET(a, b, c, d, k, s, Ti)\
319 t = a + ZSW_MD5_I(b,c,d) + X[k] + Ti;\
320 a = ZSW_MD5_ROTATE_LEFT(t, s) + b
321 /* Do the following 16 operations. */
322 SET(a, b, c, d, 0, 6, ZSW_MD5_T49);
323 SET(d, a, b, c, 7, 10, ZSW_MD5_T50);
324 SET(c, d, a, b, 14, 15, ZSW_MD5_T51);
325 SET(b, c, d, a, 5, 21, ZSW_MD5_T52);
326 SET(a, b, c, d, 12, 6, ZSW_MD5_T53);
327 SET(d, a, b, c, 3, 10, ZSW_MD5_T54);
328 SET(c, d, a, b, 10, 15, ZSW_MD5_T55);
329 SET(b, c, d, a, 1, 21, ZSW_MD5_T56);
330 SET(a, b, c, d, 8, 6, ZSW_MD5_T57);
331 SET(d, a, b, c, 15, 10, ZSW_MD5_T58);
332 SET(c, d, a, b, 6, 15, ZSW_MD5_T59);
333 SET(b, c, d, a, 13, 21, ZSW_MD5_T60);
334 SET(a, b, c, d, 4, 6, ZSW_MD5_T61);
335 SET(d, a, b, c, 11, 10, ZSW_MD5_T62);
336 SET(c, d, a, b, 2, 15, ZSW_MD5_T63);
337 SET(b, c, d, a, 9, 21, ZSW_MD5_T64);
338 #undef SET
339
340 /* Then perform the following additions. (That is increment each
341 of the four registers by the value it had before this block
342 was started.) */
343 pms->abcd[0] += a;
344 pms->abcd[1] += b;
345 pms->abcd[2] += c;
346 pms->abcd[3] += d;
347 }
348
md5_init(md5_state_t * pms)349 void md5_init(md5_state_t *pms) {
350 pms->count[0] = pms->count[1] = 0;
351 pms->abcd[0] = 0x67452301;
352 pms->abcd[1] = /*0xefcdab89*/ ZSW_MD5_T_MASK ^ 0x10325476;
353 pms->abcd[2] = /*0x98badcfe*/ ZSW_MD5_T_MASK ^ 0x67452301;
354 pms->abcd[3] = 0x10325476;
355 }
356
md5_append(md5_state_t * pms,md5_byte_t const * data,size_t nbytes)357 void md5_append(md5_state_t *pms, md5_byte_t const * data, size_t nbytes) {
358 md5_byte_t const * p = data;
359 size_t left = nbytes;
360 int offset = (pms->count[0] >> 3) & 63;
361 md5_word_t nbits = (md5_word_t)(nbytes << 3);
362
363 if (nbytes <= 0)
364 return;
365
366 /* Update the message length. */
367 pms->count[1] += nbytes >> 29;
368 pms->count[0] += nbits;
369 if (pms->count[0] < nbits)
370 pms->count[1]++;
371
372 /* Process an initial partial block. */
373 if (offset) {
374 int copy = (offset + nbytes > 64 ? 64 - offset : static_cast<int>(nbytes));
375
376 std::memcpy(pms->buf + offset, p, copy);
377 if (offset + copy < 64)
378 return;
379 p += copy;
380 left -= copy;
381 md5_process(pms, pms->buf);
382 }
383
384 /* Process full blocks. */
385 for (; left >= 64; p += 64, left -= 64)
386 md5_process(pms, p);
387
388 /* Process a final partial block. */
389 if (left)
390 std::memcpy(pms->buf, p, left);
391 }
392
md5_finish(md5_state_t * pms,md5_byte_t digest[16])393 void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) {
394 static md5_byte_t const pad[64] = {
395 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
397 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
398 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
399 };
400 md5_byte_t data[8];
401 int i;
402
403 /* Save the length before padding. */
404 for (i = 0; i < 8; ++i)
405 data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
406 /* Pad to 56 bytes mod 64. */
407 md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
408 /* Append the length. */
409 md5_append(pms, data, 8);
410 for (i = 0; i < 16; ++i)
411 digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
412 }
413
414 // some convenience c++ functions
md5_hash_string(std::string const & s)415 inline std::string md5_hash_string(std::string const & s) {
416 char digest[16];
417
418 md5_state_t state;
419
420 md5_init(&state);
421 md5_append(&state, (md5_byte_t const *)s.c_str(), s.size());
422 md5_finish(&state, (md5_byte_t *)digest);
423
424 std::string ret;
425 ret.resize(16);
426 std::copy(digest,digest+16,ret.begin());
427
428 return ret;
429 }
430
431 const char hexval[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
432
md5_hash_hex(std::string const & input)433 inline std::string md5_hash_hex(std::string const & input) {
434 std::string hash = md5_hash_string(input);
435 std::string hex;
436
437 for (size_t i = 0; i < hash.size(); i++) {
438 hex.push_back(hexval[((hash[i] >> 4) & 0xF)]);
439 hex.push_back(hexval[(hash[i]) & 0x0F]);
440 }
441
442 return hex;
443 }
444
445 } // md5
446 } // websocketpp
447
448 #endif // WEBSOCKETPP_COMMON_MD5_HPP
449