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 blake2b implements the BLAKE2b hash algorithm defined by RFC 7693 6// and the extendable output function (XOF) BLAKE2Xb. 7// 8// For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf 9// and for BLAKE2Xb see https://blake2.net/blake2x.pdf 10// 11// If you aren't sure which function you need, use BLAKE2b (Sum512 or New512). 12// If you need a secret-key MAC (message authentication code), use the New512 13// function with a non-nil key. 14// 15// BLAKE2X is a construction to compute hash values larger than 64 bytes. It 16// can produce hash values between 0 and 4 GiB. 17package blake2b 18 19import ( 20 "encoding/binary" 21 "errors" 22 "hash" 23) 24 25const ( 26 // The blocksize of BLAKE2b in bytes. 27 BlockSize = 128 28 // The hash size of BLAKE2b-512 in bytes. 29 Size = 64 30 // The hash size of BLAKE2b-384 in bytes. 31 Size384 = 48 32 // The hash size of BLAKE2b-256 in bytes. 33 Size256 = 32 34) 35 36var ( 37 useAVX2 bool 38 useAVX bool 39 useSSE4 bool 40) 41 42var ( 43 errKeySize = errors.New("blake2b: invalid key size") 44 errHashSize = errors.New("blake2b: invalid hash size") 45) 46 47var iv = [8]uint64{ 48 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, 49 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, 50} 51 52// Sum512 returns the BLAKE2b-512 checksum of the data. 53func Sum512(data []byte) [Size]byte { 54 var sum [Size]byte 55 checkSum(&sum, Size, data) 56 return sum 57} 58 59// Sum384 returns the BLAKE2b-384 checksum of the data. 60func Sum384(data []byte) [Size384]byte { 61 var sum [Size]byte 62 var sum384 [Size384]byte 63 checkSum(&sum, Size384, data) 64 copy(sum384[:], sum[:Size384]) 65 return sum384 66} 67 68// Sum256 returns the BLAKE2b-256 checksum of the data. 69func Sum256(data []byte) [Size256]byte { 70 var sum [Size]byte 71 var sum256 [Size256]byte 72 checkSum(&sum, Size256, data) 73 copy(sum256[:], sum[:Size256]) 74 return sum256 75} 76 77// New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil 78// key turns the hash into a MAC. The key must be between zero and 64 bytes long. 79func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) } 80 81// New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil 82// key turns the hash into a MAC. The key must be between zero and 64 bytes long. 83func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) } 84 85// New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil 86// key turns the hash into a MAC. The key must be between zero and 64 bytes long. 87func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) } 88 89// New returns a new hash.Hash computing the BLAKE2b checksum with a custom length. 90// A non-nil key turns the hash into a MAC. The key must be between zero and 64 bytes long. 91// The hash size can be a value between 1 and 64 but it is highly recommended to use 92// values equal or greater than: 93// - 32 if BLAKE2b is used as a hash function (The key is zero bytes long). 94// - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long). 95// When the key is nil, the returned hash.Hash implements BinaryMarshaler 96// and BinaryUnmarshaler for state (de)serialization as documented by hash.Hash. 97func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) } 98 99func newDigest(hashSize int, key []byte) (*digest, error) { 100 if hashSize < 1 || hashSize > Size { 101 return nil, errHashSize 102 } 103 if len(key) > Size { 104 return nil, errKeySize 105 } 106 d := &digest{ 107 size: hashSize, 108 keyLen: len(key), 109 } 110 copy(d.key[:], key) 111 d.Reset() 112 return d, nil 113} 114 115func checkSum(sum *[Size]byte, hashSize int, data []byte) { 116 h := iv 117 h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24) 118 var c [2]uint64 119 120 if length := len(data); length > BlockSize { 121 n := length &^ (BlockSize - 1) 122 if length == n { 123 n -= BlockSize 124 } 125 hashBlocks(&h, &c, 0, data[:n]) 126 data = data[n:] 127 } 128 129 var block [BlockSize]byte 130 offset := copy(block[:], data) 131 remaining := uint64(BlockSize - offset) 132 if c[0] < remaining { 133 c[1]-- 134 } 135 c[0] -= remaining 136 137 hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) 138 139 for i, v := range h[:(hashSize+7)/8] { 140 binary.LittleEndian.PutUint64(sum[8*i:], v) 141 } 142} 143 144type digest struct { 145 h [8]uint64 146 c [2]uint64 147 size int 148 block [BlockSize]byte 149 offset int 150 151 key [BlockSize]byte 152 keyLen int 153} 154 155const ( 156 magic = "b2b" 157 marshaledSize = len(magic) + 8*8 + 2*8 + 1 + BlockSize + 1 158) 159 160func (d *digest) MarshalBinary() ([]byte, error) { 161 if d.keyLen != 0 { 162 return nil, errors.New("crypto/blake2b: cannot marshal MACs") 163 } 164 b := make([]byte, 0, marshaledSize) 165 b = append(b, magic...) 166 for i := 0; i < 8; i++ { 167 b = appendUint64(b, d.h[i]) 168 } 169 b = appendUint64(b, d.c[0]) 170 b = appendUint64(b, d.c[1]) 171 // Maximum value for size is 64 172 b = append(b, byte(d.size)) 173 b = append(b, d.block[:]...) 174 b = append(b, byte(d.offset)) 175 return b, nil 176} 177 178func (d *digest) UnmarshalBinary(b []byte) error { 179 if len(b) < len(magic) || string(b[:len(magic)]) != magic { 180 return errors.New("crypto/blake2b: invalid hash state identifier") 181 } 182 if len(b) != marshaledSize { 183 return errors.New("crypto/blake2b: invalid hash state size") 184 } 185 b = b[len(magic):] 186 for i := 0; i < 8; i++ { 187 b, d.h[i] = consumeUint64(b) 188 } 189 b, d.c[0] = consumeUint64(b) 190 b, d.c[1] = consumeUint64(b) 191 d.size = int(b[0]) 192 b = b[1:] 193 copy(d.block[:], b[:BlockSize]) 194 b = b[BlockSize:] 195 d.offset = int(b[0]) 196 return nil 197} 198 199func (d *digest) BlockSize() int { return BlockSize } 200 201func (d *digest) Size() int { return d.size } 202 203func (d *digest) Reset() { 204 d.h = iv 205 d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24) 206 d.offset, d.c[0], d.c[1] = 0, 0, 0 207 if d.keyLen > 0 { 208 d.block = d.key 209 d.offset = BlockSize 210 } 211} 212 213func (d *digest) Write(p []byte) (n int, err error) { 214 n = len(p) 215 216 if d.offset > 0 { 217 remaining := BlockSize - d.offset 218 if n <= remaining { 219 d.offset += copy(d.block[d.offset:], p) 220 return 221 } 222 copy(d.block[d.offset:], p[:remaining]) 223 hashBlocks(&d.h, &d.c, 0, d.block[:]) 224 d.offset = 0 225 p = p[remaining:] 226 } 227 228 if length := len(p); length > BlockSize { 229 nn := length &^ (BlockSize - 1) 230 if length == nn { 231 nn -= BlockSize 232 } 233 hashBlocks(&d.h, &d.c, 0, p[:nn]) 234 p = p[nn:] 235 } 236 237 if len(p) > 0 { 238 d.offset += copy(d.block[:], p) 239 } 240 241 return 242} 243 244func (d *digest) Sum(sum []byte) []byte { 245 var hash [Size]byte 246 d.finalize(&hash) 247 return append(sum, hash[:d.size]...) 248} 249 250func (d *digest) finalize(hash *[Size]byte) { 251 var block [BlockSize]byte 252 copy(block[:], d.block[:d.offset]) 253 remaining := uint64(BlockSize - d.offset) 254 255 c := d.c 256 if c[0] < remaining { 257 c[1]-- 258 } 259 c[0] -= remaining 260 261 h := d.h 262 hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:]) 263 264 for i, v := range h { 265 binary.LittleEndian.PutUint64(hash[8*i:], v) 266 } 267} 268 269func appendUint64(b []byte, x uint64) []byte { 270 var a [8]byte 271 binary.BigEndian.PutUint64(a[:], x) 272 return append(b, a[:]...) 273} 274 275func appendUint32(b []byte, x uint32) []byte { 276 var a [4]byte 277 binary.BigEndian.PutUint32(a[:], x) 278 return append(b, a[:]...) 279} 280 281func consumeUint64(b []byte) ([]byte, uint64) { 282 x := binary.BigEndian.Uint64(b) 283 return b[8:], x 284} 285 286func consumeUint32(b []byte) ([]byte, uint32) { 287 x := binary.BigEndian.Uint32(b) 288 return b[4:], x 289} 290