HOPS
HOPS class reference
picohash.h
Go to the documentation of this file.
1 /*
2  * The code is placed under public domain by Kazuho Oku <kazuhooku@gmail.com>.
3  *
4  * The MD5 implementation is based on a public domain implementation written by
5  * Solar Designer <solar@openwall.com> in 2001, which is used by Dovecot.
6  *
7  * The SHA1 implementation is based on a public domain implementation written
8  * by Wei Dai and other contributors for libcrypt, used also in liboauth.
9  *
10  * The SHA224/SHA256 implementation is based on a public domain implementation
11  * by Sam Hocevar <sam@hocevar.net> for LibTomCrypt.
12  */
13 
21 #ifndef _picohash_h_
22 #define _picohash_h_
23 
24 #include <assert.h>
25 #include <inttypes.h>
26 #include <string.h>
27 
28 #ifdef __BIG_ENDIAN__
29 #define _PICOHASH_BIG_ENDIAN
30 #elif defined __LITTLE_ENDIAN__
31 /* override */
32 #elif defined __BYTE_ORDER
33 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
34 #define _PICOHASH_BIG_ENDIAN
35 #endif
36 #else // ! defined __LITTLE_ENDIAN__
37 #include <endian.h> // machine/endian.h
38 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
39 #define _PICOHASH_BIG_ENDIAN
40 #endif
41 #endif
42 
43 #define PICOHASH_MD5_BLOCK_LENGTH 64
44 #define PICOHASH_MD5_DIGEST_LENGTH 16
45 
46 typedef struct {
47  uint_fast32_t lo, hi;
48  uint_fast32_t a, b, c, d;
49  unsigned char buffer[64];
52 
53 static void _picohash_md5_init(_picohash_md5_ctx_t *ctx);
54 static void _picohash_md5_update(_picohash_md5_ctx_t *ctx, const void *data, size_t size);
55 static void _picohash_md5_final(_picohash_md5_ctx_t *ctx, void *digest);
56 
57 /* following are private definitions */
58 
59 /*
60  * The basic MD5 functions.
61  *
62  * F is optimized compared to its RFC 1321 definition just like in Colin
63  * Plumb's implementation.
64  */
65 #define _PICOHASH_MD5_F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
66 #define _PICOHASH_MD5_G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
67 #define _PICOHASH_MD5_H(x, y, z) ((x) ^ (y) ^ (z))
68 #define _PICOHASH_MD5_I(x, y, z) ((y) ^ ((x) | ~(z)))
69 
70 /*
71  * The MD5 transformation for all four rounds.
72  */
73 #define _PICOHASH_MD5_STEP(f, a, b, c, d, x, t, s) \
74  (a) += f((b), (c), (d)) + (x) + (t); \
75  (a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s)))); \
76  (a) += (b);
77 
78 /*
79  * SET reads 4 input bytes in little-endian byte order and stores them
80  * in a properly aligned word in host byte order.
81  *
82  * The check for little-endian architectures which tolerate unaligned
83  * memory accesses is just an optimization. Nothing will break if it
84  * doesn't work.
85  */
86 #if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
87 #define _PICOHASH_MD5_SET(n) (*(const uint32_t *)&ptr[(n)*4])
88 #define _PICOHASH_MD5_GET(n) _PICOHASH_MD5_SET(n)
89 #else
90 #define _PICOHASH_MD5_SET(n) \
91  (ctx->block[(n)] = (uint_fast32_t)ptr[(n)*4] | ((uint_fast32_t)ptr[(n)*4 + 1] << 8) | ((uint_fast32_t)ptr[(n)*4 + 2] << 16) | \
92  ((uint_fast32_t)ptr[(n)*4 + 3] << 24))
93 #define _PICOHASH_MD5_GET(n) (ctx->block[(n)])
94 #endif
95 
96 /*
97  * This processes one or more 64-byte data blocks, but does NOT update
98  * the bit counters. There're no alignment requirements.
99  */
100 static const void *_picohash_md5_body(_picohash_md5_ctx_t *ctx, const void *data, size_t size)
101 {
102  const unsigned char *ptr;
103  uint_fast32_t a, b, c, d;
104  uint_fast32_t saved_a, saved_b, saved_c, saved_d;
105 
106  ptr = (const unsigned char*) data;
107 
108  a = ctx->a;
109  b = ctx->b;
110  c = ctx->c;
111  d = ctx->d;
112 
113  do {
114  saved_a = a;
115  saved_b = b;
116  saved_c = c;
117  saved_d = d;
118 
119  /* Round 1 */
120  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(0), 0xd76aa478, 7)
121  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(1), 0xe8c7b756, 12)
122  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(2), 0x242070db, 17)
123  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(3), 0xc1bdceee, 22)
124  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(4), 0xf57c0faf, 7)
125  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(5), 0x4787c62a, 12)
126  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(6), 0xa8304613, 17)
127  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(7), 0xfd469501, 22)
128  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(8), 0x698098d8, 7)
129  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(9), 0x8b44f7af, 12)
130  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(10), 0xffff5bb1, 17)
131  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(11), 0x895cd7be, 22)
132  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, a, b, c, d, _PICOHASH_MD5_SET(12), 0x6b901122, 7)
133  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, d, a, b, c, _PICOHASH_MD5_SET(13), 0xfd987193, 12)
134  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, c, d, a, b, _PICOHASH_MD5_SET(14), 0xa679438e, 17)
135  _PICOHASH_MD5_STEP(_PICOHASH_MD5_F, b, c, d, a, _PICOHASH_MD5_SET(15), 0x49b40821, 22)
136 
137  /* Round 2 */
138  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(1), 0xf61e2562, 5)
139  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(6), 0xc040b340, 9)
140  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(11), 0x265e5a51, 14)
141  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(0), 0xe9b6c7aa, 20)
142  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(5), 0xd62f105d, 5)
143  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(10), 0x02441453, 9)
144  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(15), 0xd8a1e681, 14)
145  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(4), 0xe7d3fbc8, 20)
146  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(9), 0x21e1cde6, 5)
147  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(14), 0xc33707d6, 9)
148  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(3), 0xf4d50d87, 14)
149  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(8), 0x455a14ed, 20)
150  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, a, b, c, d, _PICOHASH_MD5_GET(13), 0xa9e3e905, 5)
151  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, d, a, b, c, _PICOHASH_MD5_GET(2), 0xfcefa3f8, 9)
152  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, c, d, a, b, _PICOHASH_MD5_GET(7), 0x676f02d9, 14)
153  _PICOHASH_MD5_STEP(_PICOHASH_MD5_G, b, c, d, a, _PICOHASH_MD5_GET(12), 0x8d2a4c8a, 20)
154 
155  /* Round 3 */
156  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(5), 0xfffa3942, 4)
157  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(8), 0x8771f681, 11)
158  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(11), 0x6d9d6122, 16)
159  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(14), 0xfde5380c, 23)
160  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(1), 0xa4beea44, 4)
161  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(4), 0x4bdecfa9, 11)
162  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(7), 0xf6bb4b60, 16)
163  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(10), 0xbebfbc70, 23)
164  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(13), 0x289b7ec6, 4)
165  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(0), 0xeaa127fa, 11)
166  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(3), 0xd4ef3085, 16)
167  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(6), 0x04881d05, 23)
168  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, a, b, c, d, _PICOHASH_MD5_GET(9), 0xd9d4d039, 4)
169  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, d, a, b, c, _PICOHASH_MD5_GET(12), 0xe6db99e5, 11)
170  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, c, d, a, b, _PICOHASH_MD5_GET(15), 0x1fa27cf8, 16)
171  _PICOHASH_MD5_STEP(_PICOHASH_MD5_H, b, c, d, a, _PICOHASH_MD5_GET(2), 0xc4ac5665, 23)
172 
173  /* Round 4 */
174  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(0), 0xf4292244, 6)
175  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(7), 0x432aff97, 10)
176  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(14), 0xab9423a7, 15)
177  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(5), 0xfc93a039, 21)
178  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(12), 0x655b59c3, 6)
179  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(3), 0x8f0ccc92, 10)
180  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(10), 0xffeff47d, 15)
181  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(1), 0x85845dd1, 21)
182  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(8), 0x6fa87e4f, 6)
183  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(15), 0xfe2ce6e0, 10)
184  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(6), 0xa3014314, 15)
185  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(13), 0x4e0811a1, 21)
186  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, a, b, c, d, _PICOHASH_MD5_GET(4), 0xf7537e82, 6)
187  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, d, a, b, c, _PICOHASH_MD5_GET(11), 0xbd3af235, 10)
188  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, c, d, a, b, _PICOHASH_MD5_GET(2), 0x2ad7d2bb, 15)
189  _PICOHASH_MD5_STEP(_PICOHASH_MD5_I, b, c, d, a, _PICOHASH_MD5_GET(9), 0xeb86d391, 21)
190 
191  a += saved_a;
192  b += saved_b;
193  c += saved_c;
194  d += saved_d;
195 
196  ptr += 64;
197  } while (size -= 64);
198 
199  ctx->a = a;
200  ctx->b = b;
201  ctx->c = c;
202  ctx->d = d;
203 
204  return ptr;
205 }
206 
207 inline void _picohash_md5_init(_picohash_md5_ctx_t *ctx)
208 {
209  ctx->a = 0x67452301;
210  ctx->b = 0xefcdab89;
211  ctx->c = 0x98badcfe;
212  ctx->d = 0x10325476;
213 
214  ctx->lo = 0;
215  ctx->hi = 0;
216 }
217 
218 inline void _picohash_md5_update(_picohash_md5_ctx_t *ctx, const void *data, size_t size)
219 {
220  uint_fast32_t saved_lo;
221  unsigned long used, free;
222 
223  saved_lo = ctx->lo;
224  if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
225  ctx->hi++;
226  ctx->hi += size >> 29;
227 
228  used = saved_lo & 0x3f;
229 
230  if (used) {
231  free = 64 - used;
232 
233  if (size < free) {
234  memcpy(&ctx->buffer[used], data, size);
235  return;
236  }
237 
238  memcpy(&ctx->buffer[used], data, free);
239  data = (const unsigned char *)data + free;
240  size -= free;
241  _picohash_md5_body(ctx, ctx->buffer, 64);
242  }
243 
244  if (size >= 64) {
245  data = _picohash_md5_body(ctx, data, size & ~(unsigned long)0x3f);
246  size &= 0x3f;
247  }
248 
249  memcpy(ctx->buffer, data, size);
250 }
251 
252 inline void _picohash_md5_final(_picohash_md5_ctx_t *ctx, void *_digest)
253 {
254  unsigned char *digest = (unsigned char *) _digest;
255  unsigned long used, free;
256 
257  used = ctx->lo & 0x3f;
258 
259  ctx->buffer[used++] = 0x80;
260 
261  free = 64 - used;
262 
263  if (free < 8) {
264  memset(&ctx->buffer[used], 0, free);
265  _picohash_md5_body(ctx, ctx->buffer, 64);
266  used = 0;
267  free = 64;
268  }
269 
270  memset(&ctx->buffer[used], 0, free - 8);
271 
272  ctx->lo <<= 3;
273  ctx->buffer[56] = ctx->lo;
274  ctx->buffer[57] = ctx->lo >> 8;
275  ctx->buffer[58] = ctx->lo >> 16;
276  ctx->buffer[59] = ctx->lo >> 24;
277  ctx->buffer[60] = ctx->hi;
278  ctx->buffer[61] = ctx->hi >> 8;
279  ctx->buffer[62] = ctx->hi >> 16;
280  ctx->buffer[63] = ctx->hi >> 24;
281 
282  _picohash_md5_body(ctx, ctx->buffer, 64);
283 
284  digest[0] = ctx->a;
285  digest[1] = ctx->a >> 8;
286  digest[2] = ctx->a >> 16;
287  digest[3] = ctx->a >> 24;
288  digest[4] = ctx->b;
289  digest[5] = ctx->b >> 8;
290  digest[6] = ctx->b >> 16;
291  digest[7] = ctx->b >> 24;
292  digest[8] = ctx->c;
293  digest[9] = ctx->c >> 8;
294  digest[10] = ctx->c >> 16;
295  digest[11] = ctx->c >> 24;
296  digest[12] = ctx->d;
297  digest[13] = ctx->d >> 8;
298  digest[14] = ctx->d >> 16;
299  digest[15] = ctx->d >> 24;
300 
301  memset(ctx, 0, sizeof(*ctx));
302 }
303 
304 
305 #endif
char buffer[MAX_BUFFER][MAX_CHARS]
Definition: fourmer.c:46
#define _PICOHASH_MD5_F(x, y, z)
Definition: picohash.h:65
uint_fast32_t hi
Definition: picohash.h:47
uint_fast32_t b
Definition: picohash.h:48
#define _PICOHASH_MD5_H(x, y, z)
Definition: picohash.h:67
uint_fast32_t a
Definition: picohash.h:48
uint_fast32_t d
Definition: picohash.h:48
#define _PICOHASH_MD5_SET(n)
Definition: picohash.h:90
#define _PICOHASH_MD5_GET(n)
Definition: picohash.h:93
#define _PICOHASH_MD5_I(x, y, z)
Definition: picohash.h:68
uint_fast32_t c
Definition: picohash.h:48
#define PICOHASH_MD5_DIGEST_LENGTH
Definition: picohash.h:44
uint_fast32_t lo
Definition: picohash.h:47
unsigned char buffer[64]
Definition: picohash.h:49
#define _PICOHASH_MD5_G(x, y, z)
Definition: picohash.h:66
#define _PICOHASH_MD5_STEP(f, a, b, c, d, x, t, s)
Definition: picohash.h:73
Definition: picohash.h:46
Definition: vex.h:111