]> git.ozlabs.org Git - ccan/blob - ccan/md4/md4.c
talloc: allow replacement allocator
[ccan] / ccan / md4 / md4.c
1 /*
2  * MD4 Message Digest Algorithm (RFC1320).
3  *
4  * Based on linux kernel 2.6.28-rc5:
5  *
6  * Implementation derived from Andrew Tridgell and Steve French's
7  * CIFS MD4 implementation, and the cryptoapi implementation
8  * originally based on the public domain implementation written
9  * by Colin Plumb in 1993.
10  *
11  * Copyright (c) Andrew Tridgell 1997-1998.
12  * Modified by Steve French (sfrench@us.ibm.com) 2002
13  * Copyright (c) Cryptoapi developers.
14  * Copyright (c) 2002 David S. Miller (davem@redhat.com)
15  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
16  *
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 2 of the License, or
20  * (at your option) any later version.
21  */
22 #include "md4.h"
23 #include <ccan/endian/endian.h>
24 #include <ccan/array_size/array_size.h>
25 #include <string.h>
26
27 static inline uint32_t lshift(uint32_t x, unsigned int s)
28 {
29         x &= 0xFFFFFFFF;
30         return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s));
31 }
32
33 static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z)
34 {
35         return (x & y) | ((~x) & z);
36 }
37
38 static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z)
39 {
40         return (x & y) | (x & z) | (y & z);
41 }
42
43 static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z)
44 {
45         return x ^ y ^ z;
46 }
47
48 #define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s))
49 #define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s))
50 #define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s))
51
52 static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words)
53 {
54         while (words--) {
55                 *buf = le32_to_cpu(*buf);
56                 buf++;
57         }
58 }
59
60 static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words)
61 {
62         while (words--) {
63                 *buf = cpu_to_le32(*buf);
64                 buf++;
65         }
66 }
67
68 static void md4_transform(uint32_t *hash, uint32_t const *in)
69 {
70         uint32_t a, b, c, d;
71
72         a = hash[0];
73         b = hash[1];
74         c = hash[2];
75         d = hash[3];
76
77         ROUND1(a, b, c, d, in[0], 3);
78         ROUND1(d, a, b, c, in[1], 7);
79         ROUND1(c, d, a, b, in[2], 11);
80         ROUND1(b, c, d, a, in[3], 19);
81         ROUND1(a, b, c, d, in[4], 3);
82         ROUND1(d, a, b, c, in[5], 7);
83         ROUND1(c, d, a, b, in[6], 11);
84         ROUND1(b, c, d, a, in[7], 19);
85         ROUND1(a, b, c, d, in[8], 3);
86         ROUND1(d, a, b, c, in[9], 7);
87         ROUND1(c, d, a, b, in[10], 11);
88         ROUND1(b, c, d, a, in[11], 19);
89         ROUND1(a, b, c, d, in[12], 3);
90         ROUND1(d, a, b, c, in[13], 7);
91         ROUND1(c, d, a, b, in[14], 11);
92         ROUND1(b, c, d, a, in[15], 19);
93
94         ROUND2(a, b, c, d,in[ 0], 3);
95         ROUND2(d, a, b, c, in[4], 5);
96         ROUND2(c, d, a, b, in[8], 9);
97         ROUND2(b, c, d, a, in[12], 13);
98         ROUND2(a, b, c, d, in[1], 3);
99         ROUND2(d, a, b, c, in[5], 5);
100         ROUND2(c, d, a, b, in[9], 9);
101         ROUND2(b, c, d, a, in[13], 13);
102         ROUND2(a, b, c, d, in[2], 3);
103         ROUND2(d, a, b, c, in[6], 5);
104         ROUND2(c, d, a, b, in[10], 9);
105         ROUND2(b, c, d, a, in[14], 13);
106         ROUND2(a, b, c, d, in[3], 3);
107         ROUND2(d, a, b, c, in[7], 5);
108         ROUND2(c, d, a, b, in[11], 9);
109         ROUND2(b, c, d, a, in[15], 13);
110
111         ROUND3(a, b, c, d,in[ 0], 3);
112         ROUND3(d, a, b, c, in[8], 9);
113         ROUND3(c, d, a, b, in[4], 11);
114         ROUND3(b, c, d, a, in[12], 15);
115         ROUND3(a, b, c, d, in[2], 3);
116         ROUND3(d, a, b, c, in[10], 9);
117         ROUND3(c, d, a, b, in[6], 11);
118         ROUND3(b, c, d, a, in[14], 15);
119         ROUND3(a, b, c, d, in[1], 3);
120         ROUND3(d, a, b, c, in[9], 9);
121         ROUND3(c, d, a, b, in[5], 11);
122         ROUND3(b, c, d, a, in[13], 15);
123         ROUND3(a, b, c, d, in[3], 3);
124         ROUND3(d, a, b, c, in[11], 9);
125         ROUND3(c, d, a, b, in[7], 11);
126         ROUND3(b, c, d, a, in[15], 15);
127
128         hash[0] += a;
129         hash[1] += b;
130         hash[2] += c;
131         hash[3] += d;
132 }
133
134 static inline void md4_transform_helper(struct md4_ctx *ctx)
135 {
136         le32_to_cpu_array(ctx->block, ARRAY_SIZE(ctx->block));
137         md4_transform(ctx->hash.words, ctx->block);
138 }
139
140 void md4_init(struct md4_ctx *mctx)
141 {
142         mctx->hash.words[0] = 0x67452301;
143         mctx->hash.words[1] = 0xefcdab89;
144         mctx->hash.words[2] = 0x98badcfe;
145         mctx->hash.words[3] = 0x10325476;
146         mctx->byte_count = 0;
147 }
148
149 void md4_hash(struct md4_ctx *mctx, const void *p, size_t len)
150 {
151         const unsigned char *data = p;
152         const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f);
153
154         mctx->byte_count += len;
155
156         if (avail > len) {
157                 memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
158                        data, len);
159                 return;
160         }
161
162         memcpy((char *)mctx->block + (sizeof(mctx->block) - avail),
163                data, avail);
164
165         md4_transform_helper(mctx);
166         data += avail;
167         len -= avail;
168
169         while (len >= sizeof(mctx->block)) {
170                 memcpy(mctx->block, data, sizeof(mctx->block));
171                 md4_transform_helper(mctx);
172                 data += sizeof(mctx->block);
173                 len -= sizeof(mctx->block);
174         }
175
176         memcpy(mctx->block, data, len);
177 }
178
179 void md4_finish(struct md4_ctx *mctx)
180 {
181         const unsigned int offset = mctx->byte_count & 0x3f;
182         char *p = (char *)mctx->block + offset;
183         int padding = 56 - (offset + 1);
184
185         *p++ = 0x80;
186         if (padding < 0) {
187                 memset(p, 0x00, padding + sizeof (uint64_t));
188                 md4_transform_helper(mctx);
189                 p = (char *)mctx->block;
190                 padding = 56;
191         }
192
193         memset(p, 0, padding);
194         mctx->block[14] = mctx->byte_count << 3;
195         mctx->block[15] = mctx->byte_count >> 29;
196         le32_to_cpu_array(mctx->block, (sizeof(mctx->block) -
197                           sizeof(uint64_t)) / sizeof(uint32_t));
198         md4_transform(mctx->hash.words, mctx->block);
199         cpu_to_le32_array(mctx->hash.words, ARRAY_SIZE(mctx->hash.words));
200 }