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.
This commit is contained in:
Pádraig Brady 2016-10-31 13:29:34 +00:00
parent 373ba16f33
commit ea94589e9e
23 changed files with 1428 additions and 24 deletions

View File

@ -2,6 +2,7 @@ Here are the names of the programs in this package,
each followed by the name(s) of its author(s).
arch: David MacKenzie, Karel Zak
b2sum: Padraig Brady, Samuel Neves
base32: Simon Josefsson
base64: Simon Josefsson
basename: David MacKenzie

5
NEWS
View File

@ -104,6 +104,11 @@ GNU coreutils NEWS -*- outline -*-
stat --format=%N for quoting file names now honors the
same QUOTING_STYLE environment variable values as ls.
** New programs
b2sum is added to support the BLAKE2 digest algorithm with
a similar interface to the existing md5sum and sha1sum, etc. commands.
** New Features
date now accepts the --debug option, to annotate the parsed date string,

4
README
View File

@ -7,8 +7,8 @@ arbitrary limits.
The programs that can be built with this package are:
[ arch base32 base64 basename cat chcon chgrp chmod chown chroot cksum comm
coreutils cp csplit cut date dd df dir dircolors dirname du echo env
[ arch b2sum base32 base64 basename cat chcon chgrp chmod chown chroot cksum
comm coreutils cp csplit cut date dd df dir dircolors dirname du echo env
expand expr factor false fmt fold groups head hostid hostname id install
join kill link ln logname ls md5sum mkdir mkfifo mknod mktemp mv nice nl
nohup nproc numfmt od paste pathchk pinky pr printenv printf ptx pwd

View File

@ -558,6 +558,7 @@ Ross Ridge rridge@calum.csclub.uwaterloo.ca
Rudolf Kastl rkastl@redhat.com
Sahil Amoli sahilamoli@gmail.com
Sami Farin sfarin@ratol.fi
Samuel Neves sneves@dei.uc.pt
Samuel Tardieu sam@rfc1149.net
Samuel Thibault samuel.thibault@ens-lyon.org
Samuli Karkkainen Samuli.Karkkainen@hut.fi

View File

@ -41,6 +41,7 @@ build_if_possible_progs='
# be buildable without problems on any target system.
normal_progs='
[
b2sum
base64
base32
basename

3
cfg.mk
View File

@ -21,6 +21,9 @@ manual_title = Core GNU utilities
# it can take a while for the faster mirror links to become usable.
url_dir_list = http://ftp.gnu.org/gnu/$(PACKAGE)
# Exclude bundled external projects from syntax checks
VC_LIST_ALWAYS_EXCLUDE_REGEX = src/blake2/.*$$
# Tests not to run as part of "make distcheck".
local-checks-to-skip = \
sc_proper_name_utf8_requires_ICONV

View File

@ -37,6 +37,7 @@
@dircategory Individual utilities
@direntry
* arch: (coreutils)arch invocation. Print machine hardware name.
* b2sum: (coreutils)b2sum invocation. Print or check BLAKE2 digests.
* base32: (coreutils)base32 invocation. Base32 encode/decode data.
* base64: (coreutils)base64 invocation. Base64 encode/decode data.
* basename: (coreutils)basename invocation. Strip directory and suffix.
@ -186,7 +187,7 @@ Free Documentation License''.
* Output of entire files:: cat tac nl od base32 base64
* Formatting file contents:: fmt pr fold
* Output of parts of files:: head tail split csplit
* Summarizing files:: wc sum cksum md5sum sha1sum sha2
* Summarizing files:: wc sum cksum b2sum md5sum sha1sum sha2
* Operating on sorted files:: sort shuf uniq comm ptx tsort
* Operating on fields:: cut paste join
* Operating on characters:: tr expand unexpand
@ -259,6 +260,7 @@ Summarizing files
* wc invocation:: Print newline, word, and byte counts
* sum invocation:: Print checksum and block counts
* cksum invocation:: Print CRC checksum and byte counts
* b2sum invocation:: Print or check BLAKE2 digests
* md5sum invocation:: Print or check MD5 digests
* sha1sum invocation:: Print or check SHA-1 digests
* sha2 utilities:: Print or check SHA-2 digests
@ -3557,6 +3559,7 @@ contents of files.
* wc invocation:: Print newline, word, and byte counts.
* sum invocation:: Print checksum and block counts.
* cksum invocation:: Print CRC checksum and byte counts.
* b2sum invocation:: Print or check BLAKE2 digests.
* md5sum invocation:: Print or check MD5 digests.
* sha1sum invocation:: Print or check SHA-1 digests.
* sha2 utilities:: Print or check SHA-2 digests.
@ -3769,6 +3772,33 @@ options}.
@exitstatus
@node b2sum invocation
@section @command{b2sum}: Print or check BLAKE2 digests
@pindex b2sum
@cindex BLAKE2
@cindex 512-bit checksum
@cindex checksum, 512-bit
@cindex fingerprint, 512-bit
@cindex message-digest, 512-bit
@command{b2sum} computes a 512-bit checksum for each specified
@var{file}. The same usage and options as the @command{md5sum}
command are supported. @xref{md5sum invocation}.
In addition @command{b2sum} supports the following options.
@table @samp
@item -l
@itemx --length
@opindex -l
@opindex --length
@cindex BLAKE2 hash length
Change (shorten) the default digest length.
This is specified in bits and thus must be a multiple of 8.
This option is ignored when @option{--check} is specified,
as the length is automatically determined when checking.
@end table
@node md5sum invocation
@section @command{md5sum}: Print or check MD5 digests

1
man/.gitignore vendored
View File

@ -1,5 +1,6 @@
Makefile
Makefile.in
b2sum.1
base32.1
base64.1
basename.1

4
man/b2sum.x Normal file
View File

@ -0,0 +1,4 @@
[NAME]
b2sum \- compute and check BLAKE2 message digest
[DESCRIPTION]
.\" Add any additional description here

View File

@ -60,6 +60,7 @@ man/install.1: src/ginstall$(EXEEXT)
man/test.1: src/[$(EXEEXT)
man/arch.1: src/arch$(EXEEXT)
man/b2sum.1: src/b2sum$(EXEEXT)
man/base32.1: src/base32$(EXEEXT)
man/base64.1: src/base64$(EXEEXT)
man/basename.1: src/basename$(EXEEXT)

View File

@ -14,8 +14,8 @@ $editor = "vi" if $? != 0 or $editor =~ /^\s*\z/;
# Keywords allowed before the colon on the first line of a commit message:
# program names and a few general category names.
my @valid = qw(
arch base32 base64 basename cat chcon chgrp chmod chown chroot cksum comm
cp csplit cut date dd df dir dircolors dirname du echo env expand
arch b2sum base32 base64 basename cat chcon chgrp chmod chown chroot cksum
comm cp csplit cut date dd df dir dircolors dirname du echo env expand
expr factor false fmt fold groups head hostid hostname id install
join kill link ln logname ls md5sum mkdir mkfifo mknod mktemp
mv nice nl nohup nproc numfmt od paste pathchk pinky pr printenv printf

1
src/.gitignore vendored
View File

@ -2,6 +2,7 @@
/.dirstamp
\[
arch
b2sum
base32
base64
basename

2
src/blake2/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/.dirstamp
/.deps

389
src/blake2/b2sum.c Normal file
View File

@ -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

19
src/blake2/b2sum.h Normal file
View File

@ -0,0 +1,19 @@
/*
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.
*/
int blake2b_stream( FILE *stream, void *resstream, size_t outbytes );
typedef int ( *blake2fn )( FILE *, void *, size_t );
#define BLAKE2S_OUTBYTES 32
#define BLAKE2B_OUTBYTES 64

160
src/blake2/blake2-impl.h Normal file
View File

@ -0,0 +1,160 @@
/*
BLAKE2 reference source code package - reference C implementations
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.
*/
#ifndef BLAKE2_IMPL_H
#define BLAKE2_IMPL_H
#include <stdint.h>
#include <string.h>
#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L)
#if defined(_MSC_VER)
#define BLAKE2_INLINE __inline
#elif defined(__GNUC__)
#define BLAKE2_INLINE __inline__
#else
#define BLAKE2_INLINE
#endif
#else
#define BLAKE2_INLINE inline
#endif
static BLAKE2_INLINE uint32_t load32( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint32_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint32_t )( p[0] ) << 0) |
(( uint32_t )( p[1] ) << 8) |
(( uint32_t )( p[2] ) << 16) |
(( uint32_t )( p[3] ) << 24) ;
#endif
}
static BLAKE2_INLINE uint64_t load64( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint64_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint64_t )( p[0] ) << 0) |
(( uint64_t )( p[1] ) << 8) |
(( uint64_t )( p[2] ) << 16) |
(( uint64_t )( p[3] ) << 24) |
(( uint64_t )( p[4] ) << 32) |
(( uint64_t )( p[5] ) << 40) |
(( uint64_t )( p[6] ) << 48) |
(( uint64_t )( p[7] ) << 56) ;
#endif
}
static BLAKE2_INLINE uint16_t load16( const void *src )
{
#if defined(NATIVE_LITTLE_ENDIAN)
uint16_t w;
memcpy(&w, src, sizeof w);
return w;
#else
const uint8_t *p = ( const uint8_t * )src;
return (( uint16_t )( p[0] ) << 0) |
(( uint16_t )( p[1] ) << 8) ;
#endif
}
static BLAKE2_INLINE void store16( void *dst, uint16_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
*p++ = ( uint8_t )w; w >>= 8;
*p++ = ( uint8_t )w;
#endif
}
static BLAKE2_INLINE void store32( void *dst, uint32_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
#endif
}
static BLAKE2_INLINE void store64( void *dst, uint64_t w )
{
#if defined(NATIVE_LITTLE_ENDIAN)
memcpy(dst, &w, sizeof w);
#else
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
p[4] = (uint8_t)(w >> 32);
p[5] = (uint8_t)(w >> 40);
p[6] = (uint8_t)(w >> 48);
p[7] = (uint8_t)(w >> 56);
#endif
}
static BLAKE2_INLINE uint64_t load48( const void *src )
{
const uint8_t *p = ( const uint8_t * )src;
return (( uint64_t )( p[0] ) << 0) |
(( uint64_t )( p[1] ) << 8) |
(( uint64_t )( p[2] ) << 16) |
(( uint64_t )( p[3] ) << 24) |
(( uint64_t )( p[4] ) << 32) |
(( uint64_t )( p[5] ) << 40) ;
}
static BLAKE2_INLINE void store48( void *dst, uint64_t w )
{
uint8_t *p = ( uint8_t * )dst;
p[0] = (uint8_t)(w >> 0);
p[1] = (uint8_t)(w >> 8);
p[2] = (uint8_t)(w >> 16);
p[3] = (uint8_t)(w >> 24);
p[4] = (uint8_t)(w >> 32);
p[5] = (uint8_t)(w >> 40);
}
static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 32 - c ) );
}
static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c )
{
return ( w >> c ) | ( w << ( 64 - c ) );
}
/* prevents compiler optimizing out memset() */
static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n)
{
static void *(*const volatile memset_v)(void *, int, size_t) = &memset;
memset_v(v, 0, n);
}
#endif

