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