File indexing completed on 2024-04-28 04:44:09

0001 /**
0002  * Copyright (C)  2004-2006  Brad Hards <bradh@frogmouth.net>
0003  *
0004  * Redistribution and use in source and binary forms, with or without
0005  * modification, are permitted provided that the following conditions
0006  * are met:
0007  *
0008  * 1. Redistributions of source code must retain the above copyright
0009  *   notice, this list of conditions and the following disclaimer.
0010  * 2. Redistributions in binary form must reproduce the above copyright
0011  *   notice, this list of conditions and the following disclaimer in the
0012  *   documentation and/or other materials provided with the distribution.
0013  *
0014  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
0015  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0016  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
0017  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0018  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0019  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
0020  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
0021  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0022  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0023  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0024  */
0025 
0026 #include <QtCrypto>
0027 #include <QtTest/QtTest>
0028 
0029 #ifdef QT_STATICPLUGIN
0030 #include "import_plugins.h"
0031 #endif
0032 
0033 class KDFUnitTest : public QObject
0034 {
0035     Q_OBJECT
0036 
0037 private Q_SLOTS:
0038     void initTestCase();
0039     void cleanupTestCase();
0040     void pbkdf1md2Tests_data();
0041     void pbkdf1md2Tests();
0042     void pbkdf1sha1Tests_data();
0043     void pbkdf1sha1Tests();
0044     void pbkdf1sha1TimeTest();
0045     void pbkdf2Tests_data();
0046     void pbkdf2Tests();
0047     void pbkdf2TimeTest();
0048     void pbkdf2extraTests();
0049     void hkdfTests_data();
0050     void hkdfTests();
0051 
0052 private:
0053     QCA::Initializer *m_init;
0054     QStringList       providersToTest;
0055 };
0056 
0057 void KDFUnitTest::initTestCase()
0058 {
0059     m_init = new QCA::Initializer;
0060 
0061     const auto providers = QCA::providers();
0062     for (QCA::Provider *provider : providers)
0063         providersToTest << provider->name();
0064 }
0065 
0066 void KDFUnitTest::cleanupTestCase()
0067 {
0068     delete m_init;
0069 }
0070 
0071 void KDFUnitTest::pbkdf1md2Tests_data()
0072 {
0073     QTest::addColumn<QString>("secret");              // usually a password or passphrase
0074     QTest::addColumn<QString>("output");              // the key you get back
0075     QTest::addColumn<QString>("salt");                // a salt or initialisation vector
0076     QTest::addColumn<unsigned int>("outputLength");   // if the algo supports variable length keys, len
0077     QTest::addColumn<unsigned int>("iterationCount"); // number of iterations
0078 
0079     // These are from Botan's test suite
0080     QTest::newRow("1") << QStringLiteral("71616c7a73656774") << QStringLiteral("7c1991f3f38a09d70cf3b1acadb70bc6")
0081                        << QStringLiteral("40cf117c3865e0cf") << static_cast<unsigned int>(16)
0082                        << static_cast<unsigned int>(1000);
0083 
0084     QTest::newRow("2") << QStringLiteral("766e68617a6a66736978626f6d787175")
0085                        << QStringLiteral("677500eda9f0c5e96e0a11f90fb9") << QStringLiteral("3a2484ce5d3e1b4d")
0086                        << static_cast<unsigned int>(14) << static_cast<unsigned int>(1);
0087 
0088     QTest::newRow("3") << QStringLiteral("66686565746e657162646d7171716e797977696f716a666c6f6976636371756a")
0089                        << QStringLiteral("91a5b689156b441bf27dd2bdd276")
0090                        << QStringLiteral("5d838b0f4fa22bfa2157f9083d87f8752e0495bb2113012761ef11b66e87c3cb")
0091                        << static_cast<unsigned int>(14) << static_cast<unsigned int>(15);
0092 
0093     QTest::newRow("4") << QStringLiteral("736e6279696e6a7075696b7176787867726c6b66")
0094                        << QStringLiteral("49516935cc9f438bafa30ff038fb")
0095                        << QStringLiteral("f22d341361b47e3390107bd973fdc0d3e0bc02a3") << static_cast<unsigned int>(14)
0096                        << static_cast<unsigned int>(2);
0097 }
0098 
0099 void KDFUnitTest::pbkdf1md2Tests()
0100 {
0101     QFETCH(QString, secret);
0102     QFETCH(QString, output);
0103     QFETCH(QString, salt);
0104     QFETCH(unsigned int, outputLength);
0105     QFETCH(unsigned int, iterationCount);
0106 
0107     bool anyProviderTested = false;
0108     foreach (QString provider, providersToTest) {
0109         if (QCA::isSupported("pbkdf1(md2)", provider)) {
0110             anyProviderTested                  = true;
0111             QCA::SecureArray          password = QCA::hexToArray(secret);
0112             QCA::InitializationVector iv(QCA::hexToArray(salt));
0113             QCA::SymmetricKey         key =
0114                 QCA::PBKDF1(QStringLiteral("md2"), provider).makeKey(password, iv, outputLength, iterationCount);
0115             QCOMPARE(QCA::arrayToHex(key.toByteArray()), output);
0116         }
0117     }
0118     if (!anyProviderTested)
0119         qWarning() << "NONE of the providers supports PBKDF version 1 with MD2:" << providersToTest;
0120 }
0121 
0122 void KDFUnitTest::pbkdf1sha1Tests_data()
0123 {
0124     QTest::addColumn<QString>("secret");              // usually a password or passphrase
0125     QTest::addColumn<QString>("output");              // the key you get back
0126     QTest::addColumn<QString>("salt");                // a salt or initialisation vector
0127     QTest::addColumn<unsigned int>("outputLength");   // if the algo supports variable length keys, len
0128     QTest::addColumn<unsigned int>("iterationCount"); // number of iterations
0129 
0130     // These are from Botan's test suite
0131     QTest::newRow("1") << QStringLiteral("66746c6b6662786474626a62766c6c7662776977")
0132                        << QStringLiteral("768b277dc970f912dbdd3edad48ad2f065d25d")
0133                        << QStringLiteral("40ac5837560251c275af5e30a6a3074e57ced38e") << static_cast<unsigned int>(19)
0134                        << static_cast<unsigned int>(6);
0135 
0136     QTest::newRow("2") << QStringLiteral("786e736f736d6b766867677a7370636e63706f63")
0137                        << QStringLiteral("4d90e846a4b6aaa02ac548014a00e97e506b2afb")
0138                        << QStringLiteral("7008a9dc1b9a81470a2360275c19dab77f716824") << static_cast<unsigned int>(20)
0139                        << static_cast<unsigned int>(6);
0140 
0141     QTest::newRow("3") << QStringLiteral("6f74696c71776c756b717473")
0142                        << QStringLiteral("71ed1a995e693efcd33155935e800037da74ea28")
0143                        << QStringLiteral("ccfc44c09339040e55d3f7f76ca6ef838fde928717241deb9ac1a4ef45a27711")
0144                        << static_cast<unsigned int>(20) << static_cast<unsigned int>(2001);
0145 
0146     QTest::newRow("4") << QStringLiteral("6b7a6e657166666c6274767374686e6663746166")
0147                        << QStringLiteral("f345fb8fbd880206b650266661f6")
0148                        << QStringLiteral("8108883fc04a01feb10661651516425dad1c93e0") << static_cast<unsigned int>(14)
0149                        << static_cast<unsigned int>(10000);
0150 
0151     QTest::newRow("5") << QStringLiteral("716b78686c7170656d7868796b6d7975636a626f")
0152                        << QStringLiteral("2d54dfed0c7ef7d20b0945ba414a")
0153                        << QStringLiteral("bc8bc53d4604977c3adb1d19c15e87b77a84c2f6") << static_cast<unsigned int>(14)
0154                        << static_cast<unsigned int>(10000);
0155 }
0156 
0157 void KDFUnitTest::pbkdf1sha1Tests()
0158 {
0159     QFETCH(QString, secret);
0160     QFETCH(QString, output);
0161     QFETCH(QString, salt);
0162     QFETCH(unsigned int, outputLength);
0163     QFETCH(unsigned int, iterationCount);
0164 
0165     bool anyProviderTested = false;
0166     foreach (QString provider, providersToTest) {
0167         if (QCA::isSupported("pbkdf1(sha1)", provider)) {
0168             anyProviderTested                  = true;
0169             QCA::SecureArray          password = QCA::hexToArray(secret);
0170             QCA::InitializationVector iv(QCA::hexToArray(salt));
0171             QCA::PBKDF1               pbkdf = QCA::PBKDF1(QStringLiteral("sha1"), provider);
0172             QCA::PBKDF1               copy  = pbkdf;
0173             copy.context(); // detach
0174             QCA::SymmetricKey key = pbkdf.makeKey(password, iv, outputLength, iterationCount);
0175             QCOMPARE(QCA::arrayToHex(key.toByteArray()), output);
0176         }
0177     }
0178     if (!anyProviderTested)
0179         qWarning() << "NONE of the providers supports PBKDF version 1 with SHA1:" << providersToTest;
0180 }
0181 
0182 void KDFUnitTest::pbkdf1sha1TimeTest()
0183 {
0184     QCA::SecureArray          password("secret");
0185     QCA::InitializationVector iv(QByteArray("salt"));
0186     unsigned int              outputLength = 20;
0187     int                       timeInterval = 200;
0188     unsigned int              iterationCount;
0189 
0190     foreach (QString provider, providersToTest) {
0191         if (QCA::isSupported("pbkdf1(sha1)", provider)) {
0192             QCA::SymmetricKey key1(QCA::PBKDF1(QStringLiteral("sha1"), provider)
0193                                        .makeKey(password, iv, outputLength, timeInterval, &iterationCount));
0194 
0195             QCA::SymmetricKey key2(
0196                 QCA::PBKDF1(QStringLiteral("sha1"), provider).makeKey(password, iv, outputLength, iterationCount));
0197 
0198             QCOMPARE(key1, key2);
0199         }
0200     }
0201 }
0202 
0203 void KDFUnitTest::pbkdf2Tests_data()
0204 {
0205     QTest::addColumn<QString>("secret");              // usually a password or passphrase
0206     QTest::addColumn<QString>("output");              // the key you get back
0207     QTest::addColumn<QString>("salt");                // a salt or initialisation vector
0208     QTest::addColumn<unsigned int>("outputLength");   // if the algo supports variable length keys, len
0209     QTest::addColumn<unsigned int>("iterationCount"); // number of iterations
0210 
0211     // These are from Botan's test suite
0212     QTest::newRow("1") << QStringLiteral("6a79756571677872736367676c707864796b6366")
0213                        << QStringLiteral("df6d9d72872404bf73e708cf3b7d")
0214                        << QStringLiteral("9b56e55328a4c97a250738f8dba1b992e8a1b508") << static_cast<unsigned int>(14)
0215                        << static_cast<unsigned int>(10000);
0216 
0217     QTest::newRow("2") << QStringLiteral("61717271737a6e7a76767a67746b73616d6d676f")
0218                        << QStringLiteral(
0219                               "fa13f40af1ade2a30f2fffd66fc8a659ef95e6388c1682fc0fe4d15a70109517a32942e39c371440")
0220                        << QStringLiteral("57487813cdd2220dfc485d932a2979ee8769ea8b") << static_cast<unsigned int>(40)
0221                        << static_cast<unsigned int>(101);
0222 
0223     QTest::newRow("3") << QStringLiteral("6c7465786d666579796c6d6c62727379696b6177")
0224                        << QStringLiteral("027afadd48f4be8dcc4f")
0225                        << QStringLiteral("ed1f39a0a7f3889aaf7e60743b3bc1cc2c738e60") << static_cast<unsigned int>(10)
0226                        << static_cast<unsigned int>(1000);
0227 
0228     QTest::newRow("4") << QStringLiteral("6378676e7972636772766c6c796c6f6c736a706f")
0229                        << QStringLiteral("7c0d009fc91b48cb6d19bafbfccff3e2ccabfe725eaa234e56bde1d551c132f2")
0230                        << QStringLiteral("94ac88200743fb0f6ac51be62166cbef08d94c15") << static_cast<unsigned int>(32)
0231                        << static_cast<unsigned int>(1);
0232 
0233     QTest::newRow("5") << QStringLiteral("7871796668727865686965646c6865776e76626a")
0234                        << QStringLiteral("4661301d3517ca4443a6a607b32b2a63f69996299df75db75f1e0b98dd0eb7d8")
0235                        << QStringLiteral("24a1a50b17d63ee8394b69fc70887f4f94883d68") << static_cast<unsigned int>(32)
0236                        << static_cast<unsigned int>(5);
0237 
0238     QTest::newRow("6") << QStringLiteral("616e6461716b706a7761627663666e706e6a6b6c")
0239                        << QStringLiteral("82fb44a521448d5aac94b5158ead1e4dcd7363081a747b9f7626752bda2d")
0240                        << QStringLiteral("9316c80801623cc2734af74bec42cf4dbaa3f6d5") << static_cast<unsigned int>(30)
0241                        << static_cast<unsigned int>(100);
0242 
0243     QTest::newRow("7") << QStringLiteral("687361767679766f636c6f79757a746c736e6975")
0244                        << QStringLiteral("f8ec2b0ac817896ac8189d787c6424ed24a6d881436687a4629802c0ecce")
0245                        << QStringLiteral("612cc61df3cf2bdb36e10c4d8c9d73192bddee05") << static_cast<unsigned int>(30)
0246                        << static_cast<unsigned int>(100);
0247 
0248     QTest::newRow("8") << QStringLiteral("6561696d72627a70636f706275736171746b6d77")
0249                        << QStringLiteral("c9a0b2622f13916036e29e7462e206e8ba5b50ce9212752eb8ea2a4aa7b40a4cc1bf")
0250                        << QStringLiteral("45248f9d0cebcb86a18243e76c972a1f3b36772a") << static_cast<unsigned int>(34)
0251                        << static_cast<unsigned int>(100);
0252 
0253     QTest::newRow("9") << QStringLiteral("67777278707178756d7364736d626d6866686d666463766c63766e677a6b6967")
0254                        << QStringLiteral(
0255                               "4c9db7ba24955225d5b845f65ef24ef1b0c6e86f2e39c8ddaa4b8abd26082d1f350381fadeaeb560dc447afc"
0256                               "68a6b47e6ea1e7412f6cf7b2d82342fccd11d3b4")
0257                        << QStringLiteral("a39b76c6eec8374a11493ad08c246a3e40dfae5064f4ee3489c273646178")
0258                        << static_cast<unsigned int>(64) << static_cast<unsigned int>(1000);
0259 }
0260 
0261 void KDFUnitTest::pbkdf2Tests()
0262 {
0263     QFETCH(QString, secret);
0264     QFETCH(QString, output);
0265     QFETCH(QString, salt);
0266     QFETCH(unsigned int, outputLength);
0267     QFETCH(unsigned int, iterationCount);
0268 
0269     bool anyProviderTested = false;
0270     foreach (QString provider, providersToTest) {
0271         if (QCA::isSupported("pbkdf2(sha1)", provider)) {
0272             anyProviderTested                  = true;
0273             QCA::SecureArray          password = QCA::hexToArray(secret);
0274             QCA::InitializationVector iv(QCA::hexToArray(salt));
0275             QCA::PBKDF2               pbkdf = QCA::PBKDF2(QStringLiteral("sha1"), provider);
0276             QCA::PBKDF2               copy  = pbkdf;
0277             copy.context(); // detach
0278             QCA::SymmetricKey key = pbkdf.makeKey(password, iv, outputLength, iterationCount);
0279             QCOMPARE(QCA::arrayToHex(key.toByteArray()), output);
0280         }
0281     }
0282 
0283     if (!anyProviderTested)
0284         qWarning() << "NONE of the providers supports PBKDF version 2 with SHA1:" << providersToTest;
0285 }
0286 
0287 void KDFUnitTest::pbkdf2TimeTest()
0288 {
0289     QCA::SecureArray          password("secret");
0290     QCA::InitializationVector iv(QByteArray("salt"));
0291     unsigned int              outputLength = 20;
0292     int                       timeInterval = 200;
0293     unsigned int              iterationCount;
0294 
0295     foreach (QString provider, providersToTest) {
0296         if (QCA::isSupported("pbkdf2(sha1)", provider)) {
0297             QCA::SymmetricKey key1(QCA::PBKDF2(QStringLiteral("sha1"), provider)
0298                                        .makeKey(password, iv, outputLength, timeInterval, &iterationCount));
0299 
0300             QCA::SymmetricKey key2(
0301                 QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, iv, outputLength, iterationCount));
0302 
0303             QCOMPARE(key1, key2);
0304         }
0305     }
0306 }
0307 
0308 void KDFUnitTest::pbkdf2extraTests()
0309 {
0310     foreach (QString provider, providersToTest) {
0311         if (QCA::isSupported("pbkdf2(sha1)", provider)) {
0312             // Not sure where this one came from...
0313             {
0314                 QCA::InitializationVector salt(QCA::SecureArray("what do ya want for nothing?"));
0315                 QCA::SecureArray          password("Jefe");
0316                 int                       iterations = 1000;
0317                 QCA::SymmetricKey         passwordOut =
0318                     QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations);
0319                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0320                          QStringLiteral("6349e09cb6b8c1485cfa9780ee3264df"));
0321             }
0322 
0323             // RFC3962, Appendix B
0324             {
0325                 QCA::InitializationVector salt(QCA::SecureArray("ATHENA.MIT.EDUraeburn"));
0326                 QCA::SecureArray          password("password");
0327                 int                       iterations = 1;
0328                 QCA::SymmetricKey         passwordOut =
0329                     QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations);
0330                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0331                          QStringLiteral("cdedb5281bb2f801565a1122b2563515"));
0332                 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations);
0333                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0334                          QStringLiteral("cdedb5281bb2f801565a1122b25635150ad1f7a04bb9f3a333ecc0e2e1f70837"));
0335             }
0336 
0337             // RFC3962, Appendix B
0338             {
0339                 QCA::InitializationVector salt(QCA::SecureArray("ATHENA.MIT.EDUraeburn"));
0340                 QCA::SecureArray          password("password");
0341                 int                       iterations = 2;
0342                 QCA::SymmetricKey         passwordOut =
0343                     QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations);
0344                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0345                          QStringLiteral("01dbee7f4a9e243e988b62c73cda935d"));
0346                 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations);
0347                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0348                          QStringLiteral("01dbee7f4a9e243e988b62c73cda935da05378b93244ec8f48a99e61ad799d86"));
0349             }
0350 
0351             // RFC3962, Appendix B
0352             {
0353                 QCA::InitializationVector salt(QCA::SecureArray("ATHENA.MIT.EDUraeburn"));
0354                 QCA::SecureArray          password("password");
0355                 int                       iterations = 1200;
0356                 QCA::SymmetricKey         passwordOut =
0357                     QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations);
0358                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0359                          QStringLiteral("5c08eb61fdf71e4e4ec3cf6ba1f5512b"));
0360                 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations);
0361                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0362                          QStringLiteral("5c08eb61fdf71e4e4ec3cf6ba1f5512ba7e52ddbc5e5142f708a31e2e62b1e13"));
0363             }
0364 
0365             // RFC3211 and RFC3962, Appendix B
0366             {
0367                 QCA::InitializationVector salt(QCA::hexToArray(QStringLiteral("1234567878563412")));
0368                 QCA::SecureArray          password("password");
0369                 int                       iterations = 5;
0370                 QCA::SymmetricKey         passwordOut =
0371                     QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations);
0372                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0373                          QStringLiteral("d1daa78615f287e6a1c8b120d7062a49"));
0374                 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations);
0375                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0376                          QStringLiteral("d1daa78615f287e6a1c8b120d7062a493f98d203e6be49a6adf4fa574b6e64ee"));
0377                 passwordOut = QCA::PBKDF2().makeKey(password, salt, 8, iterations);
0378                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()), QStringLiteral("d1daa78615f287e6"));
0379             }
0380 
0381             // RFC3962, Appendix B
0382             {
0383                 QCA::InitializationVector salt(QCA::SecureArray("pass phrase equals block size"));
0384                 QCA::SecureArray          password("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
0385                 int                       iterations = 1200;
0386                 QCA::SymmetricKey         passwordOut =
0387                     QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations);
0388                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0389                          QStringLiteral("139c30c0966bc32ba55fdbf212530ac9"));
0390                 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations);
0391                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0392                          QStringLiteral("139c30c0966bc32ba55fdbf212530ac9c5ec59f1a452f5cc9ad940fea0598ed1"));
0393             }
0394 
0395             // RFC3962, Appendix B
0396             {
0397                 try {
0398                     QCA::InitializationVector salt(QCA::SecureArray("pass phrase exceeds block size"));
0399                     QCA::SecureArray  password("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
0400                     int               iterations = 1200;
0401                     QCA::SymmetricKey passwordOut =
0402                         QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations);
0403                     QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0404                              QStringLiteral("9ccad6d468770cd51b10e6a68721be61"));
0405                     passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations);
0406                     QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0407                              QStringLiteral("9ccad6d468770cd51b10e6a68721be611a8b4d282601db3b36be9246915ec82a"));
0408                 } catch (std::exception &) {
0409                     if (provider == QLatin1String("qca-botan"))
0410                         qDebug() << "You should use a later version of Botan";
0411                     else
0412                         QFAIL("exception");
0413                 }
0414             }
0415 
0416             // RFC3962, Appendix B
0417             {
0418                 QCA::InitializationVector salt(QCA::SecureArray("EXAMPLE.COMpianist"));
0419                 QCA::SecureArray          password(QCA::hexToArray(QStringLiteral("f09d849e")));
0420                 int                       iterations = 50;
0421                 QCA::SymmetricKey         passwordOut =
0422                     QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 16, iterations);
0423                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0424                          QStringLiteral("6b9cf26d45455a43a5b8bb276a403b39"));
0425                 passwordOut = QCA::PBKDF2(QStringLiteral("sha1"), provider).makeKey(password, salt, 32, iterations);
0426                 QCOMPARE(QCA::arrayToHex(passwordOut.toByteArray()),
0427                          QStringLiteral("6b9cf26d45455a43a5b8bb276a403b39e7fe37a0c41e02c281ff3069e1e94f52"));
0428             }
0429         }
0430     }
0431 }
0432 
0433 void KDFUnitTest::hkdfTests_data()
0434 {
0435     QTest::addColumn<QString>("secret"); // usually a password or passphrase
0436     QTest::addColumn<QString>("salt");   // a salt or initialisation vector
0437     QTest::addColumn<QString>("info");   // an additional info
0438     QTest::addColumn<QString>("output"); // the key you get back
0439 
0440     // RFC 5869, Appendix A
0441     QTest::newRow("1") << QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b")
0442                        << QStringLiteral("000102030405060708090a0b0c") << QStringLiteral("f0f1f2f3f4f5f6f7f8f9")
0443                        << QStringLiteral(
0444                               "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865");
0445 
0446     QTest::newRow("2") << QStringLiteral(
0447                               "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b"
0448                               "2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f")
0449                        << QStringLiteral(
0450                               "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b"
0451                               "8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf")
0452                        << QStringLiteral(
0453                               "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadb"
0454                               "dcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
0455                        << QStringLiteral(
0456                               "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c6"
0457                               "5e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87");
0458 
0459     QTest::newRow("3") << QStringLiteral("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b") << QString() << QString()
0460                        << QStringLiteral(
0461                               "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8");
0462 }
0463 
0464 void KDFUnitTest::hkdfTests()
0465 {
0466     QFETCH(QString, secret);
0467     QFETCH(QString, salt);
0468     QFETCH(QString, info);
0469     QFETCH(QString, output);
0470 
0471     bool anyProviderTested = false;
0472     foreach (QString provider, providersToTest) {
0473         if (QCA::isSupported("hkdf(sha256)", provider)) {
0474             anyProviderTested                  = true;
0475             QCA::SecureArray          password = QCA::hexToArray(secret);
0476             QCA::InitializationVector saltv(QCA::hexToArray(salt));
0477             QCA::InitializationVector infov(QCA::hexToArray(info));
0478             QCA::HKDF                 hkdf = QCA::HKDF(QStringLiteral("sha256"), provider);
0479             QCA::HKDF                 copy = hkdf;
0480             copy.context(); // detach
0481 
0482             QCA::SymmetricKey key = hkdf.makeKey(password, saltv, infov, output.size() / 2);
0483             QCOMPARE(QCA::arrayToHex(key.toByteArray()), output);
0484         }
0485     }
0486     if (!anyProviderTested)
0487         qWarning() << "NONE of the providers supports HKDF version 1 with SHA256:" << providersToTest;
0488 }
0489 
0490 QTEST_MAIN(KDFUnitTest)
0491 
0492 #include "kdfunittest.moc"