Skip to content

Commit 66c95c5

Browse files
committed
More comments to be more explicit
Signed-off-by: Andrew Thornton <[email protected]>
1 parent 17f9402 commit 66c95c5

File tree

7 files changed

+87
-23
lines changed

7 files changed

+87
-23
lines changed

modules/auth/password/hash/argon2.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ func NewArgon2Hasher(config string) *Argon2Hasher {
4141
// This default configuration uses the following parameters:
4242
// time=2, memory=64*1024, threads=8, keyLen=50.
4343
// It will make two passes through the memory, using 64MiB in total.
44+
// This matches the original configuration for `argon2` prior to storing hash parameters
45+
// in the database.
46+
// THESE VALUES MUST NOT BE CHANGED OR BACKWARDS COMPATIBILITY WILL BREAK
4447
hasher := &Argon2Hasher{
4548
time: 2,
4649
memory: 1 << 16,

modules/auth/password/hash/bcrypt.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ func (hasher *BcryptHasher) VerifyPassword(password, hashedPassword, salt string
3434
// The provided config should be either empty or the string representation of the "<cost>"
3535
// as an integer
3636
func NewBcryptHasher(config string) *BcryptHasher {
37+
// This matches the original configuration for `bcrypt` prior to storing hash parameters
38+
// in the database.
39+
// THESE VALUES MUST NOT BE CHANGED OR BACKWARDS COMPATIBILITY WILL BREAK
3740
hasher := &BcryptHasher{
3841
cost: 10, // cost=10. i.e. 2^10 rounds of key expansion.
3942
}

modules/auth/password/hash/hash.go

Lines changed: 53 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ type PasswordVerifier interface {
3535
// PasswordHashAlgorithms are named PasswordSaltHashers with a default verifier and hash function
3636
type PasswordHashAlgorithm struct {
3737
PasswordSaltHasher
38-
Name string
38+
Specification string // The specification that is used to create the internal PasswordSaltHasher
3939
}
4040

4141
// Hash the provided password with the salt and return the hash
@@ -61,16 +61,16 @@ func (algorithm *PasswordHashAlgorithm) Hash(password, salt string) (string, err
6161

6262
// Verify the provided password matches the hashPassword when hashed with the salt
6363
func (algorithm *PasswordHashAlgorithm) VerifyPassword(providedPassword, hashedPassword, salt string) bool {
64-
// The bcrypt package has its own specialized compare function that takes into
65-
// account the stored password's bcrypt parameters.
64+
// Some PasswordSaltHashers have their own specialised compare function that takes into
65+
// account the stored parameters within the hash. e.g. bcrypt
6666
if verifier, ok := algorithm.PasswordSaltHasher.(PasswordVerifier); ok {
6767
return verifier.VerifyPassword(providedPassword, hashedPassword, salt)
6868
}
6969

7070
// Compute the hash of the password.
7171
providedPasswordHash, err := algorithm.Hash(providedPassword, salt)
7272
if err != nil {
73-
log.Error("passwordhash: %v.Hash(): %v", algorithm.Name, err)
73+
log.Error("passwordhash: %v.Hash(): %v", algorithm.Specification, err)
7474
return false
7575
}
7676

@@ -84,7 +84,7 @@ var (
8484
)
8585

8686
// Register registers a PasswordSaltHasher with the availableHasherFactories
87-
// This is not thread safe.
87+
// Caution: This is not thread safe.
8888
func Register[T PasswordSaltHasher](name string, newFn func(config string) T) {
8989
if _, has := availableHasherFactories[name]; has {
9090
panic(fmt.Errorf("duplicate registration of password salt hasher: %s", name))
@@ -96,49 +96,82 @@ func Register[T PasswordSaltHasher](name string, newFn func(config string) T) {
9696
}
9797
}
9898

99-
// In early versions of gitea the password hash algorithm field could be empty
100-
// At that point the default was `pbkdf2` without configuration values
101-
// Please note this is not the same as the DefaultAlgorithm
102-
const defaultEmptyHashAlgorithmName = "pbkdf2"
103-
104-
func Parse(algorithm string) *PasswordHashAlgorithm {
105-
if algorithm == "" {
106-
algorithm = defaultEmptyHashAlgorithmName
99+
// In early versions of gitea the password hash algorithm field of a user could be
100+
// empty. At that point the default was `pbkdf2` without configuration values
101+
//
102+
// Please note this is not the same as the DefaultAlgorithm which is used
103+
// to determine what an empty PASSWORD_HASH_ALGO setting in the app.ini means.
104+
// These are not the same even if they have the same apparent value and they mean different things.
105+
//
106+
// DO NOT COALESCE THESE VALUES
107+
const defaultEmptyHashAlgorithmSpecification = "pbkdf2"
108+
109+
// Parse will convert the provided algorithm specification in to a PasswordHashAlgorithm
110+
// If the provided specification matches the DefaultHashAlgorithm Specification it will be
111+
// used.
112+
// In addition the last non-default hasher will be cached to help reduce the load from
113+
// parsing specifications.
114+
//
115+
// NOTE: No de-aliasing is done in this function, thus any specification which does not
116+
// contain a configuration will use the default values for that hasher. These are not
117+
// necessarily the same values as those obtained by dealiasing. This allows for
118+
// seamless backwards compatibility with the original configuration.
119+
//
120+
// To further labour this point, running `Parse("pbkdf2")` does not obtain the
121+
// same algorithm as setting `PASSWORD_HASH_ALGO=pbkdf2` in app.ini, nor is it intended to.
122+
// A user that has `password_hash_algo='pbkdf2'` in the db means get the original, unconfigured algorithm
123+
// Users will be migrated automatically as they log-in to have the complete specification stored
124+
// in their `password_hash_algo` fields by other code.
125+
func Parse(algorithmSpec string) *PasswordHashAlgorithm {
126+
if algorithmSpec == "" {
127+
algorithmSpec = defaultEmptyHashAlgorithmSpecification
107128
}
108129

109-
if DefaultHashAlgorithm != nil && algorithm == DefaultHashAlgorithm.Name {
130+
if DefaultHashAlgorithm != nil && algorithmSpec == DefaultHashAlgorithm.Specification {
110131
return DefaultHashAlgorithm
111132
}
112133

113134
ptr := lastNonDefaultAlgorithm.Load()
114135
if ptr != nil {
115136
hashAlgorithm, ok := ptr.(*PasswordHashAlgorithm)
116-
if ok && hashAlgorithm.Name == algorithm {
137+
if ok && hashAlgorithm.Specification == algorithmSpec {
117138
return hashAlgorithm
118139
}
119140
}
120141

121-
vals := strings.SplitN(algorithm, "$", 2)
122-
var name string
142+
// Now convert the provided specification in to a hasherType +/- some configuration parameters
143+
vals := strings.SplitN(algorithmSpec, "$", 2)
144+
var hasherType string
123145
var config string
146+
124147
if len(vals) == 0 {
148+
// This should not happen as algorithmSpec should not be empty
149+
// due to it being assigned to defaultEmptyHashAlgorithmSpecification above
150+
// but we should be absolutely cautious here
125151
return nil
126152
}
127-
name = vals[0]
153+
154+
hasherType = vals[0]
128155
if len(vals) > 1 {
129156
config = vals[1]
130157
}
131-
newFn, has := availableHasherFactories[name]
158+
159+
newFn, has := availableHasherFactories[hasherType]
132160
if !has {
161+
// unknown hasher type
133162
return nil
134163
}
164+
135165
ph := newFn(config)
136166
if ph == nil {
167+
// The provided configuration is likely invalid - it will have been logged already
168+
// but we cannot hash safely
137169
return nil
138170
}
171+
139172
hashAlgorithm := &PasswordHashAlgorithm{
140173
PasswordSaltHasher: ph,
141-
Name: algorithm,
174+
Specification: algorithmSpec,
142175
}
143176

144177
lastNonDefaultAlgorithm.Store(hashAlgorithm)

modules/auth/password/hash/pbkdf2.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ func (hasher *PBKDF2Hasher) HashWithSaltBytes(password string, salt []byte) stri
3636
// "<iter>$<keyLen>", where <x> is the string representation
3737
// of an integer
3838
func NewPBKDF2Hasher(config string) *PBKDF2Hasher {
39+
// This default configuration uses the following parameters:
40+
// iter=10000, keyLen=50.
41+
// This matches the original configuration for `pbkdf2` prior to storing parameters
42+
// in the database.
43+
// THESE VALUES MUST NOT BE CHANGED OR BACKWARDS COMPATIBILITY WILL BREAK
3944
hasher := &PBKDF2Hasher{
4045
iter: 10_000,
4146
keyLen: 50,

modules/auth/password/hash/scrypt.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ func (hasher *ScryptHasher) HashWithSaltBytes(password string, salt []byte) stri
3636
// "<n>$<r>$<p>$<keyLen>", where <x> is the string representation
3737
// of an integer
3838
func NewScryptHasher(config string) *ScryptHasher {
39+
// This matches the original configuration for `scrypt` prior to storing hash parameters
40+
// in the database.
41+
// THESE VALUES MUST NOT BE CHANGED OR BACKWARDS COMPATIBILITY WILL BREAK
3942
hasher := &ScryptHasher{
4043
n: 1 << 16,
4144
r: 16,

modules/auth/password/hash/setting.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,22 @@
33

44
package hash
55

6+
// DefaultHashAlgorithmName represents the defualt value of PASSWORD_HASH_ALGO
7+
// configured in app.ini.
8+
//
9+
// It is NOT the same and does NOT map to the defaultEmptyHashAlgorithmSpecification.
10+
//
11+
// It will be dealiased as per aliasAlgorithmNames whereas
12+
// defaultEmptyHashAlgorithmSpecification does not undergo dealiasing.
613
const DefaultHashAlgorithmName = "pbkdf2"
714

815
var DefaultHashAlgorithm *PasswordHashAlgorithm
916

17+
// aliasAlgorithNames provides a mapping between the value of PASSWORD_HASH_ALGO
18+
// configured in the app.ini and the parameters used within the hashers internally.
19+
//
20+
// If it is necessary to change the default parameters for any hasher in future you
21+
// should change these values and not those in argon2.go etc.
1022
var aliasAlgorithmNames = map[string]string{
1123
"argon2": "argon2$2$65536$8$50",
1224
"bcrypt": "bcrypt$10",
@@ -29,6 +41,8 @@ var RecommendedHashAlgorithms = []string{
2941
"pbkdf2_hi",
3042
}
3143

44+
// SetDefaultPasswordHashAlgorithm will take a provided algorithmName and dealias it to
45+
// a complete algorithm specification.
3246
func SetDefaultPasswordHashAlgorithm(algorithmName string) (string, *PasswordHashAlgorithm) {
3347
if algorithmName == "" {
3448
algorithmName = DefaultHashAlgorithmName
@@ -38,6 +52,9 @@ func SetDefaultPasswordHashAlgorithm(algorithmName string) (string, *PasswordHas
3852
algorithmName = alias
3953
alias, has = aliasAlgorithmNames[algorithmName]
4054
}
55+
56+
// algorithmName should now be a full algorithm specification
57+
// e.g. pbkdf2$50000$50 rather than pbdkf2
4158
DefaultHashAlgorithm = Parse(algorithmName)
4259

4360
return algorithmName, DefaultHashAlgorithm

modules/auth/password/hash/setting_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func TestCheckSettingPasswordHashAlgorithm(t *testing.T) {
1515
pbkdf2Config, pbkdf2Algo := SetDefaultPasswordHashAlgorithm("pbkdf2")
1616

1717
assert.Equal(t, pbkdf2v2Config, pbkdf2Config)
18-
assert.Equal(t, pbkdf2v2Algo.Name, pbkdf2Algo.Name)
18+
assert.Equal(t, pbkdf2v2Algo.Specification, pbkdf2Algo.Specification)
1919
})
2020

2121
for a, b := range aliasAlgorithmNames {
@@ -24,7 +24,7 @@ func TestCheckSettingPasswordHashAlgorithm(t *testing.T) {
2424
bConfig, bAlgo := SetDefaultPasswordHashAlgorithm(b)
2525

2626
assert.Equal(t, bConfig, aConfig)
27-
assert.Equal(t, aAlgo.Name, bAlgo.Name)
27+
assert.Equal(t, aAlgo.Specification, bAlgo.Specification)
2828
})
2929
}
3030

@@ -33,6 +33,6 @@ func TestCheckSettingPasswordHashAlgorithm(t *testing.T) {
3333
pbkdf2v2Config, pbkdf2v2Algo := SetDefaultPasswordHashAlgorithm("pbkdf2_v2")
3434

3535
assert.Equal(t, pbkdf2v2Config, emptyConfig)
36-
assert.Equal(t, pbkdf2v2Algo.Name, emptyAlgo.Name)
36+
assert.Equal(t, pbkdf2v2Algo.Specification, emptyAlgo.Specification)
3737
})
3838
}

0 commit comments

Comments
 (0)