main
Raw Download raw file
  1package s2k
  2
  3import "crypto"
  4
  5// Config collects configuration parameters for s2k key-stretching
  6// transformations. A nil *Config is valid and results in all default
  7// values.
  8type Config struct {
  9	// S2K (String to Key) mode, used for key derivation in the context of secret key encryption
 10	// and passphrase-encrypted data. Either s2k.Argon2S2K or s2k.IteratedSaltedS2K may be used.
 11	// If the passphrase is a high-entropy key, indicated by setting PassphraseIsHighEntropy to true,
 12	// s2k.SaltedS2K can also be used.
 13	// Note: Argon2 is the strongest option but not all OpenPGP implementations are compatible with it
 14	//(pending standardisation).
 15	// 0 (simple), 1(salted), 3(iterated), 4(argon2)
 16	// 2(reserved) 100-110(private/experimental).
 17	S2KMode Mode
 18	// Only relevant if S2KMode is not set to s2k.Argon2S2K.
 19	// Hash is the default hash function to be used. If
 20	// nil, SHA256 is used.
 21	Hash crypto.Hash
 22	// Argon2 parameters for S2K (String to Key).
 23	// Only relevant if S2KMode is set to s2k.Argon2S2K.
 24	// If nil, default parameters are used.
 25	// For more details on the choice of parameters, see https://tools.ietf.org/html/rfc9106#section-4.
 26	Argon2Config *Argon2Config
 27	// Only relevant if S2KMode is set to s2k.IteratedSaltedS2K.
 28	// Iteration count for Iterated S2K (String to Key). It
 29	// determines the strength of the passphrase stretching when
 30	// the said passphrase is hashed to produce a key. S2KCount
 31	// should be between 65536 and 65011712, inclusive. If Config
 32	// is nil or S2KCount is 0, the value 16777216 used. Not all
 33	// values in the above range can be represented. S2KCount will
 34	// be rounded up to the next representable value if it cannot
 35	// be encoded exactly. When set, it is strongly encrouraged to
 36	// use a value that is at least 65536. See RFC 4880 Section
 37	// 3.7.1.3.
 38	S2KCount int
 39	// Indicates whether the passphrase passed by the application is a
 40	// high-entropy key (e.g. it's randomly generated or derived from
 41	// another passphrase using a strong key derivation function).
 42	// When true, allows the S2KMode to be s2k.SaltedS2K.
 43	// When the passphrase is not a high-entropy key, using SaltedS2K is
 44	// insecure, and not allowed by draft-ietf-openpgp-crypto-refresh-08.
 45	PassphraseIsHighEntropy bool
 46}
 47
 48// Argon2Config stores the Argon2 parameters
 49// A nil *Argon2Config is valid and results in all default
 50type Argon2Config struct {
 51	NumberOfPasses      uint8
 52	DegreeOfParallelism uint8
 53	// Memory specifies the desired Argon2 memory usage in kibibytes.
 54	// For example memory=64*1024 sets the memory cost to ~64 MB.
 55	Memory uint32
 56}
 57
 58func (c *Config) Mode() Mode {
 59	if c == nil {
 60		return IteratedSaltedS2K
 61	}
 62	return c.S2KMode
 63}
 64
 65func (c *Config) hash() crypto.Hash {
 66	if c == nil || uint(c.Hash) == 0 {
 67		return crypto.SHA256
 68	}
 69
 70	return c.Hash
 71}
 72
 73func (c *Config) Argon2() *Argon2Config {
 74	if c == nil || c.Argon2Config == nil {
 75		return nil
 76	}
 77	return c.Argon2Config
 78}
 79
 80// EncodedCount get encoded count
 81func (c *Config) EncodedCount() uint8 {
 82	if c == nil || c.S2KCount == 0 {
 83		return 224 // The common case. Corresponding to 16777216
 84	}
 85
 86	i := c.S2KCount
 87
 88	switch {
 89	case i < 65536:
 90		i = 65536
 91	case i > 65011712:
 92		i = 65011712
 93	}
 94
 95	return encodeCount(i)
 96}
 97
 98func (c *Argon2Config) Passes() uint8 {
 99	if c == nil || c.NumberOfPasses == 0 {
100		return 3
101	}
102	return c.NumberOfPasses
103}
104
105func (c *Argon2Config) Parallelism() uint8 {
106	if c == nil || c.DegreeOfParallelism == 0 {
107		return 4
108	}
109	return c.DegreeOfParallelism
110}
111
112func (c *Argon2Config) EncodedMemory() uint8 {
113	if c == nil || c.Memory == 0 {
114		return 16 // 64 MiB of RAM
115	}
116
117	memory := c.Memory
118	lowerBound := uint32(c.Parallelism()) * 8
119	upperBound := uint32(2147483648)
120
121	switch {
122	case memory < lowerBound:
123		memory = lowerBound
124	case memory > upperBound:
125		memory = upperBound
126	}
127
128	return encodeMemory(memory, c.Parallelism())
129}