195
src/blake2/blake2.h Normal file
View File

@ -0,0 +1,195 @@
/*
BLAKE2 reference source code package - reference C implementations
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.
*/
#ifndef BLAKE2_H
#define BLAKE2_H
#include <stddef.h>
#include <stdint.h>
#if defined(_MSC_VER)
#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop))
#else
#define BLAKE2_PACKED(x) x __attribute__((packed))
#endif
#if defined(__cplusplus)
extern "C" {
#endif
enum blake2s_constant
{
BLAKE2S_BLOCKBYTES = 64,
BLAKE2S_OUTBYTES = 32,
BLAKE2S_KEYBYTES = 32,
BLAKE2S_SALTBYTES = 8,
BLAKE2S_PERSONALBYTES = 8
};
enum blake2b_constant
{
BLAKE2B_BLOCKBYTES = 128,
BLAKE2B_OUTBYTES = 64,
BLAKE2B_KEYBYTES = 64,
BLAKE2B_SALTBYTES = 16,
BLAKE2B_PERSONALBYTES = 16
};
typedef struct blake2s_state__
{
uint32_t h[8];
uint32_t t[2];
uint32_t f[2];
uint8_t buf[BLAKE2S_BLOCKBYTES];
size_t buflen;
size_t outlen;
uint8_t last_node;
} blake2s_state;
typedef struct blake2b_state__
{
uint64_t h[8];
uint64_t t[2];
uint64_t f[2];
uint8_t buf[BLAKE2B_BLOCKBYTES];
size_t buflen;
size_t outlen;
uint8_t last_node;
} blake2b_state;
typedef struct blake2sp_state__
{
blake2s_state S[8][1];
blake2s_state R[1];
uint8_t buf[8 * BLAKE2S_BLOCKBYTES];
size_t buflen;
size_t outlen;
} blake2sp_state;
typedef struct blake2bp_state__
{
blake2b_state S[4][1];
blake2b_state R[1];
uint8_t buf[4 * BLAKE2B_BLOCKBYTES];
size_t buflen;
size_t outlen;
} blake2bp_state;
BLAKE2_PACKED(struct blake2s_param__
{
uint8_t digest_length; /* 1 */
uint8_t key_length; /* 2 */
uint8_t fanout; /* 3 */
uint8_t depth; /* 4 */
uint32_t leaf_length; /* 8 */
uint32_t node_offset; /* 12 */
uint16_t xof_length; /* 14 */
uint8_t node_depth; /* 15 */
uint8_t inner_length; /* 16 */
/* uint8_t reserved[0]; */
uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */
uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */
});
typedef struct blake2s_param__ blake2s_param;
BLAKE2_PACKED(struct blake2b_param__
{
uint8_t digest_length; /* 1 */
uint8_t key_length; /* 2 */
uint8_t fanout; /* 3 */
uint8_t depth; /* 4 */
uint32_t leaf_length; /* 8 */
uint32_t node_offset; /* 12 */
uint32_t xof_length; /* 16 */
uint8_t node_depth; /* 17 */
uint8_t inner_length; /* 18 */
uint8_t reserved[14]; /* 32 */
uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
});
typedef struct blake2b_param__ blake2b_param;
typedef struct blake2xs_state__
{
blake2s_state S[1];
blake2s_param P[1];
} blake2xs_state;
typedef struct blake2xb_state__
{
blake2b_state S[1];
blake2b_param P[1];
} blake2xb_state;
/* Padded structs result in a compile-time error */
enum {
BLAKE2_DUMMY_1 = 1/(sizeof(blake2s_param) == BLAKE2S_OUTBYTES),
BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES)
};
/* Streaming API */
int blake2s_init( blake2s_state *S, size_t outlen );
int blake2s_init_key( blake2s_state *S, size_t outlen, const void *key, size_t keylen );
int blake2s_init_param( blake2s_state *S, const blake2s_param *P );
int blake2s_update( blake2s_state *S, const void *in, size_t inlen );
int blake2s_final( blake2s_state *S, void *out, size_t outlen );
int blake2b_init( blake2b_state *S, size_t outlen );
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen );
int blake2b_init_param( blake2b_state *S, const blake2b_param *P );
int blake2b_update( blake2b_state *S, const void *in, size_t inlen );
int blake2b_final( blake2b_state *S, void *out, size_t outlen );
int blake2sp_init( blake2sp_state *S, size_t outlen );
int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen );
int blake2sp_update( blake2sp_state *S, const void *in, size_t inlen );
int blake2sp_final( blake2sp_state *S, void *out, size_t outlen );
int blake2bp_init( blake2bp_state *S, size_t outlen );
int blake2bp_init_key( blake2bp_state *S, size_t outlen, const void *key, size_t keylen );
int blake2bp_update( blake2bp_state *S, const void *in, size_t inlen );
int blake2bp_final( blake2bp_state *S, void *out, size_t outlen );
/* Variable output length API */
int blake2xs_init( blake2xs_state *S, const size_t outlen );
int blake2xs_init_key( blake2xs_state *S, const size_t outlen, const void *key, size_t keylen );
int blake2xs_update( blake2xs_state *S, const void *in, size_t inlen );
int blake2xs_final(blake2xs_state *S, void *out, size_t outlen);
int blake2xb_init( blake2xb_state *S, const size_t outlen );
int blake2xb_init_key( blake2xb_state *S, const size_t outlen, const void *key, size_t keylen );
int blake2xb_update( blake2xb_state *S, const void *in, size_t inlen );
int blake2xb_final(blake2xb_state *S, void *out, size_t outlen);
/* Simple API */
int blake2s( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2bp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2xs( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
int blake2xb( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
/* This is simply an alias for blake2b */
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen );
#if defined(__cplusplus)
}
#endif
#endif

379
src/blake2/blake2b-ref.c Normal file
View File

@ -0,0 +1,379 @@
/*
BLAKE2 reference source code package - reference C implementations
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 <stdint.h>
#include <string.h>
#include <stdio.h>
#include "blake2.h"
#include "blake2-impl.h"
static const uint64_t blake2b_IV[8] =
{
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
};
static const uint8_t blake2b_sigma[12][16] =
{
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
};
static void blake2b_set_lastnode( blake2b_state *S )
{
S->f[1] = (uint64_t)-1;
}
/* Some helper functions, not necessarily useful */
static int blake2b_is_lastblock( const blake2b_state *S )
{
return S->f[0] != 0;
}
static void blake2b_set_lastblock( blake2b_state *S )
{
if( S->last_node ) blake2b_set_lastnode( S );
S->f[0] = (uint64_t)-1;
}
static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc )
{
S->t[0] += inc;
S->t[1] += ( S->t[0] < inc );
}
static void blake2b_init0( blake2b_state *S )
{
size_t i;
memset( S, 0, sizeof( blake2b_state ) );
for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
}
/* init xors IV with input parameter block */
int blake2b_init_param( blake2b_state *S, const blake2b_param *P )
{
const uint8_t *p = ( const uint8_t * )( P );
size_t i;
blake2b_init0( S );
/* IV XOR ParamBlock */
for( i = 0; i < 8; ++i )
S->h[i] ^= load64( p + sizeof( S->h[i] ) * i );
S->outlen = P->digest_length;
return 0;
}
int blake2b_init( blake2b_state *S, size_t outlen )
{
blake2b_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = 0;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
return blake2b_init_param( S, P );
}
int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen )
{
blake2b_param P[1];
if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
P->digest_length = (uint8_t)outlen;
P->key_length = (uint8_t)keylen;
P->fanout = 1;
P->depth = 1;
store32( &P->leaf_length, 0 );
store32( &P->node_offset, 0 );
store32( &P->xof_length, 0 );
P->node_depth = 0;
P->inner_length = 0;
memset( P->reserved, 0, sizeof( P->reserved ) );
memset( P->salt, 0, sizeof( P->salt ) );
memset( P->personal, 0, sizeof( P->personal ) );
if( blake2b_init_param( S, P ) < 0 ) return -1;
{
uint8_t block[BLAKE2B_BLOCKBYTES];
memset( block, 0, BLAKE2B_BLOCKBYTES );
memcpy( block, key, keylen );
blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */
}
return 0;
}
#define G(r,i,a,b,c,d) \
do { \
a = a + b + m[blake2b_sigma[r][2*i+0]]; \
d = rotr64(d ^ a, 32); \
c = c + d; \
b = rotr64(b ^ c, 24); \
a = a + b + m[blake2b_sigma[r][2*i+1]]; \
d = rotr64(d ^ a, 16); \
c = c + d; \
b = rotr64(b ^ c, 63); \
} while(0)
#define ROUND(r) \
do { \
G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
G(r,2,v[ 2],v[ 6],v[10],v[14]); \
G(r,3,v[ 3],v[ 7],v[11],v[15]); \
G(r,4,v[ 0],v[ 5],v[10],v[15]); \
G(r,5,v[ 1],v[ 6],v[11],v[12]); \
G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
} while(0)
static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] )
{
uint64_t m[16];
uint64_t v[16];
size_t i;
for( i = 0; i < 16; ++i ) {
m[i] = load64( block + i * sizeof( m[i] ) );
}
for( i = 0; i < 8; ++i ) {
v[i] = S->h[i];
}
v[ 8] = blake2b_IV[0];
v[ 9] = blake2b_IV[1];
v[10] = blake2b_IV[2];
v[11] = blake2b_IV[3];
v[12] = blake2b_IV[4] ^ S->t[0];
v[13] = blake2b_IV[5] ^ S->t[1];
v[14] = blake2b_IV[6] ^ S->f[0];
v[15] = blake2b_IV[7] ^ S->f[1];
ROUND( 0 );
ROUND( 1 );
ROUND( 2 );
ROUND( 3 );
ROUND( 4 );
ROUND( 5 );
ROUND( 6 );
ROUND( 7 );
ROUND( 8 );
ROUND( 9 );
ROUND( 10 );
ROUND( 11 );
for( i = 0; i < 8; ++i ) {
S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
}
}
#undef G
#undef ROUND
int blake2b_update( blake2b_state *S, const void *pin, size_t inlen )
{
const unsigned char * in = (const unsigned char *)pin;
if( inlen > 0 )
{
size_t left = S->buflen;
size_t fill = BLAKE2B_BLOCKBYTES - left;
if( inlen > fill )
{
S->buflen = 0;
memcpy( S->buf + left, in, fill ); /* Fill buffer */
blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES );
blake2b_compress( S, S->buf ); /* Compress */
in += fill; inlen -= fill;
while(inlen > BLAKE2B_BLOCKBYTES) {
blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES);
blake2b_compress( S, in );
in += BLAKE2B_BLOCKBYTES;
inlen -= BLAKE2B_BLOCKBYTES;
}
}
memcpy( S->buf + S->buflen, in, inlen );
S->buflen += inlen;
}
return 0;
}
int blake2b_final( blake2b_state *S, void *out, size_t outlen )
{
uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
size_t i;
if( out == NULL || outlen < S->outlen )
return -1;
if( blake2b_is_lastblock( S ) )
return -1;
blake2b_increment_counter( S, S->buflen );
blake2b_set_lastblock( S );
memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */
blake2b_compress( S, S->buf );
for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */
store64( buffer + sizeof( S->h[i] ) * i, S->h[i] );
memcpy( out, buffer, S->outlen );
secure_zero_memory(buffer, sizeof(buffer));
return 0;
}
/* inlen, at least, should be uint64_t. Others can be size_t. */
int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
{
blake2b_state S[1];
/* Verify parameters */
if ( NULL == in && inlen > 0 ) return -1;
if ( NULL == out ) return -1;
if( NULL == key && keylen > 0 ) return -1;
if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1;
if( keylen > BLAKE2B_KEYBYTES ) return -1;
if( keylen > 0 )
{
if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1;
}
else
{
if( blake2b_init( S, outlen ) < 0 ) return -1;
}
blake2b_update( S, ( const uint8_t * )in, inlen );
blake2b_final( S, out, outlen );
return 0;
}
int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) {
return blake2b(out, outlen, in, inlen, key, keylen);
}
#if defined(SUPERCOP)
int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen )
{
return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 );
}
#endif
#if defined(BLAKE2B_SELFTEST)
#include <string.h>
#include "blake2-kat.h"
int main( void )
{
uint8_t key[BLAKE2B_KEYBYTES];
uint8_t buf[BLAKE2_KAT_LENGTH];
size_t i, step;
for( i = 0; i < BLAKE2B_KEYBYTES; ++i )
key[i] = ( uint8_t )i;
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
buf[i] = ( uint8_t )i;
/* Test simple API */
for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
{
uint8_t hash[BLAKE2B_OUTBYTES];
blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES );
if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) )
{
goto fail;
}
}
/* Test streaming API */
for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) {
for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
uint8_t hash[BLAKE2B_OUTBYTES];
blake2b_state S;
uint8_t * p = buf;
size_t mlen = i;
int err = 0;
if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) {
goto fail;
}
while (mlen >= step) {
if ( (err = blake2b_update(&S, p, step)) < 0 ) {
goto fail;
}
mlen -= step;
p += step;
}
if ( (err = blake2b_update(&S, p, mlen)) < 0) {
goto fail;
}
if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) {
goto fail;
}
if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) {
goto fail;
}
}
}
puts( "ok" );
return 0;
fail:
puts("error");
return -1;
}
#endif

