blob: 783f440279b6302cf79a3eed02023a8b3a38706e
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Copyright (C) 2003 Glenn L. McGrath |
4 | * Copyright (C) 2003-2004 Erik Andersen |
5 | * |
6 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
7 | */ |
8 | //config:config MD5SUM |
9 | //config: bool "md5sum" |
10 | //config: default y |
11 | //config: help |
12 | //config: md5sum is used to print or check MD5 checksums. |
13 | //config: |
14 | //config:config SHA1SUM |
15 | //config: bool "sha1sum" |
16 | //config: default y |
17 | //config: help |
18 | //config: Compute and check SHA1 message digest |
19 | //config: |
20 | //config:config SHA256SUM |
21 | //config: bool "sha256sum" |
22 | //config: default y |
23 | //config: help |
24 | //config: Compute and check SHA256 message digest |
25 | //config: |
26 | //config:config SHA512SUM |
27 | //config: bool "sha512sum" |
28 | //config: default y |
29 | //config: help |
30 | //config: Compute and check SHA512 message digest |
31 | //config: |
32 | //config:config SHA3SUM |
33 | //config: bool "sha3sum" |
34 | //config: default y |
35 | //config: help |
36 | //config: Compute and check SHA3 message digest |
37 | //config: |
38 | //config:comment "Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum" |
39 | //config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM || SHA3SUM |
40 | //config: |
41 | //config:config FEATURE_MD5_SHA1_SUM_CHECK |
42 | //config: bool "Enable -c, -s and -w options" |
43 | //config: default y |
44 | //config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM || SHA3SUM |
45 | //config: help |
46 | //config: Enabling the -c options allows files to be checked |
47 | //config: against pre-calculated hash values. |
48 | //config: |
49 | //config: -s and -w are useful options when verifying checksums. |
50 | |
51 | //applet:IF_MD5SUM(APPLET_NOEXEC(md5sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, md5sum)) |
52 | //applet:IF_SHA1SUM(APPLET_NOEXEC(sha1sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha1sum)) |
53 | //applet:IF_SHA3SUM(APPLET_NOEXEC(sha3sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha3sum)) |
54 | //applet:IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha256sum)) |
55 | //applet:IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha512sum)) |
56 | |
57 | //kbuild:lib-$(CONFIG_MD5SUM) += md5_sha1_sum.o |
58 | //kbuild:lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o |
59 | //kbuild:lib-$(CONFIG_SHA256SUM) += md5_sha1_sum.o |
60 | //kbuild:lib-$(CONFIG_SHA512SUM) += md5_sha1_sum.o |
61 | //kbuild:lib-$(CONFIG_SHA3SUM) += md5_sha1_sum.o |
62 | |
63 | //usage:#define md5sum_trivial_usage |
64 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." |
65 | //usage:#define md5sum_full_usage "\n\n" |
66 | //usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " MD5 checksums" |
67 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" |
68 | //usage: "\n -c Check sums against list in FILEs" |
69 | //usage: "\n -s Don't output anything, status code shows success" |
70 | //usage: "\n -w Warn about improperly formatted checksum lines" |
71 | //usage: ) |
72 | //usage: |
73 | //usage:#define md5sum_example_usage |
74 | //usage: "$ md5sum < busybox\n" |
75 | //usage: "6fd11e98b98a58f64ff3398d7b324003\n" |
76 | //usage: "$ md5sum busybox\n" |
77 | //usage: "6fd11e98b98a58f64ff3398d7b324003 busybox\n" |
78 | //usage: "$ md5sum -c -\n" |
79 | //usage: "6fd11e98b98a58f64ff3398d7b324003 busybox\n" |
80 | //usage: "busybox: OK\n" |
81 | //usage: "^D\n" |
82 | //usage: |
83 | //usage:#define sha1sum_trivial_usage |
84 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." |
85 | //usage:#define sha1sum_full_usage "\n\n" |
86 | //usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums" |
87 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" |
88 | //usage: "\n -c Check sums against list in FILEs" |
89 | //usage: "\n -s Don't output anything, status code shows success" |
90 | //usage: "\n -w Warn about improperly formatted checksum lines" |
91 | //usage: ) |
92 | //usage: |
93 | //usage:#define sha256sum_trivial_usage |
94 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." |
95 | //usage:#define sha256sum_full_usage "\n\n" |
96 | //usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA256 checksums" |
97 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" |
98 | //usage: "\n -c Check sums against list in FILEs" |
99 | //usage: "\n -s Don't output anything, status code shows success" |
100 | //usage: "\n -w Warn about improperly formatted checksum lines" |
101 | //usage: ) |
102 | //usage: |
103 | //usage:#define sha512sum_trivial_usage |
104 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." |
105 | //usage:#define sha512sum_full_usage "\n\n" |
106 | //usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA512 checksums" |
107 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" |
108 | //usage: "\n -c Check sums against list in FILEs" |
109 | //usage: "\n -s Don't output anything, status code shows success" |
110 | //usage: "\n -w Warn about improperly formatted checksum lines" |
111 | //usage: ) |
112 | //usage: |
113 | //usage:#define sha3sum_trivial_usage |
114 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[-a BITS] [FILE]..." |
115 | //usage:#define sha3sum_full_usage "\n\n" |
116 | //usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA3 checksums" |
117 | //usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" |
118 | //usage: "\n -c Check sums against list in FILEs" |
119 | //usage: "\n -s Don't output anything, status code shows success" |
120 | //usage: "\n -w Warn about improperly formatted checksum lines" |
121 | //usage: "\n -a BITS 224 (default), 256, 384, 512" |
122 | //usage: ) |
123 | |
124 | //FIXME: GNU coreutils 8.25 has no -s option, it has only these two long opts: |
125 | // --quiet don't print OK for each successfully verified file |
126 | // --status don't output anything, status code shows success |
127 | |
128 | #include "libbb.h" |
129 | |
130 | /* This is a NOEXEC applet. Be very careful! */ |
131 | |
132 | enum { |
133 | /* 4th letter of applet_name is... */ |
134 | HASH_MD5 = 's', /* "md5>s<um" */ |
135 | HASH_SHA1 = '1', |
136 | HASH_SHA256 = '2', |
137 | HASH_SHA3 = '3', |
138 | HASH_SHA512 = '5', |
139 | }; |
140 | |
141 | #define FLAG_SILENT 1 |
142 | #define FLAG_CHECK 2 |
143 | #define FLAG_WARN 4 |
144 | |
145 | /* This might be useful elsewhere */ |
146 | static unsigned char *hash_bin_to_hex(unsigned char *hash_value, |
147 | unsigned hash_length) |
148 | { |
149 | /* xzalloc zero-terminates */ |
150 | char *hex_value = xzalloc((hash_length * 2) + 1); |
151 | bin2hex(hex_value, (char*)hash_value, hash_length); |
152 | return (unsigned char *)hex_value; |
153 | } |
154 | |
155 | #if !ENABLE_SHA3SUM |
156 | # define hash_file(f,w) hash_file(f) |
157 | #endif |
158 | static uint8_t *hash_file(const char *filename, unsigned sha3_width) |
159 | { |
160 | int src_fd, hash_len, count; |
161 | union _ctx_ { |
162 | sha3_ctx_t sha3; |
163 | sha512_ctx_t sha512; |
164 | sha256_ctx_t sha256; |
165 | sha1_ctx_t sha1; |
166 | md5_ctx_t md5; |
167 | } context; |
168 | uint8_t *hash_value; |
169 | void FAST_FUNC (*update)(void*, const void*, size_t); |
170 | void FAST_FUNC (*final)(void*, void*); |
171 | char hash_algo; |
172 | |
173 | src_fd = open_or_warn_stdin(filename); |
174 | if (src_fd < 0) { |
175 | return NULL; |
176 | } |
177 | |
178 | hash_algo = applet_name[3]; |
179 | |
180 | /* figure specific hash algorithms */ |
181 | if (ENABLE_MD5SUM && hash_algo == HASH_MD5) { |
182 | md5_begin(&context.md5); |
183 | update = (void*)md5_hash; |
184 | final = (void*)md5_end; |
185 | hash_len = 16; |
186 | } |
187 | else if (ENABLE_SHA1SUM && hash_algo == HASH_SHA1) { |
188 | sha1_begin(&context.sha1); |
189 | update = (void*)sha1_hash; |
190 | final = (void*)sha1_end; |
191 | hash_len = 20; |
192 | } |
193 | else if (ENABLE_SHA256SUM && hash_algo == HASH_SHA256) { |
194 | sha256_begin(&context.sha256); |
195 | update = (void*)sha256_hash; |
196 | final = (void*)sha256_end; |
197 | hash_len = 32; |
198 | } |
199 | else if (ENABLE_SHA512SUM && hash_algo == HASH_SHA512) { |
200 | sha512_begin(&context.sha512); |
201 | update = (void*)sha512_hash; |
202 | final = (void*)sha512_end; |
203 | hash_len = 64; |
204 | } |
205 | #if ENABLE_SHA3SUM |
206 | else if (ENABLE_SHA3SUM && hash_algo == HASH_SHA3) { |
207 | sha3_begin(&context.sha3); |
208 | update = (void*)sha3_hash; |
209 | final = (void*)sha3_end; |
210 | /* |
211 | * Should support 224, 256, 384, 512. |
212 | * We allow any value which does not blow the algorithm up. |
213 | */ |
214 | if (sha3_width >= 1600/2 /* input block can't be <= 0 */ |
215 | || sha3_width == 0 /* hash len can't be 0 */ |
216 | || (sha3_width & 0x1f) /* should be multiple of 32 */ |
217 | /* (because input uses up to 8 byte wide word XORs. 32/4=8) */ |
218 | ) { |
219 | bb_error_msg_and_die("bad -a%u", sha3_width); |
220 | } |
221 | sha3_width /= 4; |
222 | context.sha3.input_block_bytes = 1600/8 - sha3_width; |
223 | hash_len = sha3_width/2; |
224 | } |
225 | #endif |
226 | else { |
227 | xfunc_die(); /* can't reach this */ |
228 | } |
229 | |
230 | { |
231 | RESERVE_CONFIG_UBUFFER(in_buf, 4096); |
232 | while ((count = safe_read(src_fd, in_buf, 4096)) > 0) { |
233 | update(&context, in_buf, count); |
234 | } |
235 | hash_value = NULL; |
236 | if (count < 0) |
237 | bb_perror_msg("can't read '%s'", filename); |
238 | else /* count == 0 */ { |
239 | final(&context, in_buf); |
240 | hash_value = hash_bin_to_hex(in_buf, hash_len); |
241 | } |
242 | RELEASE_CONFIG_BUFFER(in_buf); |
243 | } |
244 | |
245 | if (src_fd != STDIN_FILENO) { |
246 | close(src_fd); |
247 | } |
248 | |
249 | return hash_value; |
250 | } |
251 | |
252 | int md5_sha1_sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
253 | int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) |
254 | { |
255 | int return_value = EXIT_SUCCESS; |
256 | unsigned flags; |
257 | #if ENABLE_SHA3SUM |
258 | unsigned sha3_width = 224; |
259 | #endif |
260 | |
261 | if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK) { |
262 | /* -s and -w require -c */ |
263 | opt_complementary = "s?c:w?c"; |
264 | /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ |
265 | #if ENABLE_SHA3SUM |
266 | if (applet_name[3] == HASH_SHA3) |
267 | flags = getopt32(argv, "scwbta:+", &sha3_width); |
268 | else |
269 | #endif |
270 | flags = getopt32(argv, "scwbt"); |
271 | } else { |
272 | #if ENABLE_SHA3SUM |
273 | if (applet_name[3] == HASH_SHA3) |
274 | getopt32(argv, "a:+", &sha3_width); |
275 | else |
276 | #endif |
277 | getopt32(argv, ""); |
278 | } |
279 | argv += optind; |
280 | //argc -= optind; |
281 | if (!*argv) |
282 | *--argv = (char*)"-"; |
283 | |
284 | do { |
285 | if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) { |
286 | FILE *pre_computed_stream; |
287 | char *line; |
288 | int count_total = 0; |
289 | int count_failed = 0; |
290 | |
291 | pre_computed_stream = xfopen_stdin(*argv); |
292 | |
293 | while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) { |
294 | uint8_t *hash_value; |
295 | char *filename_ptr; |
296 | |
297 | count_total++; |
298 | filename_ptr = strstr(line, " "); |
299 | /* handle format for binary checksums */ |
300 | if (filename_ptr == NULL) { |
301 | filename_ptr = strstr(line, " *"); |
302 | } |
303 | if (filename_ptr == NULL) { |
304 | if (flags & FLAG_WARN) { |
305 | bb_error_msg("invalid format"); |
306 | } |
307 | count_failed++; |
308 | return_value = EXIT_FAILURE; |
309 | free(line); |
310 | continue; |
311 | } |
312 | *filename_ptr = '\0'; |
313 | filename_ptr += 2; |
314 | |
315 | hash_value = hash_file(filename_ptr, sha3_width); |
316 | |
317 | if (hash_value && (strcmp((char*)hash_value, line) == 0)) { |
318 | if (!(flags & FLAG_SILENT)) |
319 | printf("%s: OK\n", filename_ptr); |
320 | } else { |
321 | if (!(flags & FLAG_SILENT)) |
322 | printf("%s: FAILED\n", filename_ptr); |
323 | count_failed++; |
324 | return_value = EXIT_FAILURE; |
325 | } |
326 | /* possible free(NULL) */ |
327 | free(hash_value); |
328 | free(line); |
329 | } |
330 | if (count_failed && !(flags & FLAG_SILENT)) { |
331 | bb_error_msg("WARNING: %d of %d computed checksums did NOT match", |
332 | count_failed, count_total); |
333 | } |
334 | if (count_total == 0) { |
335 | return_value = EXIT_FAILURE; |
336 | /* |
337 | * md5sum from GNU coreutils 8.25 says: |
338 | * md5sum: <FILE>: no properly formatted MD5 checksum lines found |
339 | */ |
340 | bb_error_msg("%s: no checksum lines found", *argv); |
341 | } |
342 | fclose_if_not_stdin(pre_computed_stream); |
343 | } else { |
344 | uint8_t *hash_value = hash_file(*argv, sha3_width); |
345 | if (hash_value == NULL) { |
346 | return_value = EXIT_FAILURE; |
347 | } else { |
348 | printf("%s %s\n", hash_value, *argv); |
349 | free(hash_value); |
350 | } |
351 | } |
352 | } while (*++argv); |
353 | |
354 | return return_value; |
355 | } |
356 |