Skip to content

Commit 61a53ab

Browse files
authored
cipher: do not reuse cipher ctx for certain operations (#146)
Fixes golang-fips/go#187 Co-authored-by: Derek Parker <[email protected]>
1 parent 9dbc52b commit 61a53ab

File tree

3 files changed

+32
-56
lines changed

3 files changed

+32
-56
lines changed

aes_test.go

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -421,14 +421,6 @@ func TestDecryptInvariantReusableNonce(t *testing.T) {
421421
testDecrypt(t, true)
422422
}
423423

424-
func Test_aesCipher_finalize(t *testing.T) {
425-
// Test that aesCipher.finalize does not panic if neither Encrypt nor Decrypt have been called.
426-
// This test is important because aesCipher.finalize contains logic that is normally not exercided while testing.
427-
// We can't used NewAESCipher here because the returned object will be automatically finalized by the GC
428-
// in case test execution takes long enough, and it can't be finalized twice.
429-
openssl.EVPCipherFinalize()
430-
}
431-
432424
func TestCipherEncryptDecrypt(t *testing.T) {
433425
key := []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
434426
pt := []byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34}
@@ -541,7 +533,7 @@ func BenchmarkAESGCM_Open(b *testing.B) {
541533
b.ReportAllocs()
542534
b.SetBytes(int64(len(buf)))
543535

544-
var key = make([]byte, keySize)
536+
key := make([]byte, keySize)
545537
var nonce [12]byte
546538
var ad [13]byte
547539
c, _ := openssl.NewAESCipher(key)
@@ -564,7 +556,7 @@ func BenchmarkAESGCM_Seal(b *testing.B) {
564556
b.ReportAllocs()
565557
b.SetBytes(int64(len(buf)))
566558

567-
var key = make([]byte, keySize)
559+
key := make([]byte, keySize)
568560
var nonce [12]byte
569561
var ad [13]byte
570562
c, _ := openssl.NewAESCipher(key)

cipher.go

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package openssl
44

55
// #include "goopenssl.h"
66
import "C"
7+
78
import (
89
"crypto/cipher"
910
"encoding/binary"
@@ -145,8 +146,6 @@ func loadCipher(k cipherKind, mode cipherMode) (cipher C.GO_EVP_CIPHER_PTR) {
145146

146147
type evpCipher struct {
147148
key []byte
148-
enc_ctx C.GO_EVP_CIPHER_CTX_PTR
149-
dec_ctx C.GO_EVP_CIPHER_CTX_PTR
150149
kind cipherKind
151150
blockSize int
152151
}
@@ -159,19 +158,9 @@ func newEVPCipher(key []byte, kind cipherKind) (*evpCipher, error) {
159158
c := &evpCipher{key: make([]byte, len(key)), kind: kind}
160159
copy(c.key, key)
161160
c.blockSize = int(C.go_openssl_EVP_CIPHER_get_block_size(cipher))
162-
runtime.SetFinalizer(c, (*evpCipher).finalize)
163161
return c, nil
164162
}
165163

166-
func (c *evpCipher) finalize() {
167-
if c.enc_ctx != nil {
168-
C.go_openssl_EVP_CIPHER_CTX_free(c.enc_ctx)
169-
}
170-
if c.dec_ctx != nil {
171-
C.go_openssl_EVP_CIPHER_CTX_free(c.dec_ctx)
172-
}
173-
}
174-
175164
func (c *evpCipher) encrypt(dst, src []byte) error {
176165
if len(src) < c.blockSize {
177166
return errors.New("input not full block")
@@ -184,15 +173,13 @@ func (c *evpCipher) encrypt(dst, src []byte) error {
184173
if inexactOverlap(dst[:c.blockSize], src[:c.blockSize]) {
185174
return errors.New("invalid buffer overlap")
186175
}
187-
if c.enc_ctx == nil {
188-
var err error
189-
c.enc_ctx, err = newCipherCtx(c.kind, cipherModeECB, cipherOpEncrypt, c.key, nil)
190-
if err != nil {
191-
return err
192-
}
176+
enc_ctx, err := newCipherCtx(c.kind, cipherModeECB, cipherOpEncrypt, c.key, nil)
177+
if err != nil {
178+
return err
193179
}
180+
defer C.go_openssl_EVP_CIPHER_CTX_free(enc_ctx)
194181

195-
if C.go_openssl_EVP_EncryptUpdate_wrapper(c.enc_ctx, base(dst), base(src), C.int(c.blockSize)) != 1 {
182+
if C.go_openssl_EVP_EncryptUpdate_wrapper(enc_ctx, base(dst), base(src), C.int(c.blockSize)) != 1 {
196183
return errors.New("EncryptUpdate failed")
197184
}
198185
runtime.KeepAlive(c)
@@ -211,18 +198,17 @@ func (c *evpCipher) decrypt(dst, src []byte) error {
211198
if inexactOverlap(dst[:c.blockSize], src[:c.blockSize]) {
212199
return errors.New("invalid buffer overlap")
213200
}
214-
if c.dec_ctx == nil {
215-
var err error
216-
c.dec_ctx, err = newCipherCtx(c.kind, cipherModeECB, cipherOpDecrypt, c.key, nil)
217-
if err != nil {
218-
return err
219-
}
220-
if C.go_openssl_EVP_CIPHER_CTX_set_padding(c.dec_ctx, 0) != 1 {
221-
return errors.New("could not disable cipher padding")
222-
}
201+
dec_ctx, err := newCipherCtx(c.kind, cipherModeECB, cipherOpDecrypt, c.key, nil)
202+
if err != nil {
203+
return err
204+
}
205+
defer C.go_openssl_EVP_CIPHER_CTX_free(dec_ctx)
206+
207+
if C.go_openssl_EVP_CIPHER_CTX_set_padding(dec_ctx, 0) != 1 {
208+
return errors.New("could not disable cipher padding")
223209
}
224210

225-
C.go_openssl_EVP_DecryptUpdate_wrapper(c.dec_ctx, base(dst), base(src), C.int(c.blockSize))
211+
C.go_openssl_EVP_DecryptUpdate_wrapper(dec_ctx, base(dst), base(src), C.int(c.blockSize))
226212
runtime.KeepAlive(c)
227213
return nil
228214
}
@@ -321,7 +307,7 @@ const (
321307
)
322308

323309
type cipherGCM struct {
324-
ctx C.GO_EVP_CIPHER_CTX_PTR
310+
c *evpCipher
325311
tls cipherGCMTLS
326312
// minNextNonce is the minimum value that the next nonce can be, enforced by
327313
// all TLS modes.
@@ -379,19 +365,10 @@ func (c *evpCipher) newGCMChecked(nonceSize, tagSize int) (cipher.AEAD, error) {
379365
}
380366

381367
func (c *evpCipher) newGCM(tls cipherGCMTLS) (cipher.AEAD, error) {
382-
ctx, err := newCipherCtx(c.kind, cipherModeGCM, cipherOpNone, c.key, nil)
383-
if err != nil {
384-
return nil, err
385-
}
386-
g := &cipherGCM{ctx: ctx, tls: tls, blockSize: c.blockSize}
387-
runtime.SetFinalizer(g, (*cipherGCM).finalize)
368+
g := &cipherGCM{c: c, tls: tls, blockSize: c.blockSize}
388369
return g, nil
389370
}
390371

391-
func (g *cipherGCM) finalize() {
392-
C.go_openssl_EVP_CIPHER_CTX_free(g.ctx)
393-
}
394-
395372
func (g *cipherGCM) NonceSize() int {
396373
return gcmStandardNonceSize
397374
}
@@ -464,14 +441,19 @@ func (g *cipherGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
464441
panic("cipher: invalid buffer overlap")
465442
}
466443

444+
ctx, err := newCipherCtx(g.c.kind, cipherModeGCM, cipherOpNone, g.c.key, nil)
445+
if err != nil {
446+
panic(err)
447+
}
448+
defer C.go_openssl_EVP_CIPHER_CTX_free(ctx)
467449
// Encrypt additional data.
468450
// When sealing a TLS payload, OpenSSL app sets the additional data using
469451
// 'EVP_CIPHER_CTX_ctrl(g.ctx, C.EVP_CTRL_AEAD_TLS1_AAD, C.EVP_AEAD_TLS1_AAD_LEN, base(additionalData))'.
470452
// This makes the explicit nonce component to monotonically increase on every Seal operation without
471453
// relying in the explicit nonce being securely set externally,
472454
// and it also gives some interesting speed gains.
473455
// Unfortunately we can't use it because Go expects AEAD.Seal to honor the provided nonce.
474-
if C.go_openssl_EVP_CIPHER_CTX_seal_wrapper(g.ctx, base(out), base(nonce),
456+
if C.go_openssl_EVP_CIPHER_CTX_seal_wrapper(ctx, base(out), base(nonce),
475457
base(plaintext), C.int(len(plaintext)),
476458
base(additionalData), C.int(len(additionalData))) != 1 {
477459

@@ -506,8 +488,13 @@ func (g *cipherGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte,
506488
panic("cipher: invalid buffer overlap")
507489
}
508490

491+
ctx, err := newCipherCtx(g.c.kind, cipherModeGCM, cipherOpNone, g.c.key, nil)
492+
if err != nil {
493+
return nil, err
494+
}
495+
defer C.go_openssl_EVP_CIPHER_CTX_free(ctx)
509496
ok := C.go_openssl_EVP_CIPHER_CTX_open_wrapper(
510-
g.ctx, base(out), base(nonce),
497+
ctx, base(out), base(nonce),
511498
base(ciphertext), C.int(len(ciphertext)),
512499
base(additionalData), C.int(len(additionalData)), base(tag))
513500
runtime.KeepAlive(g)

export_test.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
11
package openssl
22

3-
var (
4-
ErrOpen = errOpen
5-
EVPCipherFinalize = new(evpCipher).finalize
6-
)
3+
var ErrOpen = errOpen

0 commit comments

Comments
 (0)