Add --checksum-choice option to choose the checksum algorithms.
[rsync.git] / checksum.c
1 /*
2  * Routines to support checksumming of bytes.
3  *
4  * Copyright (C) 1996 Andrew Tridgell
5  * Copyright (C) 1996 Paul Mackerras
6  * Copyright (C) 2004-2015 Wayne Davison
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, visit the http://fsf.org website.
20  */
21
22 #include "rsync.h"
23
24 extern int checksum_seed;
25 extern int protocol_version;
26 extern int proper_seed_order;
27 extern char *checksum_choice;
28
29 #define CSUM_NONE 0
30 #define CSUM_ARCHAIC 1
31 #define CSUM_MD4_BUSTED 2
32 #define CSUM_MD4_OLD 3
33 #define CSUM_MD4 4
34 #define CSUM_MD5 5
35
36 int xfersum_type = 0; /* used for the file transfer checksums */
37 int checksum_type = 0; /* used for the pre-transfer (--checksum) checksums */
38
39 /* Returns 1 if --whole-file must be enabled. */
40 int parse_checksum_choice(void)
41 {
42         char *cp = checksum_choice ? strchr(checksum_choice, ',') : NULL;
43         if (cp) {
44                 xfersum_type = parse_csum_name(checksum_choice, cp - checksum_choice);
45                 checksum_type = parse_csum_name(cp+1, -1);
46         } else
47                 xfersum_type = checksum_type = parse_csum_name(checksum_choice, -1);
48         return xfersum_type == CSUM_NONE;
49 }
50
51 int parse_csum_name(const char *name, int len)
52 {
53         if (len < 0 && name)
54                 len = strlen(name);
55
56         if (!name || (len == 4 && strncasecmp(name, "auto", 4) == 0)) {
57                 if (protocol_version >= 30)
58                         return CSUM_MD5;
59                 if (protocol_version >= 27)
60                         return CSUM_MD4_OLD;
61                 if (protocol_version >= 21)
62                         return CSUM_MD4_BUSTED;
63                 return CSUM_ARCHAIC;
64         }
65         if (len == 3 && strncasecmp(name, "md4", 3) == 0)
66                 return CSUM_MD4;
67         if (len == 3 && strncasecmp(name, "md5", 3) == 0)
68                 return CSUM_MD5;
69         if (len == 4 && strncasecmp(name, "none", 4) == 0)
70                 return CSUM_NONE;
71
72         rprintf(FERROR, "unknown checksum name: %s\n", name);
73         exit_cleanup(RERR_UNSUPPORTED);
74 }
75
76 int csum_len_for_type(int cst)
77 {
78         switch (cst) {
79           case CSUM_NONE:
80                 return 1;
81           case CSUM_ARCHAIC:
82                 return 2;
83           case CSUM_MD4:
84           case CSUM_MD4_OLD:
85           case CSUM_MD4_BUSTED:
86                 return MD4_DIGEST_LEN;
87           case CSUM_MD5:
88                 return MD5_DIGEST_LEN;
89         }
90         return 0;
91 }
92
93 int canonical_checksum(int csum_type)
94 {
95     return csum_type >= CSUM_MD4 ? 1 : 0;
96 }
97
98 /*
99   a simple 32 bit checksum that can be upadted from either end
100   (inspired by Mark Adler's Adler-32 checksum)
101   */
102 uint32 get_checksum1(char *buf1, int32 len)
103 {
104     int32 i;
105     uint32 s1, s2;
106     schar *buf = (schar *)buf1;
107
108     s1 = s2 = 0;
109     for (i = 0; i < (len-4); i+=4) {
110         s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3] +
111           10*CHAR_OFFSET;
112         s1 += (buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3] + 4*CHAR_OFFSET);
113     }
114     for (; i < len; i++) {
115         s1 += (buf[i]+CHAR_OFFSET); s2 += s1;
116     }
117     return (s1 & 0xffff) + (s2 << 16);
118 }
119
120 void get_checksum2(char *buf, int32 len, char *sum)
121 {
122         md_context m;
123
124         switch (xfersum_type) {
125           case CSUM_MD5: {
126                 uchar seedbuf[4];
127                 md5_begin(&m);
128                 if (proper_seed_order) {
129                         if (checksum_seed) {
130                                 SIVALu(seedbuf, 0, checksum_seed);
131                                 md5_update(&m, seedbuf, 4);
132                         }
133                         md5_update(&m, (uchar *)buf, len);
134                 } else {
135                         md5_update(&m, (uchar *)buf, len);
136                         if (checksum_seed) {
137                                 SIVALu(seedbuf, 0, checksum_seed);
138                                 md5_update(&m, seedbuf, 4);
139                         }
140                 }
141                 md5_result(&m, (uchar *)sum);
142                 break;
143           }
144           case CSUM_MD4:
145           case CSUM_MD4_OLD:
146           case CSUM_MD4_BUSTED: {
147                 int32 i;
148                 static char *buf1;
149                 static int32 len1;
150
151                 mdfour_begin(&m);
152
153                 if (len > len1) {
154                         if (buf1)
155                                 free(buf1);
156                         buf1 = new_array(char, len+4);
157                         len1 = len;
158                         if (!buf1)
159                                 out_of_memory("get_checksum2");
160                 }
161
162                 memcpy(buf1, buf, len);
163                 if (checksum_seed) {
164                         SIVAL(buf1,len,checksum_seed);
165                         len += 4;
166                 }
167
168                 for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK)
169                         mdfour_update(&m, (uchar *)(buf1+i), CSUM_CHUNK);
170
171                 /*
172                  * Prior to version 27 an incorrect MD4 checksum was computed
173                  * by failing to call mdfour_tail() for block sizes that
174                  * are multiples of 64.  This is fixed by calling mdfour_update()
175                  * even when there are no more bytes.
176                  */
177                 if (len - i > 0 || xfersum_type != CSUM_MD4_BUSTED)
178                         mdfour_update(&m, (uchar *)(buf1+i), len-i);
179
180                 mdfour_result(&m, (uchar *)sum);
181                 break;
182           }
183         }
184 }
185
186 void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
187 {
188         struct map_struct *buf;
189         OFF_T i, len = st_p->st_size;
190         md_context m;
191         int32 remainder;
192         int fd;
193
194         memset(sum, 0, MAX_DIGEST_LEN);
195
196         fd = do_open(fname, O_RDONLY, 0);
197         if (fd == -1)
198                 return;
199
200         buf = map_file(fd, len, MAX_MAP_SIZE, CSUM_CHUNK);
201
202         switch (checksum_type) {
203           case CSUM_MD5:
204                 md5_begin(&m);
205
206                 for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
207                         md5_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
208                                    CSUM_CHUNK);
209                 }
210
211                 remainder = (int32)(len - i);
212                 if (remainder > 0)
213                         md5_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
214
215                 md5_result(&m, (uchar *)sum);
216                 break;
217           case CSUM_MD4:
218           case CSUM_MD4_OLD:
219           case CSUM_MD4_BUSTED:
220                 mdfour_begin(&m);
221
222                 for (i = 0; i + CSUM_CHUNK <= len; i += CSUM_CHUNK) {
223                         mdfour_update(&m, (uchar *)map_ptr(buf, i, CSUM_CHUNK),
224                                       CSUM_CHUNK);
225                 }
226
227                 /* Prior to version 27 an incorrect MD4 checksum was computed
228                  * by failing to call mdfour_tail() for block sizes that
229                  * are multiples of 64.  This is fixed by calling mdfour_update()
230                  * even when there are no more bytes. */
231                 remainder = (int32)(len - i);
232                 if (remainder > 0 || checksum_type != CSUM_MD4_BUSTED)
233                         mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder);
234
235                 mdfour_result(&m, (uchar *)sum);
236                 break;
237           default:
238                 rprintf(FERROR, "invalid checksum-choice for the --checksum option (%d)\n", checksum_type);
239                 exit_cleanup(RERR_UNSUPPORTED);
240         }
241
242         close(fd);
243         unmap_file(buf);
244 }
245
246 static int32 sumresidue;
247 static md_context md;
248 static int cursum_type;
249
250 void sum_init(int csum_type, int seed)
251 {
252         char s[4];
253
254         if (csum_type < 0)
255                 csum_type = parse_csum_name(NULL, 0);
256         cursum_type = csum_type;
257
258         switch (csum_type) {
259           case CSUM_MD5:
260                 md5_begin(&md);
261                 break;
262           case CSUM_MD4:
263                 mdfour_begin(&md);
264                 sumresidue = 0;
265                 break;
266           case CSUM_MD4_OLD:
267           case CSUM_MD4_BUSTED:
268                 mdfour_begin(&md);
269                 sumresidue = 0;
270                 SIVAL(s, 0, seed);
271                 sum_update(s, 4);
272                 break;
273           case CSUM_NONE:
274                 break;
275         }
276 }
277
278 /**
279  * Feed data into an MD4 accumulator, md.  The results may be
280  * retrieved using sum_end().  md is used for different purposes at
281  * different points during execution.
282  *
283  * @todo Perhaps get rid of md and just pass in the address each time.
284  * Very slightly clearer and slower.
285  **/
286 void sum_update(const char *p, int32 len)
287 {
288         switch (cursum_type) {
289           case CSUM_MD5:
290                 md5_update(&md, (uchar *)p, len);
291                 break;
292           case CSUM_MD4:
293           case CSUM_MD4_OLD:
294           case CSUM_MD4_BUSTED:
295                 if (len + sumresidue < CSUM_CHUNK) {
296                         memcpy(md.buffer + sumresidue, p, len);
297                         sumresidue += len;
298                         break;
299                 }
300
301                 if (sumresidue) {
302                         int32 i = CSUM_CHUNK - sumresidue;
303                         memcpy(md.buffer + sumresidue, p, i);
304                         mdfour_update(&md, (uchar *)md.buffer, CSUM_CHUNK);
305                         len -= i;
306                         p += i;
307                 }
308
309                 while (len >= CSUM_CHUNK) {
310                         mdfour_update(&md, (uchar *)p, CSUM_CHUNK);
311                         len -= CSUM_CHUNK;
312                         p += CSUM_CHUNK;
313                 }
314
315                 sumresidue = len;
316                 if (sumresidue)
317                         memcpy(md.buffer, p, sumresidue);
318                 break;
319           case CSUM_NONE:
320                 break;
321         }
322 }
323
324 int sum_end(char *sum)
325 {
326         switch (cursum_type) {
327           case CSUM_MD5:
328                 md5_result(&md, (uchar *)sum);
329                 break;
330           case CSUM_MD4:
331           case CSUM_MD4_OLD:
332                 mdfour_update(&md, (uchar *)md.buffer, sumresidue);
333                 mdfour_result(&md, (uchar *)sum);
334                 break;
335           case CSUM_MD4_BUSTED:
336                 if (sumresidue)
337                         mdfour_update(&md, (uchar *)md.buffer, sumresidue);
338                 mdfour_result(&md, (uchar *)sum);
339                 break;
340           case CSUM_NONE:
341                 *sum = '\0';
342                 break;
343         }
344
345         return csum_len_for_type(cursum_type);
346 }