summaryrefslogtreecommitdiff
path: root/src/blake2/b2sum.c
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2016-10-31 13:29:34 +0000
committerPádraig Brady <P@draigBrady.com>2016-11-22 20:04:24 +0000
commitea94589e9ef02624a3837f97f80efd7d3dcf56bf (patch)
tree5f3f96ca978e3e43c485d914bf95c8ffdeeb41dd /src/blake2/b2sum.c
parent373ba16f332d0632f2ce987893ed67bb4334c5d2 (diff)
downloadcoreutils-ea94589e9ef02624a3837f97f80efd7d3dcf56bf.tar.xz
b2sum: a new checksum utility with md5sum like interface
Note we don't support the --algorithm option of the b2sum command in the external BLAKE2 project, as that was deemed too confusing for users. "BLAKE2b" was chosen as the default algorithm to use, which is single threaded but performs well on 64 bit. * src/blake2: CC0 source copied from external project. * cfg.mk[VC_LIST_ALWAYS_EXCLUDE_REGEX]: Exclude blake2/ from syntax checks, make update-copyright, etc. * src/local.mk: Reference the sources for b2sum, and set the compilation flags. * doc/coreutils.texi (b2sum invocation): Reference the md5sum invocation node, and add descriptions of -l. * tests/misc/b2sum.sh: Add new test. * tests/local.mk: Reference new test. * AUTHORS: Add new binary. * README: Likewise. * build-aux/gen-lists-of-programs.sh: Likewise. * man/.gitignore: Likewise. * scripts/git-hooks/commit-msg: Likewise. * man/b2sum.x: New man page template. * man/local.mk: Reference new template. * src/.gitignore: Ignore new binaries. * src/blake2/.gitignore: Ignore new build atrifacts. * src/md5sum.c (usage): Describe the new -l option. * NEWS: Mention the new program.
Diffstat (limited to 'src/blake2/b2sum.c')
-rw-r--r--src/blake2/b2sum.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/src/blake2/b2sum.c b/src/blake2/b2sum.c
new file mode 100644
index 000000000..1c565e08c
--- /dev/null
+++ b/src/blake2/b2sum.c
@@ -0,0 +1,389 @@
+/*
+ BLAKE2 reference source code package - b2sum tool
+
+ Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
+ terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
+ your option. The terms of these licenses can be found at:
+
+ - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
+ - OpenSSL license : https://www.openssl.org/source/license.html
+ - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
+
+ More information about the BLAKE2 hash function can be found at
+ https://blake2.net.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <ctype.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <stdbool.h>
+
+#include "blake2.h"
+
+/* This will help compatibility with coreutils */
+int blake2b_stream( FILE *stream, void *resstream, size_t outbytes )
+{
+ int ret = -1;
+ size_t sum, n;
+ blake2b_state S[1];
+ static const size_t buffer_length = 32768;
+ uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
+
+ if( !buffer ) return -1;
+
+ blake2b_init( S, outbytes );
+
+ while( 1 )
+ {
+ sum = 0;
+
+ while( 1 )
+ {
+ n = fread( buffer + sum, 1, buffer_length - sum, stream );
+ sum += n;
+
+ if( buffer_length == sum )
+ break;
+
+ if( 0 == n )
+ {
+ if( ferror( stream ) )
+ goto cleanup_buffer;
+
+ goto final_process;
+ }
+
+ if( feof( stream ) )
+ goto final_process;
+ }
+
+ blake2b_update( S, buffer, buffer_length );
+ }
+
+final_process:;
+
+ if( sum > 0 ) blake2b_update( S, buffer, sum );
+
+ blake2b_final( S, resstream, outbytes );
+ ret = 0;
+cleanup_buffer:
+ free( buffer );
+ return ret;
+}
+
+#if 0
+int blake2s_stream( FILE *stream, void *resstream, size_t outbytes )
+{
+ int ret = -1;
+ size_t sum, n;
+ blake2s_state S[1];
+ static const size_t buffer_length = 32768;
+ uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
+
+ if( !buffer ) return -1;
+
+ blake2s_init( S, outbytes );
+
+ while( 1 )
+ {
+ sum = 0;
+
+ while( 1 )
+ {
+ n = fread( buffer + sum, 1, buffer_length - sum, stream );
+ sum += n;
+
+ if( buffer_length == sum )
+ break;
+
+ if( 0 == n )
+ {
+ if( ferror( stream ) )
+ goto cleanup_buffer;
+
+ goto final_process;
+ }
+
+ if( feof( stream ) )
+ goto final_process;
+ }
+
+ blake2s_update( S, buffer, buffer_length );
+ }
+
+final_process:;
+
+ if( sum > 0 ) blake2s_update( S, buffer, sum );
+
+ blake2s_final( S, resstream, outbytes );
+ ret = 0;
+cleanup_buffer:
+ free( buffer );
+ return ret;
+}
+
+
+int blake2sp_stream( FILE *stream, void *resstream, size_t outbytes )
+{
+ int ret = -1;
+ size_t sum, n;
+ blake2sp_state S[1];
+ static const size_t buffer_length = 16 * ( 1UL << 20 );
+ uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
+
+ if( !buffer ) return -1;
+
+ blake2sp_init( S, outbytes );
+
+ while( 1 )
+ {
+ sum = 0;
+
+ while( 1 )
+ {
+ n = fread( buffer + sum, 1, buffer_length - sum, stream );
+ sum += n;
+
+ if( buffer_length == sum )
+ break;
+
+ if( 0 == n )
+ {
+ if( ferror( stream ) )
+ goto cleanup_buffer;
+
+ goto final_process;
+ }
+
+ if( feof( stream ) )
+ goto final_process;
+ }
+
+ blake2sp_update( S, buffer, buffer_length );
+ }
+
+final_process:;
+
+ if( sum > 0 ) blake2sp_update( S, buffer, sum );
+
+ blake2sp_final( S, resstream, outbytes );
+ ret = 0;
+cleanup_buffer:
+ free( buffer );
+ return ret;
+}
+
+
+int blake2bp_stream( FILE *stream, void *resstream, size_t outbytes )
+{
+ int ret = -1;
+ size_t sum, n;
+ blake2bp_state S[1];
+ static const size_t buffer_length = 16 * ( 1UL << 20 );
+ uint8_t *buffer = ( uint8_t * )malloc( buffer_length );
+
+ if( !buffer ) return -1;
+
+ blake2bp_init( S, outbytes );
+
+ while( 1 )
+ {
+ sum = 0;
+
+ while( 1 )
+ {
+ n = fread( buffer + sum, 1, buffer_length - sum, stream );
+ sum += n;
+
+ if( buffer_length == sum )
+ break;
+
+ if( 0 == n )
+ {
+ if( ferror( stream ) )
+ goto cleanup_buffer;
+
+ goto final_process;
+ }
+
+ if( feof( stream ) )
+ goto final_process;
+ }
+
+ blake2bp_update( S, buffer, buffer_length );
+ }
+
+final_process:;
+
+ if( sum > 0 ) blake2bp_update( S, buffer, sum );
+
+ blake2bp_final( S, resstream, outbytes );
+ ret = 0;
+cleanup_buffer:
+ free( buffer );
+ return ret;
+}
+
+typedef int ( *blake2fn )( FILE *, void *, size_t );
+
+
+static void usage( char **argv, int errcode )
+{
+ FILE *out = errcode ? stderr : stdout;
+ fprintf( out, "Usage: %s [OPTION]... [FILE]...\n", argv[0] );
+ fprintf( out, "\n" );
+ fprintf( out, "With no FILE, or when FILE is -, read standard input.\n" );
+ 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 );
+}
+
+int main( int argc, char **argv )
+{
+ blake2fn blake2_stream = blake2b_stream;
+ unsigned long maxbytes = BLAKE2B_OUTBYTES;
+ const char *algorithm = "BLAKE2b";
+ unsigned long outbytes = 0;
+ unsigned char hash[BLAKE2B_OUTBYTES] = {0};
+ bool bsdstyle = false;
+ int c, i;
+ opterr = 1;
+
+ while( 1 )
+ {
+ int option_index = 0;
+ char *end = NULL;
+ unsigned long outbits;
+ static struct option long_options[] = {
+ { "help", no_argument, 0, 0 },
+ { "tag", no_argument, 0, 0 },
+ { NULL, 0, NULL, 0 }
+ };
+
+ c = getopt_long( argc, argv, "a:l:", long_options, &option_index );
+ if( c == -1 ) break;
+ switch( c )
+ {
+ case 'a':
+ if( 0 == strcmp( optarg, "blake2b" ) )
+ {
+ blake2_stream = blake2b_stream;
+ maxbytes = BLAKE2B_OUTBYTES;
+ algorithm = "BLAKE2b";
+ }
+ else if ( 0 == strcmp( optarg, "blake2s" ) )
+ {
+ blake2_stream = blake2s_stream;
+ maxbytes = BLAKE2S_OUTBYTES;
+ algorithm = "BLAKE2s";
+ }
+ else if ( 0 == strcmp( optarg, "blake2bp" ) )
+ {
+ blake2_stream = blake2bp_stream;
+ maxbytes = BLAKE2B_OUTBYTES;
+ algorithm = "BLAKE2bp";
+ }
+ else if ( 0 == strcmp( optarg, "blake2sp" ) )
+ {
+ blake2_stream = blake2sp_stream;
+ maxbytes = BLAKE2S_OUTBYTES;
+ algorithm = "BLAKE2sp";
+ }
+ else
+ {
+ printf( "Invalid function name: `%s'\n", optarg );
+ usage( argv, 111 );
+ }
+
+ break;
+
+ case 'l':
+ outbits = strtoul(optarg, &end, 10);
+ if( !end || *end != '\0' || outbits % 8 != 0)
+ {
+ 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 );
+ else if( 0 == strcmp( "tag", long_options[option_index].name ) )
+ bsdstyle = true;
+ break;
+
+ case '?':
+ usage( argv, 1 );
+ break;
+ }
+ }
+
+ if(outbytes > maxbytes)
+ {
+ printf( "Invalid length argument: %lu\n", outbytes * 8 );
+ printf( "Maximum digest length for %s is %lu\n", algorithm, maxbytes * 8 );
+ usage( argv, 111 );
+ }
+ else if( outbytes == 0 )
+ outbytes = maxbytes;
+
+ if( optind == argc )
+ argv[argc++] = (char *) "-";
+
+ for( i = optind; i < argc; ++i )
+ {
+ FILE *f = NULL;
+ if( argv[i][0] == '-' && argv[i][1] == '\0' )
+ f = stdin;
+ else
+ f = fopen( argv[i], "rb" );
+
+ if( !f )
+ {
+ fprintf( stderr, "Could not open `%s': %s\n", argv[i], strerror( errno ) );
+ continue;
+ }
+
+ if( blake2_stream( f, hash, outbytes ) < 0 )
+ {
+ fprintf( stderr, "Failed to hash `%s'\n", argv[i] );
+ }
+ else
+ {
+ size_t j;
+ if( bsdstyle )
+ {
+ if( outbytes < maxbytes )
+ printf( "%s-%lu (%s) = ", algorithm, outbytes * 8, argv[i] );
+ else
+ printf( "%s (%s) = ", algorithm, argv[i] );
+ }
+
+ for( j = 0; j < outbytes; ++j )
+ printf( "%02x", hash[j] );
+
+ if( bsdstyle )
+ printf( "\n" );
+ else
+ printf( " %s\n", argv[i] );
+ }
+
+ if( f != stdin ) fclose( f );
+ }
+
+ return 0;
+}
+#endif