gostsum.c revision 238405
116566Ssos/**********************************************************************
216566Ssos *                        gostsum.c                                   *
316566Ssos *             Copyright (c) 2005-2006 Cryptocom LTD                  *
416566Ssos *         This file is distributed under the same license as OpenSSL *
516566Ssos *                                                                    *
616566Ssos *        Almost drop-in replacement for md5sum and sha1sum           *
716566Ssos *          which computes GOST R 34.11-94 hashsum instead            *
816566Ssos *                                                                    *
916566Ssos **********************************************************************/
1016566Ssos#include <stdio.h>
1116566Ssos#include <stdlib.h>
1216566Ssos#include <unistd.h>
1316566Ssos#include <limits.h>
1416566Ssos#include <fcntl.h>
1516566Ssos#include <string.h>
1616566Ssos#include "gosthash.h"
1716566Ssos#define BUF_SIZE 262144
1816566Ssosint hash_file(gost_hash_ctx *ctx,char *filename,char *sum,int mode);
1916566Ssosint hash_stream(gost_hash_ctx *ctx,int fd, char *sum);
2016566Ssosint get_line(FILE *f,char *hash,char *filename);
2116566Ssosvoid help()
2216566Ssos	{
2316566Ssos	fprintf(stderr,"gostsum [-bvt] [-c [file]]| [files]\n"
2416566Ssos		"\t-c check message digests (default is generate)\n"
2516566Ssos		"\t-v verbose, print file names when checking\n"
2616566Ssos		"\t-b read files in binary mode\n"
2716566Ssos		"\t-t use test GOST paramset (default is CryptoPro paramset)\n"
2816566Ssos		"The input for -c should be the list of message digests and file names\n"
2916566Ssos		"that is printed on stdout by this program when it generates digests.\n");
3016566Ssos	exit(3);
3116566Ssos	}
3216566Ssos
3316566Ssos#ifndef O_BINARY
3416566Ssos#define O_BINARY 0
3516566Ssos#endif
3616566Ssos
3731604Syokotaint main(int argc,char **argv)
3831604Syokota	{
3931604Syokota	int c,i;
4016566Ssos	int verbose=0;
4116566Ssos	int errors=0;
4216566Ssos	int open_mode = O_RDONLY;
4316566Ssos	gost_subst_block *b=  &GostR3411_94_CryptoProParamSet;
4416566Ssos	FILE *check_file = NULL;
4516566Ssos	gost_hash_ctx ctx;
4616566Ssos
4729849Scharnier	while( (c=getopt(argc,argv,"bc::tv"))!=-1)
4829849Scharnier		{
4931726Syokota		switch (c)
5029849Scharnier			{
5129849Scharnier			case 'v': verbose=1; break;
5229849Scharnier			case 't': b= &GostR3411_94_TestParamSet; break;
5329849Scharnier			case 'b': open_mode |= O_BINARY; break;
5429849Scharnier			case 'c':
5529849Scharnier				if (optarg)
5616566Ssos					{
5716566Ssos					check_file = fopen(optarg,"r");
5831604Syokota					if (!check_file)
5916566Ssos						{
6031604Syokota						perror(optarg);
6131604Syokota						exit(2);
6231604Syokota						}
6316566Ssos					}
6431604Syokota				else
6531604Syokota					{
6616566Ssos				  	check_file= stdin;
6731604Syokota					}
6831604Syokota				break;
6921885Ssos			default:
7021885Ssos				fprintf(stderr,"invalid option %c",optopt);
7121885Ssos				help();
7216566Ssos			}
7331604Syokota		}
7431604Syokota	init_gost_hash_ctx(&ctx,b);
7531604Syokota	if (check_file)
7631604Syokota		{
7731604Syokota		char inhash[65],calcsum[65],filename[PATH_MAX];
7831604Syokota		int failcount=0,count=0;;
7931604Syokota		if (check_file==stdin && optind<argc)
8031604Syokota			{
8131604Syokota			check_file=fopen(argv[optind],"r");
8231604Syokota			if (!check_file)
8331604Syokota				{
8431604Syokota				perror(argv[optind]);
8531604Syokota				exit(2);
8631604Syokota				}
8731604Syokota			}
8831604Syokota		while (get_line(check_file,inhash,filename))
8931604Syokota			{
9031604Syokota			if (!hash_file(&ctx,filename,calcsum,open_mode))
9131604Syokota				{
9231604Syokota				exit (2);
9331604Syokota				}
9416566Ssos			count++;
9529849Scharnier			if (!strncmp(calcsum,inhash,65))
9616566Ssos				{
9731604Syokota				if (verbose)
9831604Syokota					{
9931604Syokota					fprintf(stderr,"%s\tOK\n",filename);
10031604Syokota					}
10131604Syokota				}
10231604Syokota			else
10331604Syokota				{
10431604Syokota				if (verbose)
10531604Syokota					{
10631604Syokota					fprintf(stderr,"%s\tFAILED\n",filename);
10731604Syokota					}
10831604Syokota				else
10931604Syokota					{
11031604Syokota					fprintf(stderr,"%s: GOST hash sum check failed for '%s'\n",
11131604Syokota						argv[0],filename);
11231604Syokota					}
11331604Syokota				failcount++;
11431604Syokota				}
11531604Syokota			}
11631604Syokota		if (verbose && failcount)
11731604Syokota			{
11831604Syokota			fprintf(stderr,"%s: %d of %d file(f) failed GOST hash sum check\n",
11931604Syokota				argv[0],failcount,count);
12031604Syokota			}
12131604Syokota		exit (failcount?1:0);
12231604Syokota		}
12331604Syokota	if (optind==argc)
12431604Syokota		{
12531604Syokota		char sum[65];
12631604Syokota		if (!hash_stream(&ctx,fileno(stdin),sum))
12731604Syokota			{
12831604Syokota			perror("stdin");
12931604Syokota			exit(1);
13031604Syokota			}
13131604Syokota		printf("%s -\n",sum);
13231604Syokota		exit(0);
13331604Syokota		}
13431604Syokota	for (i=optind;i<argc;i++)
13531604Syokota		{
13631604Syokota		char sum[65];
13731604Syokota		if (!hash_file(&ctx,argv[i],sum,open_mode))
13831604Syokota			{
13931604Syokota			errors++;
14031604Syokota			}
14131604Syokota		else
14231604Syokota			{
14331604Syokota			printf("%s %s\n",sum,argv[i]);
14431604Syokota			}
14531604Syokota		}
14631604Syokota	exit(errors?1:0);
14731604Syokota	}
14831604Syokota
14931604Syokotaint hash_file(gost_hash_ctx *ctx,char *filename,char *sum,int mode)
15031604Syokota	{
15131604Syokota	int fd;
15231604Syokota	if ((fd=open(filename,mode))<0)
15316566Ssos		{
15431604Syokota		perror(filename);
15531604Syokota		return 0;
15631604Syokota		}
15731604Syokota	if (!hash_stream(ctx,fd,sum))
15816566Ssos		{
15931604Syokota		perror(filename);
16016566Ssos		return 0;
16131604Syokota		}
16231604Syokota	close(fd);
16331604Syokota	return 1;
16431604Syokota	}
16531604Syokota
16631604Syokotaint hash_stream(gost_hash_ctx *ctx,int fd, char *sum)
16731604Syokota	{
16831604Syokota	unsigned char buffer[BUF_SIZE];
16931604Syokota	ssize_t bytes;
17016566Ssos	int i;
17131604Syokota	start_hash(ctx);
17231604Syokota	while ((bytes=read(fd,buffer,BUF_SIZE))>0)
17316566Ssos		{
17416566Ssos		hash_block(ctx,buffer,bytes);
17531604Syokota		}
17616566Ssos	if (bytes<0)
17731604Syokota		{
17816566Ssos		return 0;
17931604Syokota		}
18016566Ssos	finish_hash(ctx,buffer);
18118222Speter	for (i=0;i<32;i++)
18231604Syokota		{
18331604Syokota		sprintf(sum+2*i,"%02x",buffer[31-i]);
18431604Syokota		}
18531604Syokota	return 1;
18631604Syokota	}
18731604Syokota
18831604Syokotaint get_line(FILE *f,char *hash,char *filename)
18916566Ssos	{
19016566Ssos	int i;
19116566Ssos	if (fread(hash,1,64,f)<64) return 0;
19231604Syokota	hash[64]=0;
19331604Syokota	for (i=0;i<64;i++)
19431604Syokota		{
19531604Syokota		if (hash[i]<'0' || (hash[i]>'9' && hash[i]<'A') || (hash[i]>'F'
19631604Syokota				&& hash[i]<'a')||hash[i]>'f')
19731604Syokota			{
19831604Syokota			fprintf(stderr,"Not a hash value '%s'\n",hash);
19931604Syokota			return 0;
20031604Syokota			}
20131604Syokota		}
20231604Syokota	if (fgetc(f)!=' ')
20331604Syokota		{
20431604Syokota		fprintf(stderr,"Malformed input line\n");
20531604Syokota		return 0;
20631604Syokota		}
20731604Syokota	i=strlen(fgets(filename,PATH_MAX,f));
20831604Syokota	while (filename[--i]=='\n'||filename[i]=='\r') filename[i]=0;
20931604Syokota	return 1;
21031604Syokota	}
21131604Syokota