argon2.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  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. //
  8. // For a detailed specification of Argon2 see [1].
  9. //
  10. // If you aren't sure which function you need, use Argon2id (IDKey) and
  11. // the parameter recommendations for your scenario.
  12. //
  13. //
  14. // Argon2i
  15. //
  16. // Argon2i (implemented by Key) is the side-channel resistant version of Argon2.
  17. // It uses data-independent memory access, which is preferred for password
  18. // hashing and password-based key derivation. Argon2i requires more passes over
  19. // memory than Argon2id to protect from trade-off attacks. The recommended
  20. // parameters (taken from [2]) for non-interactive operations are time=3 and to
  21. // use the maximum available memory.
  22. //
  23. //
  24. // Argon2id
  25. //
  26. // Argon2id (implemented by IDKey) is a hybrid version of Argon2 combining
  27. // Argon2i and Argon2d. It uses data-independent memory access for the first
  28. // half of the first iteration over the memory and data-dependent memory access
  29. // for the rest. Argon2id is side-channel resistant and provides better brute-
  30. // force cost savings due to time-memory tradeoffs than Argon2i. The recommended
  31. // parameters for non-interactive operations (taken from [2]) are time=1 and to
  32. // use the maximum available memory.
  33. //
  34. // [1] https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
  35. // [2] https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03#section-9.3
  36. package argon2
  37. import (
  38. "encoding/binary"
  39. "sync"
  40. "golang.org/x/crypto/blake2b"
  41. )
  42. // The Argon2 version implemented by this package.
  43. const Version = 0x13
  44. const (
  45. argon2d = iota
  46. argon2i
  47. argon2id
  48. )
  49. // Key derives a key from the password, salt, and cost parameters using Argon2i
  50. // returning a byte slice of length keyLen that can be used as cryptographic
  51. // key. The CPU cost and parallism degree must be greater than zero.
  52. //
  53. // For example, you can get a derived key for e.g. AES-256 (which needs a
  54. // 32-byte key) by doing: `key := argon2.Key([]byte("some password"), salt, 3,
  55. // 32*1024, 4, 32)`
  56. //
  57. // The draft RFC recommends[2] time=3, and memory=32*1024 is a sensible number.
  58. // If using that amount of memory (32 MB) is not possible in some contexts then
  59. // the time parameter can be increased to compensate.
  60. //
  61. // The time parameter specifies the number of passes over the memory and the
  62. // memory parameter specifies the size of the memory in KiB. For example
  63. // memory=32*1024 sets the memory cost to ~32 MB. The number of threads can be
  64. // adjusted to the number of available CPUs. The cost parameters should be
  65. // increased as memory latency and CPU parallelism increases. Remember to get a
  66. // good random salt.
  67. func Key(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
  68. return deriveKey(argon2i, password, salt, nil, nil, time, memory, threads, keyLen)
  69. }
  70. // IDKey derives a key from the password, salt, and cost parameters using
  71. // Argon2id returning a byte slice of length keyLen that can be used as
  72. // cryptographic key. The CPU cost and parallism degree must be greater than
  73. // zero.
  74. //
  75. // For example, you can get a derived key for e.g. AES-256 (which needs a
  76. // 32-byte key) by doing: `key := argon2.IDKey([]byte("some password"), salt, 1,
  77. // 64*1024, 4, 32)`
  78. //
  79. // The draft RFC recommends[2] time=1, and memory=64*1024 is a sensible number.
  80. // If using that amount of memory (64 MB) is not possible in some contexts then
  81. // the time parameter can be increased to compensate.
  82. //
  83. // The time parameter specifies the number of passes over the memory and the
  84. // memory parameter specifies the size of the memory in KiB. For example
  85. // memory=64*1024 sets the memory cost to ~64 MB. The number of threads can be
  86. // adjusted to the numbers of available CPUs. The cost parameters should be
  87. // increased as memory latency and CPU parallelism increases. Remember to get a
  88. // good random salt.
  89. func IDKey(password, salt []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
  90. return deriveKey(argon2id, password, salt, nil, nil, time, memory, threads, keyLen)
  91. }
  92. func deriveKey(mode int, password, salt, secret, data []byte, time, memory uint32, threads uint8, keyLen uint32) []byte {
  93. if time < 1 {
  94. panic("argon2: number of rounds too small")
  95. }
  96. if threads < 1 {
  97. panic("argon2: parallelism degree too low")
  98. }
  99. h0 := initHash(password, salt, secret, data, time, memory, uint32(threads), keyLen, mode)
  100. memory = memory / (syncPoints * uint32(threads)) * (syncPoints * uint32(threads))
  101. if memory < 2*syncPoints*uint32(threads) {
  102. memory = 2 * syncPoints * uint32(threads)
  103. }
  104. B := initBlocks(&h0, memory, uint32(threads))
  105. processBlocks(B, time, memory, uint32(threads), mode)
  106. return extractKey(B, memory, uint32(threads), keyLen)
  107. }
  108. const (
  109. blockLength = 128
  110. syncPoints = 4
  111. )
  112. type block [blockLength]uint64
  113. func initHash(password, salt, key, data []byte, time, memory, threads, keyLen uint32, mode int) [blake2b.Size + 8]byte {
  114. var (
  115. h0 [blake2b.Size + 8]byte
  116. params [24]byte
  117. tmp [4]byte
  118. )
  119. b2, _ := blake2b.New512(nil)
  120. binary.LittleEndian.PutUint32(params[0:4], threads)
  121. binary.LittleEndian.PutUint32(params[4:8], keyLen)
  122. binary.LittleEndian.PutUint32(params[8:12], memory)
  123. binary.LittleEndian.PutUint32(params[12:16], time)
  124. binary.LittleEndian.PutUint32(params[16:20], uint32(Version))
  125. binary.LittleEndian.PutUint32(params[20:24], uint32(mode))
  126. b2.Write(params[:])
  127. binary.LittleEndian.PutUint32(tmp[:], uint32(len(password)))
  128. b2.Write(tmp[:])
  129. b2.Write(password)
  130. binary.LittleEndian.PutUint32(tmp[:], uint32(len(salt)))
  131. b2.Write(tmp[:])
  132. b2.Write(salt)
  133. binary.LittleEndian.PutUint32(tmp[:], uint32(len(key)))
  134. b2.Write(tmp[:])
  135. b2.Write(key)
  136. binary.LittleEndian.PutUint32(tmp[:], uint32(len(data)))
  137. b2.Write(tmp[:])
  138. b2.Write(data)
  139. b2.Sum(h0[:0])
  140. return h0
  141. }
  142. func initBlocks(h0 *[blake2b.Size + 8]byte, memory, threads uint32) []block {
  143. var block0 [1024]byte
  144. B := make([]block, memory)
  145. for lane := uint32(0); lane < threads; lane++ {
  146. j := lane * (memory / threads)
  147. binary.LittleEndian.PutUint32(h0[blake2b.Size+4:], lane)
  148. binary.LittleEndian.PutUint32(h0[blake2b.Size:], 0)
  149. blake2bHash(block0[:], h0[:])
  150. for i := range B[j+0] {
  151. B[j+0][i] = binary.LittleEndian.Uint64(block0[i*8:])
  152. }
  153. binary.LittleEndian.PutUint32(h0[blake2b.Size:], 1)
  154. blake2bHash(block0[:], h0[:])
  155. for i := range B[j+1] {
  156. B[j+1][i] = binary.LittleEndian.Uint64(block0[i*8:])
  157. }
  158. }
  159. return B
  160. }
  161. func processBlocks(B []block, time, memory, threads uint32, mode int) {
  162. lanes := memory / threads
  163. segments := lanes / syncPoints
  164. processSegment := func(n, slice, lane uint32, wg *sync.WaitGroup) {
  165. var addresses, in, zero block
  166. if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) {
  167. in[0] = uint64(n)
  168. in[1] = uint64(lane)
  169. in[2] = uint64(slice)
  170. in[3] = uint64(memory)
  171. in[4] = uint64(time)
  172. in[5] = uint64(mode)
  173. }
  174. index := uint32(0)
  175. if n == 0 && slice == 0 {
  176. index = 2 // we have already generated the first two blocks
  177. if mode == argon2i || mode == argon2id {
  178. in[6]++
  179. processBlock(&addresses, &in, &zero)
  180. processBlock(&addresses, &addresses, &zero)
  181. }
  182. }
  183. offset := lane*lanes + slice*segments + index
  184. var random uint64
  185. for index < segments {
  186. prev := offset - 1
  187. if index == 0 && slice == 0 {
  188. prev += lanes // last block in lane
  189. }
  190. if mode == argon2i || (mode == argon2id && n == 0 && slice < syncPoints/2) {
  191. if index%blockLength == 0 {
  192. in[6]++
  193. processBlock(&addresses, &in, &zero)
  194. processBlock(&addresses, &addresses, &zero)
  195. }
  196. random = addresses[index%blockLength]
  197. } else {
  198. random = B[prev][0]
  199. }
  200. newOffset := indexAlpha(random, lanes, segments, threads, n, slice, lane, index)
  201. processBlockXOR(&B[offset], &B[prev], &B[newOffset])
  202. index, offset = index+1, offset+1
  203. }
  204. wg.Done()
  205. }
  206. for n := uint32(0); n < time; n++ {
  207. for slice := uint32(0); slice < syncPoints; slice++ {
  208. var wg sync.WaitGroup
  209. for lane := uint32(0); lane < threads; lane++ {
  210. wg.Add(1)
  211. go processSegment(n, slice, lane, &wg)
  212. }
  213. wg.Wait()
  214. }
  215. }
  216. }
  217. func extractKey(B []block, memory, threads, keyLen uint32) []byte {
  218. lanes := memory / threads
  219. for lane := uint32(0); lane < threads-1; lane++ {
  220. for i, v := range B[(lane*lanes)+lanes-1] {
  221. B[memory-1][i] ^= v
  222. }
  223. }
  224. var block [1024]byte
  225. for i, v := range B[memory-1] {
  226. binary.LittleEndian.PutUint64(block[i*8:], v)
  227. }
  228. key := make([]byte, keyLen)
  229. blake2bHash(key, block[:])
  230. return key
  231. }
  232. func indexAlpha(rand uint64, lanes, segments, threads, n, slice, lane, index uint32) uint32 {
  233. refLane := uint32(rand>>32) % threads
  234. if n == 0 && slice == 0 {
  235. refLane = lane
  236. }
  237. m, s := 3*segments, ((slice+1)%syncPoints)*segments
  238. if lane == refLane {
  239. m += index
  240. }
  241. if n == 0 {
  242. m, s = slice*segments, 0
  243. if slice == 0 || lane == refLane {
  244. m += index
  245. }
  246. }
  247. if index == 0 || lane == refLane {
  248. m--
  249. }
  250. return phi(rand, uint64(m), uint64(s), refLane, lanes)
  251. }
  252. func phi(rand, m, s uint64, lane, lanes uint32) uint32 {
  253. p := rand & 0xFFFFFFFF
  254. p = (p * p) >> 32
  255. p = (p * m) >> 32
  256. return lane*lanes + uint32((s+m-(p+1))%uint64(lanes))
  257. }