]> www.wagner.pp.ru Git - openssl-gost/engine.git/blob - gostsum12.c
Don't forget to remove some temporary files
[openssl-gost/engine.git] / gostsum12.c
1 /**********************************************************************
2  *                          gostsum12.c                               *
3  *             Copyright (c) 2005-2014 Cryptocom LTD                  *
4  *         This file is distributed under same license as OpenSSL     *
5  *                                                                    *
6  *    Implementation of GOST R 34.11-2012 hash function as            *
7  *    command line utility more or less interface                     *
8  *    compatible with md5sum and sha1sum                              *
9  *    Doesn't need OpenSSL                                            *
10  **********************************************************************/
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <limits.h>
15 #include <fcntl.h>
16 #include <string.h>
17 #include "gosthash2012.h"
18
19 #define BUF_SIZE 262144
20 #define gost_hash_ctx gost2012_hash_ctx
21 #define GOST34112012Init init_gost2012_hash_ctx
22 #define GOST34112012Update gost2012_hash_block
23 #define GOST34112012Final gost2012_finish_hash
24
25 typedef unsigned char byte;
26
27 int hashsize = 256;
28 int hash_file(gost_hash_ctx * ctx, char *filename, char *sum, int mode);
29 int hash_stream(gost_hash_ctx * ctx, int fd, char *sum);
30 int get_line(FILE *f, char *hash, char *filename, int verbose);
31
32 void help()
33 {
34     fprintf(stderr, "Calculates GOST R 34.11-2012 hash function\n\n");
35     fprintf(stderr, "gostsum12 [-bvl] [-c [file]]| [files]|-x\n"
36             "\t-c check message digests (default is generate), 256 bit only\n"
37             "\t-v verbose, print file names when checking\n"
38             "\t-b read files in binary mode\n"
39             "\t-l use 512 bit hash (default 256 bit)\n"
40             "\t-x read filenames from stdin rather than from arguments (256 bit only)\n"
41             "The input for -c should be the list of message digests and file names\n"
42             "that is printed on stdout by this program when it generates digests.\n");
43     exit(3);
44 }
45
46 #ifndef O_BINARY
47 # define O_BINARY 0
48 #endif
49
50 int start_hash12(gost_hash_ctx * ctx)
51 {
52     GOST34112012Init(ctx, hashsize);
53     return 1;
54 }
55
56 int hash12_block(gost_hash_ctx * ctx, const byte * block, size_t length)
57 {
58     GOST34112012Update(ctx, block, length);
59     return 1;
60 }
61
62 int finish_hash12(gost_hash_ctx * ctx, byte * hashval)
63 {
64     GOST34112012Final(ctx, hashval);
65     return 1;
66 }
67
68 int main(int argc, char **argv)
69 {
70     int c, i;
71     int verbose = 0;
72     int errors = 0;
73     int open_mode = O_RDONLY;
74     FILE *check_file = NULL;
75     int filenames_from_stdin = 0;
76     gost_hash_ctx ctx;
77
78     while ((c = getopt(argc, argv, "xlvc::")) != -1) {
79         switch (c) {
80         case 'v':
81             verbose = 1;
82             break;
83         case 'l':
84             hashsize = 512;
85             break;
86         case 'x':
87             filenames_from_stdin = 1;
88             break;
89         case 'c':
90             if (optarg) {
91                 check_file = fopen(optarg, "r");
92                 if (!check_file) {
93                     perror(optarg);
94                     exit(2);
95                 }
96             } else {
97                 check_file = stdin;
98             }
99             break;
100         default:
101             fprintf(stderr, "invalid option %c", optopt);
102             help();
103         }
104     }
105     if ((filenames_from_stdin == 1) && (hashsize != 256)) {
106         fprintf(stderr, "x and l are mutually exclusive\n");
107         help();
108     }
109     if ((check_file != NULL) && (hashsize != 256)) {
110         fprintf(stderr, "c and l are mutually exclusive\n");
111         help();
112     }
113     if (check_file) {
114         char inhash[65], calcsum[65], filename[PATH_MAX];
115         int failcount = 0, count = 0;;
116         if (check_file == stdin && optind < argc) {
117             check_file = fopen(argv[optind], "r");
118             if (!check_file) {
119                 perror(argv[optind]);
120                 exit(2);
121             }
122         }
123         while (get_line(check_file, inhash, filename, verbose)) {
124             if (!hash_file(&ctx, filename, calcsum, open_mode)) {
125                 errors++;
126             }
127             count++;
128             if (!strncmp(calcsum, inhash, 65)) {
129                 if (verbose) {
130                     fprintf(stderr, "%s\tOK\n", filename);
131                 }
132             } else {
133                 if (verbose) {
134                     fprintf(stderr, "%s\tFAILED\n", filename);
135                 } else {
136                     fprintf(stderr,
137                             "%s: GOST hash sum check failed for '%s'\n",
138                             argv[0], filename);
139                 }
140                 failcount++;
141             }
142         }
143         if (errors) {
144             fprintf(stderr,
145                     "%s: WARNING %d of %d file(s) cannot be processed\n",
146                     argv[0], errors, count);
147
148         }
149         if (failcount) {
150             fprintf(stderr,
151                     "%s: WARNING %d of %d file(s) failed GOST hash sum check\n",
152                     argv[0], failcount, count - errors);
153         }
154         exit((failcount || errors) ? 1 : 0);
155     } else if (filenames_from_stdin) {
156         char sum[65];
157         char filename[PATH_MAX + 1], *end;
158         while (!feof(stdin)) {
159             if (!fgets(filename, PATH_MAX, stdin))
160                 break;
161             for (end = filename; *end; end++) ;
162             end--;
163             for (; *end == '\n' || *end == '\r'; end--)
164                 *end = 0;
165             if (!hash_file(&ctx, filename, sum, open_mode)) {
166                 errors++;
167             } else {
168                 printf("%s %s\n", sum, filename);
169             }
170         }
171     } else if (optind == argc) {
172         char sum[65];
173         if (!hash_stream(&ctx, fileno(stdin), sum)) {
174             perror("stdin");
175             exit(1);
176         }
177         printf("%s -\n", sum);
178         exit(0);
179     } else {
180         for (i = optind; i < argc; i++) {
181             char sum[65];
182             if (!hash_file(&ctx, argv[i], sum, open_mode)) {
183                 errors++;
184             } else {
185                 printf("%s %s\n", sum, argv[i]);
186             }
187         }
188     }
189     exit(errors ? 1 : 0);
190 }
191
192 int hash_file(gost_hash_ctx * ctx, char *filename, char *sum, int mode)
193 {
194     int fd;
195     if ((fd = open(filename, mode)) < 0) {
196         perror(filename);
197         return 0;
198     }
199     if (!hash_stream(ctx, fd, sum)) {
200         perror(filename);
201         return 0;
202     }
203     close(fd);
204     return 1;
205 }
206
207 int hash_stream(gost_hash_ctx * ctx, int fd, char *sum)
208 {
209     unsigned char buffer[BUF_SIZE];
210     ssize_t bytes;
211     int i;
212     start_hash12(ctx);
213     while ((bytes = read(fd, buffer, BUF_SIZE)) > 0) {
214         hash12_block(ctx, buffer, bytes);
215     }
216     if (bytes < 0) {
217         return 0;
218     }
219     finish_hash12(ctx, buffer);
220     for (i = 0; i < (hashsize / 8); i++) {
221         sprintf(sum + 2 * i, "%02x", buffer[i]);
222     }
223     return 1;
224 }
225
226 int get_line(FILE *f, char *hash, char *filename, int verbose)
227 {
228     int i, len;
229     while (!feof(f)) {
230         if (!fgets(filename, PATH_MAX, f))
231             return 0;
232         len = strlen(filename);
233         if (len < 66) {
234             goto nextline;
235         }
236         if (filename[64] != ' ') {
237             goto nextline;
238         }
239         for (i = 0; i < 64; i++) {
240             if (filename[i] < '0' || (filename[i] > '9' && filename[i] < 'A')
241                 || (filename[i] > 'F' && filename[i] < 'a')
242                 || filename[i] > 'f') {
243                 goto nextline;
244             }
245         }
246         memcpy(hash, filename, 64);
247         hash[64] = 0;
248         while (filename[--len] == '\n' || filename[len] == '\r')
249             filename[len] = 0;
250         memmove(filename, filename + 65, len - 63);
251         return 1;
252     nextline:
253         if (verbose)
254             printf(filename);
255     }
256     return 0;
257 }