View File

@ -393,6 +393,12 @@ src_sha384sum_SOURCES = src/md5sum.c
src_sha384sum_CPPFLAGS = -DHASH_ALGO_SHA384=1 $(AM_CPPFLAGS)
src_sha512sum_SOURCES = src/md5sum.c
src_sha512sum_CPPFLAGS = -DHASH_ALGO_SHA512=1 $(AM_CPPFLAGS)
src_b2sum_CPPFLAGS = -include config.h -DHASH_ALGO_BLAKE2=1 \
$(AM_CPPFLAGS)
src_b2sum_SOURCES = src/md5sum.c \
src/blake2/blake2.h src/blake2/blake2-impl.h \
src/blake2/blake2b-ref.c \
src/blake2/b2sum.c src/blake2/b2sum.h
src_base64_CPPFLAGS = -DBASE_TYPE=64 $(AM_CPPFLAGS)
src_base32_SOURCES = src/base64.c

View File

@ -22,7 +22,14 @@
#include <sys/types.h>
#include "system.h"
#include "argmatch.h"
#include "quote.h"
#include "xdectoint.h"
#include "xstrtol.h"
#if HASH_ALGO_BLAKE2
# include "blake2/b2sum.h"
#endif
#if HASH_ALGO_MD5
# include "md5.h"
#endif
@ -49,6 +56,13 @@
# define DIGEST_BITS 128
# define DIGEST_REFERENCE "RFC 1321"
# define DIGEST_ALIGN 4
#elif HASH_ALGO_BLAKE2
# define PROGRAM_NAME "b2sum"
# define DIGEST_TYPE_STRING "BLAKE2"
# define DIGEST_STREAM blake2fns[b2_algorithm]
# define DIGEST_BITS 512
# define DIGEST_REFERENCE "RFC 7693"
# define DIGEST_ALIGN 8
#elif HASH_ALGO_SHA1
# define PROGRAM_NAME "sha1sum"
# define DIGEST_TYPE_STRING "SHA1"
@ -88,20 +102,30 @@
# error "Can't decide which hash algorithm to compile."
#endif
#define DIGEST_HEX_BYTES (DIGEST_BITS / 4)
#define DIGEST_BIN_BYTES (DIGEST_BITS / 8)
#define AUTHORS \
#if HASH_ALGO_BLAKE2
# define AUTHORS \
proper_name ("Padraig Brady"), \
proper_name ("Samuel Neves")
#else
# define AUTHORS \
proper_name ("Ulrich Drepper"), \
proper_name ("Scott Miller"), \
proper_name ("David Madore")
# define DIGEST_HEX_BYTES (DIGEST_BITS / 4)
#endif
#define DIGEST_BIN_BYTES (DIGEST_BITS / 8)
/* The minimum length of a valid digest line. This length does
not include any newline character at the end of a line. */
#define MIN_DIGEST_LINE_LENGTH \
(DIGEST_HEX_BYTES /* length of hexadecimal message digest */ \
+ 1 /* blank */ \
+ 1 /* minimum filename length */ )
#if HASH_ALGO_BLAKE2
# define MIN_DIGEST_LINE_LENGTH 3 /* With -l 8. */
#else
# define MIN_DIGEST_LINE_LENGTH \
(DIGEST_HEX_BYTES /* length of hexadecimal message digest */ \
+ 1 /* blank */ \
+ 1 /* minimum filename length */ )
#endif
/* True if any of the files read were the standard input. */
static bool have_read_stdin;
@ -133,6 +157,38 @@ static bool strict = false;
/* Whether a BSD reversed format checksum is detected. */
static int bsd_reversed = -1;
#if HASH_ALGO_BLAKE2
static char const *const algorithm_in_string[] =
{
"blake2b", NULL
};
static char const *const algorithm_out_string[] =
{
"BLAKE2b", NULL
};
enum Algorithm
{
BLAKE2b
};
static enum Algorithm const algorithm[] =
{
BLAKE2b
};
ARGMATCH_VERIFY (algorithm_in_string, algorithm);
ARGMATCH_VERIFY (algorithm_out_string, algorithm);
static enum Algorithm b2_algorithm;
static uintmax_t b2_length;
static blake2fn blake2fns[]=
{
blake2b_stream
};
static uintmax_t blake2_max_len[]=
{
BLAKE2B_OUTBYTES
};
#endif /* HASH_ALGO_BLAKE2 */
/* For long options that have no equivalent short option, use a
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
enum
@ -146,6 +202,9 @@ enum
static struct option const long_options[] =
{
#if HASH_ALGO_BLAKE2
{ "length", required_argument, NULL, 'l'},
#endif
{ "binary", no_argument, NULL, 'b' },
{ "check", no_argument, NULL, 'c' },
{ "ignore-missing", no_argument, NULL, IGNORE_MISSING_OPTION},
@ -176,7 +235,6 @@ Print or check %s (%d-bit) checksums.\n\
DIGEST_BITS);
emit_stdin_note ();
if (O_BINARY)
fputs (_("\
\n\
@ -187,9 +245,16 @@ Print or check %s (%d-bit) checksums.\n\
\n\
-b, --binary read in binary mode\n\
"), stdout);
printf (_("\
-c, --check read %s sums from the FILEs and check them\n"),
DIGEST_TYPE_STRING);
#if HASH_ALGO_BLAKE2
fputs (_("\
-l, --length digest length in bits; must not exceed the maximum for\n\
the blake2 algorithm and must be a multiple of 8\n\
"), stdout);
#endif
fputs (_("\
--tag create a BSD-style checksum\n\
"), stdout);
@ -350,15 +415,51 @@ split_3 (char *s, size_t s_len,
algo_name_len = strlen (DIGEST_TYPE_STRING);
if (STREQ_LEN (s + i, DIGEST_TYPE_STRING, algo_name_len))
{
if (s[i + algo_name_len] == ' ')
i += algo_name_len;
#if HASH_ALGO_BLAKE2
/* Terminate and match algorithm name. */
char const *algo_name = &s[i - algo_name_len];
while (! ISWHITE (s[i]) && s[i] != '-' && s[i] != '(')
++i;
if (s[i + algo_name_len] == '(')
bool length_specified = s[i] == '-';
bool openssl_format = s[i] == '('; /* and no length_specified */
s[i++] = '\0';
ptrdiff_t algo = argmatch (algo_name, algorithm_out_string, NULL, 0);
if (algo < 0)
return false;
else
b2_algorithm = algo;
if (openssl_format)
s[--i] = '(';
if (length_specified)
{
unsigned long int tmp_ulong;
if (xstrtoul (s + i, NULL, 0, &tmp_ulong, NULL) == LONGINT_OK
&& 0 < tmp_ulong && tmp_ulong <= blake2_max_len[b2_algorithm] * 8
&& tmp_ulong % 8 == 0)
b2_length = tmp_ulong;
else
return false;
while (ISDIGIT (s[i]))
++i;
}
else
b2_length = blake2_max_len[b2_algorithm] * 8;
digest_hex_bytes = b2_length / 4;
#endif
if (s[i] == ' ')
++i;
if (s[i] == '(')
{
++i;
*binary = 0;
return bsd_split_3 (s + i + algo_name_len + 1,
s_len - (i + algo_name_len + 1),
return bsd_split_3 (s + i, s_len - i,
hex_digest, file_name, escaped_filename);
}
return false;
}
/* Ignore this line if it is too short.
@ -370,6 +471,18 @@ split_3 (char *s, size_t s_len,
*hex_digest = (unsigned char *) &s[i];
#if HASH_ALGO_BLAKE2
/* Auto determine length. */
unsigned char const *hp = *hex_digest;
digest_hex_bytes = 0;
while (isxdigit (*hp++))
digest_hex_bytes++;
if (digest_hex_bytes < 2 || digest_hex_bytes % 2
|| blake2_max_len[b2_algorithm] * 2 < digest_hex_bytes)
return false;
b2_length = digest_hex_bytes * 4;
#endif
/* The first field has to be the n-character hexadecimal
representation of the message digest. If it is not followed
immediately by a white space it's an error. */
@ -505,7 +618,11 @@ digest_file (const char *filename, int *binary, unsigned char *bin_result,
fadvise (fp, FADVISE_SEQUENTIAL);
#if HASH_ALGO_BLAKE2
err = DIGEST_STREAM (fp, bin_result, b2_length / 8);
#else
err = DIGEST_STREAM (fp, bin_result);
#endif
if (err)
{
error (0, errno, "%s", quotef (filename));
@ -758,9 +875,28 @@ main (int argc, char **argv)
so that processes running in parallel do not intersperse their output. */
setvbuf (stdout, NULL, _IOLBF, 0);
while ((opt = getopt_long (argc, argv, "bctw", long_options, NULL)) != -1)
#if HASH_ALGO_BLAKE2
const char* short_opts = "l:bctw";
const char* b2_length_str = "";
#else
const char* short_opts = "bctw";
#endif
while ((opt = getopt_long (argc, argv, short_opts, long_options, NULL)) != -1)
switch (opt)
{
#if HASH_ALGO_BLAKE2
case 'l':
b2_length = xdectoumax (optarg, 0, UINTMAX_MAX, "",
_("invalid length"), 0);
b2_length_str = optarg;
if (b2_length % 8 != 0)
{
error (0, 0, _("invalid length: %s"), quote (b2_length_str));
die (EXIT_FAILURE, 0, _("length is not a multiple of 8"));
}
break;
#endif
case 'b':
binary = 1;
break;
@ -802,7 +938,21 @@ main (int argc, char **argv)
}
min_digest_line_length = MIN_DIGEST_LINE_LENGTH;
#if HASH_ALGO_BLAKE2
if (b2_length > blake2_max_len[b2_algorithm] * 8)
{
error (0, 0, _("invalid length: %s"), quote (b2_length_str));
die (EXIT_FAILURE, 0,
_("maximum digest length for %s is %"PRIuMAX" bits"),
quote (algorithm_in_string[b2_algorithm]),
blake2_max_len[b2_algorithm] * 8);
}
if (b2_length == 0 && ! do_check)
b2_length = blake2_max_len[b2_algorithm] * 8;
digest_hex_bytes = b2_length / 4;
#else
digest_hex_bytes = DIGEST_HEX_BYTES;
#endif
if (prefix_tag && !binary)
{
@ -901,7 +1051,13 @@ main (int argc, char **argv)
if (needs_escape)
putchar ('\\');
#if HASH_ALGO_BLAKE2
fputs (algorithm_out_string[b2_algorithm], stdout);
if (b2_length < blake2_max_len[b2_algorithm] * 8)
printf ("-%"PRIuMAX, b2_length);
#else
fputs (DIGEST_TYPE_STRING, stdout);
#endif
fputs (" (", stdout);
print_filename (file, needs_escape);
fputs (") = ", stdout);

View File

@ -296,6 +296,7 @@ all_tests = \
tests/misc/head-pos.sh \
tests/misc/head-write-error.sh \
tests/misc/kill.sh \
tests/misc/b2sum.sh \
tests/misc/md5sum.pl \
tests/misc/md5sum-bsd.sh \
tests/misc/md5sum-newline.pl \

49
tests/misc/b2sum.sh Executable file
View File

@ -0,0 +1,49 @@
#!/bin/sh
# 'b2sum' tests
# Copyright (C) 2016 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ b2sum
# Ensure we can --check the --tag format we produce
rm check.b2sum
for i in 'a' ' b' '*c' '44' ' '; do
echo "$i" > "$i"
for l in 0 128; do
b2sum -l $l --tag "$i" >> check.b2sum
done
done
# Note -l is infered from the tags in the mixed format file
b2sum --strict -c check.b2sum || fail=1
# Also ensure the openssl tagged variant works
sed 's/ //; s/ =/=/' < check.b2sum > openssl.b2sum || framework_failure_
b2sum --strict -c openssl.b2sum || fail=1
# Ensure we can check non tagged format
for l in 0 128; do
b2sum -l $l /dev/null | tee -a check.vals > check.b2sum
b2sum -l $l --strict -c check.b2sum || fail=1
b2sum --strict -c check.b2sum || fail=1
done
# Ensure the checksum values are correct. The reference
# check.vals was created with the upstream SSE reference implementation.
b2sum -l 128 check.vals > out || fail=1
printf '%s\n' '796485dd32fe9b754ea5fd6c721271d9 check.vals' > exp
compare exp out || fail=1
Exit $fail

View File

@ -28,7 +28,7 @@ print_ver_ md5sum
# I.e., one not starting with ' ' or '*'
for i in 'a' ' b' '*c' 'dd' ' '; do
echo "$i" > "$i"
md5sum "$i" >> check.md5sum
md5sum "$i" >> check.md5sum || fail=1
done
sed 's/ / /' check.md5sum > check.md5
@ -59,7 +59,7 @@ returns_ 1 md5sum --tag --text /dev/null || fail=1
rm check.md5
for i in 'a' ' b' '*c' 'dd' ' '; do
echo "$i" > "$i"
md5sum --tag "$i" >> check.md5
md5sum --tag "$i" >> check.md5 || fail=1
done
md5sum --strict -c check.md5 || fail=1
@ -70,8 +70,8 @@ nl='
tab=' '
rm check.md5
for i in 'a\b' 'a\' "a${nl}b" "a${tab}b"; do
> "$i"
md5sum --tag "$i" >> check.md5
: > "$i"
md5sum --tag "$i" >> check.md5 || fail=1
done
md5sum --strict -c check.md5 || fail=1
@ -82,7 +82,7 @@ ex_file='test
ex_output='\MD5 (test\n\\\\file) = d41d8cd98f00b204e9800998ecf8427e'
touch "$ex_file"
printf "%s\n" "$ex_output" > exp
md5sum --tag "$ex_file" > out
md5sum --tag "$ex_file" > out || fail=1
compare exp out || fail=1
Exit $fail