1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
2  *
3  * LibTomCrypt is a library that provides various cryptographic
4  * algorithms in a highly modular and flexible manner.
5  *
6  * The library is free for all purposes without any express
7  * guarantee it works.
8  */
9 
10 /*
11  * Written by Daniel Richards <kyhwana@world-net.co.nz> 6/7/2002
12  * hash.c: This app uses libtomcrypt to hash either stdin or a file
13  * This file is Public Domain. No rights are reserved.
14  * Compile with 'gcc hashsum.c -o hashsum -ltomcrypt'
15  * This example isn't really big enough to warrent splitting into
16  * more functions ;)
17 */
18 
19 #include <tomcrypt.h>
20 
21 #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L
22 #include <libgen.h>
23 #else
24 #define basename(x) x
25 #endif
26 
27 #if !defined(PATH_MAX) && defined(_MSC_VER)
28 #include <windows.h>
29 #define PATH_MAX MAX_PATH
30 #endif
31 
32 /* thanks http://stackoverflow.com/a/8198009 */
33 #define _base(x) ((x >= '0' && x <= '9') ? '0' : \
34          (x >= 'a' && x <= 'f') ? 'a' - 10 : \
35          (x >= 'A' && x <= 'F') ? 'A' - 10 : \
36             '\255')
37 #define HEXOF(x) (x - _base(x))
38 
39 static char* hashsum;
40 
cleanup(void)41 static void cleanup(void)
42 {
43    free(hashsum);
44 }
45 
die(int status)46 static void die(int status)
47 {
48    unsigned long w, x;
49    FILE* o = status == EXIT_SUCCESS ? stdout : stderr;
50    fprintf(o, "usage: %s -a algorithm [-c] [file...]\n\n", hashsum);
51    fprintf(o, "\t-c\tCheck the hash(es) of the file(s) written in [file].\n");
52    fprintf(o, "\t\t(-a not required)\n");
53    fprintf(o, "\nAlgorithms:\n\t");
54    w = 0;
55    for (x = 0; hash_descriptor[x].name != NULL; x++) {
56       w += fprintf(o, "%-14s", hash_descriptor[x].name);
57       if (w >= 70) {
58          fprintf(o, "\n\t");
59          w = 0;
60       }
61    }
62    if (w != 0) fprintf(o, "\n");
63    exit(status);
64 }
65 
printf_hex(unsigned char * hash_buffer,unsigned long w)66 static void printf_hex(unsigned char* hash_buffer, unsigned long w)
67 {
68    unsigned long x;
69    for (x = 0; x < w; x++) {
70        printf("%02x",hash_buffer[x]);
71    }
72 }
73 
check_file(int argn,int argc,char ** argv)74 static void check_file(int argn, int argc, char **argv)
75 {
76    int err, failed, invalid;
77    unsigned char is_buffer[MAXBLOCKSIZE], should_buffer[MAXBLOCKSIZE];
78    char buf[PATH_MAX + (MAXBLOCKSIZE * 3)];
79    /* iterate through all files */
80    while(argn < argc) {
81       char* s;
82       FILE* f = fopen(argv[argn], "rb");
83       if(f == NULL) {
84          int n = snprintf(buf, sizeof(buf), "%s: %s", hashsum, argv[argn]);
85          if (n > 0 && n < (int)sizeof(buf))
86             perror(buf);
87          else
88             perror(argv[argn]);
89          exit(EXIT_FAILURE);
90       }
91       failed = 0;
92       invalid = 0;
93       /* read the file line by line */
94       while((s = fgets(buf, sizeof(buf), f)) != NULL)
95       {
96          int tries, n;
97          unsigned long hash_len, w, x;
98          char* space = strstr(s, " ");
99 
100          /* skip lines with comments */
101          if (buf[0] == '#') continue;
102 
103          if (space == NULL) {
104             fprintf(stderr, "%s: no properly formatted checksum lines found\n", hashsum);
105             goto ERR;
106          }
107 
108          hash_len = space - s;
109          hash_len /= 2;
110 
111          if (hash_len > sizeof(should_buffer)) {
112             fprintf(stderr, "%s: hash too long\n", hashsum);
113             goto ERR;
114          }
115 
116          /* convert the hex-string back to binary */
117          for (x = 0; x < hash_len; ++x) {
118             should_buffer[x] = HEXOF(s[x*2]) << 4 | HEXOF(s[x*2 + 1]);
119          }
120 
121          space++;
122          if (*space != '*') {
123             fprintf(stderr, "%s: unsupported input mode '%c'\n", hashsum, *space);
124             goto ERR;
125          }
126          space++;
127 
128          for (n = 0; n < (buf + sizeof(buf)) - space; ++n) {
129             if(iscntrl((int)space[n])) {
130                space[n] = '\0';
131                break;
132             }
133          }
134 
135          /* try all hash algorithms that have the appropriate hash size */
136          tries = 0;
137          for (x = 0; hash_descriptor[x].name != NULL; ++x) {
138             if (hash_descriptor[x].hashsize == hash_len) {
139                tries++;
140                w = sizeof(is_buffer);
141                if ((err = hash_file(x, space, is_buffer, &w)) != CRYPT_OK) {
142                   fprintf(stderr, "%s: File hash error: %s: %s\n", hashsum, space, error_to_string(err));
143 ERR:
144                   fclose(f);
145                   exit(EXIT_FAILURE);
146                }
147                if(XMEMCMP(should_buffer, is_buffer, w) == 0) {
148                   printf("%s: OK\n", space);
149                   break;
150                }
151             }
152          } /* for */
153          if (hash_descriptor[x].name == NULL) {
154             if(tries > 0) {
155                printf("%s: FAILED\n", space);
156                failed++;
157             }
158             else {
159                invalid++;
160             }
161          }
162       } /* while */
163       fclose(f);
164       if(invalid) {
165          fprintf(stderr, "%s: WARNING: %d %s is improperly formatted\n", hashsum, invalid, invalid > 1?"lines":"line");
166       }
167       if(failed) {
168          fprintf(stderr, "%s: WARNING: %d computed %s did NOT match\n", hashsum, failed, failed > 1?"checksums":"checksum");
169       }
170       argn++;
171    }
172    exit(EXIT_SUCCESS);
173 }
174 
main(int argc,char ** argv)175 int main(int argc, char **argv)
176 {
177    int idxs[TAB_SIZE], idx, check, y, z, err, argn;
178    unsigned long w, x;
179    unsigned char hash_buffer[MAXBLOCKSIZE];
180 
181    hashsum = strdup(basename(argv[0]));
182    atexit(cleanup);
183 
184    /* You need to register algorithms before using them */
185    register_all_ciphers();
186    register_all_hashes();
187    if (argc > 1 && (strcmp("-h", argv[1]) == 0 || strcmp("--help", argv[1]) == 0)) {
188       die(EXIT_SUCCESS);
189    }
190    if (argc < 3) {
191       die(EXIT_FAILURE);
192    }
193 
194    for (x = 0; x < sizeof(idxs)/sizeof(idxs[0]); ++x) {
195       idxs[x] = -2;
196    }
197    argn = 1;
198    check = 0;
199    idx = 0;
200 
201    while(argn < argc){
202       if(strcmp("-a", argv[argn]) == 0) {
203          argn++;
204          if(argn < argc) {
205             idxs[idx] = find_hash(argv[argn]);
206             if (idxs[idx] == -1) {
207                struct {
208                   const char* is;
209                   const char* should;
210                } shasum_compat[] =
211                      {
212 #ifdef LTC_SHA1
213                            { "1",        sha1_desc.name },
214 #endif
215 #ifdef LTC_SHA224
216                            { "224",      sha224_desc.name  },
217 #endif
218 #ifdef LTC_SHA256
219                            { "256",      sha256_desc.name  },
220 #endif
221 #ifdef LTC_SHA384
222                            { "384",      sha384_desc.name  },
223 #endif
224 #ifdef LTC_SHA512
225                            { "512",      sha512_desc.name  },
226 #endif
227 #ifdef LTC_SHA512_224
228                            { "512224",   sha512_224_desc.name  },
229 #endif
230 #ifdef LTC_SHA512_256
231                            { "512256",   sha512_256_desc.name  },
232 #endif
233                            { NULL, NULL }
234                      };
235                for (x = 0; shasum_compat[x].is != NULL; ++x) {
236                   if(XSTRCMP(shasum_compat[x].is, argv[argn]) == 0) {
237                      idxs[idx] = find_hash(shasum_compat[x].should);
238                      break;
239                   }
240                }
241             }
242             if (idxs[idx] == -1) {
243                fprintf(stderr, "%s: Unrecognized algorithm\n", hashsum);
244                die(EXIT_FAILURE);
245             }
246             idx++;
247             if ((size_t)idx >= sizeof(idxs)/sizeof(idxs[0])) {
248                fprintf(stderr, "%s: Too many '-a' options chosen\n", hashsum);
249                die(EXIT_FAILURE);
250             }
251             argn++;
252             continue;
253          }
254          else {
255             die(EXIT_FAILURE);
256          }
257       }
258       if(strcmp("-c", argv[argn]) == 0) {
259          check = 1;
260          argn++;
261          continue;
262       }
263       break;
264    }
265 
266    if (check == 1) {
267       check_file(argn, argc, argv);
268    }
269 
270    if (argc == argn) {
271       w = sizeof(hash_buffer);
272       if ((err = hash_filehandle(idxs[0], stdin, hash_buffer, &w)) != CRYPT_OK) {
273          fprintf(stderr, "%s: File hash error: %s\n", hashsum, error_to_string(err));
274          return EXIT_FAILURE;
275       } else {
276           for (x = 0; x < w; x++) {
277               printf("%02x",hash_buffer[x]);
278           }
279           printf(" *-\n");
280       }
281    } else {
282       for (z = argn; z < argc; z++) {
283          for (y = 0; y < idx; ++y) {
284             w = sizeof(hash_buffer);
285             if ((err = hash_file(idxs[y],argv[z],hash_buffer,&w)) != CRYPT_OK) {
286                fprintf(stderr, "%s: File hash error: %s\n", hashsum, error_to_string(err));
287                return EXIT_FAILURE;
288             } else {
289                 printf_hex(hash_buffer, w);
290                 printf(" *%s\n", argv[z]);
291             }
292          }
293       }
294    }
295    return EXIT_SUCCESS;
296 }
297 
298 /* ref:         $Format:%D$ */
299 /* git commit:  $Format:%H$ */
300 /* commit time: $Format:%ai$ */
301