1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_crypto/sha256.h"
16
17 #include <cstring>
18
19 #include "pw_stream/memory_stream.h"
20 #include "pw_unit_test/framework.h"
21
22 namespace pw::crypto::sha256 {
23 namespace {
24
25 #define ASSERT_FAIL(expr) ASSERT_NE(OkStatus(), expr)
26
27 #define AS_BYTES(s) as_bytes(span(s, sizeof(s) - 1))
28
29 // Generated in Python 3 with:
30 // `hashlib.sha256('Hello, Pigweed!'.encode('ascii')).hexdigest()`.
31 #define SHA256_HASH_OF_HELLO_PIGWEED \
32 "\x8d\xce\x14\xee\x2c\xd9\xfd\x9b\xbd\x8c\x8d\x57\x68\x50\x2c\x2f" \
33 "\xfb\xb3\x52\x36\xce\x93\x47\x1b\x80\xfc\xa4\x7d\xb5\xf8\x41\x9d"
34
35 // Generated in Python with `hashlib.sha256().hexdigest()`.
36 #define SHA256_HASH_OF_EMPTY_STRING \
37 "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24" \
38 "\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55"
39
TEST(Hash,ComputesCorrectDigest)40 TEST(Hash, ComputesCorrectDigest) {
41 std::byte digest[kDigestSizeBytes];
42
43 PW_TEST_ASSERT_OK(Hash(AS_BYTES("Hello, Pigweed!"), digest));
44 ASSERT_EQ(0,
45 std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest)));
46 }
47
TEST(Hash,ComputesCorrectDigestFromReader)48 TEST(Hash, ComputesCorrectDigestFromReader) {
49 std::byte digest[kDigestSizeBytes];
50 ConstByteSpan message = AS_BYTES("Hello, Pigweed!");
51
52 stream::MemoryReader reader(message);
53 PW_TEST_ASSERT_OK(Hash(reader, digest));
54 ASSERT_EQ(0,
55 std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest)));
56 }
57
TEST(Hash,ComputesCorrectDigestOnEmptyMessage)58 TEST(Hash, ComputesCorrectDigestOnEmptyMessage) {
59 std::byte digest[kDigestSizeBytes];
60
61 PW_TEST_ASSERT_OK(Hash({}, digest));
62 ASSERT_EQ(0,
63 std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
64 }
65
TEST(Hash,ComputesCorrectDigestOnEmptyMessageFromReader)66 TEST(Hash, ComputesCorrectDigestOnEmptyMessageFromReader) {
67 std::byte digest[kDigestSizeBytes];
68
69 ConstByteSpan empty;
70 stream::MemoryReader reader(empty);
71 PW_TEST_ASSERT_OK(Hash(reader, digest));
72 ASSERT_EQ(0,
73 std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
74 }
75
TEST(Hash,DigestBufferTooSmall)76 TEST(Hash, DigestBufferTooSmall) {
77 std::array<std::byte, 31> digest = {};
78 ASSERT_FAIL(Hash({}, digest));
79 }
80
TEST(Hash,DigestBufferTooSmallForReaderBasedAPI)81 TEST(Hash, DigestBufferTooSmallForReaderBasedAPI) {
82 std::array<std::byte, 31> digest = {};
83 ConstByteSpan empty;
84 stream::MemoryReader reader(empty);
85 ASSERT_FAIL(Hash(reader, digest));
86 }
87
TEST(Hash,AcceptsLargerDigestBuffer)88 TEST(Hash, AcceptsLargerDigestBuffer) {
89 std::array<std::byte, 33> digest = {};
90 PW_TEST_ASSERT_OK(Hash({}, digest));
91 }
92
TEST(Hash,AcceptsLargerDigestBufferForReaderBasedAPI)93 TEST(Hash, AcceptsLargerDigestBufferForReaderBasedAPI) {
94 std::array<std::byte, 33> digest = {};
95
96 ConstByteSpan empty;
97 stream::MemoryReader reader(empty);
98 PW_TEST_ASSERT_OK(Hash(reader, digest));
99 }
100
TEST(Sha256,AllowsSkippedUpdate)101 TEST(Sha256, AllowsSkippedUpdate) {
102 std::byte digest[kDigestSizeBytes];
103
104 PW_TEST_ASSERT_OK(Sha256().Final(digest));
105 ASSERT_EQ(0,
106 std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
107 }
108
TEST(Sha256,AllowsEmptyUpdate)109 TEST(Sha256, AllowsEmptyUpdate) {
110 std::byte digest[kDigestSizeBytes];
111 PW_TEST_ASSERT_OK(Sha256().Update({}).Final(digest));
112 ASSERT_EQ(0,
113 std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
114 }
115
TEST(Sha256,AllowsMultipleUpdates)116 TEST(Sha256, AllowsMultipleUpdates) {
117 std::byte digest[kDigestSizeBytes];
118 PW_TEST_ASSERT_OK(Sha256()
119 .Update(AS_BYTES("Hello, "))
120 .Update(AS_BYTES("Pigweed!"))
121 .Final(digest));
122 ASSERT_EQ(0,
123 std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest)));
124 }
125
TEST(Sha256,NoFinalAfterFinal)126 TEST(Sha256, NoFinalAfterFinal) {
127 std::byte digest[kDigestSizeBytes];
128 auto h = Sha256();
129
130 PW_TEST_ASSERT_OK(h.Final(digest));
131 ASSERT_FAIL(h.Final(digest));
132 }
133
TEST(Sha256,NoUpdateAfterFinal)134 TEST(Sha256, NoUpdateAfterFinal) {
135 std::byte digest[kDigestSizeBytes];
136 auto h = Sha256();
137
138 PW_TEST_ASSERT_OK(h.Final(digest));
139 ASSERT_FAIL(h.Update(AS_BYTES("blah")).Final(digest));
140 }
141
142 } // namespace
143 } // namespace pw::crypto::sha256
144