buildr/internal/vault/pbkdf2_test.go
Peter 1261932bdc
All checks were successful
continuous-integration/drone/push Build is passing
refactor: apply golangci-lint findings
2023-06-22 19:16:00 +02:00

140 lines
3 KiB
Go

package vault_test
import (
"crypto/rand"
"errors"
"fmt"
"testing"
"code.icb4dc0.de/prskr/go-pwgen"
"code.icb4dc0.de/buildr/buildr/internal/vault"
)
func TestPbkdf2Deriver(t *testing.T) {
t.Parallel()
type args struct {
passphrase string
existingSalt []byte
}
type want struct {
keyMatcher func(key []byte) error
saltMatcher func(salt []byte) error
}
tests := []struct {
want want
name string
args args
}{
{
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 {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
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
}