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 | |
33 | class KDFUnitTest : public QObject |
34 | { |
35 | Q_OBJECT |
36 | |
37 | private 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 | |
52 | private: |
53 | QCA::Initializer *m_init; |
54 | QStringList providersToTest; |
55 | }; |
56 | |
57 | void 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 | |
66 | void KDFUnitTest::cleanupTestCase() |
67 | { |
68 | delete m_init; |
69 | } |
70 | |
71 | void 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 | |
99 | void 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 | |
122 | void 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 | |
157 | void 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 | |
182 | void 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 | |
203 | void 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 | |
261 | void 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 | |
287 | void 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 | |
308 | void KDFUnitTest::() |
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 | |
433 | void 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 | |
464 | void 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 | |
490 | QTEST_MAIN(KDFUnitTest) |
491 | |
492 | #include "kdfunittest.moc" |
493 | |