...

Source file src/golang.org/x/crypto/blake2s/blake2s.go

Documentation: golang.org/x/crypto/blake2s

     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  

View as plain text