Write generated configs 0600, treat new keys as raw AES-256, keep PBKDF2 for unprefixed material, and cache derivation at startup.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -240,3 +242,95 @@ func TestConstantTimeCompare(t *testing.T) {
|
||||
t.Error("Empty slices should compare equal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveKeyRaw(t *testing.T) {
|
||||
raw, err := GenerateRawKey()
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateRawKey: %v", err)
|
||||
}
|
||||
if !IsRawKey(raw) {
|
||||
t.Fatalf("generated key is not raw: %q", raw[:4])
|
||||
}
|
||||
key, err := ResolveKey(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveKey raw: %v", err)
|
||||
}
|
||||
if len(key) != 32 {
|
||||
t.Fatalf("raw key length %d", len(key))
|
||||
}
|
||||
decoded, err := hex.DecodeString(raw[len(RawKeyPrefix):])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(key, decoded) {
|
||||
t.Fatal("raw key was not hex-decoded as-is")
|
||||
}
|
||||
if bytes.Equal(key, DeriveKey(raw)) {
|
||||
t.Fatal("raw key must not go through PBKDF2")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveKeyLegacyHexStillPBKDF2(t *testing.T) {
|
||||
legacy := "a0e3dd20a761b118ca234160dd8b87230a001e332a97c9cfe3b8b9c99efaae03"
|
||||
decoded, err := hex.DecodeString(legacy)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := ResolveKey(legacy)
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveKey legacy hex: %v", err)
|
||||
}
|
||||
want := DeriveKey(legacy)
|
||||
if !bytes.Equal(got, want) {
|
||||
t.Fatal("unprefixed 64-hex must still use PBKDF2 (old --generate-key configs)")
|
||||
}
|
||||
if bytes.Equal(got, decoded) {
|
||||
t.Fatal("unprefixed 64-hex must not be treated as a raw AES key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveKeyPassphrase(t *testing.T) {
|
||||
pw := "test-passphrase-not-a-hex-key-value"
|
||||
got, err := ResolveKey(pw)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(got, DeriveKey(pw)) {
|
||||
t.Fatal("passphrase should use PBKDF2")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeriveKeyCached(t *testing.T) {
|
||||
pw := "cache-me-please-this-is-long-enough"
|
||||
start := time.Now()
|
||||
k1 := DeriveKey(pw)
|
||||
first := time.Since(start)
|
||||
start = time.Now()
|
||||
k2 := DeriveKey(pw)
|
||||
second := time.Since(start)
|
||||
if !bytes.Equal(k1, k2) {
|
||||
t.Fatal("cached key mismatch")
|
||||
}
|
||||
if first < 10*time.Millisecond {
|
||||
t.Logf("first PBKDF2 unexpectedly fast: %v", first)
|
||||
}
|
||||
if second > 5*time.Millisecond {
|
||||
t.Fatalf("cached DeriveKey too slow: first=%v second=%v", first, second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateRawEncryptionKey(t *testing.T) {
|
||||
raw, err := GenerateRawKey()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ValidateEncryptionKey(raw); err != nil {
|
||||
t.Fatalf("valid raw key rejected: %v", err)
|
||||
}
|
||||
if err := ValidateEncryptionKey("raw:not-hex"); err == nil {
|
||||
t.Fatal("invalid raw hex should fail")
|
||||
}
|
||||
if err := ValidateEncryptionKey("raw:abcd"); err == nil {
|
||||
t.Fatal("short raw key should fail")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user