benchmarks vs aes-gcm

This commit is contained in:
Fabio Bozzo
2024-11-28 17:17:10 +01:00
parent 0349e7e463
commit 200d6a8ae2

View File

@@ -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)
})
}
}