hashsum.c 8.6 KB

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