1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31#include <qsslkey.h>
32#include <qsslsocket.h>
33#include <QScopeGuard>
34#include <qsslconfiguration.h>
35#include <qsslellipticcurve.h>
36
37#include <QtNetwork/qhostaddress.h>
38#include <QtNetwork/qnetworkproxy.h>
39
40#include <QtCore/qstring.h>
41#include <QtCore/qdebug.h>
42#include <QtCore/qlist.h>
43
44#ifdef QT_BUILD_INTERNAL
45 #ifndef QT_NO_SSL
46 #include "private/qsslkey_p.h"
47 #define TEST_CRYPTO
48 #endif
49 #ifndef QT_NO_OPENSSL
50 #include "private/qsslsocket_openssl_symbols_p.h"
51 #endif
52#endif
53
54#include <algorithm>
55
56class tst_QSslKey : public QObject
57{
58 Q_OBJECT
59
60 struct KeyInfo {
61 QFileInfo fileInfo;
62 QSsl::KeyAlgorithm algorithm;
63 QSsl::KeyType type;
64 int length;
65 QSsl::EncodingFormat format;
66 KeyInfo(
67 const QFileInfo &fileInfo, QSsl::KeyAlgorithm algorithm, QSsl::KeyType type,
68 int length, QSsl::EncodingFormat format)
69 : fileInfo(fileInfo), algorithm(algorithm), type(type), length(length)
70 , format(format) {}
71 };
72
73 QList<KeyInfo> keyInfoList;
74
75 void createPlainTestRows(bool pemOnly = false);
76public:
77 tst_QSslKey();
78
79public slots:
80 void initTestCase();
81
82#ifndef QT_NO_SSL
83
84private slots:
85 void emptyConstructor();
86 void constructor_data();
87 void constructor();
88#ifndef QT_NO_OPENSSL
89 void constructorHandle_data();
90 void constructorHandle();
91#endif
92 void copyAndAssign_data();
93 void copyAndAssign();
94 void equalsOperator();
95 void length_data();
96 void length();
97 void toPemOrDer_data();
98 void toPemOrDer();
99 void toEncryptedPemOrDer_data();
100 void toEncryptedPemOrDer();
101
102 void passphraseChecks_data();
103 void passphraseChecks();
104 void noPassphraseChecks();
105#ifdef TEST_CRYPTO
106 void encrypt_data();
107 void encrypt();
108#endif
109
110#endif
111private:
112 QString testDataDir;
113
114 bool fileContainsUnsupportedEllipticCurve(const QString &fileName) const;
115 QVector<QString> unsupportedCurves;
116};
117
118tst_QSslKey::tst_QSslKey()
119{
120#ifndef QT_NO_SSL
121 const QString expectedCurves[] = {
122 // See how we generate them in keys/genkey.sh.
123 QStringLiteral("secp224r1"),
124 QStringLiteral("prime256v1"),
125 QStringLiteral("secp384r1"),
126 QStringLiteral("brainpoolP256r1"),
127 QStringLiteral("brainpoolP384r1"),
128 QStringLiteral("brainpoolP512r1")
129 };
130 const auto supportedCurves = QSslConfiguration::supportedEllipticCurves();
131
132 for (const auto &requestedEc : expectedCurves) {
133 auto pos = std::find_if(first: supportedCurves.begin(), last: supportedCurves.end(),
134 pred: [&requestedEc](const QSslEllipticCurve &supported) {
135 return requestedEc == supported.shortName();
136 });
137 if (pos == supportedCurves.end()) {
138 qWarning() << "EC with the name:" << requestedEc
139 << "is not supported by your build of OpenSSL and will not be tested.";
140 unsupportedCurves.push_back(t: requestedEc);
141 }
142 }
143#else
144 unsupportedCurves = {}; // not unsued anymore.
145#endif
146}
147
148bool tst_QSslKey::fileContainsUnsupportedEllipticCurve(const QString &fileName) const
149{
150 for (const auto &name : unsupportedCurves) {
151 if (fileName.contains(s: name))
152 return true;
153 }
154 return false;
155}
156
157void tst_QSslKey::initTestCase()
158{
159 testDataDir = QFileInfo(QFINDTESTDATA("rsa-without-passphrase.pem")).absolutePath();
160 if (testDataDir.isEmpty())
161 testDataDir = QCoreApplication::applicationDirPath();
162 if (!testDataDir.endsWith(s: QLatin1String("/")))
163 testDataDir += QLatin1String("/");
164
165 QDir dir(testDataDir + "keys");
166 const QFileInfoList fileInfoList = dir.entryInfoList(filters: QDir::Files | QDir::Readable);
167 QRegExp rx(QLatin1String("^(rsa|dsa|dh|ec)-(pub|pri)-(\\d+)-?[\\w-]*\\.(pem|der)$"));
168 for (const QFileInfo &fileInfo : fileInfoList) {
169 if (fileContainsUnsupportedEllipticCurve(fileName: fileInfo.fileName()))
170 continue;
171
172 if (rx.indexIn(str: fileInfo.fileName()) >= 0) {
173 keyInfoList << KeyInfo(
174 fileInfo,
175 rx.cap(nth: 1) == QLatin1String("rsa") ? QSsl::Rsa :
176 rx.cap(nth: 1) == QLatin1String("dsa") ? QSsl::Dsa :
177 rx.cap(nth: 1) == QLatin1String("dh") ? QSsl::Dh : QSsl::Ec,
178 rx.cap(nth: 2) == QLatin1String("pub") ? QSsl::PublicKey : QSsl::PrivateKey,
179 rx.cap(nth: 3).toInt(),
180 rx.cap(nth: 4) == QLatin1String("pem") ? QSsl::Pem : QSsl::Der);
181 }
182 }
183}
184
185#ifndef QT_NO_SSL
186
187static QByteArray readFile(const QString &absFilePath)
188{
189 QFile file(absFilePath);
190 if (!file.open(flags: QIODevice::ReadOnly)) {
191 QWARN("failed to open file");
192 return QByteArray();
193 }
194 return file.readAll();
195}
196
197void tst_QSslKey::emptyConstructor()
198{
199 if (!QSslSocket::supportsSsl())
200 return;
201
202 QSslKey key;
203 QVERIFY(key.isNull());
204 QVERIFY(key.length() < 0);
205
206 QSslKey key2;
207 QCOMPARE(key, key2);
208}
209
210Q_DECLARE_METATYPE(QSsl::KeyAlgorithm)
211Q_DECLARE_METATYPE(QSsl::KeyType)
212Q_DECLARE_METATYPE(QSsl::EncodingFormat)
213
214void tst_QSslKey::createPlainTestRows(bool pemOnly)
215{
216 QTest::addColumn<QString>(name: "absFilePath");
217 QTest::addColumn<QSsl::KeyAlgorithm>(name: "algorithm");
218 QTest::addColumn<QSsl::KeyType>(name: "type");
219 QTest::addColumn<int>(name: "length");
220 QTest::addColumn<QSsl::EncodingFormat>(name: "format");
221 foreach (KeyInfo keyInfo, keyInfoList) {
222 if (pemOnly && keyInfo.format != QSsl::EncodingFormat::Pem)
223 continue;
224#if defined(Q_OS_WINRT) || QT_CONFIG(schannel)
225 if (keyInfo.fileInfo.fileName().contains("RC2-64"))
226 continue; // WinRT/Schannel treats RC2 as 128 bit
227#endif
228#if !defined(QT_NO_SSL) && defined(QT_NO_OPENSSL) // generic backend
229 if (keyInfo.fileInfo.fileName().contains(QRegularExpression("-aes\\d\\d\\d-")))
230 continue; // No AES support in the generic back-end
231 if (keyInfo.fileInfo.fileName().contains("pkcs8-pkcs12"))
232 continue; // The generic back-end doesn't support PKCS#12 algorithms
233#endif
234
235 QTest::newRow(dataTag: keyInfo.fileInfo.fileName().toLatin1())
236 << keyInfo.fileInfo.absoluteFilePath() << keyInfo.algorithm << keyInfo.type
237 << keyInfo.length << keyInfo.format;
238 }
239}
240
241void tst_QSslKey::constructor_data()
242{
243 createPlainTestRows();
244}
245
246void tst_QSslKey::constructor()
247{
248 if (!QSslSocket::supportsSsl())
249 return;
250
251 QFETCH(QString, absFilePath);
252 QFETCH(QSsl::KeyAlgorithm, algorithm);
253 QFETCH(QSsl::KeyType, type);
254 QFETCH(QSsl::EncodingFormat, format);
255
256 QByteArray encoded = readFile(absFilePath);
257 QByteArray passphrase;
258 if (QByteArray(QTest::currentDataTag()).contains(c: "-pkcs8-"))
259 passphrase = QByteArray("1234");
260 QSslKey key(encoded, algorithm, format, type, passphrase);
261 QVERIFY(!key.isNull());
262}
263
264#ifndef QT_NO_OPENSSL
265
266void tst_QSslKey::constructorHandle_data()
267{
268 createPlainTestRows(pemOnly: true);
269}
270
271void tst_QSslKey::constructorHandle()
272{
273#ifndef QT_BUILD_INTERNAL
274 QSKIP("This test requires -developer-build.");
275#else
276 if (!QSslSocket::supportsSsl())
277 return;
278
279 QFETCH(QString, absFilePath);
280 QFETCH(QSsl::KeyAlgorithm, algorithm);
281 QFETCH(QSsl::KeyType, type);
282 QFETCH(int, length);
283
284 QByteArray pem = readFile(absFilePath);
285 auto func = (type == QSsl::KeyType::PublicKey
286 ? q_PEM_read_bio_PUBKEY
287 : q_PEM_read_bio_PrivateKey);
288
289 QByteArray passphrase;
290 if (QByteArray(QTest::currentDataTag()).contains(c: "-pkcs8-"))
291 passphrase = "1234";
292
293 BIO* bio = q_BIO_new(a: q_BIO_s_mem());
294 q_BIO_write(a: bio, b: pem.constData(), c: pem.length());
295 EVP_PKEY *origin = func(bio, nullptr, nullptr, static_cast<void *>(passphrase.data()));
296 Q_ASSERT(origin);
297 q_EVP_PKEY_up_ref(a: origin);
298 QSslKey key(origin, type);
299 q_BIO_free(a: bio);
300
301 EVP_PKEY *handle = q_EVP_PKEY_new();
302 switch (algorithm) {
303 case QSsl::Rsa:
304 q_EVP_PKEY_set1_RSA(a: handle, b: static_cast<RSA *>(key.handle()));
305 break;
306 case QSsl::Dsa:
307 q_EVP_PKEY_set1_DSA(a: handle, b: static_cast<DSA *>(key.handle()));
308 break;
309 case QSsl::Dh:
310 q_EVP_PKEY_set1_DH(a: handle, b: static_cast<DH *>(key.handle()));
311 break;
312#ifndef OPENSSL_NO_EC
313 case QSsl::Ec:
314 q_EVP_PKEY_set1_EC_KEY(a: handle, b: static_cast<EC_KEY *>(key.handle()));
315 break;
316#endif
317 default:
318 break;
319 }
320
321 auto cleanup = qScopeGuard(f: [origin, handle] {
322 q_EVP_PKEY_free(a: origin);
323 q_EVP_PKEY_free(a: handle);
324 });
325
326 QVERIFY(!key.isNull());
327 QCOMPARE(key.algorithm(), algorithm);
328 QCOMPARE(key.type(), type);
329 QCOMPARE(key.length(), length);
330 QCOMPARE(q_EVP_PKEY_cmp(origin, handle), 1);
331#endif
332}
333
334#endif
335
336void tst_QSslKey::copyAndAssign_data()
337{
338 createPlainTestRows();
339}
340
341void tst_QSslKey::copyAndAssign()
342{
343 if (!QSslSocket::supportsSsl())
344 return;
345
346 QFETCH(QString, absFilePath);
347 QFETCH(QSsl::KeyAlgorithm, algorithm);
348 QFETCH(QSsl::KeyType, type);
349 QFETCH(QSsl::EncodingFormat, format);
350
351 QByteArray encoded = readFile(absFilePath);
352 QByteArray passphrase;
353 if (QByteArray(QTest::currentDataTag()).contains(c: "-pkcs8-"))
354 passphrase = QByteArray("1234");
355 QSslKey key(encoded, algorithm, format, type, passphrase);
356
357 QSslKey copied(key);
358 QCOMPARE(key, copied);
359 QCOMPARE(key.algorithm(), copied.algorithm());
360 QCOMPARE(key.type(), copied.type());
361 QCOMPARE(key.length(), copied.length());
362 QCOMPARE(key.toPem(), copied.toPem());
363 QCOMPARE(key.toDer(), copied.toDer());
364
365 QSslKey assigned = key;
366 QCOMPARE(key, assigned);
367 QCOMPARE(key.algorithm(), assigned.algorithm());
368 QCOMPARE(key.type(), assigned.type());
369 QCOMPARE(key.length(), assigned.length());
370 QCOMPARE(key.toPem(), assigned.toPem());
371 QCOMPARE(key.toDer(), assigned.toDer());
372}
373
374void tst_QSslKey::equalsOperator()
375{
376 // ### unimplemented
377}
378
379void tst_QSslKey::length_data()
380{
381 createPlainTestRows();
382}
383
384void tst_QSslKey::length()
385{
386 if (!QSslSocket::supportsSsl())
387 return;
388
389 QFETCH(QString, absFilePath);
390 QFETCH(QSsl::KeyAlgorithm, algorithm);
391 QFETCH(QSsl::KeyType, type);
392 QFETCH(int, length);
393 QFETCH(QSsl::EncodingFormat, format);
394
395 QByteArray encoded = readFile(absFilePath);
396 QByteArray passphrase;
397 if (QByteArray(QTest::currentDataTag()).contains(c: "-pkcs8-"))
398 passphrase = QByteArray("1234");
399 QSslKey key(encoded, algorithm, format, type, passphrase);
400 QVERIFY(!key.isNull());
401 QCOMPARE(key.length(), length);
402}
403
404void tst_QSslKey::toPemOrDer_data()
405{
406 createPlainTestRows();
407}
408
409void tst_QSslKey::toPemOrDer()
410{
411 if (!QSslSocket::supportsSsl())
412 return;
413
414 QFETCH(QString, absFilePath);
415 QFETCH(QSsl::KeyAlgorithm, algorithm);
416 QFETCH(QSsl::KeyType, type);
417 QFETCH(QSsl::EncodingFormat, format);
418
419 QByteArray dataTag = QByteArray(QTest::currentDataTag());
420 if (dataTag.contains(c: "-pkcs8-")) // these are encrypted
421 QSKIP("Encrypted PKCS#8 keys gets decrypted when loaded. So we can't compare it to the encrypted version.");
422#ifndef QT_NO_OPENSSL
423 if (dataTag.contains(c: "pkcs8"))
424 QSKIP("OpenSSL converts PKCS#8 keys to other formats, invalidating comparisons.");
425#else // !openssl
426 if (dataTag.contains("pkcs8") && dataTag.contains("rsa"))
427 QSKIP("PKCS#8 RSA keys are changed into a different format in the generic back-end, meaning the comparison fails.");
428#endif // openssl
429
430 QByteArray encoded = readFile(absFilePath);
431 QSslKey key(encoded, algorithm, format, type);
432 QVERIFY(!key.isNull());
433 if (format == QSsl::Pem)
434 encoded.replace(before: '\r', c: "");
435 QCOMPARE(format == QSsl::Pem ? key.toPem() : key.toDer(), encoded);
436}
437
438void tst_QSslKey::toEncryptedPemOrDer_data()
439{
440 QTest::addColumn<QString>(name: "absFilePath");
441 QTest::addColumn<QSsl::KeyAlgorithm>(name: "algorithm");
442 QTest::addColumn<QSsl::KeyType>(name: "type");
443 QTest::addColumn<QSsl::EncodingFormat>(name: "format");
444 QTest::addColumn<QString>(name: "password");
445
446 QStringList passwords;
447 passwords << " " << "foobar" << "foo bar"
448 << "aAzZ`1234567890-=~!@#$%^&*()_+[]{}\\|;:'\",.<>/?"; // ### add more (?)
449 foreach (KeyInfo keyInfo, keyInfoList) {
450 if (keyInfo.fileInfo.fileName().contains(s: "pkcs8"))
451 continue; // pkcs8 keys are encrypted in a different way than the other keys
452 foreach (QString password, passwords) {
453 const QByteArray testName = keyInfo.fileInfo.fileName().toLatin1()
454 + '-' + (keyInfo.algorithm == QSsl::Rsa ? "RSA" :
455 (keyInfo.algorithm == QSsl::Dsa ? "DSA" : "EC"))
456 + '-' + (keyInfo.type == QSsl::PrivateKey ? "PrivateKey" : "PublicKey")
457 + '-' + (keyInfo.format == QSsl::Pem ? "PEM" : "DER")
458 + password.toLatin1();
459 QTest::newRow(dataTag: testName.constData())
460 << keyInfo.fileInfo.absoluteFilePath() << keyInfo.algorithm << keyInfo.type
461 << keyInfo.format << password;
462 }
463 }
464}
465
466void tst_QSslKey::toEncryptedPemOrDer()
467{
468 if (!QSslSocket::supportsSsl())
469 return;
470
471 QFETCH(QString, absFilePath);
472 QFETCH(QSsl::KeyAlgorithm, algorithm);
473 QFETCH(QSsl::KeyType, type);
474 QFETCH(QSsl::EncodingFormat, format);
475 QFETCH(QString, password);
476
477 QByteArray plain = readFile(absFilePath);
478 QSslKey key(plain, algorithm, format, type);
479 QVERIFY(!key.isNull());
480
481 QByteArray pwBytes(password.toLatin1());
482
483 if (type == QSsl::PrivateKey) {
484 QByteArray encryptedPem = key.toPem(passPhrase: pwBytes);
485 QVERIFY(!encryptedPem.isEmpty());
486 QSslKey keyPem(encryptedPem, algorithm, QSsl::Pem, type, pwBytes);
487 QVERIFY(!keyPem.isNull());
488 QCOMPARE(keyPem, key);
489 QCOMPARE(keyPem.toPem(), key.toPem());
490 } else {
491 // verify that public keys are never encrypted by toPem()
492 QByteArray encryptedPem = key.toPem(passPhrase: pwBytes);
493 QVERIFY(!encryptedPem.isEmpty());
494 QByteArray plainPem = key.toPem();
495 QVERIFY(!plainPem.isEmpty());
496 QCOMPARE(encryptedPem, plainPem);
497 }
498
499 if (type == QSsl::PrivateKey) {
500 // verify that private keys are never "encrypted" by toDer() and
501 // instead an empty string is returned, see QTBUG-41038.
502 QByteArray encryptedDer = key.toDer(passPhrase: pwBytes);
503 QVERIFY(encryptedDer.isEmpty());
504 } else {
505 // verify that public keys are never encrypted by toDer()
506 QByteArray encryptedDer = key.toDer(passPhrase: pwBytes);
507 QVERIFY(!encryptedDer.isEmpty());
508 QByteArray plainDer = key.toDer();
509 QVERIFY(!plainDer.isEmpty());
510 QCOMPARE(encryptedDer, plainDer);
511 }
512
513 // ### add a test to verify that public keys are _decrypted_ correctly (by the ctor)
514}
515
516void tst_QSslKey::passphraseChecks_data()
517{
518 QTest::addColumn<QString>(name: "fileName");
519 QTest::addColumn<QByteArray>(name: "passphrase");
520
521 const QByteArray pass("123");
522 const QByteArray aesPass("1234");
523
524 QTest::newRow(dataTag: "DES") << QString(testDataDir + "rsa-with-passphrase-des.pem") << pass;
525 QTest::newRow(dataTag: "3DES") << QString(testDataDir + "rsa-with-passphrase-3des.pem") << pass;
526 QTest::newRow(dataTag: "RC2") << QString(testDataDir + "rsa-with-passphrase-rc2.pem") << pass;
527#if (!defined(QT_NO_OPENSSL) && !defined(OPENSSL_NO_AES)) || (defined(QT_NO_OPENSSL) && QT_CONFIG(ssl))
528 QTest::newRow(dataTag: "AES128") << QString(testDataDir + "rsa-with-passphrase-aes128.pem") << aesPass;
529 QTest::newRow(dataTag: "AES192") << QString(testDataDir + "rsa-with-passphrase-aes192.pem") << aesPass;
530 QTest::newRow(dataTag: "AES256") << QString(testDataDir + "rsa-with-passphrase-aes256.pem") << aesPass;
531#endif // (OpenSSL && AES) || generic backend
532}
533
534void tst_QSslKey::passphraseChecks()
535{
536 QFETCH(QString, fileName);
537 QFETCH(QByteArray, passphrase);
538
539 QFile keyFile(fileName);
540 QVERIFY(keyFile.exists());
541 {
542 if (!keyFile.isOpen())
543 keyFile.open(flags: QIODevice::ReadOnly);
544 else
545 keyFile.reset();
546 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
547 QVERIFY(key.isNull()); // null passphrase => should not be able to decode key
548 }
549 {
550 if (!keyFile.isOpen())
551 keyFile.open(flags: QIODevice::ReadOnly);
552 else
553 keyFile.reset();
554 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
555 QVERIFY(key.isNull()); // empty passphrase => should not be able to decode key
556 }
557 {
558 if (!keyFile.isOpen())
559 keyFile.open(flags: QIODevice::ReadOnly);
560 else
561 keyFile.reset();
562 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "WRONG!");
563 QVERIFY(key.isNull()); // wrong passphrase => should not be able to decode key
564 }
565 {
566 if (!keyFile.isOpen())
567 keyFile.open(flags: QIODevice::ReadOnly);
568 else
569 keyFile.reset();
570 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, passphrase);
571 QVERIFY(!key.isNull()); // correct passphrase
572 }
573}
574
575void tst_QSslKey::noPassphraseChecks()
576{
577 // be sure and check a key without passphrase too
578 QString fileName(testDataDir + "rsa-without-passphrase.pem");
579 QFile keyFile(fileName);
580 {
581 if (!keyFile.isOpen())
582 keyFile.open(flags: QIODevice::ReadOnly);
583 else
584 keyFile.reset();
585 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey);
586 QVERIFY(!key.isNull()); // null passphrase => should be able to decode key
587 }
588 {
589 if (!keyFile.isOpen())
590 keyFile.open(flags: QIODevice::ReadOnly);
591 else
592 keyFile.reset();
593 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "");
594 QVERIFY(!key.isNull()); // empty passphrase => should be able to decode key
595 }
596 {
597 if (!keyFile.isOpen())
598 keyFile.open(flags: QIODevice::ReadOnly);
599 else
600 keyFile.reset();
601 QSslKey key(&keyFile,QSsl::Rsa,QSsl::Pem, QSsl::PrivateKey, "xxx");
602 QVERIFY(!key.isNull()); // passphrase given but key is not encrypted anyway => should work
603 }
604}
605
606#ifdef TEST_CRYPTO
607Q_DECLARE_METATYPE(QSslKeyPrivate::Cipher)
608
609void tst_QSslKey::encrypt_data()
610{
611 QTest::addColumn<QSslKeyPrivate::Cipher>(name: "cipher");
612 QTest::addColumn<QByteArray>(name: "key");
613 QTest::addColumn<QByteArray>(name: "plainText");
614 QTest::addColumn<QByteArray>(name: "cipherText");
615 QTest::addColumn<QByteArray>(name: "iv");
616
617 QByteArray iv("abcdefgh");
618 QTest::newRow(dataTag: "DES-CBC, length 0")
619 << QSslKeyPrivate::DesCbc << QByteArray("01234567")
620 << QByteArray()
621 << QByteArray::fromHex(hexEncoded: "956585228BAF9B1F")
622 << iv;
623 QTest::newRow(dataTag: "DES-CBC, length 1")
624 << QSslKeyPrivate::DesCbc << QByteArray("01234567")
625 << QByteArray(1, 'a')
626 << QByteArray::fromHex(hexEncoded: "E6880AF202BA3C12")
627 << iv;
628 QTest::newRow(dataTag: "DES-CBC, length 2")
629 << QSslKeyPrivate::DesCbc << QByteArray("01234567")
630 << QByteArray(2, 'a')
631 << QByteArray::fromHex(hexEncoded: "A82492386EED6026")
632 << iv;
633 QTest::newRow(dataTag: "DES-CBC, length 3")
634 << QSslKeyPrivate::DesCbc << QByteArray("01234567")
635 << QByteArray(3, 'a')
636 << QByteArray::fromHex(hexEncoded: "90B76D5B79519CBA")
637 << iv;
638 QTest::newRow(dataTag: "DES-CBC, length 4")
639 << QSslKeyPrivate::DesCbc << QByteArray("01234567")
640 << QByteArray(4, 'a')
641 << QByteArray::fromHex(hexEncoded: "63E3DD6FED87052A")
642 << iv;
643 QTest::newRow(dataTag: "DES-CBC, length 5")
644 << QSslKeyPrivate::DesCbc << QByteArray("01234567")
645 << QByteArray(5, 'a')
646 << QByteArray::fromHex(hexEncoded: "03ACDB0EACBDFA94")
647 << iv;
648 QTest::newRow(dataTag: "DES-CBC, length 6")
649 << QSslKeyPrivate::DesCbc << QByteArray("01234567")
650 << QByteArray(6, 'a')
651 << QByteArray::fromHex(hexEncoded: "7D95024E42A3A88A")
652 << iv;
653 QTest::newRow(dataTag: "DES-CBC, length 7")
654 << QSslKeyPrivate::DesCbc << QByteArray("01234567")
655 << QByteArray(7, 'a')
656 << QByteArray::fromHex(hexEncoded: "5003436B8A8E42E9")
657 << iv;
658 QTest::newRow(dataTag: "DES-CBC, length 8")
659 << QSslKeyPrivate::DesCbc << QByteArray("01234567")
660 << QByteArray(8, 'a')
661 << QByteArray::fromHex(hexEncoded: "E4C1F054BF5521C0A4A0FD4A2BC6C1B1")
662 << iv;
663
664 QTest::newRow(dataTag: "DES-EDE3-CBC, length 0")
665 << QSslKeyPrivate::DesEde3Cbc << QByteArray("0123456789abcdefghijklmn")
666 << QByteArray()
667 << QByteArray::fromHex(hexEncoded: "3B2B4CD0B0FD495F")
668 << iv;
669 QTest::newRow(dataTag: "DES-EDE3-CBC, length 8")
670 << QSslKeyPrivate::DesEde3Cbc << QByteArray("0123456789abcdefghijklmn")
671 << QByteArray(8, 'a')
672 << QByteArray::fromHex(hexEncoded: "F2A5A87763C54A72A3224103D90CDB03")
673 << iv;
674
675 QTest::newRow(dataTag: "RC2-40-CBC, length 0")
676 << QSslKeyPrivate::Rc2Cbc << QByteArray("01234")
677 << QByteArray()
678 << QByteArray::fromHex(hexEncoded: "6D05D52392FF6E7A")
679 << iv;
680 QTest::newRow(dataTag: "RC2-40-CBC, length 8")
681 << QSslKeyPrivate::Rc2Cbc << QByteArray("01234")
682 << QByteArray(8, 'a')
683 << QByteArray::fromHex(hexEncoded: "75768E64C5749072A5D168F3AFEB0005")
684 << iv;
685
686 QTest::newRow(dataTag: "RC2-64-CBC, length 0")
687 << QSslKeyPrivate::Rc2Cbc << QByteArray("01234567")
688 << QByteArray()
689 << QByteArray::fromHex(hexEncoded: "ADAE6BF70F420130")
690 << iv;
691 QTest::newRow(dataTag: "RC2-64-CBC, length 8")
692 << QSslKeyPrivate::Rc2Cbc << QByteArray("01234567")
693 << QByteArray(8, 'a')
694 << QByteArray::fromHex(hexEncoded: "C7BF5C80AFBE9FBEFBBB9FD935F6D0DF")
695 << iv;
696
697 QTest::newRow(dataTag: "RC2-128-CBC, length 0")
698 << QSslKeyPrivate::Rc2Cbc << QByteArray("012345679abcdefg")
699 << QByteArray()
700 << QByteArray::fromHex(hexEncoded: "1E965D483A13C8FB")
701 << iv;
702 QTest::newRow(dataTag: "RC2-128-CBC, length 8")
703 << QSslKeyPrivate::Rc2Cbc << QByteArray("012345679abcdefg")
704 << QByteArray(8, 'a')
705 << QByteArray::fromHex(hexEncoded: "5AEC1A5B295660B02613454232F7DECE")
706 << iv;
707
708#if (!defined(QT_NO_OPENSSL) && !defined(OPENSSL_NO_AES)) || (defined(QT_NO_OPENSSL) && QT_CONFIG(ssl))
709 // AES needs a longer IV
710 iv = QByteArray("abcdefghijklmnop");
711 QTest::newRow(dataTag: "AES-128-CBC, length 0")
712 << QSslKeyPrivate::Aes128Cbc << QByteArray("012345679abcdefg")
713 << QByteArray()
714 << QByteArray::fromHex(hexEncoded: "28DE1A9AA26601C30DD2527407121D1A")
715 << iv;
716 QTest::newRow(dataTag: "AES-128-CBC, length 8")
717 << QSslKeyPrivate::Aes128Cbc << QByteArray("012345679abcdefg")
718 << QByteArray(8, 'a')
719 << QByteArray::fromHex(hexEncoded: "08E880B1BA916F061C1E801D7F44D0EC")
720 << iv;
721
722 QTest::newRow(dataTag: "AES-192-CBC, length 0")
723 << QSslKeyPrivate::Aes192Cbc << QByteArray("0123456789abcdefghijklmn")
724 << QByteArray()
725 << QByteArray::fromHex(hexEncoded: "E169E0E205CDC2BA895B7CF6097673B1")
726 << iv;
727 QTest::newRow(dataTag: "AES-192-CBC, length 8")
728 << QSslKeyPrivate::Aes192Cbc << QByteArray("0123456789abcdefghijklmn")
729 << QByteArray(8, 'a')
730 << QByteArray::fromHex(hexEncoded: "3A227D6A3A13237316D30AA17FF9B0A7")
731 << iv;
732
733 QTest::newRow(dataTag: "AES-256-CBC, length 0")
734 << QSslKeyPrivate::Aes256Cbc << QByteArray("0123456789abcdefghijklmnopqrstuv")
735 << QByteArray()
736 << QByteArray::fromHex(hexEncoded: "4BAACAA0D22199C97DE206C465B7B14A")
737 << iv;
738 QTest::newRow(dataTag: "AES-256-CBC, length 8")
739 << QSslKeyPrivate::Aes256Cbc << QByteArray("0123456789abcdefghijklmnopqrstuv")
740 << QByteArray(8, 'a')
741 << QByteArray::fromHex(hexEncoded: "879C8C25EC135CDF0B14490A0A7C2F67")
742 << iv;
743#endif // (OpenSSL && AES) || generic backend
744}
745
746void tst_QSslKey::encrypt()
747{
748 QFETCH(QSslKeyPrivate::Cipher, cipher);
749 QFETCH(QByteArray, key);
750 QFETCH(QByteArray, plainText);
751 QFETCH(QByteArray, cipherText);
752 QFETCH(QByteArray, iv);
753
754#if defined(Q_OS_WINRT) || QT_CONFIG(schannel)
755 QEXPECT_FAIL("RC2-40-CBC, length 0", "WinRT/Schannel treats RC2 as 128-bit", Abort);
756 QEXPECT_FAIL("RC2-40-CBC, length 8", "WinRT/Schannel treats RC2 as 128-bit", Abort);
757 QEXPECT_FAIL("RC2-64-CBC, length 0", "WinRT/Schannel treats RC2 as 128-bit", Abort);
758 QEXPECT_FAIL("RC2-64-CBC, length 8", "WinRT/Schannel treats RC2 as 128-bit", Abort);
759#endif
760 QByteArray encrypted = QSslKeyPrivate::encrypt(cipher, data: plainText, key, iv);
761 QCOMPARE(encrypted, cipherText);
762
763 QByteArray decrypted = QSslKeyPrivate::decrypt(cipher, data: cipherText, key, iv);
764 QCOMPARE(decrypted, plainText);
765}
766#endif
767
768#endif
769
770QTEST_MAIN(tst_QSslKey)
771#include "tst_qsslkey.moc"
772

source code of qtbase/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp