argon2.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright 2017 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 argon2 implements the key derivation function Argon2.
  5. // Argon2 was selected as the winner of the Password Hashing Competition and can
  6. // be used to derive cryptographic keys from passwords.
  7. // Argon2 is specfifed at https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
  8. package argon2
  9. import (
  10. "encoding/binary"
  11. "sync"
  12. "golang.org/x/crypto/blake2b"
  13. )
  14. // The Argon2 version implemented by this package.
  15. const Version = 0x13
  16. const (
  17. argon2d = iota
  18. argon2i
  19. argon2id
  20. )
  21. // Key derives a key from the password, salt, and cost parameters using Argon2i
  22. // returning a byte slice of length keyLen that can be used as cryptographic key.
  23. // The CPU cost and parallism degree must be greater than zero.
  24. //
  25. // For example, you can get a derived key for e.g. AES-256 (which needs a 32-byte key) by doing:
  26. // `key := argon2.Key([]byte("some password"), salt, 4, 32*1024, 4, 32)`
  27. //
  28. // The recommended parameters for interactive logins as of 2017 are time=4, memory=32*1024.
  29. // The number of threads can be adjusted to the numbers of available CPUs.
  30. // The time parameter specifies the number of passes over the memory and the memory
  31. // parameter specifies the size of the memory in KiB. For example memory=32*1024 sets the
  32. // memory cost to ~32 MB.
  33. // The cost parameters should be increased as memory latency and CPU parallelism increases.
  34. // Remember to get a good random salt.
  35. func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
  36. return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen)
  37. }
  38. func deriveKey(mode int, password, salt, secret, data []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
  39. if time < 1 {
  40. panic("argon2: number of rounds too small")
  41. }
  42. if threads < 1 {
  43. panic("argon2: parallelism degree too low")
  44. }
  45. h0 := initHash(password, salt, secret, data, time, memory, uint32(threads), keyLen, mode)
  46. memory = memory / (syncPoints * uint32(threads)) * (syncPoints * uint32(threads))
  47. if memory < 2*syncPoints*uint32(threads) {
  48. memory = 2 * syncPoints * uint32(threads)
  49. }
  50. B := initBlocks(&h0, memory, uint32(threads))
  51. processBlocks(B, time, memory, uint32(threads), mode)
  52. return extractKey(B, memory, uint32(threads), keyLen)
  53. }
  54. const (
  55. blockLength = 128
  56. syncPoints = 4
  57. )
  58. type block [blockLength]uint64
  59. func initHash(password, salt, key, data []byte, time, memory, threads, keyLen uint32, mode int) [blake2b.Size + 8]byte {
  60. var (
  61. h0 [blake2b.Size + 8]byte
  62. params [24]byte
  63. tmp [4]byte
  64. )
  65. b2, _ := blake2b.New512(nil)
  66. binary.LittleEndian.PutUint32(params[0:4], threads)
  67. binary.LittleEndian.PutUint32(params[4:8], keyLen)
  68. binary.LittleEndian.PutUint32(params[8:12], memory)
  69. binary.LittleEndian.PutUint32(params[12:16], time)
  70. binary.LittleEndian.PutUint32(params[16:20], uint32(Version))
  71. binary.LittleEndian.PutUint32(params[20:24], uint32(mode))
  72. b2.Write(params[:])
  73. binary.LittleEndian.PutUint32(tmp[:], uint32(len(password)))
  74. b2.Write(tmp[:])
  75. b2.Write(password)
  76. binary.LittleEndian.PutUint32(tmp[:], uint32(len(salt)))
  77. b2.Write(tmp[:])
  78. b2.Write(salt)
  79. binary.LittleEndian.PutUint32(tmp[:], uint32(len(key)))
  80. b2.Write(tmp[:])
  81. b2.Write(key)
  82. binary.LittleEndian.PutUint32(tmp[:], uint32(len(data)))
  83. b2.Write(tmp[:])
  84. b2.Write(data)
  85. b2.Sum(h0[:0])
  86. return h0
  87. }
  88. func initBlocks(h0 *[blake2b.Size + 8]byte, memory, threads uint32) []block {
  89. var block0 [1024]byte
  90. B := make([]block, memory)
  91. for lane := uint32(0); lane < threads; lane++ {
  92. j := lane * (memory / threads)
  93. binary.LittleEndian.PutUint32(h0[blake2b.Size+4:], lane)
  94. binary.LittleEndian.PutUint32(h0[blake2b.Size:], 0)
  95. blake2bHash(block0[:], h0[:])
  96. for i := range B[j+0] {
  97. B[j+0][i] = binary.LittleEndian.Uint64(block0[i*8:])
  98. }
  99. binary.LittleEndian.PutUint32(h0[blake2b.Size:], 1)
  100. blake2bHash(block0[:], h0[:])
  101. for i := range B[j+1] {
  102. B[j+1][i] = binary.LittleEndian.Uint64(block0[i*8:])
  103. }
  104. }
  105. return B
  106. }
  107. func processBlocks(B []block, time, memory, threads uint32, mode int) {
  108. lanes := memory / threads
  109. segments := lanes / syncPoints
  110. processSegment := func(n, slice, lane uint32, wg *sync.WaitGroup) {
  111. var addresses, in, zero block
  112. if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) {
  113. in[0] = uint64(n)
  114. in[1] = uint64(lane)
  115. in[2] = uint64(slice)
  116. in[3] = uint64(memory)
  117. in[4] = uint64(time)
  118. in[5] = uint64(mode)
  119. }
  120. index := uint32(0)
  121. if n == 0 && slice == 0 {
  122. index = 2 // we have already generated the first two blocks
  123. if mode == argon2i || mode == argon2id {
  124. in[6]++
  125. processBlock(&addresses, &in, &zero)
  126. processBlock(&addresses, &addresses, &zero)
  127. }
  128. }
  129. offset := lane*lanes + slice*segments + index
  130. var random uint64
  131. for index < segments {
  132. prev := offset - 1
  133. if index == 0 && slice == 0 {
  134. prev += lanes // last block in lane
  135. }
  136. if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) {
  137. if index%blockLength == 0 {
  138. in[6]++
  139. processBlock(&addresses, &in, &zero)
  140. processBlock(&addresses, &addresses, &zero)
  141. }
  142. random = addresses[index%blockLength]
  143. } else {
  144. random = B[prev][0]
  145. }
  146. newOffset := indexAlpha(random, lanes, segments, threads, n, slice, lane, index)
  147. processBlockXOR(&B[offset], &B[prev], &B[newOffset])
  148. index, offset = index+1, offset+1
  149. }
  150. wg.Done()
  151. }
  152. for n := uint32(0); n < time; n++ {
  153. for slice := uint32(0); slice < syncPoints; slice++ {
  154. var wg sync.WaitGroup
  155. for lane := uint32(0); lane < threads; lane++ {
  156. wg.Add(1)
  157. go processSegment(n, slice, lane, &wg)
  158. }
  159. wg.Wait()
  160. }
  161. }
  162. }
  163. func extractKey(B []block, memory, threads, keyLen uint32) []byte {
  164. lanes := memory / threads
  165. for lane := uint32(0); lane < threads-1; lane++ {
  166. for i, v := range B[(lane*lanes)+lanes-1] {
  167. B[memory-1][i] ^= v
  168. }
  169. }
  170. var block [1024]byte
  171. for i, v := range B[memory-1] {
  172. binary.LittleEndian.PutUint64(block[i*8:], v)
  173. }
  174. key := make([]byte, keyLen)
  175. blake2bHash(key, block[:])
  176. return key
  177. }
  178. func indexAlpha(rand uint64, lanes, segments, threads, n, slice, lane, index uint32) uint32 {
  179. refLane := uint32(rand>>32) % threads
  180. if n == 0 && slice == 0 {
  181. refLane = lane
  182. }
  183. m, s := 3*segments, ((slice+1)%syncPoints)*segments
  184. if lane == refLane {
  185. m += index
  186. }
  187. if n == 0 {
  188. m, s = slice*segments, 0
  189. if slice == 0 || lane == refLane {
  190. m += index
  191. }
  192. }
  193. if index == 0 || lane == refLane {
  194. m--
  195. }
  196. return phi(rand, uint64(m), uint64(s), refLane, lanes)
  197. }
  198. func phi(rand, m, s uint64, lane, lanes uint32) uint32 {
  199. p := rand & 0xFFFFFFFF
  200. p = (p * p) >> 32
  201. p = (p * m) >> 32
  202. return lane*lanes + uint32((s+m-(p+1))%uint64(lanes))
  203. }