aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/internal
diff options
context:
space:
mode:
authorDaniel McCarney <daniel@binaryparadox.net>2025-01-23 14:34:46 -0500
committerGopher Robot <gobot@golang.org>2025-02-11 13:31:01 -0800
commitb941d2b6d8bd9663abec7761de366b09a2be7445 (patch)
tree0dec73fb0b1cbfa106180170a08094198fa7ba4b /src/crypto/internal
parent102406edbfff616ad5a56df5e7347ae97804ea58 (diff)
downloadgo-b941d2b6d8bd9663abec7761de366b09a2be7445.tar.xz
crypto/internal/fips140test: add cSHAKE ACVP tests
Adds ACVP test coverage for the SP 800-185 cSHAKE-128 and cSHAKE-256 algorithms based on the NIST spec: https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html Updates #69642 Change-Id: I4a6ef9a99dfe520f3177e0e7c258326475690f5f Reviewed-on: https://go-review.googlesource.com/c/go/+/648455 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Roland Shoemaker <roland@golang.org> Auto-Submit: Roland Shoemaker <roland@golang.org> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Diffstat (limited to 'src/crypto/internal')
-rw-r--r--src/crypto/internal/fips140test/acvp_capabilities.json2
-rw-r--r--src/crypto/internal/fips140test/acvp_test.config.json2
-rw-r--r--src/crypto/internal/fips140test/acvp_test.go93
3 files changed, 96 insertions, 1 deletions
diff --git a/src/crypto/internal/fips140test/acvp_capabilities.json b/src/crypto/internal/fips140test/acvp_capabilities.json
index b7fa63f75e..b2007438ec 100644
--- a/src/crypto/internal/fips140test/acvp_capabilities.json
+++ b/src/crypto/internal/fips140test/acvp_capabilities.json
@@ -13,6 +13,8 @@
{"algorithm":"SHAKE-128","inBit":false,"outBit":false,"inEmpty":true,"outputLen":[{"min":16,"max":65536,"increment":8}],"revision":"1.0"},
{"algorithm":"SHAKE-256","inBit":false,"outBit":false,"inEmpty":true,"outputLen":[{"min":16,"max":65536,"increment":8}],"revision":"1.0"},
+ {"algorithm":"cSHAKE-128","hexCustomization":false,"outputLen":[{"min":16,"max":65536,"increment":8}],"msgLen":[{"min":0,"max":65536,"increment":8}],"revision":"1.0"},
+ {"algorithm":"cSHAKE-256","hexCustomization":false,"outputLen":[{"min":16,"max":65536,"increment":8}],"msgLen":[{"min":0,"max":65536,"increment":8}],"revision":"1.0"},
{"algorithm":"HMAC-SHA2-224","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":224,"min":32}],"revision":"1.0"},
{"algorithm":"HMAC-SHA2-256","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":256,"min":32}],"revision":"1.0"},
diff --git a/src/crypto/internal/fips140test/acvp_test.config.json b/src/crypto/internal/fips140test/acvp_test.config.json
index 2f905e0870..e14a281267 100644
--- a/src/crypto/internal/fips140test/acvp_test.config.json
+++ b/src/crypto/internal/fips140test/acvp_test.config.json
@@ -13,6 +13,8 @@
{"Wrapper": "go", "In": "vectors/SHAKE-128.bz2", "Out": "expected/SHAKE-128.bz2"},
{"Wrapper": "go", "In": "vectors/SHAKE-256.bz2", "Out": "expected/SHAKE-256.bz2"},
+ {"Wrapper": "go", "In": "vectors/cSHAKE-128.bz2", "Out": "expected/cSHAKE-128.bz2"},
+ {"Wrapper": "go", "In": "vectors/cSHAKE-256.bz2", "Out": "expected/cSHAKE-256.bz2"},
{"Wrapper": "go", "In": "vectors/HMAC-SHA2-224.bz2", "Out": "expected/HMAC-SHA2-224.bz2"},
{"Wrapper": "go", "In": "vectors/HMAC-SHA2-256.bz2", "Out": "expected/HMAC-SHA2-256.bz2"},
diff --git a/src/crypto/internal/fips140test/acvp_test.go b/src/crypto/internal/fips140test/acvp_test.go
index b1857c892c..f25f3d4f0f 100644
--- a/src/crypto/internal/fips140test/acvp_test.go
+++ b/src/crypto/internal/fips140test/acvp_test.go
@@ -105,6 +105,8 @@ var (
// https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2
// SHA3 and SHAKE algorithm capabilities:
// https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-sha3-and-shake-algorithm-ca
+ // cSHAKE algorithm capabilities:
+ // https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-7.2
// HMAC algorithm capabilities:
// https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#section-7
// PBKDF2 algorithm capabilities:
@@ -179,6 +181,11 @@ var (
"SHAKE-256/VOT": cmdShakeAftVot(sha3.NewShake256()),
"SHAKE-256/MCT": cmdShakeMct(sha3.NewShake256()),
+ "cSHAKE-128": cmdCShakeAft(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake128(N, S) }),
+ "cSHAKE-128/MCT": cmdCShakeMct(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake128(N, S) }),
+ "cSHAKE-256": cmdCShakeAft(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake256(N, S) }),
+ "cSHAKE-256/MCT": cmdCShakeMct(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake256(N, S) }),
+
"HMAC-SHA2-224": cmdHmacAft(func() fips140.Hash { return sha256.New224() }),
"HMAC-SHA2-256": cmdHmacAft(func() fips140.Hash { return sha256.New() }),
"HMAC-SHA2-384": cmdHmacAft(func() fips140.Hash { return sha512.New384() }),
@@ -609,6 +616,90 @@ func cmdShakeMct(h *sha3.SHAKE) command {
}
}
+func cmdCShakeAft(hFn func(N, S []byte) *sha3.SHAKE) command {
+ return command{
+ requiredArgs: 4, // Message, output length bytes, function name, customization
+ handler: func(args [][]byte) ([][]byte, error) {
+ msg := args[0]
+ outLenBytes := binary.LittleEndian.Uint32(args[1])
+ functionName := args[2]
+ customization := args[3]
+
+ h := hFn(functionName, customization)
+ h.Write(msg)
+
+ out := make([]byte, outLenBytes)
+ h.Read(out)
+
+ return [][]byte{out}, nil
+ },
+ }
+}
+
+func cmdCShakeMct(hFn func(N, S []byte) *sha3.SHAKE) command {
+ return command{
+ requiredArgs: 6, // Message, min output length (bits), max output length (bits), output length (bits), increment (bits), customization
+ handler: func(args [][]byte) ([][]byte, error) {
+ message := args[0]
+ minOutLenBytes := binary.LittleEndian.Uint32(args[1])
+ maxOutLenBytes := binary.LittleEndian.Uint32(args[2])
+ outputLenBytes := binary.LittleEndian.Uint32(args[3])
+ incrementBytes := binary.LittleEndian.Uint32(args[4])
+ customization := args[5]
+
+ if outputLenBytes < 2 {
+ return nil, fmt.Errorf("invalid output length: %d", outputLenBytes)
+ }
+
+ rangeBits := (maxOutLenBytes*8 - minOutLenBytes*8) + 1
+ if rangeBits == 0 {
+ return nil, fmt.Errorf("invalid maxOutLenBytes and minOutLenBytes: %d, %d", maxOutLenBytes, minOutLenBytes)
+ }
+
+ // cSHAKE Monte Carlo test inner loop:
+ // https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-6.2.1
+ for i := 0; i < 1000; i++ {
+ // InnerMsg = Left(Output[i-1] || ZeroBits(128), 128);
+ boundary := min(len(message), 16)
+ innerMsg := make([]byte, 16)
+ copy(innerMsg, message[:boundary])
+
+ // Output[i] = CSHAKE(InnerMsg, OutputLen, FunctionName, Customization);
+ h := hFn(nil, customization) // Note: function name fixed to "" for MCT.
+ h.Write(innerMsg)
+ digest := make([]byte, outputLenBytes)
+ h.Read(digest)
+ message = digest
+
+ // Rightmost_Output_bits = Right(Output[i], 16);
+ rightmostOutput := digest[outputLenBytes-2:]
+ // IMPORTANT: the specification says:
+ // NOTE: For the "Rightmost_Output_bits % Range" operation, the Rightmost_Output_bits bit string
+ // should be interpretted as a little endian-encoded number.
+ // This is **a lie**! It has to be interpreted as a big-endian number.
+ rightmostOutputBE := binary.BigEndian.Uint16(rightmostOutput)
+
+ // OutputLen = MinOutLen + (floor((Rightmost_Output_bits % Range) / OutLenIncrement) * OutLenIncrement);
+ incrementBits := incrementBytes * 8
+ outputLenBits := (minOutLenBytes * 8) + (((uint32)(rightmostOutputBE)%rangeBits)/incrementBits)*incrementBits
+ outputLenBytes = outputLenBits / 8
+
+ // Customization = BitsToString(InnerMsg || Rightmost_Output_bits);
+ msgWithBits := append(innerMsg, rightmostOutput...)
+ customization = make([]byte, len(msgWithBits))
+ for i, b := range msgWithBits {
+ customization[i] = (b % 26) + 65
+ }
+ }
+
+ encodedOutputLenBytes := make([]byte, 4)
+ binary.LittleEndian.PutUint32(encodedOutputLenBytes, outputLenBytes)
+
+ return [][]byte{message, encodedOutputLenBytes, customization}, nil
+ },
+ }
+}
+
func cmdHmacAft(h func() fips140.Hash) command {
return command{
requiredArgs: 2, // Message and key
@@ -1973,7 +2064,7 @@ func TestACVP(t *testing.T) {
bsslModule = "boringssl.googlesource.com/boringssl.git"
bsslVersion = "v0.0.0-20250207174145-0bb19f6126cb"
goAcvpModule = "github.com/cpu/go-acvp"
- goAcvpVersion = "v0.0.0-20250117180340-0406d83a4b0d"
+ goAcvpVersion = "v0.0.0-20250126154732-de1ba727a0be"
)
// In crypto/tls/bogo_shim_test.go the test is skipped if run on a builder with runtime.GOOS == "windows"