diff options
Diffstat (limited to 'internal/stupidgcm')
| -rw-r--r-- | internal/stupidgcm/chacha.go | 35 | ||||
| -rw-r--r-- | internal/stupidgcm/chacha_test.go (renamed from internal/stupidgcm/stupidchacha_test.go) | 0 | ||||
| -rw-r--r-- | internal/stupidgcm/common.go | 68 | ||||
| -rw-r--r-- | internal/stupidgcm/common_test.go | 17 | ||||
| -rw-r--r-- | internal/stupidgcm/gcm.go | 45 | ||||
| -rw-r--r-- | internal/stupidgcm/gcm_test.go (renamed from internal/stupidgcm/stupidgcm_test.go) | 0 | ||||
| -rw-r--r-- | internal/stupidgcm/openssl.go | 108 | ||||
| -rw-r--r-- | internal/stupidgcm/openssl_aead.c (renamed from internal/stupidgcm/chacha.c) | 26 | ||||
| -rw-r--r-- | internal/stupidgcm/openssl_aead.h (renamed from internal/stupidgcm/chacha.h) | 13 | ||||
| -rw-r--r-- | internal/stupidgcm/stupidchacha.go | 156 | ||||
| -rw-r--r-- | internal/stupidgcm/stupidgcm.go | 204 | ||||
| -rw-r--r-- | internal/stupidgcm/xchacha.go (renamed from internal/stupidgcm/stupidxchacha.go) | 10 | ||||
| -rw-r--r-- | internal/stupidgcm/xchacha_test.go (renamed from internal/stupidgcm/stupidxchacha_test.go) | 0 | 
13 files changed, 280 insertions, 402 deletions
| diff --git a/internal/stupidgcm/chacha.go b/internal/stupidgcm/chacha.go new file mode 100644 index 0000000..37f7e1f --- /dev/null +++ b/internal/stupidgcm/chacha.go @@ -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, +		}, +	} +} diff --git a/internal/stupidgcm/stupidchacha_test.go b/internal/stupidgcm/chacha_test.go index 513b68f..513b68f 100644 --- a/internal/stupidgcm/stupidchacha_test.go +++ b/internal/stupidgcm/chacha_test.go diff --git a/internal/stupidgcm/common.go b/internal/stupidgcm/common.go new file mode 100644 index 0000000..3788315 --- /dev/null +++ b/internal/stupidgcm/common.go @@ -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 +} diff --git a/internal/stupidgcm/common_test.go b/internal/stupidgcm/common_test.go index 8123ce2..a8080ca 100644 --- a/internal/stupidgcm/common_test.go +++ b/internal/stupidgcm/common_test.go @@ -162,25 +162,26 @@ func testCorruption(t *testing.T, c cipher.AEAD) {  	}  } -type Wiper interface { -	Wipe() -} -  func testWipe(t *testing.T, c cipher.AEAD) {  	switch c2 := c.(type) {  	case *StupidGCM:  		c2.Wipe() -		if c2.key != nil { -			t.Fatal("key is not nil") +		if !c2.Wiped() { +			t.Error("c2.wiped is not set") +		} +		for _, v := range c2.key { +			if v != 0 { +				t.Fatal("c2._key is not zeroed") +			}  		}  	case *stupidChacha20poly1305:  		c2.Wipe() -		if !c2.wiped { +		if !c2.Wiped() {  			t.Error("c2.wiped is not set")  		}  		for _, v := range c2.key {  			if v != 0 { -				t.Fatal("c2.key is not zeroed") +				t.Fatal("c2._key is not zeroed")  			}  		}  	case *stupidXchacha20poly1305: diff --git a/internal/stupidgcm/gcm.go b/internal/stupidgcm/gcm.go new file mode 100644 index 0000000..439e7a7 --- /dev/null +++ b/internal/stupidgcm/gcm.go @@ -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, +		}, +	} +} diff --git a/internal/stupidgcm/stupidgcm_test.go b/internal/stupidgcm/gcm_test.go index 5323afa..5323afa 100644 --- a/internal/stupidgcm/stupidgcm_test.go +++ b/internal/stupidgcm/gcm_test.go diff --git a/internal/stupidgcm/openssl.go b/internal/stupidgcm/openssl.go new file mode 100644 index 0000000..d57d100 --- /dev/null +++ b/internal/stupidgcm/openssl.go @@ -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 +} diff --git a/internal/stupidgcm/chacha.c b/internal/stupidgcm/openssl_aead.c index 05d68af..9dc6866 100644 --- a/internal/stupidgcm/chacha.c +++ b/internal/stupidgcm/openssl_aead.c @@ -1,4 +1,4 @@ -#include "chacha.h" +#include "openssl_aead.h"  #include <openssl/evp.h>  #include <stdio.h>  //#cgo pkg-config: libcrypto @@ -9,24 +9,12 @@ static void panic(const char* const msg)      __builtin_trap();  } -static const EVP_CIPHER* getEvpCipher(enum aeadType cipherId) -{ -    switch (cipherId) { -    case aeadTypeChacha: -        return EVP_chacha20_poly1305(); -    case aeadTypeGcm: -        return EVP_aes_256_gcm(); -    } -    panic("unknown cipherId"); -    return NULL; -} -  // We only support 16-byte tags  static const int supportedTagLen = 16;  // https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode -int aead_seal( -    const enum aeadType cipherId, +int openssl_aead_seal( +    const EVP_CIPHER* evpCipher,      const unsigned char* const plaintext,      const int plaintextLen,      const unsigned char* const authData, @@ -38,8 +26,6 @@ int aead_seal(      unsigned char* const ciphertext,      const int ciphertextBufLen)  { -    const EVP_CIPHER* evpCipher = getEvpCipher(cipherId); -      // Create scratch space "ctx"      EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();      if (!ctx) { @@ -111,8 +97,8 @@ int aead_seal(      return ciphertextLen;  } -int aead_open( -    const enum aeadType cipherId, +int openssl_aead_open( +    const EVP_CIPHER* evpCipher,      const unsigned char* const ciphertext,      const int ciphertextLen,      const unsigned char* const authData, @@ -126,8 +112,6 @@ int aead_open(      unsigned char* const plaintext,      const int plaintextBufLen)  { -    const EVP_CIPHER* evpCipher = getEvpCipher(cipherId); -      // Create scratch space "ctx"      EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();      if (!ctx) { diff --git a/internal/stupidgcm/chacha.h b/internal/stupidgcm/openssl_aead.h index a5eac04..6a818b6 100644 --- a/internal/stupidgcm/chacha.h +++ b/internal/stupidgcm/openssl_aead.h @@ -1,10 +1,7 @@ -enum aeadType { -    aeadTypeChacha = 1, -    aeadTypeGcm = 2, -}; +#include <openssl/evp.h> -int aead_seal( -    const enum aeadType cipherId, +int openssl_aead_seal( +    const EVP_CIPHER* evpCipher,      const unsigned char* const plaintext,      const int plaintextLen,      const unsigned char* const authData, @@ -16,8 +13,8 @@ int aead_seal(      unsigned char* const ciphertext,      const int ciphertextBufLen); -int aead_open( -    const enum aeadType cipherId, +int openssl_aead_open( +    const EVP_CIPHER* evpCipher,      const unsigned char* const ciphertext,      const int ciphertextLen,      const unsigned char* const authData, diff --git a/internal/stupidgcm/stupidchacha.go b/internal/stupidgcm/stupidchacha.go deleted file mode 100644 index 5073aa3..0000000 --- a/internal/stupidgcm/stupidchacha.go +++ /dev/null @@ -1,156 +0,0 @@ -// +build !without_openssl - -package stupidgcm - -import ( -	"crypto/cipher" -	"fmt" -	"log" - -	"golang.org/x/crypto/chacha20poly1305" -) - -/* -#include <openssl/evp.h> -#include "chacha.h" -#cgo pkg-config: libcrypto -*/ -import "C" - -type stupidChacha20poly1305 struct { -	key   [chacha20poly1305.KeySize]byte -	wiped bool -} - -// Verify that we satisfy the cipher.AEAD interface -var _ cipher.AEAD = &stupidChacha20poly1305{} - -func newChacha20poly1305(key []byte) cipher.AEAD { -	if len(key) != chacha20poly1305.KeySize { -		log.Panicf("Only %d-byte keys are supported, you passed %d bytes", chacha20poly1305.KeySize, len(key)) -	} -	ret := new(stupidChacha20poly1305) -	copy(ret.key[:], key) -	return ret -} - -// NonceSize returns the required size of the nonce / IV. -func (g *stupidChacha20poly1305) NonceSize() int { -	return chacha20poly1305.NonceSize -} - -// Overhead returns the number of bytes that are added for authentication. -func (g *stupidChacha20poly1305) Overhead() int { -	return tagLen -} - -// Seal encrypts "in" using "iv" and "authData" and append the result to "dst" -func (g *stupidChacha20poly1305) Seal(dst, iv, in, authData []byte) []byte { -	if g.wiped { -		panic("BUG: tried to use wiped key") -	} -	if len(iv) != g.NonceSize() { -		log.Panicf("Only %d-byte IVs are supported, you passed %d bytes", g.NonceSize(), len(iv)) -	} -	if len(in) == 0 { -		log.Panic("Zero-length input data is not supported") -	} -	if len(g.key) != chacha20poly1305.KeySize { -		log.Panicf("Wrong key length: %d. Key has been wiped?", len(g.key)) -	} - -	// 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) -	} - -	C.aead_seal(C.aeadTypeChacha, -		(*C.uchar)(&in[0]), -		C.int(len(in)), -		(*C.uchar)(&authData[0]), -		C.int(len(authData)), -		(*C.uchar)(&g.key[0]), -		C.int(len(g.key)), -		(*C.uchar)(&iv[0]), -		C.int(len(iv)), -		(*C.uchar)(&buf[0]), -		C.int(len(buf))) - -	if inplace { -		return dst[:len(dst)+outLen] -	} -	return append(dst, buf...) -} - -// Open decrypts "in" using "iv" and "authData" and append the result to "dst" -func (g *stupidChacha20poly1305) Open(dst, iv, in, authData []byte) ([]byte, error) { -	if g.wiped { -		panic("BUG: tried to use wiped key") -	} -	if len(iv) != g.NonceSize() { -		log.Panicf("Only %d-byte IVs are supported", g.NonceSize()) -	} -	if len(g.key) != chacha20poly1305.KeySize { -		log.Panicf("Wrong key length: %d. Key has been wiped?", len(g.key)) -	} -	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.aead_open(C.aeadTypeChacha, -		(*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)(&g.key[0]), -		C.int(len(g.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 -} - -// 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 (g *stupidChacha20poly1305) Wipe() { -	g.wiped = true -	for i := range g.key { -		g.key[i] = 0 -	} -} diff --git a/internal/stupidgcm/stupidgcm.go b/internal/stupidgcm/stupidgcm.go deleted file mode 100644 index 46b6b86..0000000 --- a/internal/stupidgcm/stupidgcm.go +++ /dev/null @@ -1,204 +0,0 @@ -// +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> -// #include "chacha.h" -// #cgo pkg-config: libcrypto -import "C" - -import ( -	"crypto/cipher" -	"fmt" -	"log" -	"unsafe" -) - -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 { -	key         []byte -	forceDecode bool -} - -// Verify that we satisfy the cipher.AEAD 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) -	} -	// Create a private copy of the key -	key := append([]byte{}, keyIn...) -	return &StupidGCM{key: key, forceDecode: forceDecode} -} - -// NonceSize returns the required size of the nonce / IV. -func (g *StupidGCM) NonceSize() int { -	return ivLen -} - -// Overhead returns the number of bytes that are added for authentication. -func (g *StupidGCM) Overhead() int { -	return tagLen -} - -// Seal encrypts "in" using "iv" and "authData" and append the result to "dst" -func (g *StupidGCM) Seal(dst, iv, in, authData []byte) []byte { -	if len(iv) != ivLen { -		log.Panicf("Only %d-byte IVs are supported", ivLen) -	} -	if len(in) == 0 { -		log.Panic("Zero-length input data is not supported") -	} -	if len(g.key) != keyLen { -		log.Panicf("Wrong key length: %d. Key has been wiped?", len(g.key)) -	} - -	// 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) -	} - -	C.aead_seal(C.aeadTypeGcm, -		(*C.uchar)(&in[0]), -		C.int(len(in)), -		(*C.uchar)(&authData[0]), -		C.int(len(authData)), -		(*C.uchar)(&g.key[0]), -		C.int(len(g.key)), -		(*C.uchar)(&iv[0]), -		C.int(len(iv)), -		(*C.uchar)(&buf[0]), -		C.int(len(buf))) - -	if inplace { -		return dst[:len(dst)+outLen] -	} -	return append(dst, buf...) -} - -// Open decrypts "in" using "iv" and "authData" and append the result to "dst" -func (g *StupidGCM) Open(dst, iv, in, authData []byte) ([]byte, error) { -	if len(iv) != ivLen { -		log.Panicf("Only %d-byte IVs are supported", ivLen) -	} -	if len(g.key) != keyLen { -		log.Panicf("Wrong key length: %d. Key has been wiped?", len(g.key)) -	} -	if len(in) <= tagLen { -		return nil, fmt.Errorf("stupidgcm: 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:] - -	// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode - -	// Create scratch space "context" -	ctx := C.EVP_CIPHER_CTX_new() -	if ctx == nil { -		log.Panic("EVP_CIPHER_CTX_new failed") -	} - -	// Set cipher to AES-256 -	if C.EVP_DecryptInit_ex(ctx, C.EVP_aes_256_gcm(), nil, nil, nil) != 1 { -		log.Panic("EVP_DecryptInit_ex I failed") -	} - -	// Use 16-byte IV -	if C.EVP_CIPHER_CTX_ctrl(ctx, C.EVP_CTRL_GCM_SET_IVLEN, ivLen, nil) != 1 { -		log.Panic("EVP_CIPHER_CTX_ctrl EVP_CTRL_GCM_SET_IVLEN failed") -	} - -	// Set key and IV -	if C.EVP_DecryptInit_ex(ctx, nil, nil, (*C.uchar)(&g.key[0]), (*C.uchar)(&iv[0])) != 1 { -		log.Panic("EVP_DecryptInit_ex II failed") -	} - -	// Set expected GMAC tag -	if C.EVP_CIPHER_CTX_ctrl(ctx, C.EVP_CTRL_GCM_SET_TAG, tagLen, (unsafe.Pointer)(&tag[0])) != 1 { -		log.Panic("EVP_CIPHER_CTX_ctrl failed") -	} - -	// Provide authentication data -	var resultLen C.int -	if C.EVP_DecryptUpdate(ctx, nil, &resultLen, (*C.uchar)(&authData[0]), C.int(len(authData))) != 1 { -		log.Panic("EVP_DecryptUpdate authData failed") -	} -	if int(resultLen) != len(authData) { -		log.Panicf("Unexpected length %d", resultLen) -	} - -	// Decrypt "ciphertext" into "buf" -	if C.EVP_DecryptUpdate(ctx, (*C.uchar)(&buf[0]), &resultLen, (*C.uchar)(&ciphertext[0]), C.int(len(ciphertext))) != 1 { -		log.Panic("EVP_DecryptUpdate failed") -	} -	if int(resultLen) != len(ciphertext) { -		log.Panicf("Unexpected length %d", resultLen) -	} - -	// Check GMAC -	dummy := make([]byte, 16) -	res := C.EVP_DecryptFinal_ex(ctx, (*C.uchar)(&dummy[0]), &resultLen) -	if resultLen != 0 { -		log.Panicf("Unexpected length %d", resultLen) -	} - -	// Free scratch space -	C.EVP_CIPHER_CTX_free(ctx) - -	if res != 1 { -		// The error code must always be checked by the calling function, because the decrypted buffer -		// may contain corrupted data that we are returning in case the user forced reads -		if g.forceDecode { -			return append(dst, buf...), ErrAuth -		} -		return nil, ErrAuth -	} - -	if inplace { -		return dst[:len(dst)+outLen], nil -	} -	return append(dst, buf...), nil -} - -// Wipe tries to wipe the AES key from memory by overwriting it with zeros -// and setting the reference to nil. -// -// This is not bulletproof due to possible GC copies, but -// still raises the bar for extracting the key. -func (g *StupidGCM) Wipe() { -	for i := range g.key { -		g.key[i] = 0 -	} -	g.key = nil -} diff --git a/internal/stupidgcm/stupidxchacha.go b/internal/stupidgcm/xchacha.go index 9f2ac2f..d8668dc 100644 --- a/internal/stupidgcm/stupidxchacha.go +++ b/internal/stupidgcm/xchacha.go @@ -17,6 +17,8 @@ import (  )  type stupidXchacha20poly1305 struct { +	// array instead of byte slice like +	// `struct xchacha20poly1305` in x/crypto/chacha20poly1305  	key   [chacha20poly1305.KeySize]byte  	wiped bool  } @@ -41,7 +43,7 @@ func (*stupidXchacha20poly1305) NonceSize() int {  }  func (*stupidXchacha20poly1305) Overhead() int { -	return 16 +	return tagLen  }  func (x *stupidXchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []byte) []byte { @@ -61,9 +63,8 @@ func (x *stupidXchacha20poly1305) Seal(dst, nonce, plaintext, additionalData []b  		panic("plaintext too large")  	} -	c := new(stupidChacha20poly1305)  	hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16]) -	copy(c.key[:], hKey) +	c := newChacha20poly1305(hKey)  	defer c.Wipe()  	// The first 4 bytes of the final nonce are unused counter space. @@ -87,9 +88,8 @@ func (x *stupidXchacha20poly1305) Open(dst, nonce, ciphertext, additionalData []  		panic("ciphertext too large")  	} -	c := new(stupidChacha20poly1305)  	hKey, _ := chacha20.HChaCha20(x.key[:], nonce[0:16]) -	copy(c.key[:], hKey) +	c := newChacha20poly1305(hKey)  	defer c.Wipe()  	// The first 4 bytes of the final nonce are unused counter space. diff --git a/internal/stupidgcm/stupidxchacha_test.go b/internal/stupidgcm/xchacha_test.go index fdea8b5..fdea8b5 100644 --- a/internal/stupidgcm/stupidxchacha_test.go +++ b/internal/stupidgcm/xchacha_test.go | 
