| // 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 <cstring> |
| |
| #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<std::byte, 31> digest = {}; |
| ASSERT_FAIL(Hash({}, digest)); |
| } |
| |
| TEST(Hash, DigestBufferTooSmallForReaderBasedAPI) { |
| std::array<std::byte, 31> digest = {}; |
| ConstByteSpan empty; |
| stream::MemoryReader reader(empty); |
| ASSERT_FAIL(Hash(reader, digest)); |
| } |
| |
| TEST(Hash, AcceptsLargerDigestBuffer) { |
| std::array<std::byte, 33> digest = {}; |
| ASSERT_OK(Hash({}, digest)); |
| } |
| |
| TEST(Hash, AcceptsLargerDigestBufferForReaderBasedAPI) { |
| std::array<std::byte, 33> 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 |