1 /*
2 * blake2b_unittest.cc - unittests for blake2b hash function
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #include "blapi.h"
9 #include "nspr.h"
10 #include "nss.h"
11 #include "secerr.h"
12
13 #include <cstdlib>
14 #include <iostream>
15 #include <memory>
16
17 #define GTEST_HAS_RTTI 0
18 #include "gtest/gtest.h"
19
20 #include "kat/blake2b_kat.h"
21
22 template <class T>
23 struct ScopedDelete {
operator ()ScopedDelete24 void operator()(T* ptr) {
25 if (ptr) {
26 BLAKE2B_DestroyContext(ptr, PR_TRUE);
27 }
28 }
29 };
30
31 typedef std::unique_ptr<BLAKE2BContext, ScopedDelete<BLAKE2BContext>>
32 ScopedBLAKE2BContext;
33
34 class Blake2BTests : public ::testing::Test {};
35
36 class Blake2BKAT
37 : public ::testing::TestWithParam<std::pair<int, std::vector<uint8_t>>> {};
38
39 class Blake2BKATUnkeyed : public Blake2BKAT {};
40 class Blake2BKATKeyed : public Blake2BKAT {};
41
TEST_P(Blake2BKATUnkeyed,Unkeyed)42 TEST_P(Blake2BKATUnkeyed, Unkeyed) {
43 std::vector<uint8_t> values(BLAKE2B512_LENGTH);
44 SECStatus rv =
45 BLAKE2B_HashBuf(values.data(), kat_data.data(), std::get<0>(GetParam()));
46 ASSERT_EQ(SECSuccess, rv);
47 EXPECT_EQ(values, std::get<1>(GetParam()));
48 }
49
TEST_P(Blake2BKATKeyed,Keyed)50 TEST_P(Blake2BKATKeyed, Keyed) {
51 std::vector<uint8_t> values(BLAKE2B512_LENGTH);
52 SECStatus rv = BLAKE2B_MAC_HashBuf(values.data(), kat_data.data(),
53 std::get<0>(GetParam()), kat_key.data(),
54 BLAKE2B_KEY_SIZE);
55 ASSERT_EQ(SECSuccess, rv);
56 EXPECT_EQ(values, std::get<1>(GetParam()));
57 }
58
59 INSTANTIATE_TEST_SUITE_P(UnkeyedKAT, Blake2BKATUnkeyed,
60 ::testing::ValuesIn(TestcasesUnkeyed));
61 INSTANTIATE_TEST_SUITE_P(KeyedKAT, Blake2BKATKeyed,
62 ::testing::ValuesIn(TestcasesKeyed));
63
TEST_F(Blake2BTests,ContextTest)64 TEST_F(Blake2BTests, ContextTest) {
65 ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
66 ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
67
68 SECStatus rv = BLAKE2B_Begin(ctx.get());
69 ASSERT_EQ(SECSuccess, rv);
70
71 size_t src_length = 252;
72 const size_t quarter = 63;
73
74 for (int i = 0; i < 4 && src_length > 0; i++) {
75 rv = BLAKE2B_Update(ctx.get(), kat_data.data() + i * quarter,
76 PR_MIN(quarter, src_length));
77 ASSERT_EQ(SECSuccess, rv);
78
79 size_t len = BLAKE2B_FlattenSize(ctx.get());
80 std::vector<unsigned char> ctxbytes(len);
81 rv = BLAKE2B_Flatten(ctx.get(), ctxbytes.data());
82 ASSERT_EQ(SECSuccess, rv);
83 ScopedBLAKE2BContext ctx_cpy(BLAKE2B_Resurrect(ctxbytes.data(), NULL));
84 ASSERT_TRUE(ctx_cpy) << "BLAKE2B_Resurrect failed!";
85 ASSERT_EQ(SECSuccess, PORT_Memcmp(ctx.get(), ctx_cpy.get(), len));
86 src_length -= quarter;
87 }
88 ASSERT_EQ(0U, src_length);
89
90 std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
91 rv = BLAKE2B_End(ctx.get(), digest.data(), nullptr, BLAKE2B512_LENGTH);
92 ASSERT_EQ(SECSuccess, rv);
93 ASSERT_EQ(std::get<1>(TestcasesUnkeyed[252]), digest)
94 << "BLAKE2B_End failed!";
95 }
96
TEST_F(Blake2BTests,ContextTest2)97 TEST_F(Blake2BTests, ContextTest2) {
98 ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
99 ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
100
101 SECStatus rv = BLAKE2B_Begin(ctx.get());
102 ASSERT_EQ(SECSuccess, rv);
103
104 rv = BLAKE2B_Update(ctx.get(), kat_data.data(), 128);
105 ASSERT_EQ(SECSuccess, rv);
106 rv = BLAKE2B_Update(ctx.get(), kat_data.data() + 128, 127);
107 ASSERT_EQ(SECSuccess, rv);
108
109 std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
110 rv = BLAKE2B_End(ctx.get(), digest.data(), nullptr, BLAKE2B512_LENGTH);
111 ASSERT_EQ(SECSuccess, rv);
112 ASSERT_EQ(std::get<1>(TestcasesUnkeyed[255]), digest)
113 << "BLAKE2B_End failed!";
114 }
115
TEST_F(Blake2BTests,NullContextTest)116 TEST_F(Blake2BTests, NullContextTest) {
117 SECStatus rv = BLAKE2B_Begin(nullptr);
118 ASSERT_EQ(SECFailure, rv);
119
120 rv = BLAKE2B_Update(nullptr, kat_data.data(), 128);
121 ASSERT_EQ(SECFailure, rv);
122
123 std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
124 rv = BLAKE2B_End(nullptr, digest.data(), nullptr, BLAKE2B512_LENGTH);
125 ASSERT_EQ(SECFailure, rv);
126 }
127
TEST_F(Blake2BTests,CloneTest)128 TEST_F(Blake2BTests, CloneTest) {
129 ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
130 ScopedBLAKE2BContext cloned_ctx(BLAKE2B_NewContext());
131 ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
132 ASSERT_TRUE(cloned_ctx) << "BLAKE2B_NewContext failed!";
133
134 SECStatus rv = BLAKE2B_Begin(ctx.get());
135 ASSERT_EQ(SECSuccess, rv);
136 rv = BLAKE2B_Update(ctx.get(), kat_data.data(), 255);
137 ASSERT_EQ(SECSuccess, rv);
138 BLAKE2B_Clone(cloned_ctx.get(), ctx.get());
139
140 std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
141 rv = BLAKE2B_End(cloned_ctx.get(), digest.data(), nullptr, BLAKE2B512_LENGTH);
142 ASSERT_EQ(SECSuccess, rv);
143 ASSERT_EQ(std::get<1>(TestcasesUnkeyed[255]), digest)
144 << "BLAKE2B_End failed!";
145 }
146
TEST_F(Blake2BTests,NullTest)147 TEST_F(Blake2BTests, NullTest) {
148 std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
149 SECStatus rv = BLAKE2B_HashBuf(digest.data(), nullptr, 0);
150 ASSERT_EQ(SECSuccess, rv);
151 EXPECT_EQ(std::get<1>(TestcasesUnkeyed[0]), digest);
152
153 digest = std::vector<uint8_t>(BLAKE2B512_LENGTH);
154 rv = BLAKE2B_MAC_HashBuf(digest.data(), nullptr, 0, kat_key.data(),
155 BLAKE2B_KEY_SIZE);
156 ASSERT_EQ(SECSuccess, rv);
157 EXPECT_EQ(std::get<1>(TestcasesKeyed[0]), digest);
158 }
159
TEST_F(Blake2BTests,HashTest)160 TEST_F(Blake2BTests, HashTest) {
161 ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
162 ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
163
164 std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
165 SECStatus rv = BLAKE2B_Hash(digest.data(), "abc");
166 std::vector<uint8_t> expected = {
167 0xba, 0x80, 0xa5, 0x3f, 0x98, 0x1c, 0x4d, 0x0d, 0x6a, 0x27, 0x97,
168 0xb6, 0x9f, 0x12, 0xf6, 0xe9, 0x4c, 0x21, 0x2f, 0x14, 0x68, 0x5a,
169 0xc4, 0xb7, 0x4b, 0x12, 0xbb, 0x6f, 0xdb, 0xff, 0xa2, 0xd1, 0x7d,
170 0x87, 0xc5, 0x39, 0x2a, 0xab, 0x79, 0x2d, 0xc2, 0x52, 0xd5, 0xde,
171 0x45, 0x33, 0xcc, 0x95, 0x18, 0xd3, 0x8a, 0xa8, 0xdb, 0xf1, 0x92,
172 0x5a, 0xb9, 0x23, 0x86, 0xed, 0xd4, 0x00, 0x99, 0x23};
173 ASSERT_EQ(SECSuccess, rv);
174 EXPECT_EQ(expected, digest);
175 }
176
TEST_F(Blake2BTests,LongHashTest)177 TEST_F(Blake2BTests, LongHashTest) {
178 ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
179 ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
180
181 std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
182 SECStatus rv = BLAKE2B_Hash(
183 digest.data(),
184 "qwertzuiopasdfghjklyxcvbnm123456789qwertzuiopasdfghjklyxcvbnm123456789qw"
185 "ertzuiopasdfghjklyxcvbnm123456789qwertzuiopasdfghjklyxcvbnm123456789qwer"
186 "tzuiopasdfghjklyxcvbnm123456789qwertzuiopasdfghjklyxcvbnm123456789qwertz"
187 "uiopasdfghjklyxcvbnm123456789qwertzuiopasdfghjklyxcvbnm123456789");
188 std::vector<uint8_t> expected = {
189 0x1f, 0x9e, 0xe6, 0x5a, 0xa0, 0x36, 0x05, 0xfc, 0x41, 0x0e, 0x2f,
190 0x55, 0x96, 0xfd, 0xb5, 0x9d, 0x85, 0x95, 0x5e, 0x24, 0x37, 0xe7,
191 0x0d, 0xe4, 0xa0, 0x22, 0x4a, 0xe1, 0x59, 0x1f, 0x97, 0x03, 0x57,
192 0x54, 0xf0, 0xca, 0x92, 0x75, 0x2f, 0x9e, 0x86, 0xeb, 0x82, 0x4f,
193 0x9c, 0xf4, 0x02, 0x17, 0x7f, 0x76, 0x56, 0x26, 0x46, 0xf4, 0x07,
194 0xfd, 0x1f, 0x78, 0xdb, 0x7b, 0x0d, 0x24, 0x43, 0xf0};
195 ASSERT_EQ(SECSuccess, rv);
196 EXPECT_EQ(expected, digest);
197 }
198
TEST_F(Blake2BTests,TruncatedHashTest)199 TEST_F(Blake2BTests, TruncatedHashTest) {
200 ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
201 ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
202
203 SECStatus rv = BLAKE2B_Begin(ctx.get());
204 ASSERT_EQ(SECSuccess, rv);
205
206 rv = BLAKE2B_Update(ctx.get(), kat_data.data(), 128);
207 ASSERT_EQ(SECSuccess, rv);
208 rv = BLAKE2B_Update(ctx.get(), kat_data.data() + 128, 127);
209 ASSERT_EQ(SECSuccess, rv);
210
211 size_t max_digest_len = BLAKE2B512_LENGTH - 5;
212 std::vector<uint8_t> digest(max_digest_len);
213 unsigned int digest_len;
214 rv = BLAKE2B_End(ctx.get(), digest.data(), &digest_len, max_digest_len);
215 ASSERT_EQ(SECSuccess, rv);
216 ASSERT_EQ(digest.size(), digest_len);
217 ASSERT_EQ(0, memcmp(std::get<1>(TestcasesUnkeyed[255]).data(), digest.data(),
218 max_digest_len))
219 << "BLAKE2B_End failed!";
220 }
221
TEST_F(Blake2BTests,TruncatedHashTest2)222 TEST_F(Blake2BTests, TruncatedHashTest2) {
223 ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
224 ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
225
226 SECStatus rv = BLAKE2B_Begin(ctx.get());
227 ASSERT_EQ(SECSuccess, rv);
228
229 rv = BLAKE2B_Update(ctx.get(), kat_data.data(), 128);
230 ASSERT_EQ(SECSuccess, rv);
231 rv = BLAKE2B_Update(ctx.get(), kat_data.data() + 128, 127);
232 ASSERT_EQ(SECSuccess, rv);
233
234 size_t max_digest_len = BLAKE2B512_LENGTH - 60;
235 std::vector<uint8_t> digest(max_digest_len);
236 unsigned int digest_len;
237 rv = BLAKE2B_End(ctx.get(), digest.data(), &digest_len, max_digest_len);
238 ASSERT_EQ(SECSuccess, rv);
239 ASSERT_EQ(digest.size(), digest_len);
240 }
241
TEST_F(Blake2BTests,OverlongKeyTest)242 TEST_F(Blake2BTests, OverlongKeyTest) {
243 ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
244 ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
245
246 std::vector<uint8_t> key = {
247 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31,
248 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
249 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33,
250 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
251 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
252 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35};
253 std::vector<uint8_t> data = {0x61, 0x62, 0x63};
254
255 std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
256 SECStatus rv =
257 BLAKE2B_MAC_HashBuf(digest.data(), data.data(), 3, key.data(), 65);
258 EXPECT_EQ(SECFailure, rv);
259 EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
260 }
261
TEST_F(Blake2BTests,EmptyKeyTest)262 TEST_F(Blake2BTests, EmptyKeyTest) {
263 ScopedBLAKE2BContext ctx(BLAKE2B_NewContext());
264 ASSERT_TRUE(ctx) << "BLAKE2B_NewContext failed!";
265
266 uint8_t key[1]; // A vector.data() would give us a nullptr.
267 std::vector<uint8_t> data = {0x61, 0x62, 0x63};
268
269 std::vector<uint8_t> digest(BLAKE2B512_LENGTH);
270 SECStatus rv = BLAKE2B_MAC_HashBuf(digest.data(), data.data(), 3, key, 0);
271 EXPECT_EQ(SECFailure, rv);
272 EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
273 }
274
main(int argc,char ** argv)275 int main(int argc, char** argv) {
276 ::testing::InitGoogleTest(&argc, argv);
277
278 if (NSS_NoDB_Init(nullptr) != SECSuccess) {
279 return 1;
280 }
281
282 int rv = RUN_ALL_TESTS();
283
284 if (NSS_Shutdown() != SECSuccess) {
285 return 1;
286 }
287
288 return rv;
289 }
290