]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/internal/fips140/aes: mark AES-ECB as not approved
authorFilippo Valsorda <filippo@golang.org>
Mon, 16 Dec 2024 18:24:20 +0000 (19:24 +0100)
committerGopher Robot <gobot@golang.org>
Tue, 17 Dec 2024 16:02:39 +0000 (08:02 -0800)
NIST SP 800-131Ar3 ipd, scheduled for publication in 2025Q1, marks
AES-ECB as disallowed for encryption, and legacy use for decryption.

There are apparently no details on how the transition is going to work,
so to avoid surprises we just mark direct use of the Block as
non-approved.

We need to use Encrypt from higher level modes without tripping the
service indicator. Within the aes package, we just use the internal
function. For the gcm package we could do something more clever, but
this deep into the freeze, just make an exported function that we commit
to use nowhere else.

I could not figure out a decent way to block ECB on GODEBUG=fips140=only.

For #69536

Change-Id: I972a4b5da8efd0a0ab68d7dd509bec73aa2d6b68
Reviewed-on: https://go-review.googlesource.com/c/go/+/636775
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/crypto/internal/fips140/aes/aes.go
src/crypto/internal/fips140/aes/cbc.go
src/crypto/internal/fips140/aes/ctr.go
src/crypto/internal/fips140/aes/gcm/cmac.go
src/crypto/internal/fips140/aes/gcm/gcm_asm.go
src/crypto/internal/fips140/aes/gcm/gcm_generic.go

