crypto/internal/fips140test: add SHAKE-* ACVP tests

This commit adds ACVP test coverage for SHAKE-128 and SHAKE-256
based on the NIST spec:

  https://pages.nist.gov/ACVP/draft-celi-acvp-sha3.html

Updates #69642

Change-Id: Ia6899def452fcb63a03603b7919fcb0c3576474b
Reviewed-on: https://go-review.googlesource.com/c/go/+/622395
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Bypass: Dmitri Shuralyov <dmitshur@golang.org>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
This commit is contained in:
Daniel McCarney 2024-10-19 14:10:28 -04:00 committed by Gopher Robot
parent 8cb6d3b826
commit 035d3c8f53
3 changed files with 83 additions and 0 deletions

View file

@ -11,6 +11,9 @@
{"algorithm":"SHA3-384","messageLength":[{"increment":8,"max":65528,"min":0}],"revision":"2.0"},
{"algorithm":"SHA3-512","messageLength":[{"increment":8,"max":65528,"min":0}],"revision":"2.0"},
{"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":"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"},
{"algorithm":"HMAC-SHA2-384","keyLen":[{"increment":8,"max":524288,"min":8}],"macLen":[{"increment":8,"max":384,"min":32}],"revision":"1.0"},

View file

@ -11,6 +11,9 @@
{"Wrapper": "go", "In": "vectors/SHA3-384.bz2", "Out": "expected/SHA3-384.bz2"},
{"Wrapper": "go", "In": "vectors/SHA3-512.bz2", "Out": "expected/SHA3-512.bz2"},
{"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/HMAC-SHA2-224.bz2", "Out": "expected/HMAC-SHA2-224.bz2"},
{"Wrapper": "go", "In": "vectors/HMAC-SHA2-256.bz2", "Out": "expected/HMAC-SHA2-256.bz2"},
{"Wrapper": "go", "In": "vectors/HMAC-SHA2-384.bz2", "Out": "expected/HMAC-SHA2-384.bz2"},

View file

@ -95,6 +95,8 @@ const (
var (
// SHA2 algorithm capabilities:
// 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
// HMAC algorithm capabilities:
// https://pages.nist.gov/ACVP/draft-fussell-acvp-mac.html#section-7
// PBKDF2 algorithm capabilities:
@ -140,6 +142,17 @@ var (
"SHA3-512": cmdHashAft(sha3.New512()),
"SHA3-512/MCT": cmdSha3Mct(sha3.New512()),
// Note: SHAKE AFT and VOT test types can be handled by the same command
// handler impl, but use distinct acvptool command names, and so are
// registered twice with the same digest: once under "SHAKE-xxx" for AFT,
// and once under"SHAKE-xxx/VOT" for VOT.
"SHAKE-128": cmdShakeAftVot(sha3.NewShake128()),
"SHAKE-128/VOT": cmdShakeAftVot(sha3.NewShake128()),
"SHAKE-128/MCT": cmdShakeMct(sha3.NewShake128()),
"SHAKE-256": cmdShakeAftVot(sha3.NewShake256()),
"SHAKE-256/VOT": cmdShakeAftVot(sha3.NewShake256()),
"SHAKE-256/MCT": cmdShakeMct(sha3.NewShake256()),
"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() }),
@ -410,6 +423,70 @@ func cmdSha3Mct(h fips140.Hash) command {
}
}
func cmdShakeAftVot(h *sha3.SHAKE) command {
return command{
requiredArgs: 2, // Message, output length (bytes)
handler: func(args [][]byte) ([][]byte, error) {
msg := args[0]
outLenBytes := binary.LittleEndian.Uint32(args[1])
digest := make([]byte, outLenBytes)
h.Reset()
h.Write(msg)
h.Read(digest)
return [][]byte{digest}, nil
},
}
}
func cmdShakeMct(h *sha3.SHAKE) command {
return command{
requiredArgs: 4, // Seed message, min output length (bytes), max output length (bytes), output length (bytes)
handler: func(args [][]byte) ([][]byte, error) {
md := args[0]
minOutBytes := binary.LittleEndian.Uint32(args[1])
maxOutBytes := binary.LittleEndian.Uint32(args[2])
outputLenBytes := binary.LittleEndian.Uint32(args[3])
if outputLenBytes < 2 {
return nil, fmt.Errorf("invalid output length: %d", outputLenBytes)
}
rangeBytes := maxOutBytes - minOutBytes + 1
if rangeBytes == 0 {
return nil, fmt.Errorf("invalid maxOutBytes and minOutBytes: %d, %d", maxOutBytes, minOutBytes)
}
for i := 0; i < 1000; i++ {
// "The MSG[i] input to SHAKE MUST always contain at least 128 bits. If this is not the case
// as the previous digest was too short, append empty bits to the rightmost side of the digest."
boundary := min(len(md), 16)
msg := make([]byte, 16)
copy(msg, md[:boundary])
// MD[i] = SHAKE(MSG[i], OutputLen * 8)
h.Reset()
h.Write(msg)
digest := make([]byte, outputLenBytes)
h.Read(digest)
md = digest
// RightmostOutputBits = 16 rightmost bits of MD[i] as an integer
// OutputLen = minOutBytes + (RightmostOutputBits % Range)
rightmostOutput := uint32(md[outputLenBytes-2])<<8 | uint32(md[outputLenBytes-1])
outputLenBytes = minOutBytes + (rightmostOutput % rangeBytes)
}
encodedOutputLenBytes := make([]byte, 4)
binary.LittleEndian.PutUint32(encodedOutputLenBytes, outputLenBytes)
return [][]byte{md, encodedOutputLenBytes}, nil
},
}
}
func cmdHmacAft(h func() fips140.Hash) command {
return command{
requiredArgs: 2, // Message and key