1/**
2 * Copyright (C) 2004-2006 Brad Hards <bradh@frogmouth.net>
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <QtCrypto>
27#include <QtTest/QtTest>
28
29#ifdef QT_STATICPLUGIN
30#include "import_plugins.h"
31#endif
32
33class KDFUnitTest : public QObject
34{
35 Q_OBJECT
36
37private Q_SLOTS:
38 void initTestCase();
39 void cleanupTestCase();
40 void pbkdf1md2Tests_data();
41 void pbkdf1md2Tests();
42 void pbkdf1sha1Tests_data();
43 void pbkdf1sha1Tests();
44 void pbkdf1sha1TimeTest();
45 void pbkdf2Tests_data();
46 void pbkdf2Tests();
47 void pbkdf2TimeTest();
48 void pbkdf2extraTests();
49 void hkdfTests_data();
50 void hkdfTests();
51
52private:
53 QCA::Initializer *m_init;
54 QStringList providersToTest;
55};
56
57void KDFUnitTest::initTestCase()
58{
59 m_init = new QCA::Initializer;
60
61 const auto providers = QCA::providers();
62 for (QCA::Provider *provider : providers)
63 providersToTest << provider->name();
64}
65
66void KDFUnitTest::cleanupTestCase()
67{
68 delete m_init;
69}
70
71void KDFUnitTest::pbkdf1md2Tests_data()
72{
73 QTest::addColumn<QString>(name: "secret"); // usually a password or passphrase
74 QTest::addColumn<QString>(name: "output"); // the key you get back
75 QTest::addColumn<QString>(name: "salt"); // a salt or initialisation vector
76 QTest::addColumn<unsigned int>(name: "outputLength"); // if the algo supports variable length keys, len
77 QTest::addColumn<unsigned int>(name: "iterationCount"); // number of iterations
78
79 // These are from Botan's test suite
80 QTest::newRow(dataTag: "1") << QStringLiteral("71616c7a73656774") << QStringLiteral("7c1991f3f38a09d70cf3b1acadb70bc6")
81 << QStringLiteral("40cf117c3865e0cf") << static_cast<unsigned int>(16)
82 << static_cast<unsigned int>(1000);
83
84 QTest::newRow(dataTag: "2") << QStringLiteral("766e68617a6a66736978626f6d787175")
85 << QStringLiteral("677500eda9f0c5e96e0a11f90fb9") << QStringLiteral("3a2484ce5d3e1b4d")
86 << static_cast<unsigned int>(14) << static_cast<unsigned int>(1);
87
88 QTest::newRow(dataTag: "3") << QStringLiteral("66686565746e657162646d7171716e797977696f716a666c6f6976636371756a")
89 << QStringLiteral("91a5b689156b441bf27dd2bdd276")
90 << QStringLiteral("5d838b0f4fa22bfa2157f9083d87f8752e0495bb2113012761ef11b66e87c3cb")
91 << static_cast<unsigned int>(14) << static_cast<unsigned int>(15);
92
93 QTest::newRow(dataTag: "4") << QStringLiteral("736e6279696e6a7075696b7176787867726c6b66")
94 << QStringLiteral("49516935cc9f438bafa30ff038fb")
95 << QStringLiteral("f22d341361b47e3390107bd973fdc0d3e0bc02a3") << static_cast<unsigned int>(14)
96 << static_cast<unsigned int>(2);
97}
98
99void KDFUnitTest::pbkdf1md2Tests()
100{
101 QFETCH(QString, secret);
102 QFETCH(QString, output);
103 QFETCH(QString, salt);
104 QFETCH(unsigned int, outputLength);
105 QFETCH(unsigned int, iterationCount);
106
107 bool anyProviderTested = false;
108 foreach (QString provider, providersToTest) {
109 if (QCA::isSupported(features: "pbkdf1(md2)", provider)) {
110 anyProviderTested = true;
111 QCA::SecureArray password = QCA::hexToArray(hexString: secret);
112 QCA::InitializationVector iv(QCA::hexToArray(hexString: salt));
113 QCA::SymmetricKey key =
114 QCA::PBKDF1(QStringLiteral("md2"), provider).makeKey(secret: password, salt: iv, keyLength: outputLength, iterationCount);
115 QCOMPARE(QCA::arrayToHex(key.toByteArray()), output);
116 }
117 }
118 if (!anyProviderTested)
119 qWarning() << "NONE of the providers supports PBKDF version 1 with MD2:" << providersToTest;
120}
121
122void KDFUnitTest::pbkdf1sha1Tests_data()
123{
124 QTest::addColumn<QString>(name: "secret"); // usually a password or passphrase
125 QTest::addColumn<QString>(name: "output"); // the key you get back
126 QTest::addColumn<QString>(name: "salt"); // a salt or initialisation vector
127 QTest::addColumn<unsigned int>(name: "outputLength"); // if the algo supports variable length keys, len
128 QTest::addColumn<unsigned int>(name: "iterationCount"); // number of iterations
129
130 // These are from Botan's test suite
131 QTest::newRow(dataTag: "1") << QStringLiteral("66746c6b6662786474626a62766c6c7662776977")
132 << QStringLiteral("768b277dc970f912dbdd3edad48ad2f065d25d")
133 << QStringLiteral("40ac5837560251c275af5e30a6a3074e57ced38e") << static_cast<unsigned int>(19)
134 << static_cast<unsigned int>(6);
135
136 QTest::newRow(dataTag: "2") << QStringLiteral("786e736f736d6b766867677a7370636e63706f63")
137 << QStringLiteral("4d90e846a4b6aaa02ac548014a00e97e506b2afb")
138 << QStringLiteral("7008a9dc1b9a81470a2360275c19dab77f716824") << static_cast<unsigned int>(20)
139 << static_cast<unsigned int>(6);
140
141 QTest::newRow(dataTag: "3") << QStringLiteral("6f74696c71776c756b717473")
142 << QStringLiteral("71ed1a995e693efcd33155935e800037da74ea28")
143 << QStringLiteral("ccfc44c09339040e55d3f7f76ca6ef838fde928717241deb9ac1a4ef45a27711")
144 << static_cast<unsigned int>(20) << static_cast<unsigned int>(2001);
145
146 QTest::newRow(dataTag: "4") << QStringLiteral("6b7a6e657166666c6274767374686e6663746166")
147 << QStringLiteral("f345fb8fbd880206b650266661f6")
148 << QStringLiteral("8108883fc04a01feb10661651516425dad1c93e0") << static_cast<unsigned int>(14)
149 << static_cast<unsigned int>(10000);
150
151 QTest::newRow(dataTag: "5") << QStringLiteral("716b78686c7170656d7868796b6d7975636a626f")
152 << QStringLiteral("2d54dfed0c7ef7d20b0945ba414a")
153 << QStringLiteral("bc8bc53d4604977c3adb1d19c15e87b77a84c2f6") << static_cast<unsigned int>(14)
154 << static_cast<unsigned int>(10000);
155}
156
157void KDFUnitTest::pbkdf1sha1Tests()
158{
159 QFETCH(QString, secret);
160 QFETCH(QString, output);
161 QFETCH(QString, salt);
162 QFETCH(unsigned int, outputLength);
163 QFETCH(unsigned int, iterationCount);
164
165 bool anyProviderTested = false;
166 foreach (QString provider, providersToTest) {
167 if (QCA::isSupported(features: "pbkdf1(sha1)", provider)) {
168 anyProviderTested = true;
169 QCA::SecureArray password = QCA::hexToArray(hexString: secret);
170 QCA::InitializationVector iv(QCA::hexToArray(hexString: salt));
171 QCA::PBKDF1 pbkdf = QCA::PBKDF1(QStringLiteral("sha1"), provider);
172 QCA::PBKDF1 copy = pbkdf;
173 copy.context(); // detach
174 QCA::SymmetricKey key = pbkdf.makeKey(secret: password, salt: iv, keyLength: outputLength, iterationCount);
175 QCOMPARE(QCA::arrayToHex(key.toByteArray()), output);
176 }
177 }
178 if (!anyProviderTested)
179 qWarning() << "NONE of the providers supports PBKDF version 1 with SHA1:" << providersToTest;
180}
181
182void KDFUnitTest::pbkdf1sha1TimeTest()
183{
184 QCA::SecureArray password("secret");
185 QCA::InitializationVector iv(QByteArray("salt"));
186 unsigned int outputLength = 20;
187 int timeInterval = 200;
188 unsigned int iterationCount;
189
190 foreach (QString provider, providersToTest) {
191 if (QCA::isSupported(features: "pbkdf1(sha1)", provider)) {
192 QCA::SymmetricKey key1(QCA::PBKDF1(QStringLiteral("sha1"), provider)
193 .makeKey(secret: password, salt: iv, keyLength: outputLength, msecInterval: timeInterval, iterationCount: &iterationCount));
194
195 QCA::SymmetricKey key2(
196 QCA::PBKDF1(QStringLiteral("sha1"), provider).makeKey(secret: password, salt: iv, keyLength: outputLength, iterationCount));
197
198 QCOMPARE(key1, key2);
199 }
200 }
201}
202
203void KDFUnitTest::pbkdf2Tests_data()
204{
205 QTest::addColumn<QString>(name: "secret"); // usually a password or passphrase
206 QTest::addColumn<QString>(name: "output"); // the key you get back
207 QTest::addColumn<QString>(name: "salt"); // a salt or initialisation vector
208 QTest::addColumn<unsigned int>(name: "outputLength"); // if the algo supports variable length keys, len
209 QTest::addColumn<unsigned int>(name: "iterationCount"); // number of iterations
210
211 // These are from Botan's test suite
212 QTest::newRow(dataTag: "1") << QStringLiteral("6a79756571677872736367676c707864796b6366")
213 << QStringLiteral("df6d9d72872404bf73e708cf3b7d")
214 << QStringLiteral("9b56e55328a4c97a250738f8dba1b992e8a1b508") << static_cast<unsigned int>(14)
215 << static_cast<unsigned int>(10000);
216
217 QTest::newRow(dataTag: "2") << QStringLiteral("61717271737a6e7a76767a67746b73616d6d676f")
218 << QStringLiteral(
219 "fa13f40af1ade2a30f2fffd66fc8a659ef95e6388c1682fc0fe4d15a70109517a32942e39c371440")
220 << QStringLiteral("57487813cdd2220dfc485d932a2979ee8769ea8b") << static_cast<unsigned int>(40)
221 << static_cast<unsigned int>(101);
222
223 QTest::newRow(dataTag: "3") << QStringLiteral("6c7465786d666579796c6d6c62727379696b6177")
224 << QStringLiteral("027afadd48f4be8dcc4f")
225 << QStringLiteral("ed1f39a0a7f3889aaf7e60743b3bc1cc2c738e60") << static_cast<unsigned int>(10)
226 << static_cast<unsigned int>(1000);
227
228 QTest::newRow(dataTag: "4") << QStringLiteral("6378676e7972636772766c6c796c6f6c736a706f")
229 << QStringLiteral("7c0d009fc91b48cb6d19bafbfccff3e2ccabfe725eaa234e56bde1d551c132f2")
230 << QStringLiteral("94ac88200743fb0f6ac51be62166cbef08d94c15") << static_cast<unsigned int>(32)
231 << static_cast<unsigned int>(1);
232
233 QTest::newRow(dataTag: "5") << QStringLiteral("7871796668727865686965646c6865776e76626a")
234 << QStringLiteral("4661301d3517ca4443a6a607b32b2a63f69996299df75db75f1e0b98dd0eb7d8")
235 << QStringLiteral("24a1a50b17d63ee8394b69fc70887f4f94883d68") << static_cast<unsigned int>(32)
236 << static_cast<unsigned int>(5);
237
238 QTest::newRow(dataTag: "6") << QStringLiteral("616e6461716b706a7761627663666e706e6a6b6c")
239 << QStringLiteral("82fb44a521448d5aac94b5158ead1e4dcd7363081a747b9f7626752bda2d")
240 << QStringLiteral("9316c80801623cc2734af74bec42cf4dbaa3f6d5") << static_cast<unsigned int>(30)
241 << static_cast<unsigned int>(100);
242
243 QTest::newRow(dataTag: "7") << QStringLiteral("687361767679766f636c6f79757a746c736e6975")
244 << QStringLiteral("f8ec2b0ac817896ac8189d787c6424ed24a6d881436687a4629802c0ecce")
245 << QStringLiteral("612cc61df3cf2bdb36e10c4d8c9d73192bddee05") << static_cast<unsigned int>(30)
246 << static_cast<unsigned int>(100);
247
248 QTest::newRow(dataTag: "8") << QStringLiteral("6561696d72627a70636f706275736171746b6d77")
249 << QStringLiteral("c9a0b2622f13916036e29e7462e206e8ba5b50ce9212752eb8ea2a4aa7b40a4cc1bf")
250 << QStringLiteral("45248f9d0cebcb86a18243e76c972a1f3b36772a") << static_cast<unsigned int>(34)
251 << static_cast<unsigned int>(100);
252
253 QTest::newRow(dataTag: "9") << QStringLiteral("67777278707178756d7364736d626d6866686d666463766c63766e677a6b6967")
254 << QStringLiteral(
255 "4c9db7ba24955225d5b845f65ef24ef1b0c6e86f2e39c8ddaa4b8abd26082d1f350381fadeaeb560dc447afc"
256 "68a6b47e6ea1e7412f6cf7b2d82342fccd11d3b4")
257 << QStringLiteral("a39b76c6eec8374a11493ad08c246a3e40dfae5064f4ee3489c273646178")
258 << static_cast<unsigned int>(64) << static_cast<unsigned int>(1000);
259}
260
261void KDFUnitTest::pbkdf2Tests()
262{
263 QFETCH(QString, secret);
264 QFETCH(QString, output);
265 QFETCH(QString, salt);
266 QFETCH(unsigned int, outputLength);
267 QFETCH(unsigned int, iterationCount);
268
269 bool anyProviderTested = false;
270 foreach (QString provider, providersToTest) {
271 if (QCA::isSupported(features: "pbkdf2(sha1)", provider)) {
272 anyProviderTested = true;
273 QCA::SecureArray password = QCA::hexToArray(hexString: secret);
274 QCA::InitializationVector iv(QCA::hexToArray(hexString: salt));
275 QCA::PBKDF2 pbkdf = QCA::PBKDF2(QStringLiteral("sha1"), provider);
276 QCA::PBKDF2 copy = pbkdf;
277 copy.context(); // detach
278 QCA::SymmetricKey key = pbkdf.makeKey(secret: password, salt: iv, keyLength: outputLength, iterationCount);
279 QCOMPARE(QCA::arrayToHex(key.toByteArray()), output);
280 }
281 }
282
283 if (!anyProviderTested)
284 qWarning() << "NONE of the providers supports PBKDF version 2 with SHA1:" << providersToTest;
285}
286
287void KDFUnitTest::pbkdf2TimeTest()
288{
289 QCA::SecureArray password("secret");
290 QCA::InitializationVector iv(QByteArray("salt"));
291 unsigned int outputLength = 20;
292 int timeInterval = 200;
293 unsigned int iterationCount;
294
295 foreach (QString provider, providersToTest) {
296 if (QCA::isSupported(features: "pbkdf2(sha1)", provider)) {
297 QCA::SymmetricKey key1(QCA::PBKDF2(QStringLiteral("sha1"), provider)
298 .makeKey(secret: password, salt: iv, keyLength: outputLength, msecInterval: timeInterval, iterationCount: &iterationCount));
299
300 QCA::SymmetricKey key2(
301 QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt: iv, keyLength: outputLength, iterationCount));
302
303 QCOMPARE(key1, key2);
304 }
305 }
306}
307
308void KDFUnitTest::pbkdf2extraTests()
309{
310 foreach (QString provider, providersToTest) {
311 if (QCA::isSupported(features: "pbkdf2(sha1)", provider)) {
312 // Not sure where this one came from...
313 {
314 QCA::InitializationVector salt(QCA::SecureArray("what do ya want for nothing?"));
315 QCA::SecureArray password("Jefe");
316 int iterations = 1000;
317 QCA::SymmetricKey passwordOut =
318 QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 16, iterationCount: iterations);
319 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
320 QStringLiteral("6349e09cb6b8c1485cfa9780ee3264df"));
321 }
322
323 // RFC3962, Appendix B
324 {
325 QCA::InitializationVector salt(QCA::SecureArray("ATHENA.MIT.EDUraeburn"));
326 QCA::SecureArray password("password");
327 int iterations = 1;
328 QCA::SymmetricKey passwordOut =
329 QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 16, iterationCount: iterations);
330 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
331 QStringLiteral("cdedb5281bb2f801565a1122b2563515"));
332 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 32, iterationCount: iterations);
333 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
334 QStringLiteral("cdedb5281bb2f801565a1122b25635150ad1f7a04bb9f3a333ecc0e2e1f70837"));
335 }
336
337 // RFC3962, Appendix B
338 {
339 QCA::InitializationVector salt(QCA::SecureArray("ATHENA.MIT.EDUraeburn"));
340 QCA::SecureArray password("password");
341 int iterations = 2;
342 QCA::SymmetricKey passwordOut =
343 QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 16, iterationCount: iterations);
344 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
345 QStringLiteral("01dbee7f4a9e243e988b62c73cda935d"));
346 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 32, iterationCount: iterations);
347 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
348 QStringLiteral("01dbee7f4a9e243e988b62c73cda935da05378b93244ec8f48a99e61ad799d86"));
349 }
350
351 // RFC3962, Appendix B
352 {
353 QCA::InitializationVector salt(QCA::SecureArray("ATHENA.MIT.EDUraeburn"));
354 QCA::SecureArray password("password");
355 int iterations = 1200;
356 QCA::SymmetricKey passwordOut =
357 QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 16, iterationCount: iterations);
358 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
359 QStringLiteral("5c08eb61fdf71e4e4ec3cf6ba1f5512b"));
360 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 32, iterationCount: iterations);
361 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
362 QStringLiteral("5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13"));
363 }
364
365 // RFC3211 and RFC3962, Appendix B
366 {
367 QCA::InitializationVector salt(QCA::hexToArray(QStringLiteral("1234567878563412")));
368 QCA::SecureArray password("password");
369 int iterations = 5;
370 QCA::SymmetricKey passwordOut =
371 QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 16, iterationCount: iterations);
372 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
373 QStringLiteral("d1daa78615f287e6a1c8b120d7062a49"));
374 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 32, iterationCount: iterations);
375 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
376 QStringLiteral("d1daa78615f287e6a1c8b120d7062a493f98d203e6be49a6adf4fa574b6e64ee"));
377 passwordOut = QCA::PBKDF2().makeKey(secret: password, salt, keyLength: 8, iterationCount: iterations);
378 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), QStringLiteral("d1daa78615f287e6"));
379 }
380
381 // RFC3962, Appendix B
382 {
383 QCA::InitializationVector salt(QCA::SecureArray("pass phrase equals block size"));
384 QCA::SecureArray password("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
385 int iterations = 1200;
386 QCA::SymmetricKey passwordOut =
387 QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 16, iterationCount: iterations);
388 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
389 QStringLiteral("139c30c0966bc32ba55fdbf212530ac9"));
390 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 32, iterationCount: iterations);
391 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
392 QStringLiteral("139c30c0966bc32ba55fdbf212530ac9c5ec59f1a452f5cc9ad940fea0598ed1"));
393 }
394
395 // RFC3962, Appendix B
396 {
397 try {
398 QCA::InitializationVector salt(QCA::SecureArray("pass phrase exceeds block size"));
399 QCA::SecureArray password("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
400 int iterations = 1200;
401 QCA::SymmetricKey passwordOut =
402 QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 16, iterationCount: iterations);
403 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
404 QStringLiteral("9ccad6d468770cd51b10e6a68721be61"));
405 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 32, iterationCount: iterations);
406 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
407 QStringLiteral("9ccad6d468770cd51b10e6a68721be611a8b4d282601db3b36be9246915ec82a"));
408 } catch (std::exception &) {
409 if (provider == QLatin1String("qca-botan"))
410 qDebug() << "You should use a later version of Botan";
411 else
412 QFAIL("exception");
413 }
414 }
415
416 // RFC3962, Appendix B
417 {
418 QCA::InitializationVector salt(QCA::SecureArray("EXAMPLE.COMpianist"));
419 QCA::SecureArray password(QCA::hexToArray(QStringLiteral("f09d849e")));
420 int iterations = 50;
421 QCA::SymmetricKey passwordOut =
422 QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 16, iterationCount: iterations);
423 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
424 QStringLiteral("6b9cf26d45455a43a5b8bb276a403b39"));
425 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(secret: password, salt, keyLength: 32, iterationCount: iterations);
426 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
427 QStringLiteral("6b9cf26d45455a43a5b8bb276a403b39e7fe37a0c41e02c281ff3069e1e94f52"));
428 }
429 }
430 }
431}
432
433void KDFUnitTest::hkdfTests_data()
434{
435 QTest::addColumn<QString>(name: "secret"); // usually a password or passphrase
436 QTest::addColumn<QString>(name: "salt"); // a salt or initialisation vector
437 QTest::addColumn<QString>(name: "info"); // an additional info
438 QTest::addColumn<QString>(name: "output"); // the key you get back
439
440 // RFC 5869, Appendix A
441 QTest::newRow(dataTag: "1") << QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
442 << QStringLiteral("000102030405060708090a0b0c") << QStringLiteral("f0f1f2f3f4f5f6f7f8f9")
443 << QStringLiteral(
444 "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865");
445
446 QTest::newRow(dataTag: "2") << QStringLiteral(
447 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b"
448 "2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f")
449 << QStringLiteral(
450 "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b"
451 "8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf")
452 << QStringLiteral(
453 "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadb"
454 "dcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
455 << QStringLiteral(
456 "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c6"
457 "5e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87");
458
459 QTest::newRow(dataTag: "3") << QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") << QString() << QString()
460 << QStringLiteral(
461 "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8");
462}
463
464void KDFUnitTest::hkdfTests()
465{
466 QFETCH(QString, secret);
467 QFETCH(QString, salt);
468 QFETCH(QString, info);
469 QFETCH(QString, output);
470
471 bool anyProviderTested = false;
472 foreach (QString provider, providersToTest) {
473 if (QCA::isSupported(features: "hkdf(sha256)", provider)) {
474 anyProviderTested = true;
475 QCA::SecureArray password = QCA::hexToArray(hexString: secret);
476 QCA::InitializationVector saltv(QCA::hexToArray(hexString: salt));
477 QCA::InitializationVector infov(QCA::hexToArray(hexString: info));
478 QCA::HKDF hkdf = QCA::HKDF(QStringLiteral("sha256"), provider);
479 QCA::HKDF copy = hkdf;
480 copy.context(); // detach
481
482 QCA::SymmetricKey key = hkdf.makeKey(secret: password, salt: saltv, info: infov, keyLength: output.size() / 2);
483 QCOMPARE(QCA::arrayToHex(key.toByteArray()), output);
484 }
485 }
486 if (!anyProviderTested)
487 qWarning() << "NONE of the providers supports HKDF version 1 with SHA256:" << providersToTest;
488}
489
490QTEST_MAIN(KDFUnitTest)
491
492#include "kdfunittest.moc"
493

source code of qca/unittest/kdfunittest/kdfunittest.cpp