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 { 49 switch (c) 50 { 51 case 'v': verbose=1; break; 52 case 't': b= &GostR3411_94_TestParamSet; break; 53 case 'b': open_mode |= O_BINARY; break; 54 case 'c': 55 if (optarg) 56 { 57 check_file = fopen(optarg,"r"); 58 if (!check_file) 59 { 60 perror(optarg); 61 exit(2); 62 } 63 } 64 else 65 { 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 { 77 char inhash[65],calcsum[65],filename[PATH_MAX]; 78 int failcount=0,count=0;; 79 if (check_file==stdin && optind<argc) 80 { 81 check_file=fopen(argv[optind],"r"); 82 if (!check_file) 83 { 84 perror(argv[optind]); 85 exit(2); 86 } 87 } 88 while (get_line(check_file,inhash,filename)) 89 { 90 if (!hash_file(&ctx,filename,calcsum,open_mode)) 91 { 92 exit (2); 93 } 94 count++; 95 if (!strncmp(calcsum,inhash,65)) 96 { 97 if (verbose) 98 { 99 fprintf(stderr,"%s\tOK\n",filename); 100 } 101 } 102 else 103 { 104 if (verbose) 105 { 106 fprintf(stderr,"%s\tFAILED\n",filename); 107 } 108 else 109 { 110 fprintf(stderr,"%s: GOST hash sum check failed for '%s'\n", 111 argv[0],filename); 112 } 113 failcount++; 114 } 115 } 116 if (verbose && failcount) 117 { 118 fprintf(stderr,"%s: %d of %d file(f) failed GOST hash sum check\n", 119 argv[0],failcount,count); 120 } 121 exit (failcount?1:0); 122 } 123 if (optind==argc) 124 { 125 char sum[65]; 126 if (!hash_stream(&ctx,fileno(stdin),sum)) 127 { 128 perror("stdin"); 129 exit(1); 130 } 131 printf("%s -\n",sum); 132 exit(0); 133 } 134 for (i=optind;i<argc;i++) 135 { 136 char sum[65]; 137 if (!hash_file(&ctx,argv[i],sum,open_mode)) 138 { 139 errors++; 140 } 141 else 142 { 143 printf("%s %s\n",sum,argv[i]); 144 } 145 } 146 exit(errors?1:0); 147 } 148 149int hash_file(gost_hash_ctx *ctx,char *filename,char *sum,int mode) 150 { 151 int fd; 152 if ((fd=open(filename,mode))<0) 153 { 154 perror(filename); 155 return 0; 156 } 157 if (!hash_stream(ctx,fd,sum)) 158 { 159 perror(filename); 160 return 0; 161 } 162 close(fd); 163 return 1; 164 } 165 166int hash_stream(gost_hash_ctx *ctx,int fd, char *sum) 167 { 168 unsigned char buffer[BUF_SIZE]; 169 ssize_t bytes; 170 int i; 171 start_hash(ctx); 172 while ((bytes=read(fd,buffer,BUF_SIZE))>0) 173 { 174 hash_block(ctx,buffer,bytes); 175 } 176 if (bytes<0) 177 { 178 return 0; 179 } 180 finish_hash(ctx,buffer); 181 for (i=0;i<32;i++) 182 { 183 sprintf(sum+2*i,"%02x",buffer[31-i]); 184 } 185 return 1; 186 } 187 188int get_line(FILE *f,char *hash,char *filename) 189 { 190 int i; 191 if (fread(hash,1,64,f)<64) return 0; 192 hash[64]=0; 193 for (i=0;i<64;i++) 194 { 195 if (hash[i]<'0' || (hash[i]>'9' && hash[i]<'A') || (hash[i]>'F' 196 && hash[i]<'a')||hash[i]>'f') 197 { 198 fprintf(stderr,"Not a hash value '%s'\n",hash); 199 return 0; 200 } 201 } 202 if (fgetc(f)!=' ') 203 { 204 fprintf(stderr,"Malformed input line\n"); 205 return 0; 206 } 207 i=strlen(fgets(filename,PATH_MAX,f)); 208 while (filename[--i]=='\n'||filename[i]=='\r') filename[i]=0; 209 return 1; 210 } 211