gostsum.c revision 280304
120253Sjoerg/********************************************************************** 220253Sjoerg * gostsum.c * 320253Sjoerg * Copyright (c) 2005-2006 Cryptocom LTD * 420253Sjoerg * This file is distributed under the same license as OpenSSL * 520253Sjoerg * * 620253Sjoerg * Almost drop-in replacement for md5sum and sha1sum * 720253Sjoerg * which computes GOST R 34.11-94 hashsum instead * 820253Sjoerg * * 920253Sjoerg **********************************************************************/ 1020253Sjoerg#include <stdio.h> 1120253Sjoerg#include <stdlib.h> 1220253Sjoerg#include <unistd.h> 1320253Sjoerg#include <limits.h> 1420253Sjoerg#include <fcntl.h> 1520253Sjoerg#include <string.h> 1620253Sjoerg#include "gosthash.h" 1720253Sjoerg#define BUF_SIZE 262144 1820253Sjoergint hash_file(gost_hash_ctx * ctx, char *filename, char *sum, int mode); 1920253Sjoergint hash_stream(gost_hash_ctx * ctx, int fd, char *sum); 2020253Sjoergint get_line(FILE *f, char *hash, char *filename); 2120253Sjoergvoid help() 2220253Sjoerg{ 2320253Sjoerg fprintf(stderr, "gostsum [-bvt] [-c [file]]| [files]\n" 2420253Sjoerg "\t-c check message digests (default is generate)\n" 2520253Sjoerg "\t-v verbose, print file names when checking\n" 2620253Sjoerg "\t-b read files in binary mode\n" 2720253Sjoerg "\t-t use test GOST paramset (default is CryptoPro paramset)\n" 2820253Sjoerg "The input for -c should be the list of message digests and file names\n" 2920253Sjoerg "that is printed on stdout by this program when it generates digests.\n"); 3020253Sjoerg exit(3); 3120253Sjoerg} 3220253Sjoerg 3320253Sjoerg#ifndef O_BINARY 3420253Sjoerg# define O_BINARY 0 3520253Sjoerg#endif 3620253Sjoerg 3720253Sjoergint main(int argc, char **argv) 3820253Sjoerg{ 3920253Sjoerg int c, i; 4020253Sjoerg int verbose = 0; 4120253Sjoerg int errors = 0; 4220253Sjoerg int open_mode = O_RDONLY; 4320253Sjoerg gost_subst_block *b = &GostR3411_94_CryptoProParamSet; 4420253Sjoerg FILE *check_file = NULL; 4520253Sjoerg gost_hash_ctx ctx; 4620253Sjoerg 4720253Sjoerg while ((c = getopt(argc, argv, "bc::tv")) != -1) { 4820253Sjoerg switch (c) { 4920253Sjoerg case 'v': 5020253Sjoerg verbose = 1; 5120253Sjoerg break; 5220253Sjoerg case 't': 5320253Sjoerg b = &GostR3411_94_TestParamSet; 5420253Sjoerg break; 5520253Sjoerg case 'b': 5620253Sjoerg open_mode |= O_BINARY; 5720253Sjoerg break; 5820253Sjoerg case 'c': 5920253Sjoerg if (optarg) { 6020253Sjoerg check_file = fopen(optarg, "r"); 6120253Sjoerg if (!check_file) { 6220253Sjoerg perror(optarg); 6320253Sjoerg exit(2); 6420253Sjoerg } 6520253Sjoerg } else { 6620253Sjoerg check_file = stdin; 6720253Sjoerg } 6820253Sjoerg break; 6920253Sjoerg default: 7020253Sjoerg 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