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 18int hash_file(gost_hash_ctx * ctx, char *filename, char *sum, int mode); 19int hash_stream(gost_hash_ctx * ctx, int fd, char *sum); 20int get_line(FILE *f, char *hash, char *filename); 21void 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 33#ifndef O_BINARY 34# define O_BINARY 0 35#endif 36 37int main(int argc, char **argv) 38{ 39 int c, i; 40 int verbose = 0; 41 int errors = 0; 42 int open_mode = O_RDONLY; 43 gost_subst_block *b = &GostR3411_94_CryptoProParamSet; 44 FILE *check_file = NULL; 45 gost_hash_ctx ctx; 46 47 while ((c = getopt(argc, argv, "bc::tv")) != -1) { 48 switch (c) { 49 case 'v': 50 verbose = 1; 51 break; 52 case 't': 53 b = &GostR3411_94_TestParamSet; 54 break; 55 case 'b': 56 open_mode |= O_BINARY; 57 break; 58 case 'c': 59 if (optarg) { 60 check_file = fopen(optarg, "r"); 61 if (!check_file) { 62 perror(optarg); 63 exit(2); 64 } 65 } else { 66 check_file = stdin; 67 } 68 break; 69 default: 70 fprintf(stderr, "invalid option %c", optopt); 71 help(); 72 } 73 } 74 init_gost_hash_ctx(&ctx, b); 75 if (check_file) { 76 char inhash[65], calcsum[65], filename[PATH_MAX]; 77 int failcount = 0, count = 0;; 78 if (check_file == stdin && optind < argc) { 79 check_file = fopen(argv[optind], "r"); 80 if (!check_file) { 81 perror(argv[optind]); 82 exit(2); 83 } 84 } 85 while (get_line(check_file, inhash, filename)) { 86 if (!hash_file(&ctx, filename, calcsum, open_mode)) { 87 exit(2); 88 } 89 count++; 90 if (!strncmp(calcsum, inhash, 65)) { 91 if (verbose) { 92 fprintf(stderr, "%s\tOK\n", filename); 93 } 94 } else { 95 if (verbose) { 96 fprintf(stderr, "%s\tFAILED\n", filename); 97 } else { 98 fprintf(stderr, 99 "%s: GOST hash sum check failed for '%s'\n", 100 argv[0], filename); 101 } 102 failcount++; 103 } 104 } 105 if (verbose && failcount) { 106 fprintf(stderr, 107 "%s: %d of %d file(f) failed GOST hash sum check\n", 108 argv[0], failcount, count); 109 } 110 exit(failcount ? 1 : 0); 111 } 112 if (optind == argc) { 113 char sum[65]; 114 if (!hash_stream(&ctx, fileno(stdin), sum)) { 115 perror("stdin"); 116 exit(1); 117 } 118 printf("%s -\n", sum); 119 exit(0); 120 } 121 for (i = optind; i < argc; i++) { 122 char sum[65]; 123 if (!hash_file(&ctx, argv[i], sum, open_mode)) { 124 errors++; 125 } else { 126 printf("%s %s\n", sum, argv[i]); 127 } 128 } 129 exit(errors ? 1 : 0); 130} 131 132int hash_file(gost_hash_ctx * ctx, char *filename, char *sum, int mode) 133{ 134 int fd; 135 if ((fd = open(filename, mode)) < 0) { 136 perror(filename); 137 return 0; 138 } 139 if (!hash_stream(ctx, fd, sum)) { 140 perror(filename); 141 return 0; 142 } 143 close(fd); 144 return 1; 145} 146 147int hash_stream(gost_hash_ctx * ctx, int fd, char *sum) 148{ 149 unsigned char buffer[BUF_SIZE]; 150 ssize_t bytes; 151 int i; 152 start_hash(ctx); 153 while ((bytes = read(fd, buffer, BUF_SIZE)) > 0) { 154 hash_block(ctx, buffer, bytes); 155 } 156 if (bytes < 0) { 157 return 0; 158 } 159 finish_hash(ctx, buffer); 160 for (i = 0; i < 32; i++) { 161 sprintf(sum + 2 * i, "%02x", buffer[31 - i]); 162 } 163 return 1; 164} 165 166int get_line(FILE *f, char *hash, char *filename) 167{ 168 int i; 169 if (fread(hash, 1, 64, f) < 64) 170 return 0; 171 hash[64] = 0; 172 for (i = 0; i < 64; i++) { 173 if (hash[i] < '0' || (hash[i] > '9' && hash[i] < 'A') 174 || (hash[i] > 'F' && hash[i] < 'a') || hash[i] > 'f') { 175 fprintf(stderr, "Not a hash value '%s'\n", hash); 176 return 0; 177 } 178 } 179 if (fgetc(f) != ' ') { 180 fprintf(stderr, "Malformed input line\n"); 181 return 0; 182 } 183 i = strlen(fgets(filename, PATH_MAX, f)); 184 while (filename[--i] == '\n' || filename[i] == '\r') 185 filename[i] = 0; 186 return 1; 187} 188