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