diff --git a/util/fipstools/acvp/ACVP.md b/util/fipstools/acvp/ACVP.md index 2e82f15b9..201bcf917 100644 --- a/util/fipstools/acvp/ACVP.md +++ b/util/fipstools/acvp/ACVP.md @@ -90,9 +90,15 @@ The other commands are as follows. (Note that you only need to implement the com | SHA2-384 | Value to hash | Digest | | SHA2-512 | Value to hash | Digest | | SHA2-512/256 | Value to hash | Digest | +| SHA-1/MCT | Initial seed¹ | Digest | +| SHA2-224/MCT | Initial seed¹ | Digest | +| SHA2-256/MCT | Initial seed¹ | Digest | +| SHA2-384/MCT | Initial seed¹ | Digest | +| SHA2-512/MCT | Initial seed¹ | Digest | +| SHA2-512/256/MCT | Initial seed¹ | Digest | | TLSKDF/<1.0\|1.2>/<HASH> | Number output bytes, secret, label, seed1, seed2 | Output | -¹ The iterated block-cipher tests would result in excessive numbers of round trips if the module wrapper handled only basic operations. Thus some ACVP logic is pushed down for these tests so that the inner loop can be handled locally. Either read the [NIST documentation](https://usnistgov.github.io/ACVP/draft-celi-acvp-symmetric.html#name-monte-carlo-tests-for-block) to understand the iteration count and return values or, probably more fruitfully, see how these functions are handled in the `modulewrapper` directory. +¹ The iterated tests would result in excessive numbers of round trips if the module wrapper handled only basic operations. Thus some ACVP logic is pushed down for these tests so that the inner loop can be handled locally. Either read the NIST documentation ([block-ciphers](https://usnistgov.github.io/ACVP/draft-celi-acvp-symmetric.html#name-monte-carlo-tests-for-block) [hashes](https://pages.nist.gov/ACVP/draft-celi-acvp-sha.html#name-monte-carlo-tests-for-sha-1)) to understand the iteration count and return values or, probably more fruitfully, see how these functions are handled in the `modulewrapper` directory. ## Online operation diff --git a/util/fipstools/acvp/acvptool/subprocess/hash.go b/util/fipstools/acvp/acvptool/subprocess/hash.go index f28335275..4c3ddf051 100644 --- a/util/fipstools/acvp/acvptool/subprocess/hash.go +++ b/util/fipstools/acvp/acvptool/subprocess/hash.go @@ -62,15 +62,6 @@ type hashPrimitive struct { size int } -// hash uses the subprocess to hash msg and returns the digest. -func (h *hashPrimitive) hash(msg []byte, m Transactable) []byte { - result, err := m.Transact(h.algo, 1, msg) - if err != nil { - panic("hash operation failed: " + err.Error()) - } - return result[0] -} - func (h *hashPrimitive) Process(vectorSet []byte, m Transactable) (interface{}, error) { var parsed hashTestVectorSet if err := json.Unmarshal(vectorSet, &parsed); err != nil { @@ -98,9 +89,14 @@ func (h *hashPrimitive) Process(vectorSet []byte, m Transactable) (interface{}, // http://usnistgov.github.io/ACVP/artifacts/draft-celi-acvp-sha-00.html#rfc.section.3 switch group.Type { case "AFT": + result, err := m.Transact(h.algo, 1, msg) + if err != nil { + panic(h.algo + " hash operation failed: " + err.Error()) + } + response.Tests = append(response.Tests, hashTestResponse{ ID: test.ID, - DigestHex: hex.EncodeToString(h.hash(msg, m)), + DigestHex: hex.EncodeToString(result[0]), }) case "MCT": @@ -110,20 +106,15 @@ func (h *hashPrimitive) Process(vectorSet []byte, m Transactable) (interface{}, testResponse := hashTestResponse{ID: test.ID} - buf := make([]byte, 3*h.size) - var digest []byte + digest := msg for i := 0; i < 100; i++ { - copy(buf, msg) - copy(buf[h.size:], msg) - copy(buf[2*h.size:], msg) - for j := 0; j < 1000; j++ { - digest = h.hash(buf, m) - copy(buf, buf[h.size:]) - copy(buf[2*h.size:], digest) + result, err := m.Transact(h.algo+"/MCT", 1, digest) + if err != nil { + panic(h.algo + " hash operation failed: " + err.Error()) } + digest = result[0] testResponse.MCTResults = append(testResponse.MCTResults, hashMCTResult{hex.EncodeToString(digest)}) - msg = digest } response.Tests = append(response.Tests, testResponse) diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index 25da8a180..1974dce83 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc @@ -860,6 +860,30 @@ static bool Hash(const Span args[], ReplyCallback write_reply) { return write_reply({Span(digest)}); } +template +static bool HashMCT(const Span args[], + ReplyCallback write_reply) { + if (args[0].size() != DigestLength) { + return false; + } + + uint8_t buf[DigestLength * 3]; + memcpy(buf, args[0].data(), DigestLength); + memcpy(buf + DigestLength, args[0].data(), DigestLength); + memcpy(buf + 2 * DigestLength, args[0].data(), DigestLength); + + for (size_t i = 0; i < 1000; i++) { + uint8_t digest[DigestLength]; + OneShotHash(buf, sizeof(buf), digest); + memmove(buf, buf + DigestLength, DigestLength * 2); + memcpy(buf + DigestLength * 2, digest, DigestLength); + } + + return write_reply( + {Span(buf + 2 * DigestLength, DigestLength)}); +} + static uint32_t GetIterations(const Span iterations_bytes) { uint32_t iterations; if (iterations_bytes.size() != sizeof(iterations)) { @@ -1861,6 +1885,12 @@ static constexpr struct { {"SHA2-384", 1, Hash}, {"SHA2-512", 1, Hash}, {"SHA2-512/256", 1, Hash}, + {"SHA-1/MCT", 1, HashMCT}, + {"SHA2-224/MCT", 1, HashMCT}, + {"SHA2-256/MCT", 1, HashMCT}, + {"SHA2-384/MCT", 1, HashMCT}, + {"SHA2-512/MCT", 1, HashMCT}, + {"SHA2-512/256/MCT", 1, HashMCT}, {"AES/encrypt", 3, AES}, {"AES/decrypt", 3, AES}, {"AES-CBC/encrypt", 4, AES_CBC},