diff --git a/argon2i.go b/argon2i.go index 937d257..c948b28 100644 --- a/argon2i.go +++ b/argon2i.go @@ -35,14 +35,13 @@ const ( argon2iDefaultMemory = 32 * 1024 argon2iDefaultTime = 4 argon2iDefaultThreads = 4 - argon2iKeySize = 32 + argon2iDefaultKeySize = 32 argon2iDefaultSaltSize = 16 - argon2iMaxSaltSize = 16 // 0xFFFFFFFF ) // Argon2iSettings returns argon2i settings with the provided parameter. -func Argon2iSettings(m, t, p int, salts ...string) (string, error) { - settings := fmt.Sprintf("%sv=19$m=%d,t=%d,p=%d", Argon2iPrefix, m, t, p) +func Argon2iSettings(m, t, p, k int, salts ...string) (string, error) { + settings := fmt.Sprintf("%sv=19$m=%d,t=%d,p=%d,k=%d", Argon2iPrefix, m, t, p, k) salt := strings.Join(salts, "") if salt == "" { b := make([]byte, argon2iDefaultSaltSize) @@ -68,14 +67,12 @@ func argon2iAlgorithm(password, settings string) (string, error) { return "", fmt.Errorf("base64 decode [%s]: %v", salt, err) } } - if len(saltBytes) > argon2iMaxSaltSize { - saltBytes = saltBytes[:argon2iMaxSaltSize] - } memory := parameter.GetInt("m", argon2iDefaultMemory) time := parameter.GetInt("t", argon2iDefaultTime) threads := parameter.GetInt("p", argon2iDefaultThreads) + keySize := parameter.GetInt("k", argon2iDefaultKeySize) - hash := argon2.Key(passwordBytes, saltBytes, uint32(time), uint32(memory), uint8(threads), argon2iKeySize) + hash := argon2.Key(passwordBytes, saltBytes, uint32(time), uint32(memory), uint8(threads), uint32(keySize)) p := []string{} if memory != argon2iDefaultMemory { @@ -87,6 +84,9 @@ func argon2iAlgorithm(password, settings string) (string, error) { if threads != argon2iDefaultThreads { p = append(p, "p="+strconv.Itoa(threads)) } + if keySize != argon2iDefaultKeySize { + p = append(p, "k="+strconv.Itoa(keySize)) + } buf := bytes.Buffer{} buf.Write([]byte(Argon2iPrefix)) diff --git a/argon2i_test.go b/argon2i_test.go index 012bea5..f33e29c 100644 --- a/argon2i_test.go +++ b/argon2i_test.go @@ -33,22 +33,30 @@ func TestArgon2i(t *testing.T) { } } - t.Run(testFn("generate salt", "$argon2i$v=19$m=65536,t=2,p=4$", "$argon2i$v=19$m=65536,t=2$", nil)) - t.Run(testFn("password", "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ", "$argon2i$v=19$m=65536,t=2$c29tZXNhbHQ$IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4", nil)) - t.Run(testFn("another password", "$argon2i$v=19$m=65536,t=2,p=4$YW5vdGhlcnNhbHQ", "$argon2i$v=19$m=65536,t=2$YW5vdGhlcnNhbHQ$BCRltpeTFX0QYrELiOXWGZniID9nOUsBPy8Bu0SE7bM", nil)) - t.Run(testFn("password", "$argon2i$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc", "$argon2i$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdA$8BZnxCqANQ3mGYITjgezarZ/b5vivfVRVy3cWwwXGHI", nil)) - t.Run(testFn("ignore-hash-in-settings", "$argon2i$v=19$m=65536,t=2$bG9uZ3NhbHRsb25nc2FsdGxvbmc$rDmQABiNkSO3bGHbBUkShgb7wIlBP8HHfq6nDH+Sqss", "$argon2i$v=19$m=65536,t=2$bG9uZ3NhbHRsb25nc2FsdA$Cfa1JVLA/wGtR7UeWI+Q+ZOfMmyPchePKy2h+kjryG8", nil)) - t.Run(testFn("password", "$argon2i$v=19$m=65536,t=3,p=1$bG9uZ3NhbHRsb25nc2FsdA", "$argon2i$v=19$m=65536,t=3,p=1$bG9uZ3NhbHRsb25nc2FsdA$K2rLfVoQG17LuUn26otasTX1WBXjr6hi5NZXKKxmYrs", nil)) + t.Run(testFn("generate salt", "$argon2i$v=19$m=65536,t=2,p=4$", + "$argon2i$v=19$m=65536,t=2$", nil)) + t.Run(testFn("password", "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ", + "$argon2i$v=19$m=65536,t=2$c29tZXNhbHQ$IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4", nil)) + t.Run(testFn("another password", "$argon2i$v=19$m=65536,t=2,p=4$YW5vdGhlcnNhbHQ", + "$argon2i$v=19$m=65536,t=2$YW5vdGhlcnNhbHQ$BCRltpeTFX0QYrELiOXWGZniID9nOUsBPy8Bu0SE7bM", nil)) + t.Run(testFn("password", "$argon2i$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc", + "$argon2i$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc$N2zfK+oCIRMbTX04zZS4X2uLKX3SK0KkNxyCw/NURrU", nil)) + t.Run(testFn("ignore-hash-in-settings", "$argon2i$v=19$m=65536,t=2$bG9uZ3NhbHRsb25nc2FsdGxvbmc$rDmQABiNkSO3bGHbBUkShgb7wIlBP8HHfq6nDH+Sqss", + "$argon2i$v=19$m=65536,t=2$bG9uZ3NhbHRsb25nc2FsdGxvbmc$xY9IRFH+zQduVUYoZfSoT6tylET3/AUIOMS3rFF0x0o", nil)) + t.Run(testFn("password", "$argon2i$v=19$m=65536,t=3,p=1$bG9uZ3NhbHRsb25nc2FsdA", + "$argon2i$v=19$m=65536,t=3,p=1$bG9uZ3NhbHRsb25nc2FsdA$K2rLfVoQG17LuUn26otasTX1WBXjr6hi5NZXKKxmYrs", nil)) + t.Run(testFn("password", "$argon2i$v=19$m=65536,t=3,p=1,k=64$bG9uZ3NhbHRsb25nc2FsdA", + "$argon2i$v=19$m=65536,t=3,p=1,k=64$bG9uZ3NhbHRsb25nc2FsdA$7DnJ2B7gxZDMEk+HVNDpIuTtOxDkwDaA0IhvuiBn9oeBTXpqBPxP9iro2cPiFongTwoFHHpVrqiL8JvMXrb63Q", nil)) } func TestArgon2iSettings(t *testing.T) { - testFn := func(m, t, p int, expectSettingsPrefix string) (string, func(*testing.T)) { - return fmt.Sprintf("m=%d,t=%d,p=%d", m, t, p), func(tt *testing.T) { - settings, err := crypt.Argon2iSettings(m, t, p) + testFn := func(m, t, p, k int, expectSettingsPrefix string) (string, func(*testing.T)) { + return fmt.Sprintf("m=%d,t=%d,p=%d,k=%d", m, t, p, k), func(tt *testing.T) { + settings, err := crypt.Argon2iSettings(m, t, p, k) require.NoError(tt, err) assert.True(tt, strings.HasPrefix(settings, expectSettingsPrefix)) } } - t.Run(testFn(65536, 2, 4, "$argon2i$v=19$m=65536,t=2,p=4")) + t.Run(testFn(65536, 2, 4, 64, "$argon2i$v=19$m=65536,t=2,p=4,k=64")) } diff --git a/argon2id.go b/argon2id.go index 7850668..50d8ecf 100644 --- a/argon2id.go +++ b/argon2id.go @@ -39,13 +39,13 @@ const ( argon2idDefaultMemory = 32 * 1024 argon2idDefaultTime = 1 argon2idDefaultThreads = 4 - argon2idKeySize = 32 + argon2idDefaultKeySize = 32 argon2idDefaultSaltSize = 16 ) // Argon2idSettings returns argon2id settings with the provided parameter. -func Argon2idSettings(m, t, p int, salts ...string) (string, error) { - settings := fmt.Sprintf("%sv=19$m=%d,t=%d,p=%d", Argon2idPrefix, m, t, p) +func Argon2idSettings(m, t, p, k int, salts ...string) (string, error) { + settings := fmt.Sprintf("%sv=19$m=%d,t=%d,p=%d,k=%d", Argon2idPrefix, m, t, p, k) salt := strings.Join(salts, "") if salt == "" { b := make([]byte, argon2idDefaultSaltSize) @@ -74,16 +74,31 @@ func argon2idAlgorithm(password, settings string) (string, error) { memory := parameter.GetInt("m", argon2idDefaultMemory) time := parameter.GetInt("t", argon2idDefaultTime) threads := parameter.GetInt("p", argon2idDefaultThreads) + keySize := parameter.GetInt("k", argon2idDefaultKeySize) - hash := argon2.IDKey(passwordBytes, saltBytes, uint32(time), uint32(memory), uint8(threads), argon2idKeySize) + hash := argon2.IDKey(passwordBytes, saltBytes, uint32(time), uint32(memory), uint8(threads), uint32(keySize)) + + p := []string{} + if memory != argon2iDefaultMemory { + p = append(p, "m="+strconv.Itoa(memory)) + } + if time != argon2iDefaultTime { + p = append(p, "t="+strconv.Itoa(time)) + } + if threads != argon2iDefaultThreads { + p = append(p, "p="+strconv.Itoa(threads)) + } + if keySize != argon2iDefaultKeySize { + p = append(p, "k="+strconv.Itoa(keySize)) + } buf := bytes.Buffer{} - buf.Write([]byte(Argon2idPrefix)) + buf.Write([]byte(Argon2iPrefix)) buf.WriteString("v=19$") - buf.WriteString("m="+strconv.Itoa(memory)+",") - buf.WriteString("t="+strconv.Itoa(time)+",") - buf.WriteString("p="+strconv.Itoa(threads)) - buf.WriteString("$") + if len(p) > 0 { + buf.WriteString(strings.Join(p, ",")) + buf.WriteString("$") + } buf.WriteString(Base64Encoding.EncodeToString(saltBytes)) buf.WriteString("$") buf.WriteString(Base64Encoding.EncodeToString(hash)) diff --git a/argon2id_test.go b/argon2id_test.go index cea54e5..a95e81f 100644 --- a/argon2id_test.go +++ b/argon2id_test.go @@ -25,74 +25,38 @@ import ( ) func TestArgon2id(t *testing.T) { - tcs := []struct { - password string - settings string - expectedResult string - expectedErr error - }{ - { - "generate salt", - "$argon2id$v=19$m=65536,t=2,p=4$", - "$argon2id$v=19$m=65536,t=2,p=4$", - nil, - }, - { - "password", // salt = somesalt - "$argon2id$v=19$m=65536,t=2,p=4$c29tZXNhbHQ", - "$argon2id$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$GpZ3sK/oH9p7VIiV56G/64Zo/8GaUw434IimaPqxwCo", - nil, - }, - { - "another password", // salt = anothersalt - "$argon2id$v=19$m=65536,t=2,p=4$YW5vdGhlcnNhbHQ", - "$argon2id$v=19$m=65536,t=2,p=4$YW5vdGhlcnNhbHQ$ZU9gSnQfqeEZG2Wu6Wq9pek2UAttI/N8NLCEecVBRZc", - nil, - }, - { - "password", // salt = longsaltlongsaltlong - "$argon2id$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc", - "$argon2id$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc$y3Tz6SCUIw7occvkgsUYx0hwaePXLus7rxUzsOghhnE", - nil, - }, - { - "ignore-hash-in-settings", // salt = longsaltlongsaltlong - "$argon2id$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc$y3Tz6SCUIw7occvkgsUYx0hwaePXLus7rxUzsOghhnE", - "$argon2id$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc$sToxuMqIBNNRYEPy2Gh690R7qa7mkhJ627ciTZdyQSA", - nil, - }, - { - "password", // salt = longsaltlongsalt - "$argon2id$v=19$m=65536,t=3,p=1$bG9uZ3NhbHRsb25nc2FsdA", - "$argon2id$v=19$m=65536,t=3,p=1$bG9uZ3NhbHRsb25nc2FsdA$SHogC8dbNGlyrOIJTrZ4f0/r/ZmTglvCx4u5GUzw6EM", - nil, - }, + testFn := func(password, settings, expectResult string, expectErr error) (string, func(*testing.T)) { + return settings, func(t *testing.T) { + result, err := crypt.Crypt(password, settings) + require.Equal(t, expectErr, err) + assert.True(t, strings.HasPrefix(result, expectResult), "expected prefix %q, got %q", expectResult, result) + } } - for _, tc := range tcs { - t.Run(tc.settings, func(t *testing.T) { - result, err := crypt.Crypt(tc.password, tc.settings) - require.Equal(t, tc.expectedErr, err) - assert.True(t, strings.HasPrefix(result, tc.expectedResult), "expected prefix %q, got %q", tc.expectedResult, result) - }) - } + t.Run(testFn("generate salt", "$argon2id$v=19$m=65536,t=2,p=4$", + "$argon2i$v=19$m=65536,t=2$", nil)) + t.Run(testFn("password", "$argon2id$v=19$m=65536,t=2,p=4$c29tZXNhbHQ", + "$argon2i$v=19$m=65536,t=2$c29tZXNhbHQ$GpZ3sK/oH9p7VIiV56G/64Zo/8GaUw434IimaPqxwCo", nil)) + t.Run(testFn("another password", "$argon2id$v=19$m=65536,t=2,p=4$YW5vdGhlcnNhbHQ", + "$argon2i$v=19$m=65536,t=2$YW5vdGhlcnNhbHQ$ZU9gSnQfqeEZG2Wu6Wq9pek2UAttI/N8NLCEecVBRZc", nil)) + t.Run(testFn("password", "$argon2id$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc", + "$argon2i$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc$y3Tz6SCUIw7occvkgsUYx0hwaePXLus7rxUzsOghhnE", nil)) + t.Run(testFn("ignore-hash-in-settings", "$argon2id$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc$y3Tz6SCUIw7occvkgsUYx0hwaePXLus7rxUzsOghhnE", + "$argon2i$v=19$m=65536,t=2,p=1$bG9uZ3NhbHRsb25nc2FsdGxvbmc$sToxuMqIBNNRYEPy2Gh690R7qa7mkhJ627ciTZdyQSA", nil)) + t.Run(testFn("password", "$argon2id$v=19$m=65536,t=3,p=1$bG9uZ3NhbHRsb25nc2FsdA", + "$argon2i$v=19$m=65536,t=3,p=1$bG9uZ3NhbHRsb25nc2FsdA$SHogC8dbNGlyrOIJTrZ4f0/r/ZmTglvCx4u5GUzw6EM", nil)) + t.Run(testFn("password", "$argon2id$v=19$m=65536,t=3,p=1,k=64$bG9uZ3NhbHRsb25nc2FsdA", + "$argon2i$v=19$m=65536,t=3,p=1,k=64$bG9uZ3NhbHRsb25nc2FsdA$gaB/QbA34/AJkE/QbuEByjVhIF3sCvX+LHo8L3otGHhWh5q++cFMfidqGQd6qoGu3Qcm7LEPl8dQWMzyblYqYg", nil)) } func TestArgon2idSettings(t *testing.T) { - tcs := []struct { - m int - t int - p int - expectedSettingsPrefix string - }{ - {65536, 2, 4, "$argon2id$v=19$m=65536,t=2,p=4"}, + testFn := func(m, t, p, k int, expectSettingsPrefix string) (string, func(*testing.T)) { + return fmt.Sprintf("m=%d,t=%d,p=%d,k=%d", m, t, p, k), func(tt *testing.T) { + settings, err := crypt.Argon2idSettings(m, t, p, k) + require.NoError(tt, err) + assert.True(tt, strings.HasPrefix(settings, expectSettingsPrefix)) + } } - for _, tc := range tcs { - t.Run(fmt.Sprintf("m=%d,t=%d,p=%d", tc.m, tc.t, tc.p), func(t *testing.T) { - settings, err := crypt.Argon2idSettings(tc.m, tc.t, tc.p) - require.NoError(t, err) - assert.True(t, strings.HasPrefix(settings, tc.expectedSettingsPrefix)) - }) - } + t.Run(testFn(65536, 2, 4, 64, "$argon2id$v=19$m=65536,t=2,p=4,k=64")) } diff --git a/settings_test.go b/settings_test.go index a6588dc..46f9edc 100644 --- a/settings_test.go +++ b/settings_test.go @@ -40,6 +40,7 @@ func TestSettings(t *testing.T) { t.Run(testFn("$2a$08$ybX1Hjkb5N.8WEcYtBuB7u", "$2a$08$ybX1Hjkb5N.8WEcYtBuB7u")) t.Run(testFn("$2a$08$ybX1Hjkb5N.8WEcYtBuB7u$CMA/ViizL57cnTLOa5DiVM9e", "$2a$08$ybX1Hjkb5N.8WEcYtBuB7u")) t.Run(testFn("$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4", "$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ")) + t.Run(testFn("$argon2i$v=19$m=65536,t=2,p=4,k=64$c29tZXNhbHQ$IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4", "$argon2i$v=19$m=65536,t=2,p=4,k=64$c29tZXNhbHQ")) } func TestDecodeSettings(t *testing.T) { @@ -62,4 +63,5 @@ func TestDecodeSettings(t *testing.T) { t.Run(testFn("$1$rounds=300$salt$hash$", "1", crypt.Parameter{"rounds": "300"}, "salt", "hash", nil)) t.Run(testFn("$2a$08$ybX1Hjkb5N.8WEcYtBuB7u", "2a", crypt.Parameter{"cost": "8"}, "ybX1Hjkb5N.8WEcYtBuB7u", "", nil)) t.Run(testFn("$argon2i$v=19$m=65536,t=2,p=4$c29tZXNhbHQ$IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4", "argon2i", crypt.Parameter{"v": "19", "m": "65536", "t": "2", "p": "4"}, "c29tZXNhbHQ", "IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4", nil)) + t.Run(testFn("$argon2i$v=19$m=65536,t=2,p=4,k=64$c29tZXNhbHQ$IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4", "argon2i", crypt.Parameter{"v": "19", "m": "65536", "t": "2", "p": "4", "k": "64"}, "c29tZXNhbHQ", "IMit9qkFULCMA/ViizL57cnTLOa5DiVM9eMwpAvPwr4", nil)) }