Skip to content

Commit b941d2b

Browse files
cpugopherbot
authored andcommitted
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 <[email protected]> Reviewed-by: Roland Shoemaker <[email protected]> Auto-Submit: Roland Shoemaker <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
1 parent 102406e commit b941d2b

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

src/crypto/internal/fips140test/acvp_capabilities.json

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
{"algorithm":"SHAKE-128","inBit":false,"outBit":false,"inEmpty":true,"outputLen":[{"min":16,"max":65536,"increment":8}],"revision":"1.0"},
1515
{"algorithm":"SHAKE-256","inBit":false,"outBit":false,"inEmpty":true,"outputLen":[{"min":16,"max":65536,"increment":8}],"revision":"1.0"},
16+
{"algorithm":"cSHAKE-128","hexCustomization":false,"outputLen":[{"min":16,"max":65536,"increment":8}],"msgLen":[{"min":0,"max":65536,"increment":8}],"revision":"1.0"},
17+
{"algorithm":"cSHAKE-256","hexCustomization":false,"outputLen":[{"min":16,"max":65536,"increment":8}],"msgLen":[{"min":0,"max":65536,"increment":8}],"revision":"1.0"},
1618

1719
{"algorithm":"HMAC-SHA2-224","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":224,"min":32}],"revision":"1.0"},
1820
{"algorithm":"HMAC-SHA2-256","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":256,"min":32}],"revision":"1.0"},

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

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
{"Wrapper": "go", "In": "vectors/SHAKE-128.bz2", "Out": "expected/SHAKE-128.bz2"},
1515
{"Wrapper": "go", "In": "vectors/SHAKE-256.bz2", "Out": "expected/SHAKE-256.bz2"},
16+
{"Wrapper": "go", "In": "vectors/cSHAKE-128.bz2", "Out": "expected/cSHAKE-128.bz2"},
17+
{"Wrapper": "go", "In": "vectors/cSHAKE-256.bz2", "Out": "expected/cSHAKE-256.bz2"},
1618

1719
{"Wrapper": "go", "In": "vectors/HMAC-SHA2-224.bz2", "Out": "expected/HMAC-SHA2-224.bz2"},
1820
{"Wrapper": "go", "In": "vectors/HMAC-SHA2-256.bz2", "Out": "expected/HMAC-SHA2-256.bz2"},

src/crypto/internal/fips140test/acvp_test.go

+92-1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ var (
105105
// https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#section-7.2
106106
// SHA3 and SHAKE algorithm capabilities:
107107
// https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html#name-sha3-and-shake-algorithm-ca
108+
// cSHAKE algorithm capabilities:
109+
// https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-7.2
108110
// HMAC algorithm capabilities:
109111
// https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#section-7
110112
// PBKDF2 algorithm capabilities:
@@ -179,6 +181,11 @@ var (
179181
"SHAKE-256/VOT": cmdShakeAftVot(sha3.NewShake256()),
180182
"SHAKE-256/MCT": cmdShakeMct(sha3.NewShake256()),
181183

184+
"cSHAKE-128": cmdCShakeAft(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake128(N, S) }),
185+
"cSHAKE-128/MCT": cmdCShakeMct(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake128(N, S) }),
186+
"cSHAKE-256": cmdCShakeAft(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake256(N, S) }),
187+
"cSHAKE-256/MCT": cmdCShakeMct(func(N, S []byte) *sha3.SHAKE { return sha3.NewCShake256(N, S) }),
188+
182189
"HMAC-SHA2-224": cmdHmacAft(func() fips140.Hash { return sha256.New224() }),
183190
"HMAC-SHA2-256": cmdHmacAft(func() fips140.Hash { return sha256.New() }),
184191
"HMAC-SHA2-384": cmdHmacAft(func() fips140.Hash { return sha512.New384() }),
@@ -609,6 +616,90 @@ func cmdShakeMct(h *sha3.SHAKE) command {
609616
}
610617
}
611618

