package services import ( "bytes" "crypto/rand" "encoding/hex" "testing" ) // validTestKey returns a deterministic 64-char hex key for tests. func validTestKey() string { return "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" } // randomHexKey generates a random 64-char hex key. func randomHexKey(t *testing.T) string { t.Helper() b := make([]byte, 32) if _, err := rand.Read(b); err != nil { t.Fatal(err) } return hex.EncodeToString(b) } func TestNewEncryptionService_Valid(t *testing.T) { svc, err := NewEncryptionService(validTestKey()) if err != nil { t.Fatalf("unexpected error: %v", err) } if svc == nil { t.Fatal("expected non-nil service") } } func TestNewEncryptionService_InvalidHex(t *testing.T) { // 64 chars but not valid hex _, err := NewEncryptionService("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz") if err == nil { t.Fatal("expected error for invalid hex") } } func TestNewEncryptionService_WrongLength(t *testing.T) { tests := []struct { name string key string }{ {"too short", "0123456789abcdef"}, {"too long", "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef00"}, {"empty", ""}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err := NewEncryptionService(tt.key) if err == nil { t.Fatal("expected error for wrong length key") } }) } } func TestEncryptDecrypt_RoundTrip(t *testing.T) { svc, err := NewEncryptionService(validTestKey()) if err != nil { t.Fatal(err) } plaintext := []byte("Hello, encryption at rest!") ciphertext, err := svc.Encrypt(plaintext) if err != nil { t.Fatalf("encrypt failed: %v", err) } decrypted, err := svc.Decrypt(ciphertext) if err != nil { t.Fatalf("decrypt failed: %v", err) } if !bytes.Equal(plaintext, decrypted) { t.Fatalf("round-trip mismatch: got %q, want %q", decrypted, plaintext) } } func TestEncryptDecrypt_EmptyPlaintext(t *testing.T) { svc, err := NewEncryptionService(validTestKey()) if err != nil { t.Fatal(err) } ciphertext, err := svc.Encrypt([]byte{}) if err != nil { t.Fatalf("encrypt failed: %v", err) } decrypted, err := svc.Decrypt(ciphertext) if err != nil { t.Fatalf("decrypt failed: %v", err) } if len(decrypted) != 0 { t.Fatalf("expected empty plaintext, got %d bytes", len(decrypted)) } } func TestEncrypt_DifferentCiphertexts(t *testing.T) { svc, err := NewEncryptionService(validTestKey()) if err != nil { t.Fatal(err) } plaintext := []byte("same input") ct1, err := svc.Encrypt(plaintext) if err != nil { t.Fatal(err) } ct2, err := svc.Encrypt(plaintext) if err != nil { t.Fatal(err) } if bytes.Equal(ct1, ct2) { t.Fatal("encrypting the same plaintext twice should produce different ciphertexts") } } func TestDecrypt_TamperDetection(t *testing.T) { svc, err := NewEncryptionService(validTestKey()) if err != nil { t.Fatal(err) } ciphertext, err := svc.Encrypt([]byte("sensitive data")) if err != nil { t.Fatal(err) } // Flip a byte near the end (in the ciphertext portion) tampered := make([]byte, len(ciphertext)) copy(tampered, ciphertext) tampered[len(tampered)-1] ^= 0xFF _, err = svc.Decrypt(tampered) if err == nil { t.Fatal("expected error when decrypting tampered ciphertext") } } func TestDecrypt_WrongKEK(t *testing.T) { svc1, err := NewEncryptionService(validTestKey()) if err != nil { t.Fatal(err) } ciphertext, err := svc1.Encrypt([]byte("secret")) if err != nil { t.Fatal(err) } // Create a second service with a different key svc2, err := NewEncryptionService(randomHexKey(t)) if err != nil { t.Fatal(err) } _, err = svc2.Decrypt(ciphertext) if err == nil { t.Fatal("expected error when decrypting with wrong KEK") } } func TestDecrypt_TooShort(t *testing.T) { svc, err := NewEncryptionService(validTestKey()) if err != nil { t.Fatal(err) } _, err = svc.Decrypt([]byte("short")) if err == nil { t.Fatal("expected error for too-short ciphertext") } } func TestDecrypt_BadVersion(t *testing.T) { svc, err := NewEncryptionService(validTestKey()) if err != nil { t.Fatal(err) } ciphertext, err := svc.Encrypt([]byte("data")) if err != nil { t.Fatal(err) } // Change version byte ciphertext[0] = 0xFF _, err = svc.Decrypt(ciphertext) if err == nil { t.Fatal("expected error for bad version") } } func TestIsEnabled(t *testing.T) { svc, err := NewEncryptionService(validTestKey()) if err != nil { t.Fatal(err) } if !svc.IsEnabled() { t.Fatal("expected IsEnabled() to return true") } var nilSvc *EncryptionService if nilSvc.IsEnabled() { t.Fatal("expected IsEnabled() to return false for nil service") } }