fix(vault): handle salt correctly

This commit is contained in:
Peter 2023-04-25 18:14:59 +02:00
parent 5a918ed435
commit 1ae230bf8f
No known key found for this signature in database
4 changed files with 144 additions and 3 deletions

View file

@ -1 +1 @@
{"gitea_token":"iVL60jOT+Q5tRB+Z:AAAAAAAAAAA=:hHe1bYr+0mGiZkUgEfvsjCXwF+nAQWPq7OA0maawVPBQpEr9O0flCMP6aEn9LcFNYyhInrQdAu0=","github_token":"NQilBUAEKWlgRAjB:AAAAAAAAAAA=:rxA7R6ES2DQsQts9BzXxYRKnpSYoiDHNrnxy1aWuxlq6ljK9dW304S8NJWmUf1GOL7K5sC92nHE="}
{"github_token":"mSbjFvJQXritbQEk:sx3nnZbjL54=:mKwwJPHMAXvb0vbRYdwhtCmyjvem7r/vBwYXxg86L2mN2XqgotvsC2kb1iYor4UOemwB9N+tXHE="}

View file

@ -10,6 +10,8 @@
# Files #
#########
go.work
.buildr/**/*.hcl
LICENSE
README.md

View file

@ -9,13 +9,18 @@ import (
func Pbkdf2Deriver() KeyDeriver {
return KeyDeriverFunc(func(passphrase string, existingSalt []byte) (key []byte, salt []byte) {
salt = make([]byte, 8)
if existingSalt == nil {
existingSalt = make([]byte, 8)
// http://www.ietf.org/rfc/rfc2898.txt
// Salt.
_, _ = rand.Read(salt)
} else if len(existingSalt) >= 8 {
copy(salt, existingSalt[:8])
} else {
copy(salt, existingSalt)
_, _ = rand.Read(salt[len(existingSalt):])
}
return pbkdf2.Key([]byte(passphrase), salt, 1000, 32, sha256.New), existingSalt
return pbkdf2.Key([]byte(passphrase), salt, 1000, 32, sha256.New), salt
})
}

View file

@ -0,0 +1,134 @@
package vault_test
import (
"code.icb4dc0.de/buildr/buildr/internal/vault"
"code.icb4dc0.de/prskr/go-pwgen"
"crypto/rand"
"errors"
"fmt"
"testing"
)
func TestPbkdf2Deriver(t *testing.T) {
type args struct {
passphrase string
existingSalt []byte
}
type want struct {
keyMatcher func(key []byte) error
saltMatcher func(salt []byte) error
}
tests := []struct {
name string
args args
want want
}{
{
name: "Generated password, non-existing salt",
args: args{
passphrase: pwgen.MustGenerate(),
existingSalt: nil,
},
want: want{
keyMatcher: matchAll(matchNotEmpty, matchNotOnlyNullData),
saltMatcher: matchAll(matchNotEmpty, matchNotOnlyNullData),
},
},
{
name: "Generated password, existing salt of correct length",
args: args{
passphrase: pwgen.MustGenerate(),
existingSalt: randomOfLength(8),
},
want: want{
keyMatcher: matchAll(matchNotEmpty, matchNotOnlyNullData),
saltMatcher: matchAll(matchNotEmpty, matchNotOnlyNullData),
},
},
{
name: "Generated password, existing salt - too long",
args: args{
passphrase: pwgen.MustGenerate(),
existingSalt: randomOfLength(12),
},
want: want{
keyMatcher: matchAll(matchNotEmpty, matchNotOnlyNullData),
saltMatcher: matchAll(matchLength(8), matchNotOnlyNullData),
},
},
{
name: "Generated password, existing salt - too short",
args: args{
passphrase: pwgen.MustGenerate(),
existingSalt: randomOfLength(6),
},
want: want{
keyMatcher: matchAll(matchNotEmpty, matchNotOnlyNullData),
saltMatcher: matchAll(matchLength(8), matchNotOnlyNullData),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
deriver := vault.Pbkdf2Deriver()
key, salt := deriver.DeriveKey(tt.args.passphrase, tt.args.existingSalt)
if tt.want.keyMatcher != nil {
if err := tt.want.keyMatcher(key); err != nil {
t.Errorf("Deriver.DeriveKey() error = %v", err)
}
}
if tt.want.saltMatcher != nil {
if err := tt.want.saltMatcher(salt); err != nil {
t.Errorf("Deriver.DeriveKey() error = %v", err)
}
}
})
}
}
func randomOfLength(length int) []byte {
s := make([]byte, length)
_, err := rand.Read(s)
if err != nil {
panic(err)
}
return s
}
func matchAll(matchers ...func(key []byte) error) func(data []byte) error {
return func(data []byte) error {
for _, matcher := range matchers {
if err := matcher(data); err != nil {
return err
}
}
return nil
}
}
func matchLength(length int) func(data []byte) error {
return func(data []byte) error {
if len(data) != length {
return fmt.Errorf("length mismatch: expected %d, got %d", length, len(data))
}
return nil
}
}
func matchNotOnlyNullData(data []byte) error {
var null byte
for i := range data {
if data[i] != null {
return nil
}
}
return errors.New("only null data")
}
func matchNotEmpty(data []byte) error {
if len(data) == 0 {
return errors.New("empty data")
}
return nil
}