podman

Форк
0
283 строки · 9.2 Кб
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
}
284

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.