Skip to content

Commit ec60388

Browse files
authored
argon2id: strengthen parameters based on RFC recommendations (#3)
The new parameters are a little more conservative than the [recommendations](https://www.rfc-editor.org/rfc/rfc9106.html#name-parameter-choice) in rfc9106.
1 parent 497e570 commit ec60388

File tree

4 files changed

+31
-25
lines changed

4 files changed

+31
-25
lines changed

.github/workflows/go.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
run: go build -v ./...
2727

2828
- name: Test
29-
run: go test -race -v ./...
29+
run: go test -v ./...
3030

3131
- name: Benchmark
3232
run: go test -bench=. -run=XXX -benchmem -v ./...

README.md

+14-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1-
# Age Key Derivation - Go
1+
# Age (Deterministic) Key Derivation
22

33
[![Go Reference](https://pkg.go.dev/badge/github.com/awnumar/agekd.svg)](https://pkg.go.dev/github.com/awnumar/agekd) [![Go workflow](https://github.com/awnumar/agekd/actions/workflows/go.yml/badge.svg?branch=main)](https://github.com/awnumar/agekd/actions/workflows/go.yml)
44

5-
6-
7-
`agekd` is a Go library that can be used to derive [`age`](https://github.com/FiloSottile/age) X25519 identities deterministically from keys or passwords.
5+
AgeKD is a Go library that can be used to derive [`age`](https://github.com/FiloSottile/age) X25519 identities deterministically from keys or passwords.
86

97
This package **does not** provide a CLI. If you need that functionality, check out [age-keygen-deterministic](https://github.com/keisentraut/age-keygen-deterministic).
108

119
See the upstream `age` [documentation](https://pkg.go.dev/filippo.io/age) for further guidance on working with `age` identities and recipients.
1210

1311
### **This package is currently pre-v1 and is therefore subject to breaking changes.**
1412

13+
## When would you use this?
14+
15+
- You already have key material and want to use it for age operations.
16+
- Your execution environment has the capability to generate cryptographically secure keys, but it prevents your program from persisting custom keys (such as a Kubernetes pod using Hashicorp Vault).
17+
- You want to programmatically derive age identities from passwords.
18+
1519
## Installation
1620

1721
Inside your project folder, run:
@@ -44,20 +48,22 @@ To generate an age identity from a password:
4448
identity, err := agekd.X25519IdentityFromPassword(key, nil)
4549
```
4650

47-
The default Argon2id settings are:
51+
The default Argon2id parameters are:
4852

4953
```go
50-
DefaultArgon2idTime uint32 = 8
51-
DefaultArgon2idMemory uint32 = 500000 // KiB = 512 MB
54+
DefaultArgon2idTime uint32 = 4
55+
DefaultArgon2idMemory uint32 = 6291456 // KiB = 6 GiB
5256
DefaultArgon2idThreads uint8 = 8
5357
```
5458

55-
but you can provide your own with:
59+
which takes ~3s per hash on an AMD 5800X3D 8-Core CPU. You can select your own parameters with:
5660

5761
```go
5862
identity, err := agekd.X25519IdentityFromPasswordWithParameters(key, nil, time, memory, threads)
5963
```
6064

65+
For guidance on Argon2id parameter selection, refer to [rfc9106](https://www.rfc-editor.org/rfc/rfc9106.html#name-parameter-choice).
66+
6167
## Licensing
6268

6369
Unless otherwise specified within a file, this code is distributed under the [MIT license](/LICENSE).

keygen.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import (
1515
)
1616

1717
const (
18-
DefaultArgon2idTime uint32 = 8
19-
DefaultArgon2idMemory uint32 = 500000 // KiB = 512 MB
18+
DefaultArgon2idTime uint32 = 4
19+
DefaultArgon2idMemory uint32 = 6291456 // KiB = 6 GiB
2020
DefaultArgon2idThreads uint8 = 8
2121

2222
kdfLabel = "github.com/awnumar/agekd"

keygen_test.go

+14-14
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ func TestX25519IdentityFromKey(t *testing.T) {
5555
t.Fatalf("failed to create age identity: %v", err)
5656
}
5757
if id.String() != c.expID {
58-
t.Fatalf("age identity mismatch: expected '%s' got '%s'", c.expID, id.String())
58+
t.Errorf("age identity mismatch: expected '%s' got '%s'", c.expID, id.String())
5959
}
6060
if id.Recipient().String() != c.expRcp {
61-
t.Fatalf("age recipient mismatch: expected '%s' got '%s'", c.expRcp, id.Recipient().String())
61+
t.Errorf("age recipient mismatch: expected '%s' got '%s'", c.expRcp, id.Recipient().String())
6262
}
6363
}
6464
}
@@ -73,32 +73,32 @@ func TestX25519IdentityFromPassword(t *testing.T) {
7373
{
7474
key: []byte{},
7575
salt: []byte{},
76-
expID: "AGE-SECRET-KEY-1P4J8RZE9G8EQ559XYDX024NV57DMXH0YAJUFJLH87FVNFXAWPUVQVGGSK8",
77-
expRcp: "age15mehx5d4xvxfmfygc8ndx5acvy294d5j77dlwfc7ylty8hdm5uws8gfam5",
76+
expID: "AGE-SECRET-KEY-1XXCW4ETUT4MSM92U4HG54ULW2E44ZQQSPUJAN4HUDZLHA70GS3RQL7TCTC",
77+
expRcp: "age12c2ewvhx08mjf6d3hs5d7afqv7w36mddfspe69dzam4fu2g04vnsd0t96t",
7878
},
7979
{
8080
key: nil,
8181
salt: nil,
82-
expID: "AGE-SECRET-KEY-1P4J8RZE9G8EQ559XYDX024NV57DMXH0YAJUFJLH87FVNFXAWPUVQVGGSK8",
83-
expRcp: "age15mehx5d4xvxfmfygc8ndx5acvy294d5j77dlwfc7ylty8hdm5uws8gfam5",
82+
expID: "AGE-SECRET-KEY-1XXCW4ETUT4MSM92U4HG54ULW2E44ZQQSPUJAN4HUDZLHA70GS3RQL7TCTC",
83+
expRcp: "age12c2ewvhx08mjf6d3hs5d7afqv7w36mddfspe69dzam4fu2g04vnsd0t96t",
8484
},
8585
{
8686
key: []byte("hello"),
8787
salt: nil,
88-
expID: "AGE-SECRET-KEY-1CW8DLMQEKF4E7KZ7DS4EZFHRRXKRYU0LM3JG4DZCYAC8W34DLLXQ84HR66",
89-
expRcp: "age1vp667dwd3m49hvg2dzczgnj4ht6cx9rzualmlgkycglh70z4uexqp33cnm",
88+
expID: "AGE-SECRET-KEY-1K7WJRLRK7K5P5V9W5G97TJMHJPNSKKA5AC24P0CTGZ95F5F4SUVSRSL68A",
89+
expRcp: "age1lczf85u63y4r66638spjwgkrjv6smk2zejxwuzfy39sunvgqkaqqss52s0",
9090
},
9191
{
9292
key: []byte("hello"),
9393
salt: []byte("bye"),
94-
expID: "AGE-SECRET-KEY-1SR0LU44D700Q7SNH9XQX4V626N69VJZ275NZ6R98NRQYKRAKUYNS453D3Y",
95-
expRcp: "age1stylxkt70m49q2n0vxarxqx9ncmvu5zswuddja6wfet9r8me0c5s225387",
94+
expID: "AGE-SECRET-KEY-10UGH6AS5STGZ8XMT8AVD2HF25A2K429PE45N66H5CZ3ADCLFD6JQL2G4VR",
95+
expRcp: "age12cq55rlgnwu6arszt6nde2uawsm8enndeuey2ku89vn5tp6mvd0sxf86xw",
9696
},
9797
{
9898
key: []byte{125, 231, 97, 121, 25, 36, 248, 109, 22, 245, 220, 7, 19, 151, 123, 246, 40, 27, 194, 4, 133, 222, 108, 216, 32, 162, 132, 16, 142, 151, 22, 104},
9999
salt: []byte{62, 98, 62, 226, 73, 49, 93, 5, 172, 234, 232, 145, 139, 78, 172, 4, 139, 156, 74, 57, 215, 32, 72, 216, 17, 74, 220, 250, 146, 3, 190, 254},
100-
expID: "AGE-SECRET-KEY-1SK248UN253DWHNRQQR63A0C652V387ER95A5Q50F5HZEW8EHTR7STWH8EN",
101-
expRcp: "age12rxldhqtm073ee845rgvencv79dyy4aykd4qc7a7tnex8m33jvqq494kpa",
100+
expID: "AGE-SECRET-KEY-1M4MPJEN0HX2XA8TSCS7LP03NG5KWKELEEKZSCSCXLGZKYRZVNK8STKWQMQ",
101+
expRcp: "age1m5mpdh9jact30wcfujykt7fad405vhzwdjcx2nrxj3ljh8n2kcgs9e92fs",
102102
},
103103
}
104104
for _, c := range testCases {
@@ -107,10 +107,10 @@ func TestX25519IdentityFromPassword(t *testing.T) {
107107
t.Fatalf("failed to create age identity: %v", err)
108108
}
109109
if id.String() != c.expID {
110-
t.Fatalf("age identity mismatch: expected '%s' got '%s'", c.expID, id.String())
110+
t.Errorf("age identity mismatch: expected '%s' got '%s'", c.expID, id.String())
111111
}
112112
if id.Recipient().String() != c.expRcp {
113-
t.Fatalf("age recipient mismatch: expected '%s' got '%s'", c.expRcp, id.Recipient().String())
113+
t.Errorf("age recipient mismatch: expected '%s' got '%s'", c.expRcp, id.Recipient().String())
114114
}
115115
id2, err := X25519IdentityFromPasswordWithParameters(c.key, c.salt, DefaultArgon2idTime, DefaultArgon2idMemory, DefaultArgon2idThreads)
116116
if err != nil {

0 commit comments

Comments
 (0)