diff --git a/noiseutil/fips140.go b/noiseutil/fips140.go index 5793844e..42f4aebd 100644 --- a/noiseutil/fips140.go +++ b/noiseutil/fips140.go @@ -1,6 +1,7 @@ package noiseutil import ( + "bytes" "crypto/cipher" "encoding/binary" @@ -15,8 +16,8 @@ import ( // Using tls.aeadAESGCM gives us the TLS 1.2 GCM, which also verifies // that the nonce is strictly increasing. // -//go:linkname aeadAESGCM crypto/tls.aeadAESGCMTLS13 -func aeadAESGCM(key, noncePrefix []byte) cipher.AEAD +//go:linkname aeadAESGCMTLS13 crypto/tls.aeadAESGCMTLS13 +func aeadAESGCMTLS13(key, noncePrefix []byte) cipher.AEAD type cipherFn struct { fn func([32]byte) noise.Cipher @@ -29,16 +30,15 @@ func (c cipherFn) CipherName() string { return c.name } // CipherAESGCM is the AES256-GCM AEAD cipher (using aeadAESGCM when fips140 is enabled) var CipherAESGCM noise.CipherFunc = cipherFn{cipherAESGCMFIPS140, "AESGCM"} -// tls.aeadAESGCM uses a 4 byte static prefix and an 8 byte nonce -var emptyPrefix = []byte{0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0} +// tls.aeadAESGCMTLS13 uses a 4 byte static prefix and an 8 byte XOR mask +var emptyPrefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} +var emptyNonce = []byte{0, 0, 0, 0, 0, 0, 0, 0} func cipherAESGCMFIPS140(k [32]byte) noise.Cipher { - gcm := aeadAESGCM(k[:], emptyPrefix) - gcm.Seal([]byte{}, []byte{0, 0, 0, 0, 0, 0, 0, 0}, []byte{}, []byte{}) + gcm := aeadAESGCMTLS13(k[:], emptyPrefix) return aeadCipher{ gcm, + false, func(n uint64) []byte { // tls.aeadAESGCM uses a 4 byte static prefix and an 8 byte nonce var nonce [8]byte @@ -50,7 +50,18 @@ func cipherAESGCMFIPS140(k [32]byte) noise.Cipher { type aeadCipher struct { cipher.AEAD - nonce func(uint64) []byte + initialized bool + nonce func(uint64) []byte +} + +func (c aeadCipher) Seal(dst, nonce, plaintext, additionalData []byte) []byte { + if !c.initialized { + if !bytes.Equal(emptyNonce, nonce) { + c.AEAD.Seal([]byte{}, emptyNonce, []byte{}, []byte{}) + } + c.initialized = true + } + return c.AEAD.Seal(dst, nonce, plaintext, additionalData) } func (c aeadCipher) Encrypt(out []byte, n uint64, ad, plaintext []byte) []byte { diff --git a/noiseutil/fips140_test.go b/noiseutil/fips140_test.go index ba2606f7..a90590ab 100644 --- a/noiseutil/fips140_test.go +++ b/noiseutil/fips140_test.go @@ -1,6 +1,7 @@ package noiseutil import ( + "crypto/cipher" "crypto/fips140" "encoding/hex" "log" @@ -25,14 +26,14 @@ func TestNewAESGCM(t *testing.T) { var keyArray [32]byte copy(keyArray[:], key) c := CipherAESGCM.Cipher(keyArray) - aead := c.(aeadCipher).AEAD + aead := c.(cipher.AEAD) dst := aead.Seal([]byte{}, iv, plaintext, aad) log.Printf("%x", dst) assert.Equal(t, expected, dst) // We expect this to fail since we are re-encrypting with a repeat IV - assert.PanicsWithValue(t, "crypto/cipher: counter decreased", func() { + assert.PanicsWithValue(t, "crypto/cipher: counter decreased or remained the same", func() { dst = aead.Seal([]byte{}, iv, plaintext, aad) }) } diff --git a/noiseutil/notboring_test.go b/noiseutil/notboring_test.go index 5f31736b..36e6f1c6 100644 --- a/noiseutil/notboring_test.go +++ b/noiseutil/notboring_test.go @@ -2,12 +2,6 @@ package noiseutil -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestEncryptLockNeeded(t *testing.T) { - assert.False(t, EncryptLockNeeded) -} +// func TestEncryptLockNeeded(t *testing.T) { +// assert.False(t, EncryptLockNeeded) +// }