From 200d6a8ae25563ffb3250021ad9a1a2310ba8dbe Mon Sep 17 00:00:00 2001 From: Fabio Bozzo Date: Thu, 28 Nov 2024 17:17:10 +0100 Subject: [PATCH] benchmarks vs aes-gcm --- pkg/meta/internal/crypto/secretbox_test.go | 149 +++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/pkg/meta/internal/crypto/secretbox_test.go b/pkg/meta/internal/crypto/secretbox_test.go index d87f860..09d3831 100644 --- a/pkg/meta/internal/crypto/secretbox_test.go +++ b/pkg/meta/internal/crypto/secretbox_test.go @@ -2,7 +2,12 @@ package crypto import ( "bytes" + "crypto/aes" + "crypto/cipher" "crypto/rand" + "errors" + "fmt" + "io" "testing" "github.com/stretchr/testify/require" @@ -142,3 +147,147 @@ func tamperWithBytes(data []byte) []byte { tampered[24] ^= 0x01 // Modify first byte after nonce return tampered } + +func encryptWithAESKey(data, key []byte) ([]byte, error) { + if err := validateKey(key); err != nil { + return nil, err + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + aesGCM, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonce := make([]byte, aesGCM.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + + return aesGCM.Seal(nonce, nonce, data, nil), nil +} + +func decryptWithAESKey(data, key []byte) ([]byte, error) { + if err := validateKey(key); err != nil { + return nil, err + } + + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + aesGCM, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonceSize := aesGCM.NonceSize() + if len(data) < nonceSize { + return nil, ErrShortCipherText + } + + nonce, ciphertext := data[:nonceSize], data[nonceSize:] + plaintext, err := aesGCM.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, errors.New("decryption failed") + } + + return plaintext, nil +} + +func BenchmarkEncryption(b *testing.B) { + key := make([]byte, keySize) + _, err := rand.Read(key) + require.NoError(b, err) + + sizes := []int{16, 64, 256, 1024, 4096} // Test different payload sizes + for _, size := range sizes { + data := make([]byte, size) + _, err := rand.Read(data) + require.NoError(b, err) + + b.Run(fmt.Sprintf("Secretbox-%dB", size), func(b *testing.B) { + for i := 0; i < b.N; i++ { + encrypted, err := EncryptWithKey(data, key) + require.NoError(b, err) + b.SetBytes(int64(len(encrypted))) + } + }) + + b.Run(fmt.Sprintf("AES-GCM-%dB", size), func(b *testing.B) { + for i := 0; i < b.N; i++ { + encrypted, err := encryptWithAESKey(data, key) + require.NoError(b, err) + b.SetBytes(int64(len(encrypted))) + } + }) + } +} + +func BenchmarkDecryption(b *testing.B) { + key := make([]byte, keySize) + _, err := rand.Read(key) + require.NoError(b, err) + + sizes := []int{16, 64, 256, 1024, 4096} + for _, size := range sizes { + data := make([]byte, size) + _, err := rand.Read(data) + require.NoError(b, err) + + secretboxEncrypted, err := EncryptWithKey(data, key) + require.NoError(b, err) + + aesGCMEncrypted, err := encryptWithAESKey(data, key) + require.NoError(b, err) + + b.Run(fmt.Sprintf("Secretbox-%dB", size), func(b *testing.B) { + for i := 0; i < b.N; i++ { + decrypted, err := DecryptStringWithKey(secretboxEncrypted, key) + require.NoError(b, err) + b.SetBytes(int64(len(decrypted))) + } + }) + + b.Run(fmt.Sprintf("AES-GCM-%dB", size), func(b *testing.B) { + for i := 0; i < b.N; i++ { + decrypted, err := decryptWithAESKey(aesGCMEncrypted, key) + require.NoError(b, err) + b.SetBytes(int64(len(decrypted))) + } + }) + } +} + +// TestCiphertextSizeComparison shows that Secretbox encryption entails +// a slightly larger ciphertext overhead of 40 bytes, compared to AES-GCM, +// whose overhead is just 28 bytes. +func TestCiphertextSizeComparison(t *testing.T) { + key := make([]byte, keySize) + _, err := rand.Read(key) + require.NoError(t, err) + + sizes := []int{0, 16, 64, 256, 1024, 4096} + for _, size := range sizes { + t.Run(fmt.Sprintf("size-%d", size), func(t *testing.T) { + data := make([]byte, size) + _, err := rand.Read(data) + require.NoError(t, err) + + sbCiphertext, err := EncryptWithKey(data, key) + require.NoError(t, err) + + aesCiphertext, err := encryptWithAESKey(data, key) + require.NoError(t, err) + + t.Logf("Input size: %d bytes", size) + t.Logf("Secretbox size: %d bytes (overhead: %d bytes)", len(sbCiphertext), len(sbCiphertext)-size) + t.Logf("AES-GCM size: %d bytes (overhead: %d bytes)", len(aesCiphertext), len(aesCiphertext)-size) + }) + } +}