From: Daniel McCarney Date: Thu, 23 Jan 2025 19:34:46 +0000 (-0500) Subject: crypto/internal/fips140test: add cSHAKE ACVP tests X-Git-Tag: go1.25rc1~1072 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=b941d2b6d8bd9663abec7761de366b09a2be7445;p=gostls13.git 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 Reviewed-by: Roland Shoemaker Auto-Submit: Roland Shoemaker Reviewed-by: Dmitri Shuralyov --- 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"