Created
October 27, 2023 22:09
-
-
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/.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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