blake2s.go raw

   1  // Copyright 2016 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  // Package blake2s implements the BLAKE2s hash algorithm defined by RFC 7693
   6  // and the extendable output function (XOF) BLAKE2Xs.
   7  //
   8  // BLAKE2s is optimized for 8- to 32-bit platforms and produces digests of any
   9  // size between 1 and 32 bytes.
  10  // For a detailed specification of BLAKE2s see https://blake2.net/blake2.pdf
  11  // and for BLAKE2Xs see https://blake2.net/blake2x.pdf
  12  //
  13  // If you aren't sure which function you need, use BLAKE2s (Sum256 or New256).
  14  // If you need a secret-key MAC (message authentication code), use the New256
  15  // function with a non-nil key.
  16  //
  17  // BLAKE2X is a construction to compute hash values larger than 32 bytes. It
  18  // can produce hash values between 0 and 65535 bytes.
  19  package blake2s
  20  
  21  import (
  22  	"crypto"
  23  	"encoding/binary"
  24  	"errors"
  25  	"hash"
  26  )
  27  
  28  const (
  29  	// The blocksize of BLAKE2s in bytes.
  30  	BlockSize = 64
  31  
  32  	// The hash size of BLAKE2s-256 in bytes.
  33  	Size = 32
  34  
  35  	// The hash size of BLAKE2s-128 in bytes.
  36  	Size128 = 16
  37  )
  38  
  39  var errKeySize = errors.New("blake2s: invalid key size")
  40  
  41  var iv = [8]uint32{
  42  	0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
  43  	0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
  44  }
  45  
  46  // Sum256 returns the BLAKE2s-256 checksum of the data.
  47  func Sum256(data []byte) [Size]byte {
  48  	var sum [Size]byte
  49  	checkSum(&sum, Size, data)
  50  	return sum
  51  }
  52  
  53  // New256 returns a new hash.Hash computing the BLAKE2s-256 checksum. A non-nil
  54  // key turns the hash into a MAC. The key must between zero and 32 bytes long.
  55  // When the key is nil, the returned hash.Hash implements BinaryMarshaler
  56  // and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash.
  57  func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
  58  
  59  func init() {
  60  	crypto.RegisterHash(crypto.BLAKE2s_256, func() hash.Hash {
  61  		h, _ := New256(nil)
  62  		return h
  63  	})
  64  }
  65  
  66  // New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a
  67  // non-empty key. Note that a 128-bit digest is too small to be secure as a
  68  // cryptographic hash and should only be used as a MAC, thus the key argument
  69  // is not optional.
  70  func New128(key []byte) (hash.Hash, error) {
  71  	if len(key) == 0 {
  72  		return nil, errors.New("blake2s: a key is required for a 128-bit hash")
  73  	}
  74  	return newDigest(Size128, key)
  75  }
  76  
  77  func newDigest(hashSize int, key []byte) (*digest, error) {
  78  	if len(key) > Size {
  79  		return nil, errKeySize
  80  	}
  81  	d := &digest{
  82  		size:   hashSize,
  83  		keyLen: len(key),
  84  	}
  85  	copy(d.key[:], key)
  86  	d.Reset()
  87  	return d, nil
  88  }
  89  
  90  func checkSum(sum *[Size]byte, hashSize int, data []byte) {
  91  	var (
  92  		h [8]uint32
  93  		c [2]uint32
  94  	)
  95  
  96  	h = iv
  97  	h[0] ^= uint32(hashSize) | (1 << 16) | (1 << 24)
  98  
  99  	if length := len(data); length > BlockSize {
 100  		n := length &^ (BlockSize - 1)
 101  		if length == n {
 102  			n -= BlockSize
 103  		}
 104  		hashBlocks(&h, &c, 0, data[:n])
 105  		data = data[n:]
 106  	}
 107  
 108  	var block [BlockSize]byte
 109  	offset := copy(block[:], data)
 110  	remaining := uint32(BlockSize - offset)
 111  
 112  	if c[0] < remaining {
 113  		c[1]--
 114  	}
 115  	c[0] -= remaining
 116  
 117  	hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
 118  
 119  	for i, v := range h {
 120  		binary.LittleEndian.PutUint32(sum[4*i:], v)
 121  	}
 122  }
 123  
 124  type digest struct {
 125  	h      [8]uint32
 126  	c      [2]uint32
 127  	size   int
 128  	block  [BlockSize]byte
 129  	offset int
 130  
 131  	key    [BlockSize]byte
 132  	keyLen int
 133  }
 134  
 135  const (
 136  	magic         = "b2s"
 137  	marshaledSize = len(magic) + 8*4 + 2*4 + 1 + BlockSize + 1
 138  )
 139  
 140  func (d *digest) MarshalBinary() ([]byte, error) {
 141  	if d.keyLen != 0 {
 142  		return nil, errors.New("crypto/blake2s: cannot marshal MACs")
 143  	}
 144  	b := make([]byte, 0, marshaledSize)
 145  	b = append(b, magic...)
 146  	for i := 0; i < 8; i++ {
 147  		b = appendUint32(b, d.h[i])
 148  	}
 149  	b = appendUint32(b, d.c[0])
 150  	b = appendUint32(b, d.c[1])
 151  	// Maximum value for size is 32
 152  	b = append(b, byte(d.size))
 153  	b = append(b, d.block[:]...)
 154  	b = append(b, byte(d.offset))
 155  	return b, nil
 156  }
 157  
 158  func (d *digest) UnmarshalBinary(b []byte) error {
 159  	if len(b) < len(magic) || string(b[:len(magic)]) != magic {
 160  		return errors.New("crypto/blake2s: invalid hash state identifier")
 161  	}
 162  	if len(b) != marshaledSize {
 163  		return errors.New("crypto/blake2s: invalid hash state size")
 164  	}
 165  	b = b[len(magic):]
 166  	for i := 0; i < 8; i++ {
 167  		b, d.h[i] = consumeUint32(b)
 168  	}
 169  	b, d.c[0] = consumeUint32(b)
 170  	b, d.c[1] = consumeUint32(b)
 171  	d.size = int(b[0])
 172  	b = b[1:]
 173  	copy(d.block[:], b[:BlockSize])
 174  	b = b[BlockSize:]
 175  	d.offset = int(b[0])
 176  	return nil
 177  }
 178  
 179  func (d *digest) BlockSize() int { return BlockSize }
 180  
 181  func (d *digest) Size() int { return d.size }
 182  
 183  func (d *digest) Reset() {
 184  	d.h = iv
 185  	d.h[0] ^= uint32(d.size) | (uint32(d.keyLen) << 8) | (1 << 16) | (1 << 24)
 186  	d.offset, d.c[0], d.c[1] = 0, 0, 0
 187  	if d.keyLen > 0 {
 188  		d.block = d.key
 189  		d.offset = BlockSize
 190  	}
 191  }
 192  
 193  func (d *digest) Write(p []byte) (n int, err error) {
 194  	n = len(p)
 195  
 196  	if d.offset > 0 {
 197  		remaining := BlockSize - d.offset
 198  		if n <= remaining {
 199  			d.offset += copy(d.block[d.offset:], p)
 200  			return
 201  		}
 202  		copy(d.block[d.offset:], p[:remaining])
 203  		hashBlocks(&d.h, &d.c, 0, d.block[:])
 204  		d.offset = 0
 205  		p = p[remaining:]
 206  	}
 207  
 208  	if length := len(p); length > BlockSize {
 209  		nn := length &^ (BlockSize - 1)
 210  		if length == nn {
 211  			nn -= BlockSize
 212  		}
 213  		hashBlocks(&d.h, &d.c, 0, p[:nn])
 214  		p = p[nn:]
 215  	}
 216  
 217  	d.offset += copy(d.block[:], p)
 218  	return
 219  }
 220  
 221  func (d *digest) Sum(sum []byte) []byte {
 222  	var hash [Size]byte
 223  	d.finalize(&hash)
 224  	return append(sum, hash[:d.size]...)
 225  }
 226  
 227  func (d *digest) finalize(hash *[Size]byte) {
 228  	var block [BlockSize]byte
 229  	h := d.h
 230  	c := d.c
 231  
 232  	copy(block[:], d.block[:d.offset])
 233  	remaining := uint32(BlockSize - d.offset)
 234  	if c[0] < remaining {
 235  		c[1]--
 236  	}
 237  	c[0] -= remaining
 238  
 239  	hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
 240  	for i, v := range h {
 241  		binary.LittleEndian.PutUint32(hash[4*i:], v)
 242  	}
 243  }
 244  
 245  func appendUint32(b []byte, x uint32) []byte {
 246  	var a [4]byte
 247  	binary.BigEndian.PutUint32(a[:], x)
 248  	return append(b, a[:]...)
 249  }
 250  
 251  func consumeUint32(b []byte) ([]byte, uint32) {
 252  	x := binary.BigEndian.Uint32(b)
 253  	return b[4:], x
 254  }
 255