2 * Routines to support checksumming of bytes.
4 * Copyright (C) 1996 Andrew Tridgell
5 * Copyright (C) 1996 Paul Mackerras
6 * Copyright (C) 2004-2007 Wayne Davison
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.
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.
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.
24 extern int checksum_seed
;
25 extern int protocol_version
;
27 int csum_length
= SHORT_SUM_LENGTH
; /* initial value */
30 a simple 32 bit checksum that can be upadted from either end
31 (inspired by Mark Adler's Adler-32 checksum)
33 uint32
get_checksum1(char *buf1
, int32 len
)
37 schar
*buf
= (schar
*)buf1
;
40 for (i
= 0; i
< (len
-4); i
+=4) {
41 s2
+= 4*(s1
+ buf
[i
]) + 3*buf
[i
+1] + 2*buf
[i
+2] + buf
[i
+3] +
43 s1
+= (buf
[i
+0] + buf
[i
+1] + buf
[i
+2] + buf
[i
+3] + 4*CHAR_OFFSET
);
45 for (; i
< len
; i
++) {
46 s1
+= (buf
[i
]+CHAR_OFFSET
); s2
+= s1
;
48 return (s1
& 0xffff) + (s2
<< 16);
52 void get_checksum2(char *buf
, int32 len
, char *sum
)
56 if (protocol_version
>= 30) {
59 md5_update(&m
, (uchar
*)buf
, len
);
61 SIVAL(seedbuf
, 0, checksum_seed
);
62 md5_update(&m
, seedbuf
, 4);
64 md5_result(&m
, (uchar
*)sum
);
75 buf1
= new_array(char, len
+4);
78 out_of_memory("get_checksum2");
81 memcpy(buf1
, buf
, len
);
83 SIVAL(buf1
,len
,checksum_seed
);
87 for (i
= 0; i
+ CSUM_CHUNK
<= len
; i
+= CSUM_CHUNK
)
88 mdfour_update(&m
, (uchar
*)(buf1
+i
), CSUM_CHUNK
);
91 * Prior to version 27 an incorrect MD4 checksum was computed
92 * by failing to call mdfour_tail() for block sizes that
93 * are multiples of 64. This is fixed by calling mdfour_update()
94 * even when there are no more bytes.
96 if (len
- i
> 0 || protocol_version
>= 27)
97 mdfour_update(&m
, (uchar
*)(buf1
+i
), len
-i
);
99 mdfour_result(&m
, (uchar
*)sum
);
103 void file_checksum(char *fname
, char *sum
, OFF_T size
)
105 struct map_struct
*buf
;
111 memset(sum
, 0, MAX_DIGEST_LEN
);
113 fd
= do_open(fname
, O_RDONLY
, 0);
117 buf
= map_file(fd
, size
, MAX_MAP_SIZE
, CSUM_CHUNK
);
119 if (protocol_version
>= 30) {
122 for (i
= 0; i
+ CSUM_CHUNK
<= len
; i
+= CSUM_CHUNK
) {
123 md5_update(&m
, (uchar
*)map_ptr(buf
, i
, CSUM_CHUNK
),
127 remainder
= (int32
)(len
- i
);
129 md5_update(&m
, (uchar
*)map_ptr(buf
, i
, remainder
), remainder
);
131 md5_result(&m
, (uchar
*)sum
);
135 for (i
= 0; i
+ CSUM_CHUNK
<= len
; i
+= CSUM_CHUNK
) {
136 mdfour_update(&m
, (uchar
*)map_ptr(buf
, i
, CSUM_CHUNK
),
140 /* Prior to version 27 an incorrect MD4 checksum was computed
141 * by failing to call mdfour_tail() for block sizes that
142 * are multiples of 64. This is fixed by calling mdfour_update()
143 * even when there are no more bytes. */
144 remainder
= (int32
)(len
- i
);
145 if (remainder
> 0 || protocol_version
>= 27)
146 mdfour_update(&m
, (uchar
*)map_ptr(buf
, i
, remainder
), remainder
);
148 mdfour_result(&m
, (uchar
*)sum
);
155 static int32 sumresidue
;
156 static md_context md
;
158 void sum_init(int seed
)
162 if (protocol_version
>= 30)
173 * Feed data into an MD4 accumulator, md. The results may be
174 * retrieved using sum_end(). md is used for different purposes at
175 * different points during execution.
177 * @todo Perhaps get rid of md and just pass in the address each time.
178 * Very slightly clearer and slower.
180 void sum_update(const char *p
, int32 len
)
182 if (protocol_version
>= 30) {
183 md5_update(&md
, (uchar
*)p
, len
);
187 if (len
+ sumresidue
< CSUM_CHUNK
) {
188 memcpy(md
.buffer
+ sumresidue
, p
, len
);
194 int32 i
= CSUM_CHUNK
- sumresidue
;
195 memcpy(md
.buffer
+ sumresidue
, p
, i
);
196 mdfour_update(&md
, (uchar
*)md
.buffer
, CSUM_CHUNK
);
201 while (len
>= CSUM_CHUNK
) {
202 mdfour_update(&md
, (uchar
*)p
, CSUM_CHUNK
);
209 memcpy(md
.buffer
, p
, sumresidue
);
212 int sum_end(char *sum
)
214 if (protocol_version
>= 30) {
215 md5_result(&md
, (uchar
*)sum
);
216 return MD5_DIGEST_LEN
;
219 if (sumresidue
|| protocol_version
>= 27)
220 mdfour_update(&md
, (uchar
*)md
.buffer
, sumresidue
);
222 mdfour_result(&md
, (uchar
*)sum
);
224 return MD4_DIGEST_LEN
;