"bytes"
"crypto/elliptic"
"crypto/internal/cryptotest"
+ "crypto/internal/entropy/v1.0.0"
"crypto/internal/fips140"
"crypto/internal/fips140/aes"
"crypto/internal/fips140/aes/gcm"
var noPAAPAI = os.Getenv("GONOPAAPAI") == "1"
+// Use the capabilities, configuration and commands for the entropy source.
+// This is used to test the separate entropy source in crypto/internal/entropy
+// since the algorithm name alone can't indicate which to test.
+var entropyTesting = os.Getenv("GOENTROPYSOURCEACVP") == "1"
+
func TestMain(m *testing.M) {
if noPAAPAI {
for _, p := range impl.Packages() {
//go:embed acvp_capabilities.json
capabilitiesJson []byte
+ // Separate capabilities specific to testing the entropy source's SHA2-384 implementation.
+ // This implementation differs from the FIPS module's SHA2-384 in its supported input sizes.
+ // Set the GOENTROPYSOURCEACVP environment variable to use these capabilities in place of
+ // capabilitiesJson
+ //go:embed acvp_capabilities.entropy.json
+ entropyCapabilitiesJson []byte
+
// commands should reflect what config says we support. E.g. adding a command here will be a NOP
// unless the configuration/acvp_capabilities.json indicates the command's associated algorithm
// is supported.
"SHA3-512": cmdHashAft(sha3.New512()),
"SHA3-512/MCT": cmdSha3Mct(sha3.New512()),
+ // Note: the "/ENTROPY" suffix is our own creation, and applied conditionally
+ // based on the environment variable that indicates our acvp_test module wrapper
+ // is being used for evaluating the separate SHA-384 implementation for the
+ // CPU jitter entropy conditioning. Set GOENTROPYSOURCEACVP=1 to use these commands
+ // in place of SHA2-384.
+ "SHA2-384/ENTROPY": cmdEntropyHashEntropySha384Aft(),
+ "SHA2-384/MCT/ENTROPY": cmdEntropyHashEntropySha384Mct(),
+
// 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,
return fmt.Errorf("reading request: %w", err)
}
+ if entropyTesting && strings.HasPrefix(req.name, "SHA2-384") {
+ req.name = fmt.Sprintf("%s/ENTROPY", req.name)
+ }
+
cmd, exists := commands[req.name]
if !exists {
return fmt.Errorf("unknown command: %q", req.name)
// which takes no arguments and returns a single byte string
// which is a JSON blob of ACVP algorithm configuration."
func cmdGetConfig() command {
+ // If GOENTROPYSOURCEACVP is set, then use the entropyCapabilitiesJson
+ // instead of capabilitiesJson.
+ capabilities := [][]byte{capabilitiesJson}
+ if entropyTesting {
+ capabilities = [][]byte{entropyCapabilitiesJson}
+ }
+
return command{
handler: func(args [][]byte) ([][]byte, error) {
- return [][]byte{capabilitiesJson}, nil
+ return capabilities, nil
},
}
}
}
}
+// cmdEntropyHashEntropySha384Aft returns a command handler that tests the
+// entropy package's SHA2-384 digest for AFT inputs.
+func cmdEntropyHashEntropySha384Aft() command {
+ return command{
+ requiredArgs: 1, // Message to hash.
+ handler: func(args [][]byte) ([][]byte, error) {
+ digest := entropy.TestingOnlySHA384(args[0])
+ return [][]byte{digest[:]}, nil
+ },
+ }
+}
+
+// cmdEntropyHashEntropySha384Mct returns a command handler that tests the
+// entropy package's SHA2-384 digest for MCT inputs.
+func cmdEntropyHashEntropySha384Mct() command {
+ return command{
+ requiredArgs: 1, // Seed message.
+ handler: func(args [][]byte) ([][]byte, error) {
+ hSize := 48
+ seed := args[0]
+
+ digest := make([]byte, 0, hSize)
+ buf := make([]byte, 0, 3*hSize)
+ buf = append(buf, seed...)
+ buf = append(buf, seed...)
+ buf = append(buf, seed...)
+
+ for i := 0; i < 1000; i++ {
+ digestRaw := entropy.TestingOnlySHA384(buf)
+ digest = digestRaw[:hSize]
+
+ copy(buf, buf[hSize:])
+ copy(buf[2*hSize:], digest)
+ }
+
+ return [][]byte{buf[hSize*2:]}, nil
+ },
+ }
+}
+
// cmdSha3Mct returns a command handler for the specified hash
// algorithm for SHA-3 monte carlo test (MCT) test cases.
//