Skip to content

Commit ae26a30

Browse files
cpuFiloSottile
authored andcommitted
crypto/internal/fips140test: add CMAC-AES ACVP tests
Adds ACVP test coverage for CMAC-AES based on the NIST spec: https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html Updates golang#69642 Change-Id: Ie731863b84c6f8d74c64daa6a6848354420151b2 Reviewed-on: https://go-review.googlesource.com/c/go/+/635762 Reviewed-by: Roland Shoemaker <[email protected]> Reviewed-by: Cherry Mui <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent ff27d27 commit ae26a30

File tree

3 files changed

+60
-2
lines changed

3 files changed

+60
-2
lines changed

src/crypto/internal/fips140test/acvp_capabilities.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,6 @@
5353
{"algorithm":"ACVP-AES-CBC","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"revision":"1.0"},
5454
{"algorithm":"ACVP-AES-CTR","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":8,"max":128,"increment":8}],"incrementalCounter":true,"overflowCounter":true,"performCounterTests":true,"revision":"1.0"},
5555
{"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[96,104,112,120,128],"ivLen":[96],"ivGen":"external","revision":"1.0"},
56-
{"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[128],"ivLen":[96],"ivGen":"internal","ivGenMode":"8.2.2","revision":"1.0"}
56+
{"algorithm":"ACVP-AES-GCM","direction":["encrypt","decrypt"],"keyLen":[128,192,256],"payloadLen":[{"min":0,"max":65536,"increment":8}],"aadLen":[{"min":0,"max":65536,"increment":8}],"tagLen":[128],"ivLen":[96],"ivGen":"internal","ivGenMode":"8.2.2","revision":"1.0"},
57+
{"algorithm":"CMAC-AES","capabilities":[{"direction":["gen","ver"],"msgLen":[{"min":0,"max":524288,"increment":8}],"keyLen":[128,256],"macLen":[{"min":8,"max":128,"increment":8}]}],"revision":"1.0"}
5758
]

src/crypto/internal/fips140test/acvp_test.config.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,7 @@
3535

3636
{"Wrapper": "go", "In": "vectors/ACVP-AES-CBC.bz2", "Out": "expected/ACVP-AES-CBC.bz2"},
3737
{"Wrapper": "go", "In": "vectors/ACVP-AES-CTR.bz2", "Out": "expected/ACVP-AES-CTR.bz2"},
38-
{"Wrapper": "go", "In": "vectors/ACVP-AES-GCM.bz2", "Out": "expected/ACVP-AES-GCM.bz2"}
38+
{"Wrapper": "go", "In": "vectors/ACVP-AES-GCM.bz2", "Out": "expected/ACVP-AES-GCM.bz2"},
39+
40+
{"Wrapper": "go", "In": "vectors/CMAC-AES.bz2", "Out": "expected/CMAC-AES.bz2"}
3941
]

src/crypto/internal/fips140test/acvp_test.go

+55
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"crypto/internal/fips140/sha256"
3636
"crypto/internal/fips140/sha3"
3737
"crypto/internal/fips140/sha512"
38+
"crypto/internal/fips140/subtle"
3839
"crypto/rand"
3940
_ "embed"
4041
"encoding/binary"
@@ -189,6 +190,9 @@ var (
189190
"AES-GCM/open": cmdAesGcmOpen(false),
190191
"AES-GCM-randnonce/seal": cmdAesGcmSeal(true),
191192
"AES-GCM-randnonce/open": cmdAesGcmOpen(true),
193+
194+
"CMAC-AES": cmdCmacAesAft(),
195+
"CMAC-AES/verify": cmdCmacAesVerifyAft(),
192196
}
193197
)
194198

@@ -1154,6 +1158,57 @@ func cmdAesGcmOpen(randNonce bool) command {
11541158
}
11551159
}
11561160

1161+
func cmdCmacAesAft() command {
1162+
return command{
1163+
requiredArgs: 3, // Number of output bytes, key, message
1164+
handler: func(args [][]byte) ([][]byte, error) {
1165+
// safe to truncate to int based on our capabilities describing a max MAC output len of 128 bits.
1166+
outputLen := int(binary.LittleEndian.Uint32(args[0]))
1167+
key := args[1]
1168+
message := args[2]
1169+
1170+
blockCipher, err := aes.New(key)
1171+
if err != nil {
1172+
return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err)
1173+
}
1174+
1175+
cmac := gcm.NewCMAC(blockCipher)
1176+
tag := cmac.MAC(message)
1177+
1178+
if outputLen > len(tag) {
1179+
return nil, fmt.Errorf("invalid output length: expected %d, got %d", outputLen, len(tag))
1180+
}
1181+
1182+
return [][]byte{tag[:outputLen]}, nil
1183+
},
1184+
}
1185+
}
1186+
1187+
func cmdCmacAesVerifyAft() command {
1188+
return command{
1189+
requiredArgs: 3, // Key, message, claimed MAC
1190+
handler: func(args [][]byte) ([][]byte, error) {
1191+
key := args[0]
1192+
message := args[1]
1193+
claimedMAC := args[2]
1194+
1195+
blockCipher, err := aes.New(key)
1196+
if err != nil {
1197+
return nil, fmt.Errorf("creating AES block cipher with key len %d: %w", len(key), err)
1198+
}
1199+
1200+
cmac := gcm.NewCMAC(blockCipher)
1201+
tag := cmac.MAC(message)
1202+
1203+
if subtle.ConstantTimeCompare(tag[:len(claimedMAC)], claimedMAC) != 1 {
1204+
return [][]byte{{0}}, nil
1205+
}
1206+
1207+
return [][]byte{{1}}, nil
1208+
},
1209+
}
1210+
}
1211+
11571212
func TestACVP(t *testing.T) {
11581213
testenv.SkipIfShortAndSlow(t)
11591214

0 commit comments

Comments
 (0)