]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/internal/fips140test: add SHAKE-* ACVP tests
authorDaniel McCarney <daniel@binaryparadox.net>
Sat, 19 Oct 2024 18:10:28 +0000 (14:10 -0400)
committerGopher Robot <gobot@golang.org>
Mon, 10 Feb 2025 17:33:03 +0000 (09:33 -0800)
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>
src/crypto/internal/fips140test/acvp_capabilities.json
src/crypto/internal/fips140test/acvp_test.config.json
src/crypto/internal/fips140test/acvp_test.go

index 117bd9e30b3f8aa0b2537357f035e9b1a2a7b52d..77f21c3347efdcb9447867523afee30bfebc391a 100644 (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"},
index c2bb9fc662dcebcaea0fcc8f912c89cfc8b07706..1cdfd8f85edae7dcd00ab1612fef5f5462efeda2 100644 (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"},
index 2f425effd5a11cf09c78cad55f24781fa904c6fe..23dcdecd9328a39cdf866874a7fab1d74d975fa8 100644 (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