1 /*
2 BLAKE2 reference source code package - b2sum tool
3
4 Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
5 terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
6 your option. The terms of these licenses can be found at:
7
8 - CC0 1.0 Universal : https://creativecommons.org/publicdomain/zero/1.0
9 - OpenSSL license : https://www.openssl.org/source/license.html
10 - Apache 2.0 : https://www.apache.org/licenses/LICENSE-2.0
11
12 More information about the BLAKE2 hash function can be found at
13 https://blake2.net.
14 */
15
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include <ctype.h>
26 #include <unistd.h>
27 #include <getopt.h>
28
29 #include "blake2.h"
30
31 #if 0
32 /* This will help compatibility with coreutils */
33 int blake2s_stream( FILE *stream, void *resstream, size_t outbytes )
34 {
35 int ret = -1;
36 size_t sum, n;
37 blake2s_state S[1];
38 static const size_t buffer_length = 32768;
39 uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
40
41 if( !buffer ) return -1;
42
43 blake2s_init( S, outbytes );
44
45 while( 1 )
46 {
47 sum = 0;
48
49 while( 1 )
50 {
51 n = fread( buffer + sum, 1, buffer_length - sum, stream );
52 sum += n;
53
54 if( buffer_length == sum )
55 break;
56
57 if( 0 == n )
58 {
59 if( ferror( stream ) )
60 goto cleanup_buffer;
61
62 goto final_process;
63 }
64
65 if( feof( stream ) )
66 goto final_process;
67 }
68
69 blake2s_update( S, buffer, buffer_length );
70 }
71
72 final_process:;
73
74 if( sum > 0 ) blake2s_update( S, buffer, sum );
75
76 blake2s_final( S, resstream, outbytes );
77 ret = 0;
78 cleanup_buffer:
79 free( buffer );
80 return ret;
81 }
82 #endif
83
blake2b_stream(FILE * stream,void * resstream,size_t outbytes)84 int blake2b_stream( FILE *stream, void *resstream, size_t outbytes )
85 {
86 int ret = -1;
87 size_t sum, n;
88 blake2b_state S[1];
89 static const size_t buffer_length = 32768;
90 uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
91
92 if( !buffer ) return -1;
93
94 blake2b_init( S, outbytes );
95
96 while( 1 )
97 {
98 sum = 0;
99
100 while( 1 )
101 {
102 n = fread( buffer + sum, 1, buffer_length - sum, stream );
103 sum += n;
104
105 if( buffer_length == sum )
106 break;
107
108 if( 0 == n )
109 {
110 if( ferror( stream ) )
111 goto cleanup_buffer;
112
113 goto final_process;
114 }
115
116 if( feof( stream ) )
117 goto final_process;
118 }
119
120 blake2b_update( S, buffer, buffer_length );
121 }
122
123 final_process:;
124
125 if( sum > 0 ) blake2b_update( S, buffer, sum );
126
127 blake2b_final( S, resstream, outbytes );
128 ret = 0;
129 cleanup_buffer:
130 free( buffer );
131 return ret;
132 }
133
134 #if 0
135
136 int blake2sp_stream( FILE *stream, void *resstream, size_t outbytes )
137 {
138 int ret = -1;
139 size_t sum, n;
140 blake2sp_state S[1];
141 static const size_t buffer_length = 16 * ( 1UL << 20 );
142 uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
143
144 if( !buffer ) return -1;
145
146 blake2sp_init( S, outbytes );
147
148 while( 1 )
149 {
150 sum = 0;
151
152 while( 1 )
153 {
154 n = fread( buffer + sum, 1, buffer_length - sum, stream );
155 sum += n;
156
157 if( buffer_length == sum )
158 break;
159
160 if( 0 == n )
161 {
162 if( ferror( stream ) )
163 goto cleanup_buffer;
164
165 goto final_process;
166 }
167
168 if( feof( stream ) )
169 goto final_process;
170 }
171
172 blake2sp_update( S, buffer, buffer_length );
173 }
174
175 final_process:;
176
177 if( sum > 0 ) blake2sp_update( S, buffer, sum );
178
179 blake2sp_final( S, resstream, outbytes );
180 ret = 0;
181 cleanup_buffer:
182 free( buffer );
183 return ret;
184 }
185
186
187 int blake2bp_stream( FILE *stream, void *resstream, size_t outbytes )
188 {
189 int ret = -1;
190 size_t sum, n;
191 blake2bp_state S[1];
192 static const size_t buffer_length = 16 * ( 1UL << 20 );
193 uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
194
195 if( !buffer ) return -1;
196
197 blake2bp_init( S, outbytes );
198
199 while( 1 )
200 {
201 sum = 0;
202
203 while( 1 )
204 {
205 n = fread( buffer + sum, 1, buffer_length - sum, stream );
206 sum += n;
207
208 if( buffer_length == sum )
209 break;
210
211 if( 0 == n )
212 {
213 if( ferror( stream ) )
214 goto cleanup_buffer;
215
216 goto final_process;
217 }
218
219 if( feof( stream ) )
220 goto final_process;
221 }
222
223 blake2bp_update( S, buffer, buffer_length );
224 }
225
226 final_process:;
227
228 if( sum > 0 ) blake2bp_update( S, buffer, sum );
229
230 blake2bp_final( S, resstream, outbytes );
231 ret = 0;
232 cleanup_buffer:
233 free( buffer );
234 return ret;
235 }
236
237 typedef int ( *blake2fn )( FILE *, void *, size_t );
238
239
240 static void usage( char **argv, int errcode )
241 {
242 FILE *out = errcode ? stderr : stdout;
243 fprintf( out, "Usage: %s [OPTION]... [FILE]...\n", argv[0] );
244 fprintf( out, "\n" );
245 fprintf( out, "With no FILE, or when FILE is -, read standard input.\n" );
246 fprintf( out, "\n" );
247 fprintf( out, " -a <algo> hash algorithm (blake2b is default): \n"
248 " [blake2b|blake2s|blake2bp|blake2sp]\n" );
249 fprintf( out, " -l <length> digest length in bits, must not exceed the maximum for\n"
250 " the selected algorithm and must be a multiple of 8\n" );
251 fprintf( out, " --tag create a BSD-style checksum\n" );
252 fprintf( out, " --help display this help and exit\n" );
253 exit( errcode );
254 }
255
256
257 int main( int argc, char **argv )
258 {
259 blake2fn blake2_stream = blake2b_stream;
260 unsigned long maxbytes = BLAKE2B_OUTBYTES;
261 const char *algorithm = "BLAKE2b";
262 unsigned long outbytes = 0;
263 unsigned char hash[BLAKE2B_OUTBYTES] = {0};
264 bool bsdstyle = false;
265 int c, i;
266 opterr = 1;
267
268 while( 1 )
269 {
270 int option_index = 0;
271 char *end = nullptr;
272 unsigned long outbits;
273 static struct option long_options[] = {
274 { "help", no_argument, 0, 0 },
275 { "tag", no_argument, 0, 0 },
276 { nullptr, 0, nullptr, 0 }
277 };
278
279 c = getopt_long( argc, argv, "a:l:", long_options, &option_index );
280 if( c == -1 ) break;
281 switch( c )
282 {
283 case 'a':
284 if( 0 == strcmp( optarg, "blake2b" ) )
285 {
286 blake2_stream = blake2b_stream;
287 maxbytes = BLAKE2B_OUTBYTES;
288 algorithm = "BLAKE2b";
289 }
290 else if ( 0 == strcmp( optarg, "blake2s" ) )
291 {
292 blake2_stream = blake2s_stream;
293 maxbytes = BLAKE2S_OUTBYTES;
294 algorithm = "BLAKE2s";
295 }
296 else if ( 0 == strcmp( optarg, "blake2bp" ) )
297 {
298 blake2_stream = blake2bp_stream;
299 maxbytes = BLAKE2B_OUTBYTES;
300 algorithm = "BLAKE2bp";
301 }
302 else if ( 0 == strcmp( optarg, "blake2sp" ) )
303 {
304 blake2_stream = blake2sp_stream;
305 maxbytes = BLAKE2S_OUTBYTES;
306 algorithm = "BLAKE2sp";
307 }
308 else
309 {
310 printf( "Invalid function name: `%s'\n", optarg );
311 usage( argv, 111 );
312 }
313
314 break;
315
316 case 'l':
317 outbits = strtoul(optarg, &end, 10);
318 if( !end || *end != '\0' || outbits % 8 != 0)
319 {
320 printf( "Invalid length argument: `%s'\n", optarg);
321 usage( argv, 111 );
322 }
323 outbytes = outbits / 8;
324 break;
325
326 case 0:
327 if( 0 == strcmp( "help", long_options[option_index].name ) )
328 usage( argv, 0 );
329 else if( 0 == strcmp( "tag", long_options[option_index].name ) )
330 bsdstyle = true;
331 break;
332
333 case '?':
334 usage( argv, 1 );
335 break;
336 }
337 }
338
339 if(outbytes > maxbytes)
340 {
341 printf( "Invalid length argument: %lu\n", outbytes * 8 );
342 printf( "Maximum digest length for %s is %lu\n", algorithm, maxbytes * 8 );
343 usage( argv, 111 );
344 }
345 else if( outbytes == 0 )
346 outbytes = maxbytes;
347
348 if( optind == argc )
349 argv[argc++] = (char *) "-";
350
351 for( i = optind; i < argc; ++i )
352 {
353 FILE *f = nullptr;
354 if( argv[i][0] == '-' && argv[i][1] == '\0' )
355 f = stdin;
356 else
357 f = fopen( argv[i], "rb" );
358
359 if( !f )
360 {
361 fprintf( stderr, "Could not open `%s': %s\n", argv[i], strerror( errno ) );
362 continue;
363 }
364
365 if( blake2_stream( f, hash, outbytes ) < 0 )
366 {
367 fprintf( stderr, "Failed to hash `%s'\n", argv[i] );
368 }
369 else
370 {
371 size_t j;
372 if( bsdstyle )
373 {
374 if( outbytes < maxbytes )
375 printf( "%s-%lu (%s) = ", algorithm, outbytes * 8, argv[i] );
376 else
377 printf( "%s (%s) = ", algorithm, argv[i] );
378 }
379
380 for( j = 0; j < outbytes; ++j )
381 printf( "%02x", hash[j] );
382
383 if( bsdstyle )
384 printf( "\n" );
385 else
386 printf( " %s\n", argv[i] );
387 }
388
389 if( f == stdin )
390 clearerr( f );
391 else if( fclose( f ) != 0 )
392 fprintf( stderr, "Could not close `%s': %s\n", argv[i], strerror( errno ) );
393 }
394
395 return 0;
396 }
397 #endif
398