1021848ef72c9421c668cc25d305cf763a02a4c4
[openssl.git] / engines / ccgost / gostsum.c
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
18 int hash_file(gost_hash_ctx * ctx, char *filename, char *sum, int mode);
19 int hash_stream(gost_hash_ctx * ctx, int fd, char *sum);
20 int get_line(FILE *f, char *hash, char *filename);
21 void 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
37 int 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
132 int 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
147 int 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
166 int 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 }