diff options
Diffstat (limited to 'internal')
| -rw-r--r-- | internal/stupidgcm/stupidgcm.go | 15 | ||||
| -rw-r--r-- | internal/stupidgcm/stupidgcm_test.go | 39 | 
2 files changed, 53 insertions, 1 deletions
| diff --git a/internal/stupidgcm/stupidgcm.go b/internal/stupidgcm/stupidgcm.go index 5cc6c3c..54915df 100644 --- a/internal/stupidgcm/stupidgcm.go +++ b/internal/stupidgcm/stupidgcm.go @@ -55,7 +55,17 @@ func (g stupidGCM) Seal(dst, iv, in, authData []byte) []byte {  	if len(in) == 0 {  		log.Panic("Zero-length input data is not supported")  	} -	buf := make([]byte, len(in)+tagLen) + +	// 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) +	}  	// https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption#Authenticated_Encryption_using_GCM_mode @@ -115,6 +125,9 @@ func (g stupidGCM) Seal(dst, iv, in, authData []byte) []byte {  	// Free scratch space  	C.EVP_CIPHER_CTX_free(ctx) +	if inplace { +		return dst[:len(dst)+outLen] +	}  	return append(dst, buf...)  } diff --git a/internal/stupidgcm/stupidgcm_test.go b/internal/stupidgcm/stupidgcm_test.go index eb322f2..4d37d08 100644 --- a/internal/stupidgcm/stupidgcm_test.go +++ b/internal/stupidgcm/stupidgcm_test.go @@ -73,6 +73,45 @@ func TestEncryptDecrypt(t *testing.T) {  	}  } +// Seal re-uses the "dst" buffer it is large enough. +// Check that this works correctly by testing different "dst" capacities from +// 5000 to 16 and "in" lengths from 1 to 5000. +func TestInplaceSeal(t *testing.T) { +	key := randBytes(32) +	sGCM := New(key, false) +	authData := randBytes(24) +	iv := randBytes(16) + +	gAES, err := aes.NewCipher(key) +	if err != nil { +		t.Fatal(err) +	} +	gGCM, err := cipher.NewGCMWithNonceSize(gAES, 16) +	if err != nil { +		t.Fatal(err) +	} +	max := 5016 +	// Check all block sizes from 1 to 5000 +	for i := 1; i < max-16; i++ { +		in := make([]byte, i) +		dst := make([]byte, max-i) +		dst = dst[:16] + +		sOut := sGCM.Seal(dst, iv, in, authData) +		dst2 := make([]byte, 16) +		gOut := gGCM.Seal(dst2, iv, in, authData) + +		// Ciphertext must be identical to Go GCM +		if !bytes.Equal(sOut, gOut) { +			t.Fatalf("Compare failed for encryption, size %d", i) +			t.Log("sOut:") +			t.Log("\n" + hex.Dump(sOut)) +			t.Log("gOut:") +			t.Log("\n" + hex.Dump(gOut)) +		} +	} +} +  // TestCorruption verifies that changes in the ciphertext result in a decryption  // error  func TestCorruption(t *testing.T) { | 