619+
func cmdCShakeAft(hFn func(N, S []byte) *sha3.SHAKE) command {
620+
return command{
621+
requiredArgs: 4, // Message, output length bytes, function name, customization
622+
handler: func(args [][]byte) ([][]byte, error) {
623+
msg := args[0]
624+
outLenBytes := binary.LittleEndian.Uint32(args[1])
625+
functionName := args[2]
626+
customization := args[3]
627+
628+
h := hFn(functionName, customization)
629+
h.Write(msg)
630+
631+
out := make([]byte, outLenBytes)
632+
h.Read(out)
633+
634+
return [][]byte{out}, nil
635+
},
636+
}
637+
}
638+
639+
func cmdCShakeMct(hFn func(N, S []byte) *sha3.SHAKE) command {
640+
return command{
641+
requiredArgs: 6, // Message, min output length (bits), max output length (bits), output length (bits), increment (bits), customization
642+
handler: func(args [][]byte) ([][]byte, error) {
643+
message := args[0]
644+
minOutLenBytes := binary.LittleEndian.Uint32(args[1])
645+
maxOutLenBytes := binary.LittleEndian.Uint32(args[2])
646+
outputLenBytes := binary.LittleEndian.Uint32(args[3])
647+
incrementBytes := binary.LittleEndian.Uint32(args[4])
648+
customization := args[5]
649+
650+
if outputLenBytes < 2 {
651+
return nil, fmt.Errorf("invalid output length: %d", outputLenBytes)
652+
}
653+
654+
rangeBits := (maxOutLenBytes*8 - minOutLenBytes*8) + 1
655+
if rangeBits == 0 {
656+
return nil, fmt.Errorf("invalid maxOutLenBytes and minOutLenBytes: %d, %d", maxOutLenBytes, minOutLenBytes)
657+
}
658+
659+
// cSHAKE Monte Carlo test inner loop:
660+
// https://pages.nist.gov/ACVP/draft-celi-acvp-xof.html#section-6.2.1
661+
for i := 0; i < 1000; i++ {
662+
// InnerMsg = Left(Output[i-1] || ZeroBits(128), 128);
663+
boundary := min(len(message), 16)
664+
innerMsg := make([]byte, 16)
665+
copy(innerMsg, message[:boundary])
666+
667+
// Output[i] = CSHAKE(InnerMsg, OutputLen, FunctionName, Customization);
668+
h := hFn(nil, customization) // Note: function name fixed to "" for MCT.
669+
h.Write(innerMsg)
670+
digest := make([]byte, outputLenBytes)
671+
h.Read(digest)
672+
message = digest
673+
674+
// Rightmost_Output_bits = Right(Output[i], 16);
675+
rightmostOutput := digest[outputLenBytes-2:]
676+
// IMPORTANT: the specification says:
677+
// NOTE: For the "Rightmost_Output_bits % Range" operation, the Rightmost_Output_bits bit string
678+
// should be interpretted as a little endian-encoded number.
679+
// This is **a lie**! It has to be interpreted as a big-endian number.
680+
rightmostOutputBE := binary.BigEndian.Uint16(rightmostOutput)
681+
682+
// OutputLen = MinOutLen + (floor((Rightmost_Output_bits % Range) / OutLenIncrement) * OutLenIncrement);
683+
incrementBits := incrementBytes * 8
684+
outputLenBits := (minOutLenBytes * 8) + (((uint32)(rightmostOutputBE)%rangeBits)/incrementBits)*incrementBits
685+
outputLenBytes = outputLenBits / 8
686+
687+
// Customization = BitsToString(InnerMsg || Rightmost_Output_bits);
688+
msgWithBits := append(innerMsg, rightmostOutput...)
689+
customization = make([]byte, len(msgWithBits))
690+
for i, b := range msgWithBits {
691+
customization[i] = (b % 26) + 65
692+
}
693+
}
694+
695+
encodedOutputLenBytes := make([]byte, 4)
696+
binary.LittleEndian.PutUint32(encodedOutputLenBytes, outputLenBytes)
697+
698+
return [][]byte{message, encodedOutputLenBytes, customization}, nil
699+
},
700+
}
701+
}
702+
612703
func cmdHmacAft(h func() fips140.Hash) command {
613704
return command{
614705
requiredArgs: 2, // Message and key
@@ -1973,7 +2064,7 @@ func TestACVP(t *testing.T) {
19732064
bsslModule = "boringssl.googlesource.com/boringssl.git"
19742065
bsslVersion = "v0.0.0-20250207174145-0bb19f6126cb"
19752066
goAcvpModule = "github.com/cpu/go-acvp"
1976-
goAcvpVersion = "v0.0.0-20250117180340-0406d83a4b0d"
2067+
goAcvpVersion = "v0.0.0-20250126154732-de1ba727a0be"
19772068
)
19782069

19792070
// In crypto/tls/bogo_shim_test.go the test is skipped if run on a builder with runtime.GOOS == "windows"

0 commit comments

Comments
 (0)