// Copyright 2021 The Pigweed Authors // // Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include "pw_crypto/sha256.h" #include #include "gtest/gtest.h" #include "pw_stream/memory_stream.h" namespace pw::crypto::sha256 { namespace { #define ASSERT_OK(expr) ASSERT_EQ(OkStatus(), expr) #define ASSERT_FAIL(expr) ASSERT_NE(OkStatus(), expr) #define AS_BYTES(s) std::as_bytes(std::span(s, sizeof(s) - 1)) // Generated in Python 3 with: // `hashlib.sha256('Hello, Pigweed!'.encode('ascii')).hexdigest()`. #define SHA256_HASH_OF_HELLO_PIGWEED \ "\x8d\xce\x14\xee\x2c\xd9\xfd\x9b\xbd\x8c\x8d\x57\x68\x50\x2c\x2f" \ "\xfb\xb3\x52\x36\xce\x93\x47\x1b\x80\xfc\xa4\x7d\xb5\xf8\x41\x9d" // Generated in Python with `hashlib.sha256().hexdigest()`. #define SHA256_HASH_OF_EMPTY_STRING \ "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24" \ "\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55" TEST(Hash, ComputesCorrectDigest) { std::byte digest[kDigestSizeBytes]; ASSERT_OK(Hash(AS_BYTES("Hello, Pigweed!"), digest)); ASSERT_EQ(0, std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest))); } TEST(Hash, ComputesCorrectDigestFromReader) { std::byte digest[kDigestSizeBytes]; ConstByteSpan message = AS_BYTES("Hello, Pigweed!"); stream::MemoryReader reader(message); ASSERT_OK(Hash(reader, digest)); ASSERT_EQ(0, std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest))); } TEST(Hash, ComputesCorrectDigestOnEmptyMessage) { std::byte digest[kDigestSizeBytes]; ASSERT_OK(Hash({}, digest)); ASSERT_EQ(0, std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest))); } TEST(Hash, ComputesCorrectDigestOnEmptyMessageFromReader) { std::byte digest[kDigestSizeBytes]; ConstByteSpan empty; stream::MemoryReader reader(empty); ASSERT_OK(Hash(reader, digest)); ASSERT_EQ(0, std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest))); } TEST(Hash, DigestBufferTooSmall) { std::array digest = {}; ASSERT_FAIL(Hash({}, digest)); } TEST(Hash, DigestBufferTooSmallForReaderBasedAPI) { std::array digest = {}; ConstByteSpan empty; stream::MemoryReader reader(empty); ASSERT_FAIL(Hash(reader, digest)); } TEST(Hash, AcceptsLargerDigestBuffer) { std::array digest = {}; ASSERT_OK(Hash({}, digest)); } TEST(Hash, AcceptsLargerDigestBufferForReaderBasedAPI) { std::array digest = {}; ConstByteSpan empty; stream::MemoryReader reader(empty); ASSERT_OK(Hash(reader, digest)); } TEST(Sha256, AllowsSkippedUpdate) { std::byte digest[kDigestSizeBytes]; ASSERT_OK(Sha256().Final(digest)); ASSERT_EQ(0, std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest))); } TEST(Sha256, AllowsEmptyUpdate) { std::byte digest[kDigestSizeBytes]; ASSERT_OK(Sha256().Update({}).Final(digest)); ASSERT_EQ(0, std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest))); } TEST(Sha256, AllowsMultipleUpdates) { std::byte digest[kDigestSizeBytes]; ASSERT_OK(Sha256() .Update(AS_BYTES("Hello, ")) .Update(AS_BYTES("Pigweed!")) .Final(digest)); ASSERT_EQ(0, std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest))); } TEST(Sha256, NoFinalAfterFinal) { std::byte digest[kDigestSizeBytes]; auto h = Sha256(); ASSERT_OK(h.Final(digest)); ASSERT_FAIL(h.Final(digest)); } TEST(Sha256, NoUpdateAfterFinal) { std::byte digest[kDigestSizeBytes]; auto h = Sha256(); ASSERT_OK(h.Final(digest)); ASSERT_FAIL(h.Update(AS_BYTES("blah")).Final(digest)); } } // namespace } // namespace pw::crypto::sha256