diff --git a/pkg/crypt/crypt.go b/pkg/crypt/crypt.go index 0325385..bf1e059 100644 --- a/pkg/crypt/crypt.go +++ b/pkg/crypt/crypt.go @@ -3,6 +3,7 @@ package crypt import ( "crypto/md5" "crypto/sha1" + "errors" "crypto/sha256" "crypto/sha512" "encoding/binary" @@ -217,5 +218,8 @@ func (s *Service) VerifyPGP(publicKey, data, signature []byte) error { // SymmetricallyEncryptPGP encrypts data with a passphrase. func (s *Service) SymmetricallyEncryptPGP(passphrase, data []byte) ([]byte, error) { s.ensurePGP() + if len(passphrase) == 0 { + return nil, errors.New("passphrase cannot be empty") + } return s.pgp.SymmetricallyEncrypt(passphrase, data) } diff --git a/pkg/crypt/crypt_internal_test.go b/pkg/crypt/crypt_internal_test.go index 9ee8dd2..d389a52 100644 --- a/pkg/crypt/crypt_internal_test.go +++ b/pkg/crypt/crypt_internal_test.go @@ -6,8 +6,28 @@ import ( "github.com/stretchr/testify/assert" ) -func TestEnsureRSA(t *testing.T) { +// TestEnsureRSA_Good tests that the RSA service is initialized correctly. +func TestEnsureRSA_Good(t *testing.T) { s := &Service{} s.ensureRSA() assert.NotNil(t, s.rsa) } + +// TestEnsureRSA_Bad tests that calling ensureRSA multiple times does not change the RSA service. +func TestEnsureRSA_Bad(t *testing.T) { + s := &Service{} + s.ensureRSA() + rsa1 := s.rsa + s.ensureRSA() + rsa2 := s.rsa + assert.Same(t, rsa1, rsa2) +} + +// TestEnsureRSA_Ugly tests that ensureRSA works correctly on a service with a pre-initialized RSA service. +func TestEnsureRSA_Ugly(t *testing.T) { + s := NewService() // NewService initializes the RSA service + rsa1 := s.rsa + s.ensureRSA() + rsa2 := s.rsa + assert.Same(t, rsa1, rsa2) +} diff --git a/pkg/crypt/crypt_test.go b/pkg/crypt/crypt_test.go index 1184cf2..e741229 100644 --- a/pkg/crypt/crypt_test.go +++ b/pkg/crypt/crypt_test.go @@ -155,6 +155,63 @@ func TestPGP_Good(t *testing.T) { assert.NotNil(t, ciphertext) } +func TestPGP_Bad(t *testing.T) { + // Generate two key pairs + pubKey1, privKey1, err := service.GeneratePGPKeyPair("test1", "test1@test.com", "") + assert.NoError(t, err) + pubKey2, privKey2, err := service.GeneratePGPKeyPair("test2", "test2@test.com", "") + assert.NoError(t, err) + + message := []byte("secret message") + + // Test decryption with the wrong key + ciphertext, err := service.EncryptPGP(pubKey1, message) + assert.NoError(t, err) + // This should fail because we are using the wrong private key. + _, err = service.DecryptPGP(privKey2, ciphertext) // Intentionally using wrong key + assert.Error(t, err) + + // Test verification with the wrong key + signature, err := service.SignPGP(privKey1, message) + assert.NoError(t, err) + err = service.VerifyPGP(pubKey2, message, signature) + assert.Error(t, err) + + // Test verification with a tampered message + tamperedMessage := []byte("tampered message") + err = service.VerifyPGP(pubKey1, tamperedMessage, signature) + assert.Error(t, err) +} + +func TestPGP_Ugly(t *testing.T) { + // Test with malformed keys + _, err := service.EncryptPGP([]byte("not a real key"), []byte("message")) + assert.Error(t, err) + + _, err = service.DecryptPGP([]byte("not a real key"), []byte("message")) + assert.Error(t, err) + + _, err = service.SignPGP([]byte("not a real key"), []byte("message")) + assert.Error(t, err) + + err = service.VerifyPGP([]byte("not a real key"), []byte("message"), []byte("not a real signature")) + assert.Error(t, err) + + // Test with empty message + pubKey, privKey, err := service.GeneratePGPKeyPair("test", "test@test.com", "") + assert.NoError(t, err) + message := []byte("") + ciphertext, err := service.EncryptPGP(pubKey, message) + assert.NoError(t, err) + plaintext, err := service.DecryptPGP(privKey, ciphertext, ) + assert.NoError(t, err) + assert.Equal(t, message, plaintext) + + // Test symmetric encryption with empty passphrase + _, err = service.SymmetricallyEncryptPGP([]byte(""), message) + assert.Error(t, err) +} + // --- IsHashAlgo Tests --- func TestIsHashAlgo_Good(t *testing.T) { diff --git a/pkg/enchantrix/enchantrix_test.go b/pkg/enchantrix/enchantrix_test.go index 5c6af64..7d7c174 100644 --- a/pkg/enchantrix/enchantrix_test.go +++ b/pkg/enchantrix/enchantrix_test.go @@ -40,6 +40,21 @@ func TestTransmute_Bad(t *testing.T) { assert.Error(t, err) } +func TestTransmute_Ugly(t *testing.T) { + // Test with nil data + _, err := enchantrix.Transmute(nil, []enchantrix.Sigil{&enchantrix.ReverseSigil{}}) + assert.NoError(t, err) + + // Test with nil sigils + _, err = enchantrix.Transmute([]byte("hello"), nil) + assert.NoError(t, err) + + // Test with no sigils + result, err := enchantrix.Transmute([]byte("hello"), []enchantrix.Sigil{}) + assert.NoError(t, err) + assert.Equal(t, "hello", string(result)) +} + // --- Factory Tests --- func TestNewSigil_Good(t *testing.T) { @@ -63,3 +78,20 @@ func TestNewSigil_Bad(t *testing.T) { assert.Nil(t, sigil) assert.Contains(t, err.Error(), "unknown sigil name") } + +func TestNewSigil_Ugly(t *testing.T) { + // Test with empty string + sigil, err := enchantrix.NewSigil("") + assert.Error(t, err) + assert.Nil(t, sigil) + + // Test with whitespace + sigil, err = enchantrix.NewSigil(" ") + assert.Error(t, err) + assert.Nil(t, sigil) + + // Test with non-printable characters + sigil, err = enchantrix.NewSigil("\x00\x01\x02") + assert.Error(t, err) + assert.Nil(t, sigil) +} diff --git a/pkg/enchantrix/sigils.go b/pkg/enchantrix/sigils.go index 6fc5cfa..d63c475 100644 --- a/pkg/enchantrix/sigils.go +++ b/pkg/enchantrix/sigils.go @@ -26,6 +26,9 @@ type ReverseSigil struct{} // In reverses the bytes of the data. func (s *ReverseSigil) In(data []byte) ([]byte, error) { + if data == nil { + return nil, nil + } reversed := make([]byte, len(data)) for i, j := 0, len(data)-1; i < len(data); i, j = i+1, j-1 { reversed[i] = data[j] @@ -43,6 +46,9 @@ type HexSigil struct{} // In encodes the data to hexadecimal. func (s *HexSigil) In(data []byte) ([]byte, error) { + if data == nil { + return nil, nil + } dst := make([]byte, hex.EncodedLen(len(data))) hex.Encode(dst, data) return dst, nil @@ -50,6 +56,9 @@ func (s *HexSigil) In(data []byte) ([]byte, error) { // Out decodes the data from hexadecimal. func (s *HexSigil) Out(data []byte) ([]byte, error) { + if data == nil { + return nil, nil + } dst := make([]byte, hex.DecodedLen(len(data))) _, err := hex.Decode(dst, data) return dst, err @@ -60,6 +69,9 @@ type Base64Sigil struct{} // In encodes the data to base64. func (s *Base64Sigil) In(data []byte) ([]byte, error) { + if data == nil { + return nil, nil + } dst := make([]byte, base64.StdEncoding.EncodedLen(len(data))) base64.StdEncoding.Encode(dst, data) return dst, nil @@ -67,6 +79,9 @@ func (s *Base64Sigil) In(data []byte) ([]byte, error) { // Out decodes the data from base64. func (s *Base64Sigil) Out(data []byte) ([]byte, error) { + if data == nil { + return nil, nil + } dst := make([]byte, base64.StdEncoding.DecodedLen(len(data))) n, err := base64.StdEncoding.Decode(dst, data) return dst[:n], err @@ -79,6 +94,9 @@ type GzipSigil struct { // In compresses the data using gzip. func (s *GzipSigil) In(data []byte) ([]byte, error) { + if data == nil { + return nil, nil + } var b bytes.Buffer w := s.writer if w == nil { @@ -96,6 +114,9 @@ func (s *GzipSigil) In(data []byte) ([]byte, error) { // Out decompresses the data using gzip. func (s *GzipSigil) Out(data []byte) ([]byte, error) { + if data == nil { + return nil, nil + } r, err := gzip.NewReader(bytes.NewReader(data)) if err != nil { return nil, err diff --git a/pkg/enchantrix/sigils_test.go b/pkg/enchantrix/sigils_test.go index c191bd2..6e48b2a 100644 --- a/pkg/enchantrix/sigils_test.go +++ b/pkg/enchantrix/sigils_test.go @@ -28,7 +28,7 @@ func (m *failOnSecondWrite) Write(p []byte) (n int, err error) { return len(p), nil } -func TestReverseSigil(t *testing.T) { +func TestReverseSigil_Good(t *testing.T) { s := &ReverseSigil{} data := []byte("hello") reversed, err := s.In(data) @@ -37,15 +37,23 @@ func TestReverseSigil(t *testing.T) { original, err := s.Out(reversed) assert.NoError(t, err) assert.Equal(t, "hello", string(original)) +} - // Ugly - empty string +func TestReverseSigil_Ugly(t *testing.T) { + s := &ReverseSigil{} + // Test with empty string empty := []byte("") reversedEmpty, err := s.In(empty) assert.NoError(t, err) assert.Equal(t, "", string(reversedEmpty)) + + // Test with nil + reversedNil, err := s.In(nil) + assert.NoError(t, err) + assert.Nil(t, reversedNil) } -func TestHexSigil(t *testing.T) { +func TestHexSigil_Good(t *testing.T) { s := &HexSigil{} data := []byte("hello") encoded, err := s.In(data) @@ -54,13 +62,29 @@ func TestHexSigil(t *testing.T) { decoded, err := s.Out(encoded) assert.NoError(t, err) assert.Equal(t, "hello", string(decoded)) +} - // Bad - invalid hex string - _, err = s.Out([]byte("not hex")) +func TestHexSigil_Bad(t *testing.T) { + s := &HexSigil{} + _, err := s.Out([]byte("not hex")) assert.Error(t, err) } -func TestBase64Sigil(t *testing.T) { +func TestHexSigil_Ugly(t *testing.T) { + s := &HexSigil{} + // Test with empty string + empty := []byte("") + encodedEmpty, err := s.In(empty) + assert.NoError(t, err) + assert.Equal(t, "", string(encodedEmpty)) + + // Test with nil + encodedNil, err := s.In(nil) + assert.NoError(t, err) + assert.Nil(t, encodedNil) +} + +func TestBase64Sigil_Good(t *testing.T) { s := &Base64Sigil{} data := []byte("hello") encoded, err := s.In(data) @@ -69,13 +93,29 @@ func TestBase64Sigil(t *testing.T) { decoded, err := s.Out(encoded) assert.NoError(t, err) assert.Equal(t, "hello", string(decoded)) +} - // Bad - invalid base64 string - _, err = s.Out([]byte("not base64")) +func TestBase64Sigil_Bad(t *testing.T) { + s := &Base64Sigil{} + _, err := s.Out([]byte("not base64")) assert.Error(t, err) } -func TestGzipSigil(t *testing.T) { +func TestBase64Sigil_Ugly(t *testing.T) { + s := &Base64Sigil{} + // Test with empty string + empty := []byte("") + encodedEmpty, err := s.In(empty) + assert.NoError(t, err) + assert.Equal(t, "", string(encodedEmpty)) + + // Test with nil + encodedNil, err := s.In(nil) + assert.NoError(t, err) + assert.Nil(t, encodedNil) +} + +func TestGzipSigil_Good(t *testing.T) { s := &GzipSigil{} data := []byte("hello") compressed, err := s.In(data) @@ -84,9 +124,14 @@ func TestGzipSigil(t *testing.T) { decompressed, err := s.Out(compressed) assert.NoError(t, err) assert.Equal(t, "hello", string(decompressed)) +} - // Bad - invalid gzip data - _, err = s.Out([]byte("not gzip")) +func TestGzipSigil_Bad(t *testing.T) { + s := &GzipSigil{} + data := []byte("hello") + + // Test with invalid gzip data + _, err := s.Out([]byte("not gzip")) assert.Error(t, err) // Test writer error @@ -100,27 +145,60 @@ func TestGzipSigil(t *testing.T) { assert.Error(t, err) } -func TestJSONSigil(t *testing.T) { +func TestGzipSigil_Ugly(t *testing.T) { + s := &GzipSigil{} + // Test with empty string + empty := []byte("") + compressedEmpty, err := s.In(empty) + assert.NoError(t, err) + decompressedEmpty, err := s.Out(compressedEmpty) + assert.NoError(t, err) + assert.Equal(t, "", string(decompressedEmpty)) + + // Test with nil + compressedNil, err := s.In(nil) + assert.NoError(t, err) + decompressedNil, err := s.Out(compressedNil) + assert.NoError(t, err) + assert.Nil(t, decompressedNil) +} + +func TestJSONSigil_Good(t *testing.T) { s := &JSONSigil{Indent: true} data := []byte(`{"hello":"world"}`) indented, err := s.In(data) assert.NoError(t, err) assert.Equal(t, "{\n \"hello\": \"world\"\n}", string(indented)) + s.Indent = false compacted, err := s.In(indented) assert.NoError(t, err) assert.Equal(t, `{"hello":"world"}`, string(compacted)) - // Bad - invalid json - _, err = s.In([]byte("not json")) - assert.Error(t, err) - - // Out is a no-op, so it should return the data as-is + // Out is a no-op outData, err := s.Out(data) assert.NoError(t, err) assert.Equal(t, data, outData) } +func TestJSONSigil_Bad(t *testing.T) { + s := &JSONSigil{} + _, err := s.In([]byte("not json")) + assert.Error(t, err) +} + +func TestJSONSigil_Ugly(t *testing.T) { + s := &JSONSigil{} + // Test with empty string + empty := []byte("") + _, err := s.In(empty) + assert.Error(t, err) + + // Test with nil + _, err = s.In(nil) + assert.Error(t, err) +} + func TestHashSigils_Good(t *testing.T) { // Using the input "hello" for all hash tests data := []byte("hello") @@ -172,3 +250,19 @@ func TestHashSigil_Bad(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "hash algorithm not available") } + +func TestHashSigil_Ugly(t *testing.T) { + s, err := NewSigil("sha256") + assert.NoError(t, err) + + // Test with empty string + empty := []byte("") + hashedEmpty, err := s.In(empty) + assert.NoError(t, err) + assert.NotEmpty(t, hashedEmpty) + + // Test with nil + hashedNil, err := s.In(nil) + assert.NoError(t, err) + assert.NotEmpty(t, hashedNil) +}