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.
19package blake2s // import "golang.org/x/crypto/blake2s"
20
21import (
22	"encoding/binary"
23	"errors"
24	"hash"
25)
26
27const (
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
38var errKeySize = errors.New("blake2s: invalid key size")
39
40var 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.
46func 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.
56func 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.
62func 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
69func 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
82func 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
116type 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
127const (
128	magic         = "b2s"
129	marshaledSize = len(magic) + 8*4 + 2*4 + 1 + BlockSize + 1
130)
131
132func (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
150func (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
171func (d *digest) BlockSize() int { return BlockSize }
172
173func (d *digest) Size() int { return d.size }
174
175func (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
185func (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
213func (d *digest) Sum(sum []byte) []byte {
214	var hash [Size]byte
215	d.finalize(&hash)
216	return append(sum, hash[:d.size]...)
217}
218
219func (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
237func appendUint32(b []byte, x uint32) []byte {
238	var a [4]byte
239	binary.BigEndian.PutUint32(a[:], x)
240	return append(b, a[:]...)
241}
242
243func consumeUint32(b []byte) ([]byte, uint32) {
244	x := binary.BigEndian.Uint32(b)
245	return b[4:], x
246}
247