index 739f1a3dbe659974cd723e17a4e36d223b438265..62f6919eda817809c3cbd896097624cbebc55602 100644 (file)
@@ -94,6 +94,8 @@ func newBlockExpanded(c *blockExpanded, key []byte) {
 func (c *Block) BlockSize() int { return BlockSize }
 
 func (c *Block) Encrypt(dst, src []byte) {
+       // AES-ECB is not approved in FIPS 140-3 mode.
+       fips140.RecordNonApproved()
        if len(src) < BlockSize {
                panic("crypto/aes: input not full block")
        }
@@ -103,11 +105,12 @@ func (c *Block) Encrypt(dst, src []byte) {
        if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
                panic("crypto/aes: invalid buffer overlap")
        }
-       fips140.RecordApproved()
        encryptBlock(c, dst, src)
 }
 
 func (c *Block) Decrypt(dst, src []byte) {
+       // AES-ECB is not approved in FIPS 140-3 mode.
+       fips140.RecordNonApproved()
        if len(src) < BlockSize {
                panic("crypto/aes: input not full block")
        }
@@ -117,6 +120,12 @@ func (c *Block) Decrypt(dst, src []byte) {
        if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
                panic("crypto/aes: invalid buffer overlap")
        }
-       fips140.RecordApproved()
        decryptBlock(c, dst, src)
 }
+
+// EncryptBlockInternal applies the AES encryption function to one block.
+//
+// It is an internal function meant only for the gcm package.
+func EncryptBlockInternal(c *Block, dst, src []byte) {
+       encryptBlock(c, dst, src)
+}
index c7837b9d87d102628a003558c107d4e1f6b2cb91..f92af23a2a55619a09324bc1ad6c0e44d3269f0e 100644 (file)
@@ -50,7 +50,7 @@ func cryptBlocksEncGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) {
        for len(src) > 0 {
                // Write the xor to dst, then encrypt in place.
                subtle.XORBytes(dst[:BlockSize], src[:BlockSize], iv)
-               b.Encrypt(dst[:BlockSize], dst[:BlockSize])
+               encryptBlock(b, dst[:BlockSize], dst[:BlockSize])
 
                // Move to the next block with this block as the next iv.
                iv = dst[:BlockSize]
@@ -111,7 +111,7 @@ func cryptBlocksDecGeneric(b *Block, civ *[BlockSize]byte, dst, src []byte) {
        copy(civ[:], src[start:end])
 
        for start >= 0 {
-               b.Decrypt(dst[start:end], src[start:end])
+               decryptBlock(b, dst[start:end], src[start:end])
 
                if start > 0 {
                        subtle.XORBytes(dst[start:end], dst[start:end], src[prev:start])
index f612034d85ff1ac8d5e900cab9e0a43a1ac7608a..2b0ee44cddb66c6d17ded21377a255d9715cee34 100644 (file)
@@ -132,7 +132,7 @@ func ctrBlocks(b *Block, dst, src []byte, ivlo, ivhi uint64) {
                byteorder.BEPutUint64(buf[i:], ivhi)
                byteorder.BEPutUint64(buf[i+8:], ivlo)
                ivlo, ivhi = add128(ivlo, ivhi, 1)
-               b.Encrypt(buf[i:], buf[i:])
+               encryptBlock(b, buf[i:], buf[i:])
        }
        // XOR into buf first, in case src and dst overlap (see above).
        subtle.XORBytes(buf, src, buf)
index e0a9dc43dede7e30d8dd5f4317f3c7b85c138546..3a979a5c70870f0a4c05a8075e378a262c126817 100644 (file)
@@ -28,7 +28,7 @@ func NewCMAC(b *aes.Block) *CMAC {
 }
 
 func (c *CMAC) deriveSubkeys() {
-       c.b.Encrypt(c.k1[:], c.k1[:])
+       aes.EncryptBlockInternal(&c.b, c.k1[:], c.k1[:])
        msb := shiftLeft(&c.k1)
        c.k1[len(c.k1)-1] ^= msb * 0b10000111
 
@@ -45,7 +45,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
                // Special-cased as a single empty partial final block.
                x = c.k2
                x[len(m)] ^= 0b10000000
-               c.b.Encrypt(x[:], x[:])
+               aes.EncryptBlockInternal(&c.b, x[:], x[:])
                return x
        }
        for len(m) >= aes.BlockSize {
@@ -54,7 +54,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
                        // Final complete block.
                        subtle.XORBytes(x[:], c.k1[:], x[:])
                }
-               c.b.Encrypt(x[:], x[:])
+               aes.EncryptBlockInternal(&c.b, x[:], x[:])
                m = m[aes.BlockSize:]
        }
        if len(m) > 0 {
@@ -62,7 +62,7 @@ func (c *CMAC) MAC(m []byte) [aes.BlockSize]byte {
                subtle.XORBytes(x[:], m, x[:])
                subtle.XORBytes(x[:], c.k2[:], x[:])
                x[len(m)] ^= 0b10000000
-               c.b.Encrypt(x[:], x[:])
+               aes.EncryptBlockInternal(&c.b, x[:], x[:])
        }
        return x
 }
index d513f77a2f342b4ab1f479a3eeb039252bd53043..7924e457dee829d9b75a846c9ebb7d5b6ecd9b59 100644 (file)
@@ -81,7 +81,7 @@ func seal(out []byte, g *GCM, nonce, plaintext, data []byte) {
                gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
        }
 
-       g.cipher.Encrypt(tagMask[:], counter[:])
+       aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
 
        var tagOut [gcmTagSize]byte
        gcmAesData(&g.productTable, data, &tagOut)
@@ -114,7 +114,7 @@ func open(out []byte, g *GCM, nonce, ciphertext, data []byte) error {
                gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
        }
 
-       g.cipher.Encrypt(tagMask[:], counter[:])
+       aes.EncryptBlockInternal(&g.cipher, tagMask[:], counter[:])
 
        var expectedTag [gcmTagSize]byte
        gcmAesData(&g.productTable, data, &expectedTag)
index 778392661dae6e8f9118304488e00cd8142b5932..385955ed77838b8b5eb860a439d7d6e3c237cb26 100644 (file)
@@ -12,7 +12,7 @@ import (
 
 func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
        var H, counter, tagMask [gcmBlockSize]byte
-       g.cipher.Encrypt(H[:], H[:])
+       aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
        deriveCounterGeneric(&H, &counter, nonce)
        gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
 
@@ -25,7 +25,7 @@ func sealGeneric(out []byte, g *GCM, nonce, plaintext, additionalData []byte) {
 
 func openGeneric(out []byte, g *GCM, nonce, ciphertext, additionalData []byte) error {
        var H, counter, tagMask [gcmBlockSize]byte
-       g.cipher.Encrypt(H[:], H[:])
+       aes.EncryptBlockInternal(&g.cipher, H[:], H[:])
        deriveCounterGeneric(&H, &counter, nonce)
        gcmCounterCryptGeneric(&g.cipher, tagMask[:], tagMask[:], &counter)
 
@@ -70,7 +70,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz
        var mask [gcmBlockSize]byte
 
        for len(src) >= gcmBlockSize {
-               b.Encrypt(mask[:], counter[:])
+               aes.EncryptBlockInternal(b, mask[:], counter[:])
                gcmInc32(counter)
 
                subtle.XORBytes(out, src, mask[:])
@@ -79,7 +79,7 @@ func gcmCounterCryptGeneric(b *aes.Block, out, src []byte, counter *[gcmBlockSiz
        }
 
        if len(src) > 0 {
-               b.Encrypt(mask[:], counter[:])
+               aes.EncryptBlockInternal(b, mask[:], counter[:])
                gcmInc32(counter)
                subtle.XORBytes(out, src, mask[:])
        }