Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate argon2 params on read #246

Merged
merged 4 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 24 additions & 2 deletions openpgp/s2k/s2k.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,8 @@ func Generate(rand io.Reader, c *Config) (*Params, error) {
}

params = &Params{
mode: SaltedS2K,
hashId: hashId,
mode: SaltedS2K,
hashId: hashId,
}
} else { // Enforce IteratedSaltedS2K method otherwise
hashId, ok := algorithm.HashToHashId(c.hash())
Expand Down Expand Up @@ -283,6 +283,9 @@ func ParseIntoParams(r io.Reader) (params *Params, err error) {
params.passes = buf[Argon2SaltSize]
params.parallelism = buf[Argon2SaltSize+1]
params.memoryExp = buf[Argon2SaltSize+2]
if err := validateArgon2Params(params); err != nil {
return nil, err
}
return params, nil
case GnuS2K:
// This is a GNU extension. See
Expand Down Expand Up @@ -412,3 +415,22 @@ func Serialize(w io.Writer, key []byte, rand io.Reader, passphrase []byte, c *Co
f(key, passphrase)
return nil
}

// validateArgon2Params checks that the argon2 parameters are valid according to RFC9580.
func validateArgon2Params(params *Params) error {
// The number of passes t and the degree of parallelism p MUST be non-zero.
if params.parallelism == 0 {
return errors.StructuralError("invalid argon2 params: parallelism is 0")
}
if params.passes == 0 {
return errors.StructuralError("invalid argon2 params: iterations is 0")
}

// The encoded memory size MUST be a value from 3+ceil(log2(p)) to 31,
// such that the decoded memory size m is a value from 8*p to 2^31.
if params.memoryExp > 31 || decodeMemory(params.memoryExp) < 8*uint32(params.parallelism) {
return errors.StructuralError("invalid argon2 params: memory is out of bounds")
}

return nil
}
46 changes: 46 additions & 0 deletions openpgp/s2k/s2k_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,49 @@ func testSerializeConfigOK(t *testing.T, c *Config) *Params {

return params
}

func TestValidateArgon2Params(t *testing.T) {
tests := []struct {
params Params
wantErr bool
}{
{
params: Params{parallelism: 4, passes: 3, memoryExp: 6},
wantErr: false,
},
{
params: Params{parallelism: 0, passes: 3, memoryExp: 6},
wantErr: true,
},
{
params: Params{parallelism: 4, passes: 0, memoryExp: 6},
wantErr: true,
},
{
params: Params{parallelism: 4, passes: 3, memoryExp: 4},
wantErr: true,
},
{
params: Params{parallelism: 4, passes: 3, memoryExp: 32},
wantErr: true,
},
{
params: Params{parallelism: 4, passes: 3, memoryExp: 5},
wantErr: false,
},
{
params: Params{parallelism: 4, passes: 3, memoryExp: 31},
wantErr: false,
},
}

for _, tt := range tests {
err := validateArgon2Params(&tt.params)
if tt.wantErr && err == nil {
t.Errorf("validateArgon2Params: expected an error")
}
if !tt.wantErr && err != nil {
t.Error("validateArgon2Params: expected no error")
}
}
}
Loading