File indexing completed on 2024-05-05 04:45:02
0001 /* 0002 * Copyright (C) 2004 Justin Karneges <justin@affinix.com> 0003 * Copyright (C) 2004-2006 Brad Hards <bradh@frogmouth.net> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Lesser General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2.1 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Lesser General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Lesser General Public 0016 * License along with this library; if not, write to the Free Software 0017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 0018 * 0019 */ 0020 #include <QElapsedTimer> 0021 #include <QtCrypto> 0022 #include <QtPlugin> 0023 0024 #include <qstringlist.h> 0025 0026 #include <botan/auto_rng.h> 0027 #include <botan/block_cipher.h> 0028 #include <botan/filters.h> 0029 #include <botan/hash.h> 0030 #include <botan/kdf.h> 0031 #include <botan/pbkdf.h> 0032 #include <botan/stream_cipher.h> 0033 #include <botan/version.h> 0034 0035 #include <cstdlib> 0036 #include <iostream> 0037 0038 //----------------------------------------------------------- 0039 class botanRandomContext : public QCA::RandomContext 0040 { 0041 Q_OBJECT 0042 public: 0043 botanRandomContext(QCA::Provider *p) 0044 : RandomContext(p) 0045 { 0046 } 0047 0048 Context *clone() const override 0049 { 0050 return new botanRandomContext(*this); 0051 } 0052 0053 QCA::SecureArray nextBytes(int size) override 0054 { 0055 QCA::SecureArray buf(size); 0056 Botan::AutoSeeded_RNG rng; 0057 rng.randomize(reinterpret_cast<Botan::byte *>(buf.data()), buf.size()); 0058 return buf; 0059 } 0060 }; 0061 0062 static QString qcaHashToBotanHash(const QString &type) 0063 { 0064 if (type == QLatin1String("md2")) 0065 return QStringLiteral("MD2"); 0066 else if (type == QLatin1String("md4")) 0067 return QStringLiteral("MD4"); 0068 else if (type == QLatin1String("md5")) 0069 return QStringLiteral("MD5"); 0070 else if (type == QLatin1String("sha1")) 0071 return QStringLiteral("SHA-1"); 0072 else if (type == QLatin1String("sha256")) 0073 return QStringLiteral("SHA-256"); 0074 else if (type == QLatin1String("sha384")) 0075 return QStringLiteral("SHA-384"); 0076 else if (type == QLatin1String("sha512")) 0077 return QStringLiteral("SHA-512"); 0078 else if (type == QLatin1String("ripemd160")) 0079 return QStringLiteral("RIPEMD-160"); 0080 0081 return {}; 0082 } 0083 0084 //----------------------------------------------------------- 0085 class BotanHashContext : public QCA::HashContext 0086 { 0087 Q_OBJECT 0088 public: 0089 BotanHashContext(QCA::Provider *p, const QString &type) 0090 : QCA::HashContext(p, type) 0091 { 0092 const QString hashName = qcaHashToBotanHash(type); 0093 m_hashObj = Botan::HashFunction::create(hashName.toStdString()).release(); 0094 } 0095 0096 ~BotanHashContext() override 0097 { 0098 delete m_hashObj; 0099 } 0100 0101 bool isOk() const 0102 { 0103 return m_hashObj; 0104 } 0105 0106 Context *clone() const override 0107 { 0108 return new BotanHashContext(provider(), type()); 0109 } 0110 0111 void clear() override 0112 { 0113 m_hashObj->clear(); 0114 } 0115 0116 void update(const QCA::MemoryRegion &a) override 0117 { 0118 m_hashObj->update((const Botan::byte *)a.data(), a.size()); 0119 } 0120 0121 QCA::MemoryRegion final() override 0122 { 0123 QCA::SecureArray a(m_hashObj->output_length()); 0124 m_hashObj->final((Botan::byte *)a.data()); 0125 return a; 0126 } 0127 0128 private: 0129 Botan::HashFunction *m_hashObj; 0130 }; 0131 0132 static QString qcaHmacToBotanHmac(const QString &type) 0133 { 0134 if (type == QLatin1String("hmac(md5)")) 0135 return QStringLiteral("HMAC(MD5)"); 0136 else if (type == QLatin1String("hmac(sha1)")) 0137 return QStringLiteral("HMAC(SHA-1)"); 0138 else if (type == QLatin1String("hmac(sha224)")) 0139 return QStringLiteral("HMAC(SHA-224)"); 0140 else if (type == QLatin1String("hmac(sha256)")) 0141 return QStringLiteral("HMAC(SHA-256)"); 0142 else if (type == QLatin1String("hmac(sha384)")) 0143 return QStringLiteral("HMAC(SHA-384)"); 0144 else if (type == QLatin1String("hmac(sha512)")) 0145 return QStringLiteral("HMAC(SHA-512)"); 0146 else if (type == QLatin1String("hmac(ripemd160)")) 0147 return QStringLiteral("HMAC(RIPEMD-160)"); 0148 0149 return {}; 0150 } 0151 0152 //----------------------------------------------------------- 0153 class BotanHMACContext : public QCA::MACContext 0154 { 0155 Q_OBJECT 0156 public: 0157 BotanHMACContext(QCA::Provider *p, const QString &type) 0158 : QCA::MACContext(p, type) 0159 , m_hashObj(Botan::MessageAuthenticationCode::create(qcaHmacToBotanHmac(type).toStdString())) 0160 { 0161 if (nullptr == m_hashObj) { 0162 std::cout << "null context object " << qcaHmacToBotanHmac(type).toStdString() << std::endl; 0163 } 0164 } 0165 0166 ~BotanHMACContext() override 0167 { 0168 } 0169 0170 void setup(const QCA::SymmetricKey &key) override 0171 { 0172 // this often gets called with an empty key, because that is the default 0173 // in the QCA MessageAuthenticationCode constructor. Botan doesn't like 0174 // that happening. 0175 if (key.size() > 0) { 0176 m_hashObj->set_key((const Botan::byte *)key.data(), key.size()); 0177 } 0178 } 0179 0180 Context *clone() const override 0181 { 0182 return new BotanHMACContext(provider(), type()); 0183 } 0184 0185 void clear() 0186 { 0187 m_hashObj->clear(); 0188 } 0189 0190 QCA::KeyLength keyLength() const override 0191 { 0192 return anyKeyLength(); 0193 } 0194 0195 void update(const QCA::MemoryRegion &a) override 0196 { 0197 m_hashObj->update((const Botan::byte *)a.data(), a.size()); 0198 } 0199 0200 void final(QCA::MemoryRegion *out) override 0201 { 0202 QCA::SecureArray sa(m_hashObj->output_length(), 0); 0203 m_hashObj->final((Botan::byte *)sa.data()); 0204 *out = sa; 0205 } 0206 0207 protected: 0208 std::unique_ptr<Botan::MessageAuthenticationCode> m_hashObj; 0209 }; 0210 0211 static QString qcaPbkdfToBotanPbkdf(const QString &pbkdf) 0212 { 0213 if (pbkdf == QLatin1String("pbkdf1(sha1)")) 0214 return QStringLiteral("PBKDF1(SHA-1)"); 0215 else if (pbkdf == QLatin1String("pbkdf1(md2)")) 0216 return QStringLiteral("PBKDF1(MD2)"); 0217 else if (pbkdf == QLatin1String("pbkdf2(sha1)")) 0218 return QStringLiteral("PBKDF2(SHA-1)"); 0219 0220 return {}; 0221 } 0222 0223 //----------------------------------------------------------- 0224 class BotanPBKDFContext : public QCA::KDFContext 0225 { 0226 Q_OBJECT 0227 public: 0228 BotanPBKDFContext(QCA::Provider *p, const QString &type) 0229 : QCA::KDFContext(p, type) 0230 { 0231 try { 0232 const QString kdfName = qcaPbkdfToBotanPbkdf(type); 0233 m_s2k = Botan::get_s2k(kdfName.toStdString()); 0234 } catch (Botan::Exception &e) { 0235 m_s2k = nullptr; 0236 } 0237 } 0238 0239 ~BotanPBKDFContext() override 0240 { 0241 delete m_s2k; 0242 } 0243 0244 bool isOk() const 0245 { 0246 return m_s2k; 0247 } 0248 0249 Context *clone() const override 0250 { 0251 return new BotanPBKDFContext(provider(), type()); 0252 } 0253 0254 QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, 0255 const QCA::InitializationVector &salt, 0256 unsigned int keyLength, 0257 unsigned int iterationCount) override 0258 { 0259 if (!m_s2k) 0260 return {}; 0261 0262 const std::string secretString(secret.data(), secret.size()); 0263 const Botan::OctetString key = 0264 m_s2k->derive_key(keyLength, secretString, (const Botan::byte *)salt.data(), salt.size(), iterationCount); 0265 const QCA::SecureArray retval(QByteArray((const char *)key.begin(), key.length())); 0266 return QCA::SymmetricKey(retval); 0267 } 0268 0269 QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, 0270 const QCA::InitializationVector &salt, 0271 unsigned int keyLength, 0272 int msecInterval, 0273 unsigned int *iterationCount) override 0274 { 0275 Q_ASSERT(iterationCount != nullptr); 0276 Botan::OctetString key; 0277 QElapsedTimer timer; 0278 const std::string secretString(secret.data(), secret.size()); 0279 0280 *iterationCount = 0; 0281 timer.start(); 0282 while (timer.elapsed() < msecInterval) { 0283 key = m_s2k->derive_key(keyLength, secretString, (const Botan::byte *)salt.data(), salt.size(), 1); 0284 ++(*iterationCount); 0285 } 0286 return makeKey(secret, salt, keyLength, *iterationCount); 0287 } 0288 0289 protected: 0290 Botan::S2K *m_s2k; 0291 }; 0292 0293 static QString qcaHkdfToBotanHkdf(const QString &type) 0294 { 0295 if (type == QLatin1String("hkdf(sha256)")) 0296 return QStringLiteral("HKDF(SHA-256)"); 0297 0298 return {}; 0299 } 0300 0301 //----------------------------------------------------------- 0302 class BotanHKDFContext : public QCA::HKDFContext 0303 { 0304 Q_OBJECT 0305 public: 0306 BotanHKDFContext(QCA::Provider *p, const QString &type) 0307 : QCA::HKDFContext(p, type) 0308 , m_hkdf(Botan::KDF::create(qcaHkdfToBotanHkdf(type).toStdString())) 0309 { 0310 } 0311 0312 ~BotanHKDFContext() override 0313 { 0314 } 0315 0316 Context *clone() const override 0317 { 0318 return new BotanHKDFContext(provider(), type()); 0319 } 0320 0321 QCA::SymmetricKey makeKey(const QCA::SecureArray &secret, 0322 const QCA::InitializationVector &salt, 0323 const QCA::InitializationVector &info, 0324 unsigned int keyLength) override 0325 { 0326 Botan::secure_vector<uint8_t> key(keyLength); 0327 m_hkdf->kdf(key.data(), 0328 keyLength, 0329 reinterpret_cast<const Botan::byte *>(secret.data()), 0330 secret.size(), 0331 reinterpret_cast<const Botan::byte *>(salt.data()), 0332 salt.size(), 0333 reinterpret_cast<const Botan::byte *>(info.data()), 0334 info.size()); 0335 QCA::SecureArray retval(QByteArray::fromRawData(reinterpret_cast<const char *>(key.data()), key.size())); 0336 return QCA::SymmetricKey(retval); 0337 } 0338 0339 protected: 0340 std::unique_ptr<Botan::KDF> m_hkdf; 0341 }; 0342 0343 static void 0344 qcaCipherToBotanCipher(const QString &type, std::string *algoName, std::string *algoMode, std::string *algoPadding) 0345 { 0346 if (type == QLatin1String("aes128-ecb")) { 0347 *algoName = "AES-128"; 0348 *algoMode = "ECB"; 0349 *algoPadding = "NoPadding"; 0350 } else if (type == QLatin1String("aes128-cbc")) { 0351 *algoName = "AES-128"; 0352 *algoMode = "CBC"; 0353 *algoPadding = "NoPadding"; 0354 } else if (type == QLatin1String("aes128-cfb")) { 0355 *algoName = "AES-128"; 0356 *algoMode = "CFB"; 0357 *algoPadding = "NoPadding"; 0358 } else if (type == QLatin1String("aes128-ofb")) { 0359 *algoName = "AES-128"; 0360 *algoMode = "OFB"; 0361 *algoPadding = "NoPadding"; 0362 } else if (type == QLatin1String("aes192-ecb")) { 0363 *algoName = "AES-192"; 0364 *algoMode = "ECB"; 0365 *algoPadding = "NoPadding"; 0366 } else if (type == QLatin1String("aes192-cbc")) { 0367 *algoName = "AES-192"; 0368 *algoMode = "CBC"; 0369 *algoPadding = "NoPadding"; 0370 } else if (type == QLatin1String("aes192-cfb")) { 0371 *algoName = "AES-192"; 0372 *algoMode = "CFB"; 0373 *algoPadding = "NoPadding"; 0374 } else if (type == QLatin1String("aes192-ofb")) { 0375 *algoName = "AES-192"; 0376 *algoMode = "OFB"; 0377 *algoPadding = "NoPadding"; 0378 } else if (type == QLatin1String("aes256-ecb")) { 0379 *algoName = "AES-256"; 0380 *algoMode = "ECB"; 0381 *algoPadding = "NoPadding"; 0382 } else if (type == QLatin1String("aes256-cbc")) { 0383 *algoName = "AES-256"; 0384 *algoMode = "CBC"; 0385 *algoPadding = "NoPadding"; 0386 } else if (type == QLatin1String("aes256-cfb")) { 0387 *algoName = "AES-256"; 0388 *algoMode = "CFB"; 0389 *algoPadding = "NoPadding"; 0390 } else if (type == QLatin1String("aes256-ofb")) { 0391 *algoName = "AES-256"; 0392 *algoMode = "OFB"; 0393 *algoPadding = "NoPadding"; 0394 } else if (type == QLatin1String("blowfish-ecb")) { 0395 *algoName = "Blowfish"; 0396 *algoMode = "ECB"; 0397 *algoPadding = "NoPadding"; 0398 } else if (type == QLatin1String("blowfish-cbc")) { 0399 *algoName = "Blowfish"; 0400 *algoMode = "CBC"; 0401 *algoPadding = "NoPadding"; 0402 } else if (type == QLatin1String("blowfish-cbc-pkcs7")) { 0403 *algoName = "Blowfish"; 0404 *algoMode = "CBC"; 0405 *algoPadding = "PKCS7"; 0406 } else if (type == QLatin1String("blowfish-cfb")) { 0407 *algoName = "Blowfish"; 0408 *algoMode = "CFB"; 0409 *algoPadding = "NoPadding"; 0410 } else if (type == QLatin1String("blowfish-ofb")) { 0411 *algoName = "Blowfish"; 0412 *algoMode = "OFB"; 0413 *algoPadding = "NoPadding"; 0414 } else if (type == QLatin1String("des-ecb")) { 0415 *algoName = "DES"; 0416 *algoMode = "ECB"; 0417 *algoPadding = "NoPadding"; 0418 } else if (type == QLatin1String("des-ecb-pkcs7")) { 0419 *algoName = "DES"; 0420 *algoMode = "ECB"; 0421 *algoPadding = "PKCS7"; 0422 } else if (type == QLatin1String("des-cbc")) { 0423 *algoName = "DES"; 0424 *algoMode = "CBC"; 0425 *algoPadding = "NoPadding"; 0426 } else if (type == QLatin1String("des-cbc-pkcs7")) { 0427 *algoName = "DES"; 0428 *algoMode = "CBC"; 0429 *algoPadding = "PKCS7"; 0430 } else if (type == QLatin1String("des-cfb")) { 0431 *algoName = "DES"; 0432 *algoMode = "CFB"; 0433 *algoPadding = "NoPadding"; 0434 } else if (type == QLatin1String("des-ofb")) { 0435 *algoName = "DES"; 0436 *algoMode = "OFB"; 0437 *algoPadding = "NoPadding"; 0438 } else if (type == QLatin1String("tripledes-ecb")) { 0439 *algoName = "TripleDES"; 0440 *algoMode = "ECB"; 0441 *algoPadding = "NoPadding"; 0442 } 0443 } 0444 0445 static std::string qcaCipherToBotanCipher(const QString &qcaCipher) 0446 { 0447 std::string algoName, algoMode, algoPadding; 0448 qcaCipherToBotanCipher(qcaCipher, &algoName, &algoMode, &algoPadding); 0449 return algoName + '/' + algoMode + '/' + algoPadding; // NOLINT(performance-inefficient-string-concatenation) 0450 } 0451 0452 #if BOTAN_VERSION_MAJOR == 2 0453 #define BOTAN_CIPHER_DIR_ENCRYPTION Botan::ENCRYPTION 0454 #define BOTAN_CIPHER_DIR_DECRYPTION Botan::DECRYPTION 0455 #elif BOTAN_VERSION_MAJOR == 3 0456 #define BOTAN_CIPHER_DIR_ENCRYPTION Botan::Cipher_Dir::Encryption 0457 #define BOTAN_CIPHER_DIR_DECRYPTION Botan::Cipher_Dir::Decryption 0458 #endif 0459 0460 //----------------------------------------------------------- 0461 class BotanCipherContext : public QCA::CipherContext 0462 { 0463 Q_OBJECT 0464 public: 0465 BotanCipherContext(QCA::Provider *p, const QString &type) 0466 : QCA::CipherContext(p, type) 0467 { 0468 qcaCipherToBotanCipher(type, &m_algoName, &m_algoMode, &m_algoPadding); 0469 } 0470 0471 void setup(QCA::Direction dir, 0472 const QCA::SymmetricKey &key, 0473 const QCA::InitializationVector &iv, 0474 const QCA::AuthTag &tag) override 0475 { 0476 Q_UNUSED(tag); 0477 try { 0478 m_dir = dir; 0479 const Botan::SymmetricKey keyCopy((Botan::byte *)key.data(), key.size()); 0480 0481 if (iv.size() == 0) { 0482 if (QCA::Encode == dir) { 0483 m_crypter = new Botan::Pipe(Botan::get_cipher( 0484 m_algoName + '/' + m_algoMode + '/' + m_algoPadding, keyCopy, BOTAN_CIPHER_DIR_ENCRYPTION)); 0485 } else { 0486 m_crypter = new Botan::Pipe(Botan::get_cipher( 0487 m_algoName + '/' + m_algoMode + '/' + m_algoPadding, keyCopy, BOTAN_CIPHER_DIR_DECRYPTION)); 0488 } 0489 } else { 0490 const Botan::InitializationVector ivCopy((Botan::byte *)iv.data(), iv.size()); 0491 if (QCA::Encode == dir) { 0492 m_crypter = new Botan::Pipe(Botan::get_cipher(m_algoName + '/' + m_algoMode + '/' + m_algoPadding, 0493 keyCopy, 0494 ivCopy, 0495 BOTAN_CIPHER_DIR_ENCRYPTION)); 0496 } else { 0497 m_crypter = new Botan::Pipe(Botan::get_cipher(m_algoName + '/' + m_algoMode + '/' + m_algoPadding, 0498 keyCopy, 0499 ivCopy, 0500 BOTAN_CIPHER_DIR_DECRYPTION)); 0501 } 0502 } 0503 m_crypter->start_msg(); 0504 } catch (Botan::Exception &e) { 0505 m_crypter = nullptr; 0506 std::cout << "caught: " << e.what() << std::endl; 0507 } 0508 } 0509 0510 Context *clone() const override 0511 { 0512 return new BotanCipherContext(*this); 0513 } 0514 0515 int blockSize() const override 0516 { 0517 if (const std::unique_ptr<Botan::BlockCipher> bc = Botan::BlockCipher::create(m_algoName)) 0518 return bc->block_size(); 0519 0520 throw Botan::Algorithm_Not_Found(m_algoName); 0521 } 0522 0523 QCA::AuthTag tag() const override 0524 { 0525 // For future implementation 0526 return QCA::AuthTag(); 0527 } 0528 0529 bool update(const QCA::SecureArray &in, QCA::SecureArray *out) override 0530 { 0531 if (!m_crypter) 0532 return false; 0533 m_crypter->write((Botan::byte *)in.data(), in.size()); 0534 QCA::SecureArray result(m_crypter->remaining()); 0535 // Perhaps bytes_read is redundant and can be dropped 0536 const size_t bytes_read = m_crypter->read((Botan::byte *)result.data(), result.size()); 0537 result.resize(bytes_read); 0538 *out = result; 0539 return true; 0540 } 0541 0542 bool final(QCA::SecureArray *out) override 0543 { 0544 m_crypter->end_msg(); 0545 QCA::SecureArray result(m_crypter->remaining()); 0546 // Perhaps bytes_read is redundant and can be dropped 0547 const size_t bytes_read = m_crypter->read((Botan::byte *)result.data(), result.size()); 0548 result.resize(bytes_read); 0549 *out = result; 0550 return true; 0551 } 0552 0553 QCA::KeyLength keyLength() const override 0554 { 0555 Botan::Key_Length_Specification kls(0); 0556 if (const std::unique_ptr<Botan::BlockCipher> bc = Botan::BlockCipher::create(m_algoName)) 0557 kls = bc->key_spec(); 0558 else if (const std::unique_ptr<Botan::StreamCipher> sc = Botan::StreamCipher::create(m_algoName)) 0559 kls = sc->key_spec(); 0560 else if (const std::unique_ptr<Botan::MessageAuthenticationCode> mac = 0561 Botan::MessageAuthenticationCode::create(m_algoName)) 0562 kls = mac->key_spec(); 0563 return QCA::KeyLength(kls.minimum_keylength(), kls.maximum_keylength(), kls.keylength_multiple()); 0564 } 0565 0566 ~BotanCipherContext() override 0567 { 0568 delete m_crypter; 0569 } 0570 0571 protected: 0572 QCA::Direction m_dir; 0573 std::string m_algoName; 0574 std::string m_algoMode; 0575 std::string m_algoPadding; 0576 Botan::Keyed_Filter *m_cipher; 0577 Botan::Pipe *m_crypter; 0578 }; 0579 0580 //========================================================== 0581 class botanProvider : public QCA::Provider 0582 { 0583 public: 0584 void init() override 0585 { 0586 } 0587 0588 ~botanProvider() override 0589 { 0590 // We should be cleaning up there, but 0591 // this causes the unit tests to segfault 0592 // delete m_init; 0593 } 0594 0595 int qcaVersion() const override 0596 { 0597 return QCA_VERSION; 0598 } 0599 0600 QString name() const override 0601 { 0602 return QStringLiteral("qca-botan"); 0603 } 0604 0605 const QStringList &pbkdfTypes() const 0606 { 0607 static QStringList list; 0608 if (list.isEmpty()) { 0609 static const QStringList allTypes = { 0610 QStringLiteral("pbkdf1(sha1)"), QStringLiteral("pbkdf1(md2)"), QStringLiteral("pbkdf2(sha1)")}; 0611 for (const QString &type : allTypes) { 0612 std::unique_ptr<BotanPBKDFContext> pbkdf(new BotanPBKDFContext(nullptr, type)); 0613 if (pbkdf->isOk()) 0614 list += type; 0615 } 0616 } 0617 return list; 0618 } 0619 0620 const QStringList &hashTypes() const 0621 { 0622 static QStringList supported; 0623 if (supported.isEmpty()) { 0624 QStringList list; 0625 list += QStringLiteral("md2"); 0626 list += QStringLiteral("md4"); 0627 list += QStringLiteral("md5"); 0628 list += QStringLiteral("sha1"); 0629 list += QStringLiteral("sha256"); 0630 list += QStringLiteral("sha384"); 0631 list += QStringLiteral("sha512"); 0632 list += QStringLiteral("ripemd160"); 0633 0634 for (const QString &hash : qAsConst(list)) { 0635 std::unique_ptr<BotanHashContext> hashContext(new BotanHashContext(nullptr, hash)); 0636 if (hashContext->isOk()) { 0637 supported << hash; 0638 } 0639 } 0640 } 0641 return supported; 0642 } 0643 0644 const QStringList &cipherTypes() const 0645 { 0646 static QStringList supported; 0647 if (supported.isEmpty()) { 0648 QStringList list; 0649 list += QStringLiteral("aes128-ecb"); 0650 list += QStringLiteral("aes128-cbc"); 0651 list += QStringLiteral("aes128-cfb"); 0652 list += QStringLiteral("aes128-ofb"); 0653 list += QStringLiteral("aes192-ecb"); 0654 list += QStringLiteral("aes192-cbc"); 0655 list += QStringLiteral("aes192-cfb"); 0656 list += QStringLiteral("aes192-ofb"); 0657 list += QStringLiteral("aes256-ecb"); 0658 list += QStringLiteral("aes256-cbc"); 0659 list += QStringLiteral("aes256-cfb"); 0660 list += QStringLiteral("aes256-ofb"); 0661 list += QStringLiteral("des-ecb"); 0662 list += QStringLiteral("des-ecb-pkcs7"); 0663 list += QStringLiteral("des-cbc"); 0664 list += QStringLiteral("des-cbc-pkcs7"); 0665 list += QStringLiteral("des-cfb"); 0666 list += QStringLiteral("des-ofb"); 0667 list += QStringLiteral("tripledes-ecb"); 0668 list += QStringLiteral("blowfish-ecb"); 0669 list += QStringLiteral("blowfish-cbc"); 0670 list += QStringLiteral("blowfish-cbc-pkcs7"); 0671 list += QStringLiteral("blowfish-cfb"); 0672 list += QStringLiteral("blowfish-ofb"); 0673 0674 for (const QString &cipher : qAsConst(list)) { 0675 const std::string bothanCipher = qcaCipherToBotanCipher(cipher); 0676 try { 0677 std::unique_ptr<Botan::Keyed_Filter> enc( 0678 Botan::get_cipher(bothanCipher, BOTAN_CIPHER_DIR_ENCRYPTION)); 0679 std::unique_ptr<Botan::Keyed_Filter> dec( 0680 Botan::get_cipher(bothanCipher, BOTAN_CIPHER_DIR_DECRYPTION)); 0681 supported += cipher; 0682 } catch (Botan::Exception &e) { 0683 } 0684 } 0685 } 0686 return supported; 0687 } 0688 0689 const QStringList &hmacTypes() const 0690 { 0691 static QStringList list; 0692 if (list.isEmpty()) { 0693 list += QStringLiteral("hmac(md5)"); 0694 list += QStringLiteral("hmac(sha1)"); 0695 // HMAC with SHA2 doesn't appear to work correctly in Botan. 0696 list += QStringLiteral("hmac(sha224)"); 0697 list += QStringLiteral("hmac(sha256)"); 0698 list += QStringLiteral("hmac(sha384)"); 0699 list += QStringLiteral("hmac(sha512)"); 0700 list += QStringLiteral("hmac(ripemd160)"); 0701 } 0702 return list; 0703 } 0704 0705 QStringList hkdfTypes() const 0706 { 0707 static QStringList list; 0708 if (list.isEmpty()) { 0709 list += QStringLiteral("hkdf(sha256)"); 0710 } 0711 return list; 0712 } 0713 0714 QStringList features() const override 0715 { 0716 static QStringList list; 0717 if (list.isEmpty()) { 0718 list += QStringLiteral("random"); 0719 list += hmacTypes(); 0720 list += pbkdfTypes(); 0721 list += hkdfTypes(); 0722 list += cipherTypes(); 0723 list += hashTypes(); 0724 } 0725 return list; 0726 } 0727 0728 Context *createContext(const QString &type) override 0729 { 0730 if (type == QLatin1String("random")) 0731 return new botanRandomContext(this); 0732 else if (hashTypes().contains(type)) 0733 return new BotanHashContext(this, type); 0734 else if (hmacTypes().contains(type)) 0735 return new BotanHMACContext(this, type); 0736 else if (pbkdfTypes().contains(type)) 0737 return new BotanPBKDFContext(this, type); 0738 else if (hkdfTypes().contains(type)) 0739 return new BotanHKDFContext(this, type); 0740 else if (cipherTypes().contains(type)) 0741 return new BotanCipherContext(this, type); 0742 else 0743 return nullptr; 0744 } 0745 0746 private: 0747 }; 0748 0749 class botanPlugin : public QObject, public QCAPlugin 0750 { 0751 Q_OBJECT 0752 Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0") 0753 Q_INTERFACES(QCAPlugin) 0754 public: 0755 QCA::Provider *createProvider() override 0756 { 0757 return new botanProvider; 0758 } 0759 }; 0760 0761 #include "qca-botan.moc"