// Copyright 2017 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include #include #include // These unit tests are for the Digest object in ulib/digest. namespace { //////////////// // Test support. using digest::Digest; // echo -n | sha256sum const char* kZeroDigest = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; // echo -n | sha256sum | cut -c1-64 | tr -d '\n' | xxd -p -r | sha256sum const char* kDoubleZeroDigest = "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456"; //////////////// // Test cases bool DigestStrings(void) { BEGIN_TEST; Digest actual; zx_status_t rc = actual.Parse(kZeroDigest, strlen(kZeroDigest)); char buf[(Digest::kLength * 2) + 1]; rc = actual.ToString(buf, sizeof(buf)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); ASSERT_EQ(strncmp(kZeroDigest, buf, sizeof(buf)), 0, __FUNCTION__); END_TEST; } bool DigestZero(void) { BEGIN_TEST; Digest actual, expected; zx_status_t rc = expected.Parse(kZeroDigest, strlen(kZeroDigest)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); actual.Hash(nullptr, 0); ASSERT_TRUE(actual == expected, __FUNCTION__); END_TEST; } bool DigestSelf(void) { BEGIN_TEST; Digest actual, expected; zx_status_t rc = expected.Parse(kDoubleZeroDigest, strlen(kDoubleZeroDigest)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); rc = actual.Parse(kZeroDigest, strlen(kZeroDigest)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); uint8_t buf[Digest::kLength]; rc = actual.CopyTo(buf, sizeof(buf)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); actual.Hash(buf, Digest::kLength); ASSERT_TRUE(actual == expected, __FUNCTION__); END_TEST; } bool DigestSplit(void) { BEGIN_TEST; Digest actual, expected; actual.Init(); size_t n = strlen(kZeroDigest); expected.Hash(kZeroDigest, n); for (size_t i = 1; i < n; ++i) { actual.Init(); actual.Update(kZeroDigest, i); actual.Update(kZeroDigest + i, n - i); actual.Final(); ASSERT_TRUE(actual == expected, __FUNCTION__); } END_TEST; } bool DigestCWrappers(void) { BEGIN_TEST; uint8_t buf[Digest::kLength]; zx_status_t rc = digest_hash(nullptr, 0, buf, sizeof(buf) - 1); ASSERT_EQ(rc, ZX_ERR_BUFFER_TOO_SMALL, "Small buffer should be rejected"); rc = digest_hash(nullptr, 0, buf, sizeof(buf)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); Digest expected; rc = expected.Parse(kZeroDigest, strlen(kZeroDigest)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); ASSERT_TRUE(expected == buf, __FUNCTION__); digest_t* digest = nullptr; rc = digest_init(&digest); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); expected.Hash(buf, sizeof(buf)); digest_update(digest, buf, sizeof(buf)); rc = digest_final(digest, buf, sizeof(buf)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); ASSERT_TRUE(expected == buf, __FUNCTION__); END_TEST; } bool DigestEquality(void) { BEGIN_TEST; Digest actual, expected; zx_status_t rc = expected.Parse(kZeroDigest, strlen(kZeroDigest)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); rc = actual.Parse(kZeroDigest, strlen(kZeroDigest)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); ASSERT_FALSE(actual == nullptr, "Does not equal NULL"); ASSERT_TRUE(actual == actual, "Equals self"); const uint8_t* actual_bytes = actual.AcquireBytes(); const uint8_t* expected_bytes = expected.AcquireBytes(); ASSERT_TRUE(actual == actual_bytes, "Equals self.bytes_"); ASSERT_TRUE(actual == expected, "Equals expected"); ASSERT_TRUE(actual == expected_bytes, "Equals expected.bytes_"); ASSERT_TRUE(actual != nullptr, "Doesn't equal NULL"); ASSERT_FALSE(actual != actual, "Doesn't not equal self"); ASSERT_FALSE(actual != actual_bytes, "Doesn't not equal self.bytes_"); ASSERT_FALSE(actual != expected, "Doesn't not equal expected"); ASSERT_FALSE(actual != expected_bytes, "Doesn't not equal expected.bytes_"); expected.ReleaseBytes(); actual.ReleaseBytes(); END_TEST; } bool DigestMove(void) { BEGIN_TEST; const Digest uninitialized_digest; Digest digest1; { // Verify that digest1 is not valid, and that it's current digest value // is all zeros. Verify that when move digest1 into digest2, that // both retain this property (not valid, digest full of zeros) ASSERT_TRUE(digest1 == uninitialized_digest); ASSERT_FALSE(digest1.is_valid()); Digest digest2(std::move(digest1)); ASSERT_TRUE(digest1 == uninitialized_digest); ASSERT_FALSE(digest1.is_valid()); ASSERT_TRUE(digest2 == uninitialized_digest); ASSERT_FALSE(digest2.is_valid()); } // Start a hash operation in digest1, verify that this does not update the // initial hash value. zx_status_t rc = digest1.Init(); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); ASSERT_TRUE(digest1 == uninitialized_digest); ASSERT_TRUE(digest1.is_valid()); // Hash some nothing into the hash. Again veryify the digest is still // valid, but that the internal result is still full of nothing. digest1.Hash(nullptr, 0); ASSERT_TRUE(digest1 == uninitialized_digest); ASSERT_TRUE(digest1.is_valid()); // Move the hash into digest2. Verify that the context goes with the move // operation. Digest digest2(std::move(digest1)); ASSERT_TRUE(digest1 == uninitialized_digest); ASSERT_FALSE(digest1.is_valid()); ASSERT_TRUE(digest1 == uninitialized_digest); ASSERT_TRUE(digest2.is_valid()); // Finish the hash operation started in digest1 which was moved into // digest2. Verify that digest2 is no longer valid, but that the result is // what we had expected. Digest zero_digest; rc = zero_digest.Parse(kZeroDigest, strlen(kZeroDigest)); ASSERT_EQ(rc, ZX_OK, zx_status_get_string(rc)); digest2.Final(); ASSERT_FALSE(digest2.is_valid()); ASSERT_TRUE(digest2 == zero_digest); // Move the result of the hash into a new digest3. Verify that neither is // valid, but that the result was properly moved. Digest digest3(std::move(digest2)); ASSERT_FALSE(digest2.is_valid()); ASSERT_FALSE(digest3.is_valid()); ASSERT_TRUE(digest2 == uninitialized_digest); ASSERT_TRUE(digest3 == zero_digest); END_TEST; } } // namespace BEGIN_TEST_CASE(DigestTests) RUN_TEST(DigestStrings) RUN_TEST(DigestZero) RUN_TEST(DigestSelf) RUN_TEST(DigestSplit) RUN_TEST(DigestCWrappers) RUN_TEST(DigestEquality) END_TEST_CASE(DigestTests)