...

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

View as plain text