-rw-r--r-- | rsync/mdfour.c | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/rsync/mdfour.c b/rsync/mdfour.c new file mode 100644 index 0000000..4c3568d --- a/dev/null +++ b/rsync/mdfour.c | |||
@@ -0,0 +1,326 @@ | |||
1 | /*= -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * librsync -- the library for network deltas | ||
4 | * $Id$ | ||
5 | * | ||
6 | * Copyright (C) 2000, 2001 by Martin Pool <mbp@samba.org> | ||
7 | * Copyright (C) 1997-1999 by Andrew Tridgell | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU Lesser General Public License as published by | ||
11 | * the Free Software Foundation; either version 2.1 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU Lesser General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU Lesser General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | /* MD4 message digest algorithm. | ||
25 | * | ||
26 | * TODO: Perhaps use the MD4 routine from OpenSSL if it's installed. | ||
27 | * It's probably not worth the trouble. | ||
28 | * | ||
29 | * This was originally written by Andrew Tridgell for use in Samba. */ | ||
30 | |||
31 | #include <config_rsync.h> | ||
32 | |||
33 | #include <stdlib.h> | ||
34 | #include <string.h> | ||
35 | #include <stdio.h> | ||
36 | |||
37 | #include "rsync.h" | ||
38 | #include "trace.h" | ||
39 | #include "types.h" | ||
40 | |||
41 | |||
42 | static void (*rs_mdfour_block)(rs_mdfour_t *md, void const *p) = NULL; | ||
43 | |||
44 | |||
45 | #define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z))) | ||
46 | #define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))) | ||
47 | #define H(X,Y,Z) ((X)^(Y)^(Z)) | ||
48 | #define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s)))) | ||
49 | |||
50 | #define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s) | ||
51 | #define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s) | ||
52 | #define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s) | ||
53 | |||
54 | /** | ||
55 | * Update an MD4 accumulator from a 64-byte chunk. | ||
56 | * | ||
57 | * This cannot be used for the last chunk of the file, which must be | ||
58 | * padded and contain the file length. rs_mdfour_tail() is used for | ||
59 | * that. | ||
60 | * | ||
61 | * \todo Recode to be fast, and to use system integer types. Perhaps | ||
62 | * if we can find an mdfour implementation already on the system | ||
63 | * (e.g. in OpenSSL) then we should use it instead of our own? | ||
64 | * | ||
65 | * \param X A series of integer, read little-endian from the file. | ||
66 | */ | ||
67 | static void | ||
68 | rs_mdfour64(rs_mdfour_t * m, const void *p) | ||
69 | { | ||
70 | uint32_t AA, BB, CC, DD; | ||
71 | uint32_t A, B, C, D; | ||
72 | const uint32_t *X = (const uint32_t *) p; | ||
73 | |||
74 | A = m->A; | ||
75 | B = m->B; | ||
76 | C = m->C; | ||
77 | D = m->D; | ||
78 | AA = A; | ||
79 | BB = B; | ||
80 | CC = C; | ||
81 | DD = D; | ||
82 | |||
83 | ROUND1(A, B, C, D, 0, 3); | ||
84 | ROUND1(D, A, B, C, 1, 7); | ||
85 | ROUND1(C, D, A, B, 2, 11); | ||
86 | ROUND1(B, C, D, A, 3, 19); | ||
87 | ROUND1(A, B, C, D, 4, 3); | ||
88 | ROUND1(D, A, B, C, 5, 7); | ||
89 | ROUND1(C, D, A, B, 6, 11); | ||
90 | ROUND1(B, C, D, A, 7, 19); | ||
91 | ROUND1(A, B, C, D, 8, 3); | ||
92 | ROUND1(D, A, B, C, 9, 7); | ||
93 | ROUND1(C, D, A, B, 10, 11); | ||
94 | ROUND1(B, C, D, A, 11, 19); | ||
95 | ROUND1(A, B, C, D, 12, 3); | ||
96 | ROUND1(D, A, B, C, 13, 7); | ||
97 | ROUND1(C, D, A, B, 14, 11); | ||
98 | ROUND1(B, C, D, A, 15, 19); | ||
99 | |||
100 | ROUND2(A, B, C, D, 0, 3); | ||
101 | ROUND2(D, A, B, C, 4, 5); | ||
102 | ROUND2(C, D, A, B, 8, 9); | ||
103 | ROUND2(B, C, D, A, 12, 13); | ||
104 | ROUND2(A, B, C, D, 1, 3); | ||
105 | ROUND2(D, A, B, C, 5, 5); | ||
106 | ROUND2(C, D, A, B, 9, 9); | ||
107 | ROUND2(B, C, D, A, 13, 13); | ||
108 | ROUND2(A, B, C, D, 2, 3); | ||
109 | ROUND2(D, A, B, C, 6, 5); | ||
110 | ROUND2(C, D, A, B, 10, 9); | ||
111 | ROUND2(B, C, D, A, 14, 13); | ||
112 | ROUND2(A, B, C, D, 3, 3); | ||
113 | ROUND2(D, A, B, C, 7, 5); | ||
114 | ROUND2(C, D, A, B, 11, 9); | ||
115 | ROUND2(B, C, D, A, 15, 13); | ||
116 | |||
117 | ROUND3(A, B, C, D, 0, 3); | ||
118 | ROUND3(D, A, B, C, 8, 9); | ||
119 | ROUND3(C, D, A, B, 4, 11); | ||
120 | ROUND3(B, C, D, A, 12, 15); | ||
121 | ROUND3(A, B, C, D, 2, 3); | ||
122 | ROUND3(D, A, B, C, 10, 9); | ||
123 | ROUND3(C, D, A, B, 6, 11); | ||
124 | ROUND3(B, C, D, A, 14, 15); | ||
125 | ROUND3(A, B, C, D, 1, 3); | ||
126 | ROUND3(D, A, B, C, 9, 9); | ||
127 | ROUND3(C, D, A, B, 5, 11); | ||
128 | ROUND3(B, C, D, A, 13, 15); | ||
129 | ROUND3(A, B, C, D, 3, 3); | ||
130 | ROUND3(D, A, B, C, 11, 9); | ||
131 | ROUND3(C, D, A, B, 7, 11); | ||
132 | ROUND3(B, C, D, A, 15, 15); | ||
133 | |||
134 | A += AA; | ||
135 | B += BB; | ||
136 | C += CC; | ||
137 | D += DD; | ||
138 | |||
139 | m->A = A; | ||
140 | m->B = B; | ||
141 | m->C = C; | ||
142 | m->D = D; | ||
143 | } | ||
144 | |||
145 | |||
146 | /* These next two routines are necessary because MD4 is specified in | ||
147 | * terms of little-endian int32s, but we have a byte buffer. On | ||
148 | * little-endian platforms, I think we can just use the buffer pointer | ||
149 | * directly. | ||
150 | * | ||
151 | * There are some nice endianness routines in glib, including | ||
152 | * assembler variants. If we ever depended on glib, then it could be | ||
153 | * good to use them instead. */ | ||
154 | static void | ||
155 | copy64( /* @out@ */ uint32_t * M, unsigned char const *in) | ||
156 | { | ||
157 | int i; | ||
158 | |||
159 | for (i = 0; i < 16; i++) | ||
160 | M[i] = (in[i * 4 + 3] << 24) | (in[i * 4 + 2] << 16) | | ||
161 | (in[i * 4 + 1] << 8) | (in[i * 4 + 0] << 0); | ||
162 | } | ||
163 | |||
164 | static void | ||
165 | copy4( /* @out@ */ unsigned char *out, uint32_t const x) | ||
166 | { | ||
167 | out[0] = x & 0xFF; | ||
168 | out[1] = (x >> 8) & 0xFF; | ||
169 | out[2] = (x >> 16) & 0xFF; | ||
170 | out[3] = (x >> 24) & 0xFF; | ||
171 | } | ||
172 | |||
173 | |||
174 | |||
175 | /** | ||
176 | * Accumulate a block, making appropriate conversions for bigendian | ||
177 | * machines. | ||
178 | */ | ||
179 | static void | ||
180 | rs_mdfour_block_slow(rs_mdfour_t *md, void const *p) | ||
181 | { | ||
182 | uint32_t M[16]; | ||
183 | |||
184 | copy64(M, p); | ||
185 | rs_mdfour64(md, M); | ||
186 | } | ||
187 | |||
188 | |||
189 | static void | ||
190 | rs_mdfour_choose_packer(void) | ||
191 | { | ||
192 | static const char foo[] = { 0xde, 0xad, 0xbe, 0xef}; | ||
193 | const uint32_t *p = (const uint32_t *) foo; | ||
194 | |||
195 | if (sizeof(uint32_t) != 4) | ||
196 | rs_fatal("internal error: uint32_t is not really 32 bits!"); | ||
197 | if (sizeof(foo) != 4) | ||
198 | rs_fatal("internal error: something wierd about char arrays"); | ||
199 | |||
200 | if (*p == 0xdeadbeef) { | ||
201 | rs_trace("big-endian machine"); | ||
202 | rs_mdfour_block = rs_mdfour_block_slow; | ||
203 | } else if (*p == 0xefbeadde) { | ||
204 | rs_trace("little-endian machine"); | ||
205 | rs_mdfour_block = rs_mdfour64; | ||
206 | } else { | ||
207 | rs_fatal("can't determine endianness from %#x", *p); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | |||
212 | void | ||
213 | rs_mdfour_begin(rs_mdfour_t * md) | ||
214 | { | ||
215 | if (!rs_mdfour_block) | ||
216 | rs_mdfour_choose_packer(); | ||
217 | |||
218 | memset(md, 0, sizeof(*md)); | ||
219 | md->A = 0x67452301; | ||
220 | md->B = 0xefcdab89; | ||
221 | md->C = 0x98badcfe; | ||
222 | md->D = 0x10325476; | ||
223 | md->totalN = 0; | ||
224 | } | ||
225 | |||
226 | |||
227 | /** | ||
228 | * Handle special behaviour for processing the last block of a file | ||
229 | * when calculating its MD4 checksum. | ||
230 | * | ||
231 | * This must be called exactly once per file. | ||
232 | */ | ||
233 | static void | ||
234 | rs_mdfour_tail(rs_mdfour_t * m, unsigned char const *in, int n) | ||
235 | { | ||
236 | unsigned char buf[128]; | ||
237 | uint32_t b; | ||
238 | |||
239 | m->totalN += n; | ||
240 | |||
241 | b = m->totalN * 8; | ||
242 | |||
243 | memset(buf, 0, 128); | ||
244 | if (n) | ||
245 | memcpy(buf, in, n); | ||
246 | buf[n] = 0x80; | ||
247 | |||
248 | if (n <= 55) { | ||
249 | copy4(buf + 56, b); | ||
250 | rs_mdfour_block(m, buf); | ||
251 | } else { | ||
252 | copy4(buf + 120, b); | ||
253 | rs_mdfour_block(m, buf); | ||
254 | rs_mdfour_block(m, buf + 64); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | |||
259 | /** | ||
260 | * Feed some data into the MD4 accumulator. | ||
261 | * | ||
262 | * \param n Number of bytes fed in. | ||
263 | */ | ||
264 | void | ||
265 | rs_mdfour_update(rs_mdfour_t * md, void const *in_void, size_t n) | ||
266 | { | ||
267 | unsigned char const *in = (unsigned char const *) in_void; | ||
268 | |||
269 | if (n == 0) | ||
270 | return; | ||
271 | |||
272 | if (md->tail_len) { | ||
273 | size_t tail_gap = 64 - md->tail_len; | ||
274 | |||
275 | /* If there's any leftover data in the tail buffer, then first | ||
276 | * we have to make it up to a whole block and process it. */ | ||
277 | if (tail_gap > n) | ||
278 | tail_gap = n; | ||
279 | memcpy(&md->tail[md->tail_len], in, tail_gap); | ||
280 | md->tail_len += tail_gap; | ||
281 | in += tail_gap; | ||
282 | n -= tail_gap; | ||
283 | |||
284 | if (md->tail_len != 64) | ||
285 | return; | ||
286 | |||
287 | rs_mdfour_block(md, md->tail); | ||
288 | md->tail_len = 0; | ||
289 | md->totalN += 64; | ||
290 | } | ||
291 | |||
292 | while (n >= 64) { | ||
293 | rs_mdfour_block(md, in); | ||
294 | in += 64; | ||
295 | n -= 64; | ||
296 | md->totalN += 64; | ||
297 | } | ||
298 | |||
299 | if (n) { | ||
300 | memcpy(md->tail, in, n); | ||
301 | md->tail_len = n; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | |||
306 | void | ||
307 | rs_mdfour_result(rs_mdfour_t * md, unsigned char *out) | ||
308 | { | ||
309 | rs_mdfour_tail(md, md->tail, md->tail_len); | ||
310 | |||
311 | copy4(out, md->A); | ||
312 | copy4(out + 4, md->B); | ||
313 | copy4(out + 8, md->C); | ||
314 | copy4(out + 12, md->D); | ||
315 | } | ||
316 | |||
317 | |||
318 | void | ||
319 | rs_mdfour(unsigned char *out, void const *in, size_t n) | ||
320 | { | ||
321 | rs_mdfour_t md; | ||
322 | |||
323 | rs_mdfour_begin(&md); | ||
324 | rs_mdfour_update(&md, in, n); | ||
325 | rs_mdfour_result(&md, out); | ||
326 | } | ||