Skip to content

Commit

Permalink
Merge pull request #13 from D3vl0per/argon-usability
Browse files Browse the repository at this point in the history
Argon parameter parsing refactor
  • Loading branch information
D3vl0per authored Nov 29, 2023
2 parents ca4d532 + 2ef6dbf commit 1ba10e6
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 54 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
lint
.env
coverage.html
coverage.html
coverage.txt
100 changes: 50 additions & 50 deletions hash/kdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,89 +100,89 @@ func (a *Argon2ID) Validate(data []byte, argonString string) (bool, error) {
return false, err
}

providedHash, err := base64.RawStdEncoding.DecodeString(parameters["hash"])
if err != nil {
return false, errors.New(generic.StrCnct([]string{"hash base64 decode error: ", err.Error()}...))
}

a.Salt, err = base64.RawStdEncoding.DecodeString(parameters["salt"])
if err != nil {
return false, errors.New(generic.StrCnct([]string{"salt base64 decode error: ", err.Error()}...))
if len(a.Salt) == 0 {
a.Salt = parameters.Salt
}

if a.Iterations == 0 {
parsed, err := strconv.ParseInt(parameters["iterations"], 10, 32)
if err != nil {
return false, errors.New(generic.StrCnct([]string{"iteration parameter parsing error: ", err.Error()}...))
}

a.Iterations = uint32(parsed)
a.Iterations = parameters.Iterations
}

if a.Memory == 0 {
parsed, err := strconv.ParseInt(parameters["memory"], 10, 32)
if err != nil {
return false, errors.New(generic.StrCnct([]string{"memory parameter parsing error: ", err.Error()}...))
}

a.Memory = uint32(parsed)
a.Memory = parameters.Memory
}

if a.Parallelism == 0 {
parsed, err := strconv.ParseInt(parameters["parallelism"], 10, 8)
if err != nil {
return false, errors.New(generic.StrCnct([]string{"parallelism parameter parsing error: ", err.Error()}...))
}

a.Parallelism = uint8(parsed)
}

if a.KeyLen == 0 {
a.KeyLen = AKeyLen
a.Parallelism = parameters.Parallelism
}

hashed := a.argon2ID(data)

return generic.Compare(hashed.Hash, providedHash), nil
return generic.Compare(hashed.Hash, parameters.Hash), nil
}

type Parameters struct {
Algorithm string
Version string
Memory uint32
Iterations uint32
Parallelism uint8
Salt []byte
Hash []byte
}

func (a *Argon2ID) ExtractParameters(input string) (map[string]string, error) {
pattern := `\$(argon2id)\$v=(\d+)\$m=(\d+),t=(\d+),p=(\d+)\$([^$]+)\$([^$]+)$`
func (a *Argon2ID) ExtractParameters(input string) (Parameters, error) {
pattern := `\$(argon2id)\$v=(19)\$m=(\d+),t=(\d+),p=(\d+)\$([^$]+)\$([^$]+)$`

re := regexp.MustCompile(pattern)

matches := re.FindStringSubmatch(input)

if len(matches) != 8 {
return nil, errors.New("invalid input format")
return Parameters{}, errors.New("invalid input format")
}

parameters := map[string]string{
"algorithm": matches[1],
"version": matches[2],
"memory": matches[3],
"iterations": matches[4],
"parallelism": matches[5],
"salt": matches[6],
"hash": matches[7],
parameters := Parameters{
Algorithm: matches[1],
Version: matches[2],
}

if len(parameters["algorithm"]) == 0 || !generic.CompareString(parameters["algorithm"], "argon2id") {
return map[string]string{}, errors.New(generic.StrCnct([]string{"invalid algorithm: ", parameters["algorithm"]}...))
var err error

parameters.Hash, err = base64.RawStdEncoding.DecodeString(matches[7])
if err != nil {
return Parameters{}, errors.New(generic.StrCnct([]string{"hash base64 decode error: ", err.Error()}...))
}

if len(parameters["version"]) == 0 || !generic.CompareString(parameters["version"], strconv.FormatInt(int64(argon2.Version), 10)) {
return map[string]string{}, errors.New(generic.StrCnct([]string{"invalid version: ", parameters["version"]}...))
parameters.Salt, err = base64.RawStdEncoding.DecodeString(matches[6])
if err != nil {
return Parameters{}, errors.New(generic.StrCnct([]string{"salt base64 decode error: ", err.Error()}...))
}

if len(parameters["hash"]) == 0 {
return map[string]string{}, errors.New("missing hash")
if len(parameters.Salt) != 16 {
return Parameters{}, errors.New("salt must be 16 byte long")
}

if len(parameters["salt"]) == 0 {
return map[string]string{}, errors.New("missing salt")
memory, err := strconv.ParseInt(matches[3], 10, 32)
if err != nil {
return Parameters{}, errors.New(generic.StrCnct([]string{"memory parameter parsing error: ", err.Error()}...))
}

parameters.Memory = uint32(memory)

iterations, err := strconv.ParseInt(matches[4], 10, 32)
if err != nil {
return Parameters{}, errors.New(generic.StrCnct([]string{"iteration parameter parsing error: ", err.Error()}...))
}
parameters.Iterations = uint32(iterations)

parallelism, err := strconv.ParseInt(matches[5], 10, 8)
if err != nil {
return Parameters{}, errors.New(generic.StrCnct([]string{"parallelism parameter parsing error: ", err.Error()}...))
}

parameters.Parallelism = uint8(parallelism)

return parameters, nil
}

Expand Down
15 changes: 12 additions & 3 deletions hash/kdf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestArgon2ID(t *testing.T) {
{
name: "Custom key length",
argon: hasher.Argon2ID{
KeyLen: 64,
KeyLen: 1,
},
},
{
Expand Down Expand Up @@ -75,7 +75,11 @@ func TestArgon2ID(t *testing.T) {
r.NoError(t, err)
t.Log("Argon parameters: ", parameters)

isValid, err := tt.argon.Validate(data, argonString)
validator := hasher.Argon2ID{
KeyLen: tt.argon.KeyLen,
}

isValid, err := validator.Validate(data, argonString)
r.NoError(t, err)
a.True(t, isValid)
})
Expand Down Expand Up @@ -107,7 +111,7 @@ func TestArgon2IDWrongParameters(t *testing.T) {
{
name: "Fault test, version is 18",
argonString: "$argon2id$v=18$m=10,t=2,p=1$SVJYMU1hdXB4czFTT3E4dw$+KPtJ/q0tnhCck+sbDva6g",
err: "invalid version",
err: "invalid input format",
},
{
name: "Fault test, version is asdasd",
Expand Down Expand Up @@ -159,6 +163,11 @@ func TestArgon2IDWrongParameters(t *testing.T) {
argonString: "$argon2id$v=19$m=10,t=2,p=asr$SVJYMU1hdXB4czFTT3E4dw$+KPtJ/q0tnhCck+sbDva6g",
err: "invalid input format",
},
{
name: "Fault test, salt is shorter than 16 bytes",
argonString: "$argon2id$v=19$m=10,t=2,p=1$pB2aWKPIqITWA7tofI9y$+KPtJ/q0tnhCck+sbDva6g",
err: "salt must be 16 byte long",
},
}

for _, tt := range tests {
Expand Down

0 comments on commit 1ba10e6

Please sign in to comment.