File: s2k_config.go

package info (click to toggle)
golang-github-protonmail-go-crypto 1.1.6-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,932 kB
  • sloc: makefile: 10
file content (129 lines) | stat: -rw-r--r-- 3,857 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package s2k

import "crypto"

// Config collects configuration parameters for s2k key-stretching
// transformations. A nil *Config is valid and results in all default
// values.
type Config struct {
	// S2K (String to Key) mode, used for key derivation in the context of secret key encryption
	// and passphrase-encrypted data. Either s2k.Argon2S2K or s2k.IteratedSaltedS2K may be used.
	// If the passphrase is a high-entropy key, indicated by setting PassphraseIsHighEntropy to true,
	// s2k.SaltedS2K can also be used.
	// Note: Argon2 is the strongest option but not all OpenPGP implementations are compatible with it
	//(pending standardisation).
	// 0 (simple), 1(salted), 3(iterated), 4(argon2)
	// 2(reserved) 100-110(private/experimental).
	S2KMode Mode
	// Only relevant if S2KMode is not set to s2k.Argon2S2K.
	// Hash is the default hash function to be used. If
	// nil, SHA256 is used.
	Hash crypto.Hash
	// Argon2 parameters for S2K (String to Key).
	// Only relevant if S2KMode is set to s2k.Argon2S2K.
	// If nil, default parameters are used.
	// For more details on the choice of parameters, see https://tools.ietf.org/html/rfc9106#section-4.
	Argon2Config *Argon2Config
	// Only relevant if S2KMode is set to s2k.IteratedSaltedS2K.
	// Iteration count for Iterated S2K (String to Key). It
	// determines the strength of the passphrase stretching when
	// the said passphrase is hashed to produce a key. S2KCount
	// should be between 65536 and 65011712, inclusive. If Config
	// is nil or S2KCount is 0, the value 16777216 used. Not all
	// values in the above range can be represented. S2KCount will
	// be rounded up to the next representable value if it cannot
	// be encoded exactly. When set, it is strongly encrouraged to
	// use a value that is at least 65536. See RFC 4880 Section
	// 3.7.1.3.
	S2KCount int
	// Indicates whether the passphrase passed by the application is a
	// high-entropy key (e.g. it's randomly generated or derived from
	// another passphrase using a strong key derivation function).
	// When true, allows the S2KMode to be s2k.SaltedS2K.
	// When the passphrase is not a high-entropy key, using SaltedS2K is
	// insecure, and not allowed by draft-ietf-openpgp-crypto-refresh-08.
	PassphraseIsHighEntropy bool
}

// Argon2Config stores the Argon2 parameters
// A nil *Argon2Config is valid and results in all default
type Argon2Config struct {
	NumberOfPasses      uint8
	DegreeOfParallelism uint8
	// Memory specifies the desired Argon2 memory usage in kibibytes.
	// For example memory=64*1024 sets the memory cost to ~64 MB.
	Memory uint32
}

func (c *Config) Mode() Mode {
	if c == nil {
		return IteratedSaltedS2K
	}
	return c.S2KMode
}

func (c *Config) hash() crypto.Hash {
	if c == nil || uint(c.Hash) == 0 {
		return crypto.SHA256
	}

	return c.Hash
}

func (c *Config) Argon2() *Argon2Config {
	if c == nil || c.Argon2Config == nil {
		return nil
	}
	return c.Argon2Config
}

// EncodedCount get encoded count
func (c *Config) EncodedCount() uint8 {
	if c == nil || c.S2KCount == 0 {
		return 224 // The common case. Corresponding to 16777216
	}

	i := c.S2KCount

	switch {
	case i < 65536:
		i = 65536
	case i > 65011712:
		i = 65011712
	}

	return encodeCount(i)
}

func (c *Argon2Config) Passes() uint8 {
	if c == nil || c.NumberOfPasses == 0 {
		return 3
	}
	return c.NumberOfPasses
}

func (c *Argon2Config) Parallelism() uint8 {
	if c == nil || c.DegreeOfParallelism == 0 {
		return 4
	}
	return c.DegreeOfParallelism
}

func (c *Argon2Config) EncodedMemory() uint8 {
	if c == nil || c.Memory == 0 {
		return 16 // 64 MiB of RAM
	}

	memory := c.Memory
	lowerBound := uint32(c.Parallelism()) * 8
	upperBound := uint32(2147483648)

	switch {
	case memory < lowerBound:
		memory = lowerBound
	case memory > upperBound:
		memory = upperBound
	}

	return encodeMemory(memory, c.Parallelism())
}