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