shithub: blake2

ref: ac1a816f4679e3643f396539bd1850f4b95e5d98
dir: /b2sum/b2sum.c/

View raw version
/*
   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 <u.h>
#include <libc.h>

#include "blake2.h"

/* This will help compatibility with coreutils */
int blake2s_stream( int stream, void *resstream, int outbytes )
{
  int ret = -1;
  int sum, n;
  blake2s_state S[1];
  static const int buffer_length = 32768;
  u8int *buffer = ( u8int * )malloc( buffer_length );

  if( !buffer ) return -1;

  blake2s_init( S, outbytes );

  while( 1 )
  {
    sum = 0;

    while( 1 )
    {
      n = read( stream, buffer + sum, buffer_length - sum );
      sum += n;

      if( buffer_length == sum )
        break;

      if( n < 0 )
        goto cleanup_buffer;

      if( 0 == n )
        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 blake2b_stream( int stream, void *resstream, int outbytes )
{
  int ret = -1;
  int sum, n;
  blake2b_state S[1];
  static const int buffer_length = 32768;
  u8int *buffer = ( u8int * )malloc( buffer_length );

  if( !buffer ) return -1;

  blake2b_init( S, outbytes );

  while( 1 )
  {
    sum = 0;

    while( 1 )
    {
      n = read( stream, buffer + sum, buffer_length - sum );
      sum += n;

      if( buffer_length == sum )
        break;

      if( n < 0 )
        goto cleanup_buffer;

      if( 0 == n )
        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;
}

int blake2sp_stream( int stream, void *resstream, int outbytes )
{
  int ret = -1;
  int sum, n;
  blake2sp_state S[1];
  static const int buffer_length = 16 * ( 1UL << 20 );
  u8int *buffer = ( u8int * )malloc( buffer_length );

  if( !buffer ) return -1;

  blake2sp_init( S, outbytes );

  while( 1 )
  {
    sum = 0;

    while( 1 )
    {
      n = read( stream, buffer + sum, buffer_length - sum );
      sum += n;

      if( buffer_length == sum )
        break;

      if( n < 0 )
        goto cleanup_buffer;

      if( 0 == n )
        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( int stream, void *resstream, int outbytes )
{
  int ret = -1;
  int sum, n;
  blake2bp_state S[1];
  static const int buffer_length = 16 * ( 1UL << 20 );
  u8int *buffer = ( u8int * )malloc( buffer_length );

  if( !buffer ) return -1;

  blake2bp_init( S, outbytes );

  while( 1 )
  {
    sum = 0;

    while( 1 )
    {
      n = read( stream, buffer + sum, buffer_length - sum );
      sum += n;

      if( buffer_length == sum )
        break;

      if( n < 0 )
        goto cleanup_buffer;

      if( 0 == n )
        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 )( int, void *, int );


static void usage( void )
{
  fprint( 2, "Usage: %s [OPTION]... [FILE]...\n", argv0 );
  fprint( 2, "\n" );
  fprint( 2, "With no FILE, or when FILE is -, read standard input.\n" );
  fprint( 2, "\n" );
  fprint( 2, "  -a <algo>    hash algorithm (blake2b is default): \n"
                "               [blake2b|blake2s|blake2bp|blake2sp]\n" );
  fprint( 2, "  -l <length>  digest length in bits, must not exceed the maximum for\n"
                "               the selected algorithm and must be a multiple of 8\n" );
  fprint( 2, "  --tag        create a BSD-style checksum\n" );
  fprint( 2, "  --help       display this help and exit\n" );
  exits("usage");
}


void hash( char *name, int fd, blake2fn fn, int outbytes )
{
  unsigned char hash[BLAKE2B_OUTBYTES] = {0};

  if( fn( fd, hash, outbytes ) < 0 )
  {
    fprint( 2, "failed to hash '%s'\n", name);
    return;
  }
  else
  {
    int j;
    for( j = 0; j < outbytes; ++j )
      print( "%02x", hash[j] );

    print("\n");
  }
}

int main( int argc, char **argv )
{
  blake2fn blake2_stream = blake2b_stream;
  unsigned long maxbytes = BLAKE2B_OUTBYTES;
  const char *algorithm = "BLAKE2b";
  unsigned long outbytes = 0;
  int i;
  char *algo;
  ulong outbits;

  ARGBEGIN {
  case 'a':
    algo = EARGF(usage());
    if( 0 == strcmp( algo, "blake2b" ) )
    {
      blake2_stream = blake2b_stream;
      maxbytes = BLAKE2B_OUTBYTES;
      algorithm = "BLAKE2b";
    }
    else if ( 0 == strcmp( algo, "blake2s" ) )
    {
      blake2_stream = blake2s_stream;
      maxbytes = BLAKE2S_OUTBYTES;
      algorithm = "BLAKE2s";
    }
    else if ( 0 == strcmp( algo, "blake2bp" ) )
    {
      blake2_stream = blake2bp_stream;
      maxbytes = BLAKE2B_OUTBYTES;
      algorithm = "BLAKE2bp";
    }
    else if ( 0 == strcmp( algo, "blake2sp" ) )
    {
      blake2_stream = blake2sp_stream;
      maxbytes = BLAKE2S_OUTBYTES;
      algorithm = "BLAKE2sp";
    }
    else
    {
      fprint( 2, "Invalid function name: `%s'\n", algo );
      usage();
    }
    break;
  case 'l':
    outbits = strtoul(EARGF(usage()), nil, 0);
    outbytes = outbits/8;
    break;
  default:
    usage();
  } ARGEND

  if(outbytes > maxbytes)
  {
    print( "Invalid length argument: %lud\n", outbytes * 8 );
    print( "Maximum digest length for %s is %lud\n", algorithm, maxbytes * 8 );
    usage();
  }
  else if( outbytes == 0 )
    outbytes = maxbytes;

  if(argc == 0)
  {
    hash("<stdin>", 0, blake2_stream, outbytes);
  }
  else for(i = 0; i < argc; i++)
  {
    int fd = open(argv[i], OREAD);
    if(fd < 0)
    {
      fprint(2, "could not open '%s': %r\n", argv[i]);
      continue;
    }
    hash(argv[i], fd, blake2_stream, outbytes);
    close(fd);
  }

  exits(nil);
}