-
Notifications
You must be signed in to change notification settings - Fork 258
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
stupidgcm: introduce stupidAEADCommon and use for both chacha & gcm
Nice deduplication and brings the GCM decrypt speed up to par. internal/speed$ benchstat old new name old time/op new time/op delta StupidGCM-4 4.71µs ± 0% 4.66µs ± 0% -0.99% (p=0.008 n=5+5) StupidGCMDecrypt-4 5.77µs ± 1% 4.51µs ± 0% -21.80% (p=0.008 n=5+5) name old speed new speed delta StupidGCM-4 870MB/s ± 0% 879MB/s ± 0% +1.01% (p=0.008 n=5+5) StupidGCMDecrypt-4 710MB/s ± 1% 908MB/s ± 0% +27.87% (p=0.008 n=5+5)
- Loading branch information
Showing
13 changed files
with
280 additions
and
402 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// +build !without_openssl | ||
|
||
package stupidgcm | ||
|
||
import ( | ||
"crypto/cipher" | ||
"log" | ||
|
||
"golang.org/x/crypto/chacha20poly1305" | ||
) | ||
|
||
/* | ||
#include <openssl/evp.h> | ||
*/ | ||
import "C" | ||
|
||
type stupidChacha20poly1305 struct { | ||
stupidAEADCommon | ||
} | ||
|
||
// Verify that we satisfy the cipher.AEAD interface | ||
var _ cipher.AEAD = &stupidChacha20poly1305{} | ||
|
||
func newChacha20poly1305(key []byte) *stupidChacha20poly1305 { | ||
if len(key) != chacha20poly1305.KeySize { | ||
log.Panicf("Only %d-byte keys are supported, you passed %d bytes", chacha20poly1305.KeySize, len(key)) | ||
} | ||
return &stupidChacha20poly1305{ | ||
stupidAEADCommon{ | ||
key: append([]byte{}, key...), // private copy | ||
openSSLEVPCipher: C.EVP_chacha20_poly1305(), | ||
nonceSize: chacha20poly1305.NonceSize, | ||
}, | ||
} | ||
} |
File renamed without changes.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package stupidgcm | ||
|
||
import ( | ||
"log" | ||
) | ||
|
||
/* | ||
#include <openssl/evp.h> | ||
*/ | ||
import "C" | ||
|
||
type stupidAEADCommon struct { | ||
wiped bool | ||
key []byte | ||
openSSLEVPCipher *C.EVP_CIPHER | ||
nonceSize int | ||
} | ||
|
||
// Overhead returns the number of bytes that are added for authentication. | ||
// | ||
// Part of the cipher.AEAD interface. | ||
func (c *stupidAEADCommon) Overhead() int { | ||
return tagLen | ||
} | ||
|
||
// NonceSize returns the required size of the nonce / IV | ||
// | ||
// Part of the cipher.AEAD interface. | ||
func (c *stupidAEADCommon) NonceSize() int { | ||
return c.nonceSize | ||
} | ||
|
||
// Seal encrypts "in" using "iv" and "authData" and append the result to "dst" | ||
// | ||
// Part of the cipher.AEAD interface. | ||
func (c *stupidAEADCommon) Seal(dst, iv, in, authData []byte) []byte { | ||
return openSSLSeal(c, dst, iv, in, authData) | ||
} | ||
|
||
// Open decrypts "in" using "iv" and "authData" and append the result to "dst" | ||
// | ||
// Part of the cipher.AEAD interface. | ||
func (c *stupidAEADCommon) Open(dst, iv, in, authData []byte) ([]byte, error) { | ||
return openSSLOpen(c, dst, iv, in, authData) | ||
} | ||
|
||
// Wipe tries to wipe the key from memory by overwriting it with zeros. | ||
// | ||
// This is not bulletproof due to possible GC copies, but | ||
// still raises the bar for extracting the key. | ||
func (c *stupidAEADCommon) Wipe() { | ||
key := c.key | ||
c.wiped = true | ||
c.key = nil | ||
for i := range key { | ||
key[i] = 0 | ||
} | ||
} | ||
|
||
func (c *stupidAEADCommon) Wiped() bool { | ||
if c.wiped { | ||
return true | ||
} | ||
if len(c.key) != keyLen { | ||
log.Panicf("wrong key length %d", len(c.key)) | ||
} | ||
return false | ||
} |
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// +build !without_openssl | ||
|
||
// Package stupidgcm is a thin wrapper for OpenSSL's GCM encryption and | ||
// decryption functions. It only support 32-byte keys and 16-bit IVs. | ||
package stupidgcm | ||
|
||
// #include <openssl/evp.h> | ||
import "C" | ||
|
||
import ( | ||
"crypto/cipher" | ||
"log" | ||
) | ||
|
||
const ( | ||
// BuiltWithoutOpenssl indicates if openssl been disabled at compile-time | ||
BuiltWithoutOpenssl = false | ||
|
||
keyLen = 32 | ||
ivLen = 16 | ||
tagLen = 16 | ||
) | ||
|
||
// StupidGCM implements the cipher.AEAD interface | ||
type StupidGCM struct { | ||
stupidAEADCommon | ||
} | ||
|
||
// Verify that we satisfy the interface | ||
var _ cipher.AEAD = &StupidGCM{} | ||
|
||
// New returns a new cipher.AEAD implementation.. | ||
func New(keyIn []byte, forceDecode bool) cipher.AEAD { | ||
if len(keyIn) != keyLen { | ||
log.Panicf("Only %d-byte keys are supported", keyLen) | ||
} | ||
return &StupidGCM{ | ||
stupidAEADCommon{ | ||
// Create a private copy of the key | ||
key: append([]byte{}, keyIn...), | ||
openSSLEVPCipher: C.EVP_aes_256_gcm(), | ||
nonceSize: ivLen, | ||
}, | ||
} | ||
} |
File renamed without changes.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package stupidgcm | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
) | ||
|
||
/* | ||
#include "openssl_aead.h" | ||
#cgo pkg-config: libcrypto | ||
*/ | ||
import "C" | ||
|
||
func openSSLSeal(a *stupidAEADCommon, dst, iv, in, authData []byte) []byte { | ||
if a.Wiped() { | ||
panic("BUG: tried to use wiped key") | ||
} | ||
if len(iv) != a.NonceSize() { | ||
log.Panicf("Only %d-byte IVs are supported, you passed %d bytes", a.NonceSize(), len(iv)) | ||
} | ||
if len(in) == 0 { | ||
log.Panic("Zero-length input data is not supported") | ||
} | ||
|
||
// If the "dst" slice is large enough we can use it as our output buffer | ||
outLen := len(in) + tagLen | ||
var buf []byte | ||
inplace := false | ||
if cap(dst)-len(dst) >= outLen { | ||
inplace = true | ||
buf = dst[len(dst) : len(dst)+outLen] | ||
} else { | ||
buf = make([]byte, outLen) | ||
} | ||
|
||
res := int(C.openssl_aead_seal(a.openSSLEVPCipher, | ||
(*C.uchar)(&in[0]), | ||
C.int(len(in)), | ||
(*C.uchar)(&authData[0]), | ||
C.int(len(authData)), | ||
(*C.uchar)(&a.key[0]), | ||
C.int(len(a.key)), | ||
(*C.uchar)(&iv[0]), | ||
C.int(len(iv)), | ||
(*C.uchar)(&buf[0]), | ||
C.int(len(buf)))) | ||
|
||
if res != outLen { | ||
log.Panicf("expected length %d, got %d", outLen, res) | ||
} | ||
|
||
if inplace { | ||
return dst[:len(dst)+outLen] | ||
} | ||
return append(dst, buf...) | ||
} | ||
|
||
func openSSLOpen(a *stupidAEADCommon, dst, iv, in, authData []byte) ([]byte, error) { | ||
if a.Wiped() { | ||
panic("BUG: tried to use wiped key") | ||
} | ||
if len(iv) != a.NonceSize() { | ||
log.Panicf("Only %d-byte IVs are supported, you passed %d bytes", a.NonceSize(), len(iv)) | ||
} | ||
if len(in) <= tagLen { | ||
return nil, fmt.Errorf("stupidChacha20poly1305: input data too short (%d bytes)", len(in)) | ||
} | ||
|
||
// If the "dst" slice is large enough we can use it as our output buffer | ||
outLen := len(in) - tagLen | ||
var buf []byte | ||
inplace := false | ||
if cap(dst)-len(dst) >= outLen { | ||
inplace = true | ||
buf = dst[len(dst) : len(dst)+outLen] | ||
} else { | ||
buf = make([]byte, len(in)-tagLen) | ||
} | ||
|
||
ciphertext := in[:len(in)-tagLen] | ||
tag := in[len(in)-tagLen:] | ||
|
||
res := int(C.openssl_aead_open(a.openSSLEVPCipher, | ||
(*C.uchar)(&ciphertext[0]), | ||
C.int(len(ciphertext)), | ||
(*C.uchar)(&authData[0]), | ||
C.int(len(authData)), | ||
(*C.uchar)(&tag[0]), | ||
C.int(len(tag)), | ||
(*C.uchar)(&a.key[0]), | ||
C.int(len(a.key)), | ||
(*C.uchar)(&iv[0]), | ||
C.int(len(iv)), | ||
(*C.uchar)(&buf[0]), | ||
C.int(len(buf)))) | ||
|
||
if res < 0 { | ||
return nil, ErrAuth | ||
} | ||
if res != outLen { | ||
log.Panicf("unexpected length %d", res) | ||
} | ||
|
||
if inplace { | ||
return dst[:len(dst)+outLen], nil | ||
} | ||
return append(dst, buf...), nil | ||
} |
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
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
Oops, something went wrong.