mirror of
https://github.com/golang/go.git
synced 2025-10-19 19:13:18 +00:00
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>
This commit is contained in:
parent
102406edbf
commit
b941d2b6d8
3 changed files with 96 additions and 1 deletions
|
@ -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"},
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue