You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
5.5 KiB

  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. // Package blake2b implements the BLAKE2b hash algorithm defined by RFC 7693
  5. // and the extendable output function (XOF) BLAKE2Xb.
  6. //
  7. // For a detailed specification of BLAKE2b see https://blake2.net/blake2.pdf
  8. // and for BLAKE2Xb see https://blake2.net/blake2x.pdf
  9. //
  10. // If you aren't sure which function you need, use BLAKE2b (Sum512 or New512).
  11. // If you need a secret-key MAC (message authentication code), use the New512
  12. // function with a non-nil key.
  13. //
  14. // BLAKE2X is a construction to compute hash values larger than 64 bytes. It
  15. // can produce hash values between 0 and 4 GiB.
  16. package blake2b
  17. import (
  18. "encoding/binary"
  19. "errors"
  20. "hash"
  21. )
  22. const (
  23. // The blocksize of BLAKE2b in bytes.
  24. BlockSize = 128
  25. // The hash size of BLAKE2b-512 in bytes.
  26. Size = 64
  27. // The hash size of BLAKE2b-384 in bytes.
  28. Size384 = 48
  29. // The hash size of BLAKE2b-256 in bytes.
  30. Size256 = 32
  31. )
  32. var (
  33. useAVX2 bool
  34. useAVX bool
  35. useSSE4 bool
  36. )
  37. var (
  38. errKeySize = errors.New("blake2b: invalid key size")
  39. errHashSize = errors.New("blake2b: invalid hash size")
  40. )
  41. var iv = [8]uint64{
  42. 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
  43. 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
  44. }
  45. // Sum512 returns the BLAKE2b-512 checksum of the data.
  46. func Sum512(data []byte) [Size]byte {
  47. var sum [Size]byte
  48. checkSum(&sum, Size, data)
  49. return sum
  50. }
  51. // Sum384 returns the BLAKE2b-384 checksum of the data.
  52. func Sum384(data []byte) [Size384]byte {
  53. var sum [Size]byte
  54. var sum384 [Size384]byte
  55. checkSum(&sum, Size384, data)
  56. copy(sum384[:], sum[:Size384])
  57. return sum384
  58. }
  59. // Sum256 returns the BLAKE2b-256 checksum of the data.
  60. func Sum256(data []byte) [Size256]byte {
  61. var sum [Size]byte
  62. var sum256 [Size256]byte
  63. checkSum(&sum, Size256, data)
  64. copy(sum256[:], sum[:Size256])
  65. return sum256
  66. }
  67. // New512 returns a new hash.Hash computing the BLAKE2b-512 checksum. A non-nil
  68. // key turns the hash into a MAC. The key must between zero and 64 bytes long.
  69. func New512(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
  70. // New384 returns a new hash.Hash computing the BLAKE2b-384 checksum. A non-nil
  71. // key turns the hash into a MAC. The key must between zero and 64 bytes long.
  72. func New384(key []byte) (hash.Hash, error) { return newDigest(Size384, key) }
  73. // New256 returns a new hash.Hash computing the BLAKE2b-256 checksum. A non-nil
  74. // key turns the hash into a MAC. The key must between zero and 64 bytes long.
  75. func New256(key []byte) (hash.Hash, error) { return newDigest(Size256, key) }
  76. // New returns a new hash.Hash computing the BLAKE2b checksum with a custom length.
  77. // A non-nil key turns the hash into a MAC. The key must between zero and 64 bytes long.
  78. // The hash size can be a value between 1 and 64 but it is highly recommended to use
  79. // values equal or greater than:
  80. // - 32 if BLAKE2b is used as a hash function (The key is zero bytes long).
  81. // - 16 if BLAKE2b is used as a MAC function (The key is at least 16 bytes long).
  82. func New(size int, key []byte) (hash.Hash, error) { return newDigest(size, key) }
  83. func newDigest(hashSize int, key []byte) (*digest, error) {
  84. if hashSize < 1 || hashSize > Size {
  85. return nil, errHashSize
  86. }
  87. if len(key) > Size {
  88. return nil, errKeySize
  89. }
  90. d := &digest{
  91. size: hashSize,
  92. keyLen: len(key),
  93. }
  94. copy(d.key[:], key)
  95. d.Reset()
  96. return d, nil
  97. }
  98. func checkSum(sum *[Size]byte, hashSize int, data []byte) {
  99. h := iv
  100. h[0] ^= uint64(hashSize) | (1 << 16) | (1 << 24)
  101. var c [2]uint64
  102. if length := len(data); length > BlockSize {
  103. n := length &^ (BlockSize - 1)
  104. if length == n {
  105. n -= BlockSize
  106. }
  107. hashBlocks(&h, &c, 0, data[:n])
  108. data = data[n:]
  109. }
  110. var block [BlockSize]byte
  111. offset := copy(block[:], data)
  112. remaining := uint64(BlockSize - offset)
  113. if c[0] < remaining {
  114. c[1]--
  115. }
  116. c[0] -= remaining
  117. hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
  118. for i, v := range h[:(hashSize+7)/8] {
  119. binary.LittleEndian.PutUint64(sum[8*i:], v)
  120. }
  121. }
  122. type digest struct {
  123. h [8]uint64
  124. c [2]uint64
  125. size int
  126. block [BlockSize]byte
  127. offset int
  128. key [BlockSize]byte
  129. keyLen int
  130. }
  131. func (d *digest) BlockSize() int { return BlockSize }
  132. func (d *digest) Size() int { return d.size }
  133. func (d *digest) Reset() {
  134. d.h = iv
  135. d.h[0] ^= uint64(d.size) | (uint64(d.keyLen) << 8) | (1 << 16) | (1 << 24)
  136. d.offset, d.c[0], d.c[1] = 0, 0, 0
  137. if d.keyLen > 0 {
  138. d.block = d.key
  139. d.offset = BlockSize
  140. }
  141. }
  142. func (d *digest) Write(p []byte) (n int, err error) {
  143. n = len(p)
  144. if d.offset > 0 {
  145. remaining := BlockSize - d.offset
  146. if n <= remaining {
  147. d.offset += copy(d.block[d.offset:], p)
  148. return
  149. }
  150. copy(d.block[d.offset:], p[:remaining])
  151. hashBlocks(&d.h, &d.c, 0, d.block[:])
  152. d.offset = 0
  153. p = p[remaining:]
  154. }
  155. if length := len(p); length > BlockSize {
  156. nn := length &^ (BlockSize - 1)
  157. if length == nn {
  158. nn -= BlockSize
  159. }
  160. hashBlocks(&d.h, &d.c, 0, p[:nn])
  161. p = p[nn:]
  162. }
  163. if len(p) > 0 {
  164. d.offset += copy(d.block[:], p)
  165. }
  166. return
  167. }
  168. func (d *digest) Sum(sum []byte) []byte {
  169. var hash [Size]byte
  170. d.finalize(&hash)
  171. return append(sum, hash[:d.size]...)
  172. }
  173. func (d *digest) finalize(hash *[Size]byte) {
  174. var block [BlockSize]byte
  175. copy(block[:], d.block[:d.offset])
  176. remaining := uint64(BlockSize - d.offset)
  177. c := d.c
  178. if c[0] < remaining {
  179. c[1]--
  180. }
  181. c[0] -= remaining
  182. h := d.h
  183. hashBlocks(&h, &c, 0xFFFFFFFFFFFFFFFF, block[:])
  184. for i, v := range h {
  185. binary.LittleEndian.PutUint64(hash[8*i:], v)
  186. }
  187. }