Skip to content

Instantly share code, notes, and snippets.

@bbengfort
Created October 27, 2023 22:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bbengfort/6b6c7957380ec3cda22ea36b21e2d4f2 to your computer and use it in GitHub Desktop.
Save bbengfort/6b6c7957380ec3cda22ea36b21e2d4f2 to your computer and use it in GitHub Desktop.
Data encryption and compression are heavyweight algorithms that must be used with care in performance intensive applications; but when applying both mechanics to the same data, which should come first? These benchmarks compare Go gzip compression with AES-GCM cryptography. For more see: https://rotational.io/blog/compression-vs-cryptography/.
package cryptpress
import (
"bytes"
"compress/gzip"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
)
func init() {
key = make([]byte, 32)
if _, err := rand.Read(key); err != nil {
panic(err)
}
}
var key []byte
func CryptPress(data []byte) ([]byte, error) {
secret, err := Encrypt(data)
if err != nil {
return nil, err
}
return Compress(secret)
}
func DecryptPress(data []byte) ([]byte, error) {
secret, err := Decompress(data)
if err != nil {
return nil, err
}
return Decrypt(secret)
}
func PressCrypt(data []byte) ([]byte, error) {
small, err := Compress(data)
if err != nil {
return nil, err
}
return Encrypt(small)
}
func DepressCrypt(data []byte) ([]byte, error) {
small, err := Decrypt(data)
if err != nil {
return nil, err
}
return Decompress(small)
}
func Encrypt(plaintext []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonce := make([]byte, 12)
if _, err := rand.Read(nonce); err != nil {
return nil, err
}
ciphertext := gcm.Seal(nil, nonce, plaintext, nil)
ciphertext = append(ciphertext, nonce...)
return ciphertext, nil
}
func Decrypt(ciphertext []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
plaintext, err := gcm.Open(nil, ciphertext[len(ciphertext)-12:], ciphertext[:len(ciphertext)-12], nil)
if err != nil {
return nil, err
}
return plaintext, nil
}
func Compress(data []byte) ([]byte, error) {
buf := &bytes.Buffer{}
archive, _ := gzip.NewWriterLevel(buf, gzip.BestSpeed)
if _, err := archive.Write(data); err != nil {
return nil, err
}
if err := archive.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func Decompress(data []byte) ([]byte, error) {
buf := bytes.NewBuffer(data)
archive, err := gzip.NewReader(buf)
if err != nil {
return nil, err
}
defer archive.Close()
return io.ReadAll(archive)
}
package cryptpress_test
import (
"os"
"testing"
"github.com/bbengfort/cryptpress"
"github.com/stretchr/testify/require"
)
func TestCryptPress(t *testing.T) {
data := []byte("the eagle flies at midnight to catch the man with the one red shoe and everything in between.")
inter, err := cryptpress.CryptPress(data)
require.NoError(t, err, "could not cryptpress data")
actual, err := cryptpress.DecryptPress(inter)
require.NoError(t, err, "could not decryptpress data")
require.Equal(t, actual, data)
}
func TestPressCrypt(t *testing.T) {
data := []byte("the eagle flies at midnight to catch the man with the one red shoe and everything in between.")
inter, err := cryptpress.PressCrypt(data)
require.NoError(t, err, "could not presscrypt data")
actual, err := cryptpress.DepressCrypt(inter)
require.NoError(t, err, "could not depresscrypt data")
require.Equal(t, actual, data)
}
func BenchmarkStandalone(b *testing.B) {
fixture := loadFixture(b)
b.Run("Encrypt", func(b *testing.B) {
for i := 0; i < b.N; i++ {
cryptpress.Encrypt(fixture)
}
})
ciphertext, err := cryptpress.Encrypt(fixture)
require.NoError(b, err)
b.Run("Decrypt", func(b *testing.B) {
for i := 0; i < b.N; i++ {
cryptpress.Decrypt(ciphertext)
}
})
b.Run("Compress", func(b *testing.B) {
for i := 0; i < b.N; i++ {
cryptpress.Compress(fixture)
}
})
small, err := cryptpress.Compress(fixture)
require.NoError(b, err)
b.Run("Decompress", func(b *testing.B) {
for i := 0; i < b.N; i++ {
cryptpress.Decompress(small)
}
})
}
func BenchmarkCryptPress(b *testing.B) {
fixture := loadFixture(b)
b.Run("CryptPress", func(b *testing.B) {
for i := 0; i < b.N; i++ {
cryptpress.CryptPress(fixture)
}
})
ciphertext, err := cryptpress.CryptPress(fixture)
require.NoError(b, err)
b.Run("DecryptPress", func(b *testing.B) {
for i := 0; i < b.N; i++ {
cryptpress.DecryptPress(ciphertext)
}
})
}
func BenchmarkPressCrypt(b *testing.B) {
fixture := loadFixture(b)
b.Run("PressCrypt", func(b *testing.B) {
for i := 0; i < b.N; i++ {
cryptpress.PressCrypt(fixture)
}
})
ciphertext, err := cryptpress.PressCrypt(fixture)
require.NoError(b, err)
b.Run("DepressCrypt", func(b *testing.B) {
for i := 0; i < b.N; i++ {
cryptpress.DepressCrypt(ciphertext)
}
})
}
func loadFixture(t require.TestingT) []byte {
f, err := os.ReadFile("testdata/response.txt")
require.NoError(t, err)
return f
}
module github.com/bbengfort/cryptpress
go 1.21.1
require github.com/stretchr/testify v1.8.4
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
method compact fast
Encrypt 480928 483403
Decrypt 350098 358485
Compress 36125634 5485121
Decompress 2977850 4048195
CryptPress 24525044 3491544
DecryptPress 1327536 1147431
PressCrypt 36019805 5518679
DepressCrypt 2998849 4128016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment