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 "gtest/gtest.h"
20 #include "pw_stream/memory_stream.h"
21
22 namespace pw::crypto::sha256 {
23 namespace {
24
25 #define ASSERT_OK(expr) ASSERT_EQ(OkStatus(), expr)
26 #define ASSERT_FAIL(expr) ASSERT_NE(OkStatus(), expr)
27
28 #define AS_BYTES(s) as_bytes(span(s, sizeof(s) - 1))
29
30 // Generated in Python 3 with:
31 // `hashlib.sha256('Hello, Pigweed!'.encode('ascii')).hexdigest()`.
32 #define SHA256_HASH_OF_HELLO_PIGWEED \
33 "\x8d\xce\x14\xee\x2c\xd9\xfd\x9b\xbd\x8c\x8d\x57\x68\x50\x2c\x2f" \
34 "\xfb\xb3\x52\x36\xce\x93\x47\x1b\x80\xfc\xa4\x7d\xb5\xf8\x41\x9d"
35
36 // Generated in Python with `hashlib.sha256().hexdigest()`.
37 #define SHA256_HASH_OF_EMPTY_STRING \
38 "\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\x9a\xfb\xf4\xc8\x99\x6f\xb9\x24" \
39 "\x27\xae\x41\xe4\x64\x9b\x93\x4c\xa4\x95\x99\x1b\x78\x52\xb8\x55"
40
TEST(Hash,ComputesCorrectDigest)41 TEST(Hash, ComputesCorrectDigest) {
42 std::byte digest[kDigestSizeBytes];
43
44 ASSERT_OK(Hash(AS_BYTES("Hello, Pigweed!"), digest));
45 ASSERT_EQ(0,
46 std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest)));
47 }
48
TEST(Hash,ComputesCorrectDigestFromReader)49 TEST(Hash, ComputesCorrectDigestFromReader) {
50 std::byte digest[kDigestSizeBytes];
51 ConstByteSpan message = AS_BYTES("Hello, Pigweed!");
52
53 stream::MemoryReader reader(message);
54 ASSERT_OK(Hash(reader, digest));
55 ASSERT_EQ(0,
56 std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest)));
57 }
58
TEST(Hash,ComputesCorrectDigestOnEmptyMessage)59 TEST(Hash, ComputesCorrectDigestOnEmptyMessage) {
60 std::byte digest[kDigestSizeBytes];
61
62 ASSERT_OK(Hash({}, digest));
63 ASSERT_EQ(0,
64 std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
65 }
66
TEST(Hash,ComputesCorrectDigestOnEmptyMessageFromReader)67 TEST(Hash, ComputesCorrectDigestOnEmptyMessageFromReader) {
68 std::byte digest[kDigestSizeBytes];
69
70 ConstByteSpan empty;
71 stream::MemoryReader reader(empty);
72 ASSERT_OK(Hash(reader, digest));
73 ASSERT_EQ(0,
74 std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
75 }
76
TEST(Hash,DigestBufferTooSmall)77 TEST(Hash, DigestBufferTooSmall) {
78 std::array<std::byte, 31> digest = {};
79 ASSERT_FAIL(Hash({}, digest));
80 }
81
TEST(Hash,DigestBufferTooSmallForReaderBasedAPI)82 TEST(Hash, DigestBufferTooSmallForReaderBasedAPI) {
83 std::array<std::byte, 31> digest = {};
84 ConstByteSpan empty;
85 stream::MemoryReader reader(empty);
86 ASSERT_FAIL(Hash(reader, digest));
87 }
88
TEST(Hash,AcceptsLargerDigestBuffer)89 TEST(Hash, AcceptsLargerDigestBuffer) {
90 std::array<std::byte, 33> digest = {};
91 ASSERT_OK(Hash({}, digest));
92 }
93
TEST(Hash,AcceptsLargerDigestBufferForReaderBasedAPI)94 TEST(Hash, AcceptsLargerDigestBufferForReaderBasedAPI) {
95 std::array<std::byte, 33> digest = {};
96
97 ConstByteSpan empty;
98 stream::MemoryReader reader(empty);
99 ASSERT_OK(Hash(reader, digest));
100 }
101
TEST(Sha256,AllowsSkippedUpdate)102 TEST(Sha256, AllowsSkippedUpdate) {
103 std::byte digest[kDigestSizeBytes];
104
105 ASSERT_OK(Sha256().Final(digest));
106 ASSERT_EQ(0,
107 std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
108 }
109
TEST(Sha256,AllowsEmptyUpdate)110 TEST(Sha256, AllowsEmptyUpdate) {
111 std::byte digest[kDigestSizeBytes];
112 ASSERT_OK(Sha256().Update({}).Final(digest));
113 ASSERT_EQ(0,
114 std::memcmp(digest, SHA256_HASH_OF_EMPTY_STRING, sizeof(digest)));
115 }
116
TEST(Sha256,AllowsMultipleUpdates)117 TEST(Sha256, AllowsMultipleUpdates) {
118 std::byte digest[kDigestSizeBytes];
119 ASSERT_OK(Sha256()
120 .Update(AS_BYTES("Hello, "))
121 .Update(AS_BYTES("Pigweed!"))
122 .Final(digest));
123 ASSERT_EQ(0,
124 std::memcmp(digest, SHA256_HASH_OF_HELLO_PIGWEED, sizeof(digest)));
125 }
126
TEST(Sha256,NoFinalAfterFinal)127 TEST(Sha256, NoFinalAfterFinal) {
128 std::byte digest[kDigestSizeBytes];
129 auto h = Sha256();
130
131 ASSERT_OK(h.Final(digest));
132 ASSERT_FAIL(h.Final(digest));
133 }
134
TEST(Sha256,NoUpdateAfterFinal)135 TEST(Sha256, NoUpdateAfterFinal) {
136 std::byte digest[kDigestSizeBytes];
137 auto h = Sha256();
138
139 ASSERT_OK(h.Final(digest));
140 ASSERT_FAIL(h.Update(AS_BYTES("blah")).Final(digest));
141 }
142
143 } // namespace
144 } // namespace pw::crypto::sha256
145