shithub: blake2

Download patch

ref: 3b2fb9f2cdfa4ef250a817ae3d2c8bfbbf87e66e
parent: 3a9a49defb741ae55fe98d112e9faedd80a958f9
author: Paul Barker <paul@paulbarker.me.uk>
date: Sun Jan 3 06:39:42 EST 2016

b2sum: Add digest length argument

It may be desirable to produce a digest with a shorter length than the default
using a BLAKE2 algorithm. For example, the crypto_generichash() function in
libsodium uses BLAKE2b but shortens the digest to 256 bits by default and it is
useful for debugging to generate similar hashes with b2sum for comparison.

The requested digest length is specified in bits, must be a multiple of 8 and
cannot exceed the total output length of the selected algoritm. No minimum
digest length is enforced.

If a shorter-than-default digest length is selected, this is indicated in the
output when the '--tag' option is given.

--- a/b2sum/b2sum.c
+++ b/b2sum/b2sum.c
@@ -25,7 +25,7 @@
 #include "blake2.h"
 
 /* This will help compatibility with coreutils */
-int blake2s_stream( FILE *stream, void *resstream )
+int blake2s_stream( FILE *stream, void *resstream, size_t outbytes )
 {
   int ret = -1;
   size_t sum, n;
@@ -35,7 +35,7 @@
 
   if( !buffer ) return -1;
 
-  blake2s_init( S, BLAKE2S_OUTBYTES );
+  blake2s_init( S, outbytes );
 
   while( 1 )
   {
@@ -68,7 +68,7 @@
 
   if( sum > 0 ) blake2s_update( S, buffer, sum );
 
-  blake2s_final( S, resstream, BLAKE2S_OUTBYTES );
+  blake2s_final( S, resstream, outbytes );
   ret = 0;
 cleanup_buffer:
   free( buffer );
@@ -75,7 +75,7 @@
   return ret;
 }
 
-int blake2b_stream( FILE *stream, void *resstream )
+int blake2b_stream( FILE *stream, void *resstream, size_t outbytes )
 {
   int ret = -1;
   size_t sum, n;
@@ -85,7 +85,7 @@
 
   if( !buffer ) return -1;
 
-  blake2b_init( S, BLAKE2B_OUTBYTES );
+  blake2b_init( S, outbytes );
 
   while( 1 )
   {
@@ -118,7 +118,7 @@
 
   if( sum > 0 ) blake2b_update( S, buffer, sum );
 
-  blake2b_final( S, resstream, BLAKE2B_OUTBYTES );
+  blake2b_final( S, resstream, outbytes );
   ret = 0;
 cleanup_buffer:
   free( buffer );
@@ -125,7 +125,7 @@
   return ret;
 }
 
-int blake2sp_stream( FILE *stream, void *resstream )
+int blake2sp_stream( FILE *stream, void *resstream, size_t outbytes )
 {
   int ret = -1;
   size_t sum, n;
@@ -135,7 +135,7 @@
 
   if( !buffer ) return -1;
 
-  blake2sp_init( S, BLAKE2S_OUTBYTES );
+  blake2sp_init( S, outbytes );
 
   while( 1 )
   {
@@ -168,7 +168,7 @@
 
   if( sum > 0 ) blake2sp_update( S, buffer, sum );
 
-  blake2sp_final( S, resstream, BLAKE2S_OUTBYTES );
+  blake2sp_final( S, resstream, outbytes );
   ret = 0;
 cleanup_buffer:
   free( buffer );
@@ -176,7 +176,7 @@
 }
 
 
-int blake2bp_stream( FILE *stream, void *resstream )
+int blake2bp_stream( FILE *stream, void *resstream, size_t outbytes )
 {
   int ret = -1;
   size_t sum, n;
@@ -186,7 +186,7 @@
 
   if( !buffer ) return -1;
 
-  blake2bp_init( S, BLAKE2B_OUTBYTES );
+  blake2bp_init( S, outbytes );
 
   while( 1 )
   {
@@ -219,7 +219,7 @@
 
   if( sum > 0 ) blake2bp_update( S, buffer, sum );
 
-  blake2bp_final( S, resstream, BLAKE2B_OUTBYTES );
+  blake2bp_final( S, resstream, outbytes );
   ret = 0;
 cleanup_buffer:
   free( buffer );
@@ -226,7 +226,7 @@
   return ret;
 }
 
-typedef int ( *blake2fn )( FILE *, void * );
+typedef int ( *blake2fn )( FILE *, void *, size_t );
 
 
 static void usage( char **argv, int errcode )
@@ -238,6 +238,8 @@
   fprintf( out, "\n" );
   fprintf( out, "  -a <algo>    hash algorithm (blake2b is default): \n"
                 "               [blake2b|blake2s|blake2bp|blake2sp]\n" );
+  fprintf( out, "  -l <length>  digest length in bits, must not exceed the maximum for\n"
+                "               the selected algorithm and must be a multiple of 8\n" );
   fprintf( out, "  --tag        create a BSD-style checksum\n" );
   fprintf( out, "  --help       display this help and exit\n" );
   exit( errcode );
@@ -247,8 +249,9 @@
 int main( int argc, char **argv )
 {
   blake2fn blake2_stream = blake2b_stream;
-  size_t outlen   = BLAKE2B_OUTBYTES;
+  size_t maxbytes = BLAKE2B_OUTBYTES;
   const char *algorithm = "BLAKE2b";
+  size_t outbytes = 0;
   unsigned char hash[BLAKE2B_OUTBYTES] = {0};
   bool bsdstyle = false;
   int c;
@@ -258,6 +261,8 @@
   {
     int this_option_optind = optind ? optind : 1;
     int option_index = 0;
+    char *end = NULL;
+    size_t outbits;
     static struct option long_options[] = {
       { "help",  no_argument, 0,  0  },
       { "tag",   no_argument, 0,  0  },
@@ -264,7 +269,7 @@
       { NULL, 0, NULL, 0 }
     };
 
-    c = getopt_long( argc, argv, "a:", long_options, &option_index );
+    c = getopt_long( argc, argv, "a:l:", long_options, &option_index );
     if( c == -1 ) break;
     switch( c )
     {
@@ -272,25 +277,25 @@
       if( 0 == strcmp( optarg, "blake2b" ) )
       {
         blake2_stream = blake2b_stream;
-        outlen = BLAKE2B_OUTBYTES;
+        maxbytes = BLAKE2B_OUTBYTES;
         algorithm = "BLAKE2b";
       }
       else if ( 0 == strcmp( optarg, "blake2s" ) )
       {
         blake2_stream = blake2s_stream;
-        outlen = BLAKE2S_OUTBYTES;
+        maxbytes = BLAKE2S_OUTBYTES;
         algorithm = "BLAKE2s";
       }
       else if ( 0 == strcmp( optarg, "blake2bp" ) )
       {
         blake2_stream = blake2bp_stream;
-        outlen = BLAKE2B_OUTBYTES;
+        maxbytes = BLAKE2B_OUTBYTES;
         algorithm = "BLAKE2bp";
       }
       else if ( 0 == strcmp( optarg, "blake2sp" ) )
       {
         blake2_stream = blake2sp_stream;
-        outlen = BLAKE2S_OUTBYTES;
+        maxbytes = BLAKE2S_OUTBYTES;
         algorithm = "BLAKE2sp";
       }
       else
@@ -301,6 +306,16 @@
 
       break;
 
+    case 'l':
+      outbits = strtoul(optarg, &end, 10);
+      if( !end || *end != '\0' || outbits % 8 )
+      {
+        printf( "Invalid length argument: `%s'\n", optarg);
+        usage( argv, 111 );
+      }
+      outbytes = outbits / 8;
+      break;
+
     case 0:
       if( 0 == strcmp( "help", long_options[option_index].name ) )
         usage( argv, 0 );
@@ -314,6 +329,15 @@
     }
   }
 
+  if(outbytes > maxbytes)
+  {
+    printf( "Invalid length argument: %zu\n", outbytes * 8 );
+    printf( "Maximum digest length for %s is %zu\n", algorithm, maxbytes * 8 );
+    usage( argv, 111 );
+  }
+  else if( outbytes == 0 )
+    outbytes = maxbytes;
+
   if( optind == argc )
     argv[argc++] = (char *) "-";
 
@@ -331,7 +355,7 @@
       continue;
     }
 
-    if( blake2_stream( f, hash ) < 0 )
+    if( blake2_stream( f, hash, outbytes ) < 0 )
     {
       fprintf( stderr, "Failed to hash `%s'\n", argv[i] );
     }
@@ -339,10 +363,13 @@
     {
       if( bsdstyle )
       {
-        printf( "%s (%s) = ", algorithm, argv[i] );
+        if( outbytes < maxbytes )
+          printf( "%s-%zu (%s) = ", algorithm, outbytes * 8, argv[i] );
+        else
+          printf( "%s (%s) = ", algorithm, argv[i] );
       }
 
-      for( size_t j = 0; j < outlen; ++j )
+      for( size_t j = 0; j < outbytes; ++j )
         printf( "%02x", hash[j] );
 
       if( bsdstyle )
--