blake2s.go (5919B)
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 }