gostsum.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /**********************************************************************
  2. * gostsum.c *
  3. * Copyright (c) 2005-2006 Cryptocom LTD *
  4. * This file is distributed under the same license as OpenSSL *
  5. * *
  6. * Almost drop-in replacement for md5sum and sha1sum *
  7. * which computes GOST R 34.11-94 hashsum instead *
  8. * *
  9. **********************************************************************/
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <unistd.h>
  13. #include <limits.h>
  14. #include <fcntl.h>
  15. #include <string.h>
  16. #include "gosthash.h"
  17. #define BUF_SIZE 262144
  18. int hash_file(gost_hash_ctx * ctx, char *filename, char *sum, int mode);
  19. int hash_stream(gost_hash_ctx * ctx, int fd, char *sum);
  20. int get_line(FILE *f, char *hash, char *filename);
  21. void help()
  22. {
  23. fprintf(stderr, "gostsum [-bvt] [-c [file]]| [files]\n"
  24. "\t-c check message digests (default is generate)\n"
  25. "\t-v verbose, print file names when checking\n"
  26. "\t-b read files in binary mode\n"
  27. "\t-t use test GOST paramset (default is CryptoPro paramset)\n"
  28. "The input for -c should be the list of message digests and file names\n"
  29. "that is printed on stdout by this program when it generates digests.\n");
  30. exit(3);
  31. }
  32. #ifndef O_BINARY
  33. # define O_BINARY 0
  34. #endif
  35. int main(int argc, char **argv)
  36. {
  37. int c, i;
  38. int verbose = 0;
  39. int errors = 0;
  40. int open_mode = O_RDONLY;
  41. gost_subst_block *b = &GostR3411_94_CryptoProParamSet;
  42. FILE *check_file = NULL;
  43. gost_hash_ctx ctx;
  44. while ((c = getopt(argc, argv, "bc::tv")) != -1) {
  45. switch (c) {
  46. case 'v':
  47. verbose = 1;
  48. break;
  49. case 't':
  50. b = &GostR3411_94_TestParamSet;
  51. break;
  52. case 'b':
  53. open_mode |= O_BINARY;
  54. break;
  55. case 'c':
  56. if (optarg) {
  57. check_file = fopen(optarg, "r");
  58. if (!check_file) {
  59. perror(optarg);
  60. exit(2);
  61. }
  62. } else {
  63. check_file = stdin;
  64. }
  65. break;
  66. default:
  67. fprintf(stderr, "invalid option %c", optopt);
  68. help();
  69. }
  70. }
  71. init_gost_hash_ctx(&ctx, b);
  72. if (check_file) {
  73. char inhash[65], calcsum[65], filename[PATH_MAX];
  74. int failcount = 0, count = 0;;
  75. if (check_file == stdin && optind < argc) {
  76. check_file = fopen(argv[optind], "r");
  77. if (!check_file) {
  78. perror(argv[optind]);
  79. exit(2);
  80. }
  81. }
  82. while (get_line(check_file, inhash, filename)) {
  83. if (!hash_file(&ctx, filename, calcsum, open_mode)) {
  84. exit(2);
  85. }
  86. count++;
  87. if (!strncmp(calcsum, inhash, 65)) {
  88. if (verbose) {
  89. fprintf(stderr, "%s\tOK\n", filename);
  90. }
  91. } else {
  92. if (verbose) {
  93. fprintf(stderr, "%s\tFAILED\n", filename);
  94. } else {
  95. fprintf(stderr,
  96. "%s: GOST hash sum check failed for '%s'\n",
  97. argv[0], filename);
  98. }
  99. failcount++;
  100. }
  101. }
  102. if (verbose && failcount) {
  103. fprintf(stderr,
  104. "%s: %d of %d file(f) failed GOST hash sum check\n",
  105. argv[0], failcount, count);
  106. }
  107. exit(failcount ? 1 : 0);
  108. }
  109. if (optind == argc) {
  110. char sum[65];
  111. if (!hash_stream(&ctx, fileno(stdin), sum)) {
  112. perror("stdin");
  113. exit(1);
  114. }
  115. printf("%s -\n", sum);
  116. exit(0);
  117. }
  118. for (i = optind; i < argc; i++) {
  119. char sum[65];
  120. if (!hash_file(&ctx, argv[i], sum, open_mode)) {
  121. errors++;
  122. } else {
  123. printf("%s %s\n", sum, argv[i]);
  124. }
  125. }
  126. exit(errors ? 1 : 0);
  127. }
  128. int hash_file(gost_hash_ctx * ctx, char *filename, char *sum, int mode)
  129. {
  130. int fd;
  131. if ((fd = open(filename, mode)) < 0) {
  132. perror(filename);
  133. return 0;
  134. }
  135. if (!hash_stream(ctx, fd, sum)) {
  136. perror(filename);
  137. return 0;
  138. }
  139. close(fd);
  140. return 1;
  141. }
  142. int hash_stream(gost_hash_ctx * ctx, int fd, char *sum)
  143. {
  144. unsigned char buffer[BUF_SIZE];
  145. ssize_t bytes;
  146. int i;
  147. start_hash(ctx);
  148. while ((bytes = read(fd, buffer, BUF_SIZE)) > 0) {
  149. hash_block(ctx, buffer, bytes);
  150. }
  151. if (bytes < 0) {
  152. return 0;
  153. }
  154. finish_hash(ctx, buffer);
  155. for (i = 0; i < 32; i++) {
  156. sprintf(sum + 2 * i, "%02x", buffer[31 - i]);
  157. }
  158. return 1;
  159. }
  160. int get_line(FILE *f, char *hash, char *filename)
  161. {
  162. int i;
  163. if (fread(hash, 1, 64, f) < 64)
  164. return 0;
  165. hash[64] = 0;
  166. for (i = 0; i < 64; i++) {
  167. if (hash[i] < '0' || (hash[i] > '9' && hash[i] < 'A')
  168. || (hash[i] > 'F' && hash[i] < 'a') || hash[i] > 'f') {
  169. fprintf(stderr, "Not a hash value '%s'\n", hash);
  170. return 0;
  171. }
  172. }
  173. if (fgetc(f) != ' ') {
  174. fprintf(stderr, "Malformed input line\n");
  175. return 0;
  176. }
  177. i = strlen(fgets(filename, PATH_MAX, f));
  178. while (filename[--i] == '\n' || filename[i] == '\r')
  179. filename[i] = 0;
  180. return 1;
  181. }