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