3b897c18f723ccfe16717e37072f4883bbae699b
[platform/upstream/busybox.git] / coreutils / md5_sha1_sum.c
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
9 #include "libbb.h"
10
11 /* This is a NOEXEC applet. Be very careful! */
12
13 enum {
14         /* 4th letter of applet_name is... */
15         HASH_MD5 = 's', /* "md5>s<um" */
16         HASH_SHA1 = '1',
17         HASH_SHA256 = '2',
18         HASH_SHA512 = '5',
19 };
20
21 #define FLAG_SILENT  1
22 #define FLAG_CHECK   2
23 #define FLAG_WARN    4
24
25 /* This might be useful elsewhere */
26 static unsigned char *hash_bin_to_hex(unsigned char *hash_value,
27                                 unsigned hash_length)
28 {
29         /* xzalloc zero-terminates */
30         char *hex_value = xzalloc((hash_length * 2) + 1);
31         bin2hex(hex_value, (char*)hash_value, hash_length);
32         return (unsigned char *)hex_value;
33 }
34
35 static uint8_t *hash_file(const char *filename)
36 {
37         int src_fd, hash_len, count;
38         union _ctx_ {
39                 sha512_ctx_t sha512;
40                 sha256_ctx_t sha256;
41                 sha1_ctx_t sha1;
42                 md5_ctx_t md5;
43         } context;
44         uint8_t *hash_value = NULL;
45         RESERVE_CONFIG_UBUFFER(in_buf, 4096);
46         void FAST_FUNC (*update)(void*, const void*, size_t);
47         void FAST_FUNC (*final)(void*, void*);
48         char hash_algo;
49
50         src_fd = open_or_warn_stdin(filename);
51         if (src_fd < 0) {
52                 return NULL;
53         }
54
55         hash_algo = applet_name[3];
56
57         /* figure specific hash algorithims */
58         if (ENABLE_MD5SUM && hash_algo == HASH_MD5) {
59                 md5_begin(&context.md5);
60                 update = (void*)md5_hash;
61                 final = (void*)md5_end;
62                 hash_len = 16;
63         } else if (ENABLE_SHA1SUM && hash_algo == HASH_SHA1) {
64                 sha1_begin(&context.sha1);
65                 update = (void*)sha1_hash;
66                 final = (void*)sha1_end;
67                 hash_len = 20;
68         } else if (ENABLE_SHA256SUM && hash_algo == HASH_SHA256) {
69                 sha256_begin(&context.sha256);
70                 update = (void*)sha256_hash;
71                 final = (void*)sha256_end;
72                 hash_len = 32;
73         } else if (ENABLE_SHA512SUM && hash_algo == HASH_SHA512) {
74                 sha512_begin(&context.sha512);
75                 update = (void*)sha512_hash;
76                 final = (void*)sha512_end;
77                 hash_len = 64;
78         } else {
79                 xfunc_die(); /* can't reach this */
80         }
81
82         while ((count = safe_read(src_fd, in_buf, 4096)) > 0) {
83                 update(&context, in_buf, count);
84         }
85
86         if (count == 0) {
87                 final(&context, in_buf);
88                 hash_value = hash_bin_to_hex(in_buf, hash_len);
89         }
90
91         RELEASE_CONFIG_BUFFER(in_buf);
92
93         if (src_fd != STDIN_FILENO) {
94                 close(src_fd);
95         }
96
97         return hash_value;
98 }
99
100 int md5_sha1_sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
101 int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv)
102 {
103         int return_value = EXIT_SUCCESS;
104         unsigned flags;
105
106         if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK) {
107                 /* -b "binary", -t "text" are ignored (shaNNNsum compat) */
108                 flags = getopt32(argv, "scwbt");
109                 argv += optind;
110                 //argc -= optind;
111         } else {
112                 argv += 1;
113                 //argc -= 1;
114         }
115         if (!*argv)
116                 *--argv = (char*)"-";
117
118         if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && !(flags & FLAG_CHECK)) {
119                 if (flags & FLAG_SILENT) {
120                         bb_error_msg_and_die("-%c is meaningful only with -c", 's');
121                 }
122                 if (flags & FLAG_WARN) {
123                         bb_error_msg_and_die("-%c is meaningful only with -c", 'w');
124                 }
125         }
126
127         if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) {
128                 FILE *pre_computed_stream;
129                 int count_total = 0;
130                 int count_failed = 0;
131                 char *line;
132
133                 if (argv[1]) {
134                         bb_error_msg_and_die("only one argument may be specified with -c");
135                 }
136
137                 pre_computed_stream = xfopen_stdin(argv[0]);
138
139                 while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) {
140                         uint8_t *hash_value;
141                         char *filename_ptr;
142
143                         count_total++;
144                         filename_ptr = strstr(line, "  ");
145                         /* handle format for binary checksums */
146                         if (filename_ptr == NULL) {
147                                 filename_ptr = strstr(line, " *");
148                         }
149                         if (filename_ptr == NULL) {
150                                 if (flags & FLAG_WARN) {
151                                         bb_error_msg("invalid format");
152                                 }
153                                 count_failed++;
154                                 return_value = EXIT_FAILURE;
155                                 free(line);
156                                 continue;
157                         }
158                         *filename_ptr = '\0';
159                         filename_ptr += 2;
160
161                         hash_value = hash_file(filename_ptr);
162
163                         if (hash_value && (strcmp((char*)hash_value, line) == 0)) {
164                                 if (!(flags & FLAG_SILENT))
165                                         printf("%s: OK\n", filename_ptr);
166                         } else {
167                                 if (!(flags & FLAG_SILENT))
168                                         printf("%s: FAILED\n", filename_ptr);
169                                 count_failed++;
170                                 return_value = EXIT_FAILURE;
171                         }
172                         /* possible free(NULL) */
173                         free(hash_value);
174                         free(line);
175                 }
176                 if (count_failed && !(flags & FLAG_SILENT)) {
177                         bb_error_msg("WARNING: %d of %d computed checksums did NOT match",
178                                                  count_failed, count_total);
179                 }
180                 /*
181                 if (fclose_if_not_stdin(pre_computed_stream) == EOF) {
182                         bb_perror_msg_and_die("can't close file %s", file_ptr);
183                 }
184                 */
185         } else {
186                 do {
187                         uint8_t *hash_value = hash_file(*argv);
188                         if (hash_value == NULL) {
189                                 return_value = EXIT_FAILURE;
190                         } else {
191                                 printf("%s  %s\n", hash_value, *argv);
192                                 free(hash_value);
193                         }
194                 } while (*++argv);
195         }
196         return return_value;
197 }