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