You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
187 lines
5.5 KiB
187 lines
5.5 KiB
/********************************************************************** |
|
* gostsum.c * |
|
* Copyright (c) 2005-2006 Cryptocom LTD * |
|
* This file is distributed under the same license as OpenSSL * |
|
* * |
|
* Almost drop-in replacement for md5sum and sha1sum * |
|
* which computes GOST R 34.11-94 hashsum instead * |
|
* * |
|
**********************************************************************/ |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <unistd.h> |
|
#include <limits.h> |
|
#include <fcntl.h> |
|
#include <string.h> |
|
#include "gosthash.h" |
|
#define BUF_SIZE 262144 |
|
int hash_file(gost_hash_ctx * ctx, char *filename, char *sum, int mode); |
|
int hash_stream(gost_hash_ctx * ctx, int fd, char *sum); |
|
int get_line(FILE *f, char *hash, char *filename); |
|
void help() |
|
{ |
|
fprintf(stderr, "gostsum [-bvt] [-c [file]]| [files]\n" |
|
"\t-c check message digests (default is generate)\n" |
|
"\t-v verbose, print file names when checking\n" |
|
"\t-b read files in binary mode\n" |
|
"\t-t use test GOST paramset (default is CryptoPro paramset)\n" |
|
"The input for -c should be the list of message digests and file names\n" |
|
"that is printed on stdout by this program when it generates digests.\n"); |
|
exit(3); |
|
} |
|
|
|
#ifndef O_BINARY |
|
# define O_BINARY 0 |
|
#endif |
|
|
|
int main(int argc, char **argv) |
|
{ |
|
int c, i; |
|
int verbose = 0; |
|
int errors = 0; |
|
int open_mode = O_RDONLY; |
|
gost_subst_block *b = &GostR3411_94_CryptoProParamSet; |
|
FILE *check_file = NULL; |
|
gost_hash_ctx ctx; |
|
|
|
while ((c = getopt(argc, argv, "bc::tv")) != -1) { |
|
switch (c) { |
|
case 'v': |
|
verbose = 1; |
|
break; |
|
case 't': |
|
b = &GostR3411_94_TestParamSet; |
|
break; |
|
case 'b': |
|
open_mode |= O_BINARY; |
|
break; |
|
case 'c': |
|
if (optarg) { |
|
check_file = fopen(optarg, "r"); |
|
if (!check_file) { |
|
perror(optarg); |
|
exit(2); |
|
} |
|
} else { |
|
check_file = stdin; |
|
} |
|
break; |
|
default: |
|
fprintf(stderr, "invalid option %c", optopt); |
|
help(); |
|
} |
|
} |
|
init_gost_hash_ctx(&ctx, b); |
|
if (check_file) { |
|
char inhash[65], calcsum[65], filename[PATH_MAX]; |
|
int failcount = 0, count = 0;; |
|
if (check_file == stdin && optind < argc) { |
|
check_file = fopen(argv[optind], "r"); |
|
if (!check_file) { |
|
perror(argv[optind]); |
|
exit(2); |
|
} |
|
} |
|
while (get_line(check_file, inhash, filename)) { |
|
if (!hash_file(&ctx, filename, calcsum, open_mode)) { |
|
exit(2); |
|
} |
|
count++; |
|
if (!strncmp(calcsum, inhash, 65)) { |
|
if (verbose) { |
|
fprintf(stderr, "%s\tOK\n", filename); |
|
} |
|
} else { |
|
if (verbose) { |
|
fprintf(stderr, "%s\tFAILED\n", filename); |
|
} else { |
|
fprintf(stderr, |
|
"%s: GOST hash sum check failed for '%s'\n", |
|
argv[0], filename); |
|
} |
|
failcount++; |
|
} |
|
} |
|
if (verbose && failcount) { |
|
fprintf(stderr, |
|
"%s: %d of %d file(f) failed GOST hash sum check\n", |
|
argv[0], failcount, count); |
|
} |
|
exit(failcount ? 1 : 0); |
|
} |
|
if (optind == argc) { |
|
char sum[65]; |
|
if (!hash_stream(&ctx, fileno(stdin), sum)) { |
|
perror("stdin"); |
|
exit(1); |
|
} |
|
printf("%s -\n", sum); |
|
exit(0); |
|
} |
|
for (i = optind; i < argc; i++) { |
|
char sum[65]; |
|
if (!hash_file(&ctx, argv[i], sum, open_mode)) { |
|
errors++; |
|
} else { |
|
printf("%s %s\n", sum, argv[i]); |
|
} |
|
} |
|
exit(errors ? 1 : 0); |
|
} |
|
|
|
int hash_file(gost_hash_ctx * ctx, char *filename, char *sum, int mode) |
|
{ |
|
int fd; |
|
if ((fd = open(filename, mode)) < 0) { |
|
perror(filename); |
|
return 0; |
|
} |
|
if (!hash_stream(ctx, fd, sum)) { |
|
perror(filename); |
|
return 0; |
|
} |
|
close(fd); |
|
return 1; |
|
} |
|
|
|
int hash_stream(gost_hash_ctx * ctx, int fd, char *sum) |
|
{ |
|
unsigned char buffer[BUF_SIZE]; |
|
ssize_t bytes; |
|
int i; |
|
start_hash(ctx); |
|
while ((bytes = read(fd, buffer, BUF_SIZE)) > 0) { |
|
hash_block(ctx, buffer, bytes); |
|
} |
|
if (bytes < 0) { |
|
return 0; |
|
} |
|
finish_hash(ctx, buffer); |
|
for (i = 0; i < 32; i++) { |
|
sprintf(sum + 2 * i, "%02x", buffer[31 - i]); |
|
} |
|
return 1; |
|
} |
|
|
|
int get_line(FILE *f, char *hash, char *filename) |
|
{ |
|
int i; |
|
if (fread(hash, 1, 64, f) < 64) |
|
return 0; |
|
hash[64] = 0; |
|
for (i = 0; i < 64; i++) { |
|
if (hash[i] < '0' || (hash[i] > '9' && hash[i] < 'A') |
|
|| (hash[i] > 'F' && hash[i] < 'a') || hash[i] > 'f') { |
|
fprintf(stderr, "Not a hash value '%s'\n", hash); |
|
return 0; |
|
} |
|
} |
|
if (fgetc(f) != ' ') { |
|
fprintf(stderr, "Malformed input line\n"); |
|
return 0; |
|
} |
|
i = strlen(fgets(filename, PATH_MAX, f)); |
|
while (filename[--i] == '\n' || filename[i] == '\r') |
|
filename[i] = 0; |
|
return 1; |
|
}
|
|
|