b2sum: a new checksum utility with md5sum like interface
[coreutils.git] / src / blake2 / b2sum.c
blob1c565e08c6d39c703b08fc96ab7e179453e6d3ad
1 /*
2 BLAKE2 reference source code package - b2sum tool
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:
8 - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
9 - OpenSSL license : https://www.openssl.org/source/license.html
10 - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
12 More information about the BLAKE2 hash function can be found at
13 https://blake2.net.
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <assert.h>
20 #include <errno.h>
22 #include <ctype.h>
23 #include <unistd.h>
24 #include <getopt.h>
25 #include <stdbool.h>
27 #include "blake2.h"
29 /* This will help compatibility with coreutils */
30 int blake2b_stream( FILE *stream, void *resstream, size_t outbytes )
32 int ret = -1;
33 size_t sum, n;
34 blake2b_state S[1];
35 static const size_t buffer_length = 32768;
36 uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
38 if( !buffer ) return -1;
40 blake2b_init( S, outbytes );
42 while( 1 )
44 sum = 0;
46 while( 1 )
48 n = fread( buffer + sum, 1, buffer_length - sum, stream );
49 sum += n;
51 if( buffer_length == sum )
52 break;
54 if( 0 == n )
56 if( ferror( stream ) )
57 goto cleanup_buffer;
59 goto final_process;
62 if( feof( stream ) )
63 goto final_process;
66 blake2b_update( S, buffer, buffer_length );
69 final_process:;
71 if( sum > 0 ) blake2b_update( S, buffer, sum );
73 blake2b_final( S, resstream, outbytes );
74 ret = 0;
75 cleanup_buffer:
76 free( buffer );
77 return ret;
80 #if 0
81 int blake2s_stream( FILE *stream, void *resstream, size_t outbytes )
83 int ret = -1;
84 size_t sum, n;
85 blake2s_state S[1];
86 static const size_t buffer_length = 32768;
87 uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
89 if( !buffer ) return -1;
91 blake2s_init( S, outbytes );
93 while( 1 )
95 sum = 0;
97 while( 1 )
99 n = fread( buffer + sum, 1, buffer_length - sum, stream );
100 sum += n;
102 if( buffer_length == sum )
103 break;
105 if( 0 == n )
107 if( ferror( stream ) )
108 goto cleanup_buffer;
110 goto final_process;
113 if( feof( stream ) )
114 goto final_process;
117 blake2s_update( S, buffer, buffer_length );
120 final_process:;
122 if( sum > 0 ) blake2s_update( S, buffer, sum );
124 blake2s_final( S, resstream, outbytes );
125 ret = 0;
126 cleanup_buffer:
127 free( buffer );
128 return ret;
132 int blake2sp_stream( FILE *stream, void *resstream, size_t outbytes )
134 int ret = -1;
135 size_t sum, n;
136 blake2sp_state S[1];
137 static const size_t buffer_length = 16 * ( 1UL << 20 );
138 uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
140 if( !buffer ) return -1;
142 blake2sp_init( S, outbytes );
144 while( 1 )
146 sum = 0;
148 while( 1 )
150 n = fread( buffer + sum, 1, buffer_length - sum, stream );
151 sum += n;
153 if( buffer_length == sum )
154 break;
156 if( 0 == n )
158 if( ferror( stream ) )
159 goto cleanup_buffer;
161 goto final_process;
164 if( feof( stream ) )
165 goto final_process;
168 blake2sp_update( S, buffer, buffer_length );
171 final_process:;
173 if( sum > 0 ) blake2sp_update( S, buffer, sum );
175 blake2sp_final( S, resstream, outbytes );
176 ret = 0;
177 cleanup_buffer:
178 free( buffer );
179 return ret;
183 int blake2bp_stream( FILE *stream, void *resstream, size_t outbytes )
185 int ret = -1;
186 size_t sum, n;
187 blake2bp_state S[1];
188 static const size_t buffer_length = 16 * ( 1UL << 20 );
189 uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
191 if( !buffer ) return -1;
193 blake2bp_init( S, outbytes );
195 while( 1 )
197 sum = 0;
199 while( 1 )
201 n = fread( buffer + sum, 1, buffer_length - sum, stream );
202 sum += n;
204 if( buffer_length == sum )
205 break;
207 if( 0 == n )
209 if( ferror( stream ) )
210 goto cleanup_buffer;
212 goto final_process;
215 if( feof( stream ) )
216 goto final_process;
219 blake2bp_update( S, buffer, buffer_length );
222 final_process:;
224 if( sum > 0 ) blake2bp_update( S, buffer, sum );
226 blake2bp_final( S, resstream, outbytes );
227 ret = 0;
228 cleanup_buffer:
229 free( buffer );
230 return ret;
233 typedef int ( *blake2fn )( FILE *, void *, size_t );
236 static void usage( char **argv, int errcode )
238 FILE *out = errcode ? stderr : stdout;
239 fprintf( out, "Usage: %s [OPTION]... [FILE]...\n", argv[0] );
240 fprintf( out, "\n" );
241 fprintf( out, "With no FILE, or when FILE is -, read standard input.\n" );
242 fprintf( out, "\n" );
243 fprintf( out, " -a <algo> hash algorithm (blake2b is default): \n"
244 " [blake2b|blake2s|blake2bp|blake2sp]\n" );
245 fprintf( out, " -l <length> digest length in bits, must not exceed the maximum for\n"
246 " the selected algorithm and must be a multiple of 8\n" );
247 fprintf( out, " --tag create a BSD-style checksum\n" );
248 fprintf( out, " --help display this help and exit\n" );
249 exit( errcode );
252 int main( int argc, char **argv )
254 blake2fn blake2_stream = blake2b_stream;
255 unsigned long maxbytes = BLAKE2B_OUTBYTES;
256 const char *algorithm = "BLAKE2b";
257 unsigned long outbytes = 0;
258 unsigned char hash[BLAKE2B_OUTBYTES] = {0};
259 bool bsdstyle = false;
260 int c, i;
261 opterr = 1;
263 while( 1 )
265 int option_index = 0;
266 char *end = NULL;
267 unsigned long outbits;
268 static struct option long_options[] = {
269 { "help", no_argument, 0, 0 },
270 { "tag", no_argument, 0, 0 },
271 { NULL, 0, NULL, 0 }
274 c = getopt_long( argc, argv, "a:l:", long_options, &option_index );
275 if( c == -1 ) break;
276 switch( c )
278 case 'a':
279 if( 0 == strcmp( optarg, "blake2b" ) )
281 blake2_stream = blake2b_stream;
282 maxbytes = BLAKE2B_OUTBYTES;
283 algorithm = "BLAKE2b";
285 else if ( 0 == strcmp( optarg, "blake2s" ) )
287 blake2_stream = blake2s_stream;
288 maxbytes = BLAKE2S_OUTBYTES;
289 algorithm = "BLAKE2s";
291 else if ( 0 == strcmp( optarg, "blake2bp" ) )
293 blake2_stream = blake2bp_stream;
294 maxbytes = BLAKE2B_OUTBYTES;
295 algorithm = "BLAKE2bp";
297 else if ( 0 == strcmp( optarg, "blake2sp" ) )
299 blake2_stream = blake2sp_stream;
300 maxbytes = BLAKE2S_OUTBYTES;
301 algorithm = "BLAKE2sp";
303 else
305 printf( "Invalid function name: `%s'\n", optarg );
306 usage( argv, 111 );
309 break;
311 case 'l':
312 outbits = strtoul(optarg, &end, 10);
313 if( !end || *end != '\0' || outbits % 8 != 0)
315 printf( "Invalid length argument: `%s'\n", optarg);
316 usage( argv, 111 );
318 outbytes = outbits / 8;
319 break;
321 case 0:
322 if( 0 == strcmp( "help", long_options[option_index].name ) )
323 usage( argv, 0 );
324 else if( 0 == strcmp( "tag", long_options[option_index].name ) )
325 bsdstyle = true;
326 break;
328 case '?':
329 usage( argv, 1 );
330 break;
334 if(outbytes > maxbytes)
336 printf( "Invalid length argument: %lu\n", outbytes * 8 );
337 printf( "Maximum digest length for %s is %lu\n", algorithm, maxbytes * 8 );
338 usage( argv, 111 );
340 else if( outbytes == 0 )
341 outbytes = maxbytes;
343 if( optind == argc )
344 argv[argc++] = (char *) "-";
346 for( i = optind; i < argc; ++i )
348 FILE *f = NULL;
349 if( argv[i][0] == '-' && argv[i][1] == '\0' )
350 f = stdin;
351 else
352 f = fopen( argv[i], "rb" );
354 if( !f )
356 fprintf( stderr, "Could not open `%s': %s\n", argv[i], strerror( errno ) );
357 continue;
360 if( blake2_stream( f, hash, outbytes ) < 0 )
362 fprintf( stderr, "Failed to hash `%s'\n", argv[i] );
364 else
366 size_t j;
367 if( bsdstyle )
369 if( outbytes < maxbytes )
370 printf( "%s-%lu (%s) = ", algorithm, outbytes * 8, argv[i] );
371 else
372 printf( "%s (%s) = ", algorithm, argv[i] );
375 for( j = 0; j < outbytes; ++j )
376 printf( "%02x", hash[j] );
378 if( bsdstyle )
379 printf( "\n" );
380 else
381 printf( " %s\n", argv[i] );
384 if( f != stdin ) fclose( f );
387 return 0;
389 #endif