package crypto_test import ( "crypto/rand" "encoding/base64" "encoding/hex" "testing" "github.com/stretchr/testify/require" "gateway/internal/library/crypto" ) func mustRandomKey(t *testing.T) []byte { t.Helper() key := make([]byte, 32) _, err := rand.Read(key) require.NoError(t, err) return key } func TestAESGCM_RoundTrip(t *testing.T) { key := mustRandomKey(t) c, err := crypto.NewAESGCM(key) require.NoError(t, err) pt := []byte("totp-secret-bytes") blob, err := c.Encrypt(pt) require.NoError(t, err) require.NotEqual(t, pt, blob) out, err := c.Decrypt(blob) require.NoError(t, err) require.Equal(t, pt, out) } func TestAESGCM_NonceUnique(t *testing.T) { c, err := crypto.NewAESGCM(mustRandomKey(t)) require.NoError(t, err) a, err := c.Encrypt([]byte("same")) require.NoError(t, err) b, err := c.Encrypt([]byte("same")) require.NoError(t, err) require.NotEqual(t, a, b, "nonce should randomize each ciphertext") } func TestAESGCM_FromStringHexAndBase64(t *testing.T) { key := mustRandomKey(t) hexKey := hex.EncodeToString(key) b64Key := base64.StdEncoding.EncodeToString(key) c1, err := crypto.NewAESGCMFromString(hexKey) require.NoError(t, err) c2, err := crypto.NewAESGCMFromString(b64Key) require.NoError(t, err) pt := []byte("payload") blob, err := c1.Encrypt(pt) require.NoError(t, err) out, err := c2.Decrypt(blob) require.NoError(t, err) require.Equal(t, pt, out) } func TestAESGCM_InvalidKey(t *testing.T) { _, err := crypto.NewAESGCM([]byte("short")) require.ErrorIs(t, err, crypto.ErrInvalidKey) _, err = crypto.NewAESGCMFromString("") require.ErrorIs(t, err, crypto.ErrInvalidKey) _, err = crypto.NewAESGCMFromString("not-a-valid-key-encoding!!!") require.ErrorIs(t, err, crypto.ErrInvalidKey) } func TestAESGCM_DecryptTooShort(t *testing.T) { c, err := crypto.NewAESGCM(mustRandomKey(t)) require.NoError(t, err) _, err = c.Decrypt([]byte{0x01, 0x02}) require.ErrorIs(t, err, crypto.ErrCipherTextTooShort) } func TestAESGCM_DecryptTampered(t *testing.T) { c, err := crypto.NewAESGCM(mustRandomKey(t)) require.NoError(t, err) blob, err := c.Encrypt([]byte("hello")) require.NoError(t, err) blob[len(blob)-1] ^= 0xFF _, err = c.Decrypt(blob) require.Error(t, err) require.NotErrorIs(t, err, crypto.ErrCipherTextTooShort) } func TestAESGCM_StringRoundTrip(t *testing.T) { c, err := crypto.NewAESGCM(mustRandomKey(t)) require.NoError(t, err) encoded, err := c.EncryptToString([]byte("secret")) require.NoError(t, err) out, err := c.DecryptFromString(encoded) require.NoError(t, err) require.Equal(t, []byte("secret"), out) }