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.

187 lines
4.2 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 blake2s implements the BLAKE2s hash algorithm defined by RFC 7693
  5. // and the extendable output function (XOF) BLAKE2Xs.
  6. //
  7. // For a detailed specification of BLAKE2s see https://blake2.net/blake2.pdf
  8. // and for BLAKE2Xs see https://blake2.net/blake2x.pdf
  9. //
  10. // If you aren't sure which function you need, use BLAKE2s (Sum256 or New256).
  11. // If you need a secret-key MAC (message authentication code), use the New256
  12. // function with a non-nil key.
  13. //
  14. // BLAKE2X is a construction to compute hash values larger than 32 bytes. It
  15. // can produce hash values between 0 and 65535 bytes.
  16. package blake2s // import "golang.org/x/crypto/blake2s"
  17. import (
  18. "encoding/binary"
  19. "errors"
  20. "hash"
  21. )
  22. const (
  23. // The blocksize of BLAKE2s in bytes.
  24. BlockSize = 64
  25. // The hash size of BLAKE2s-256 in bytes.
  26. Size = 32
  27. // The hash size of BLAKE2s-128 in bytes.
  28. Size128 = 16
  29. )
  30. var errKeySize = errors.New("blake2s: invalid key size")
  31. var iv = [8]uint32{
  32. 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
  33. 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
  34. }
  35. // Sum256 returns the BLAKE2s-256 checksum of the data.
  36. func Sum256(data []byte) [Size]byte {
  37. var sum [Size]byte
  38. checkSum(&sum, Size, data)
  39. return sum
  40. }
  41. // New256 returns a new hash.Hash computing the BLAKE2s-256 checksum. A non-nil
  42. // key turns the hash into a MAC. The key must between zero and 32 bytes long.
  43. func New256(key []byte) (hash.Hash, error) { return newDigest(Size, key) }
  44. // New128 returns a new hash.Hash computing the BLAKE2s-128 checksum given a
  45. // non-empty key. Note that a 128-bit digest is too small to be secure as a
  46. // cryptographic hash and should only be used as a MAC, thus the key argument
  47. // is not optional.
  48. func New128(key []byte) (hash.Hash, error) {
  49. if len(key) == 0 {
  50. return nil, errors.New("blake2s: a key is required for a 128-bit hash")
  51. }
  52. return newDigest(Size128, key)
  53. }
  54. func newDigest(hashSize int, key []byte) (*digest, error) {
  55. if len(key) > Size {
  56. return nil, errKeySize
  57. }
  58. d := &digest{
  59. size: hashSize,
  60. keyLen: len(key),
  61. }
  62. copy(d.key[:], key)
  63. d.Reset()
  64. return d, nil
  65. }
  66. func checkSum(sum *[Size]byte, hashSize int, data []byte) {
  67. var (
  68. h [8]uint32
  69. c [2]uint32
  70. )
  71. h = iv
  72. h[0] ^= uint32(hashSize) | (1 << 16) | (1 << 24)
  73. if length := len(data); length > BlockSize {
  74. n := length &^ (BlockSize - 1)
  75. if length == n {
  76. n -= BlockSize
  77. }
  78. hashBlocks(&h, &c, 0, data[:n])
  79. data = data[n:]
  80. }
  81. var block [BlockSize]byte
  82. offset := copy(block[:], data)
  83. remaining := uint32(BlockSize - offset)
  84. if c[0] < remaining {
  85. c[1]--
  86. }
  87. c[0] -= remaining
  88. hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
  89. for i, v := range h {
  90. binary.LittleEndian.PutUint32(sum[4*i:], v)
  91. }
  92. }
  93. type digest struct {
  94. h [8]uint32
  95. c [2]uint32
  96. size int
  97. block [BlockSize]byte
  98. offset int
  99. key [BlockSize]byte
  100. keyLen int
  101. }
  102. func (d *digest) BlockSize() int { return BlockSize }
  103. func (d *digest) Size() int { return d.size }
  104. func (d *digest) Reset() {
  105. d.h = iv
  106. d.h[0] ^= uint32(d.size) | (uint32(d.keyLen) << 8) | (1 << 16) | (1 << 24)
  107. d.offset, d.c[0], d.c[1] = 0, 0, 0
  108. if d.keyLen > 0 {
  109. d.block = d.key
  110. d.offset = BlockSize
  111. }
  112. }
  113. func (d *digest) Write(p []byte) (n int, err error) {
  114. n = len(p)
  115. if d.offset > 0 {
  116. remaining := BlockSize - d.offset
  117. if n <= remaining {
  118. d.offset += copy(d.block[d.offset:], p)
  119. return
  120. }
  121. copy(d.block[d.offset:], p[:remaining])
  122. hashBlocks(&d.h, &d.c, 0, d.block[:])
  123. d.offset = 0
  124. p = p[remaining:]
  125. }
  126. if length := len(p); length > BlockSize {
  127. nn := length &^ (BlockSize - 1)
  128. if length == nn {
  129. nn -= BlockSize
  130. }
  131. hashBlocks(&d.h, &d.c, 0, p[:nn])
  132. p = p[nn:]
  133. }
  134. d.offset += copy(d.block[:], p)
  135. return
  136. }
  137. func (d *digest) Sum(sum []byte) []byte {
  138. var hash [Size]byte
  139. d.finalize(&hash)
  140. return append(sum, hash[:d.size]...)
  141. }
  142. func (d *digest) finalize(hash *[Size]byte) {
  143. var block [BlockSize]byte
  144. h := d.h
  145. c := d.c
  146. copy(block[:], d.block[:d.offset])
  147. remaining := uint32(BlockSize - d.offset)
  148. if c[0] < remaining {
  149. c[1]--
  150. }
  151. c[0] -= remaining
  152. hashBlocks(&h, &c, 0xFFFFFFFF, block[:])
  153. for i, v := range h {
  154. binary.LittleEndian.PutUint32(hash[4*i:], v)
  155. }
  156. }