File indexing completed on 2025-02-02 14:47:23
0001 /* 0002 * Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com> 0003 * Copyright (C) 2004,2005,2007 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 0018 * 02110-1301 USA 0019 * 0020 */ 0021 0022 #include "qca_basic.h" 0023 0024 #include "qcaprovider.h" 0025 0026 #include <QMutexLocker> 0027 #include <QtGlobal> 0028 0029 namespace QCA { 0030 0031 // from qca_core.cpp 0032 QMutex *global_random_mutex(); 0033 Random *global_random(); 0034 Provider::Context *getContext(const QString &type, Provider *p); 0035 0036 // from qca_publickey.cpp 0037 ProviderList allProviders(); 0038 Provider *providerForName(const QString &name); 0039 0040 static void mergeList(QStringList *a, const QStringList &b) 0041 { 0042 foreach (const QString &s, b) { 0043 if (!a->contains(s)) 0044 a->append(s); 0045 } 0046 } 0047 0048 static QStringList get_hash_types(Provider *p) 0049 { 0050 QStringList out; 0051 InfoContext *c = static_cast<InfoContext *>(getContext(QStringLiteral("info"), p)); 0052 if (!c) 0053 return out; 0054 out = c->supportedHashTypes(); 0055 delete c; 0056 return out; 0057 } 0058 0059 static QStringList get_cipher_types(Provider *p) 0060 { 0061 QStringList out; 0062 InfoContext *c = static_cast<InfoContext *>(getContext(QStringLiteral("info"), p)); 0063 if (!c) 0064 return out; 0065 out = c->supportedCipherTypes(); 0066 delete c; 0067 return out; 0068 } 0069 0070 static QStringList get_mac_types(Provider *p) 0071 { 0072 QStringList out; 0073 InfoContext *c = static_cast<InfoContext *>(getContext(QStringLiteral("info"), p)); 0074 if (!c) 0075 return out; 0076 out = c->supportedMACTypes(); 0077 delete c; 0078 return out; 0079 } 0080 0081 static QStringList get_types(QStringList (*get_func)(Provider *p), const QString &provider) 0082 { 0083 QStringList out; 0084 if (!provider.isEmpty()) { 0085 Provider *p = providerForName(provider); 0086 if (p) 0087 out = get_func(p); 0088 } else { 0089 const ProviderList pl = allProviders(); 0090 foreach (Provider *p, pl) 0091 mergeList(&out, get_func(p)); 0092 } 0093 return out; 0094 } 0095 0096 static QStringList supportedHashTypes(const QString &provider) 0097 { 0098 return get_types(get_hash_types, provider); 0099 } 0100 0101 static QStringList supportedCipherTypes(const QString &provider) 0102 { 0103 return get_types(get_cipher_types, provider); 0104 } 0105 0106 static QStringList supportedMACTypes(const QString &provider) 0107 { 0108 return get_types(get_mac_types, provider); 0109 } 0110 0111 //---------------------------------------------------------------------------- 0112 // Random 0113 //---------------------------------------------------------------------------- 0114 Random::Random(const QString &provider) 0115 : Algorithm(QStringLiteral("random"), provider) 0116 { 0117 } 0118 0119 Random::Random(const Random &from) 0120 : Algorithm(from) 0121 { 0122 } 0123 0124 Random::~Random() 0125 { 0126 } 0127 0128 Random &Random::operator=(const Random &from) 0129 { 0130 Algorithm::operator=(from); 0131 return *this; 0132 } 0133 0134 uchar Random::nextByte() 0135 { 0136 return (uchar)(nextBytes(1)[0]); 0137 } 0138 0139 SecureArray Random::nextBytes(int size) 0140 { 0141 return static_cast<RandomContext *>(context())->nextBytes(size); 0142 } 0143 0144 uchar Random::randomChar() 0145 { 0146 QMutexLocker locker(global_random_mutex()); 0147 return global_random()->nextByte(); 0148 } 0149 0150 int Random::randomInt() 0151 { 0152 QMutexLocker locker(global_random_mutex()); 0153 const SecureArray a = global_random()->nextBytes(sizeof(int)); 0154 int x; 0155 memcpy(&x, a.data(), a.size()); 0156 return x; 0157 } 0158 0159 SecureArray Random::randomArray(int size) 0160 { 0161 QMutexLocker locker(global_random_mutex()); 0162 return global_random()->nextBytes(size); 0163 } 0164 0165 //---------------------------------------------------------------------------- 0166 // Hash 0167 //---------------------------------------------------------------------------- 0168 Hash::Hash(const QString &type, const QString &provider) 0169 : Algorithm(type, provider) 0170 { 0171 } 0172 0173 Hash::Hash(const Hash &from) 0174 : Algorithm(from) 0175 , BufferedComputation(from) 0176 { 0177 } 0178 0179 Hash::~Hash() 0180 { 0181 } 0182 0183 Hash &Hash::operator=(const Hash &from) 0184 { 0185 Algorithm::operator=(from); 0186 return *this; 0187 } 0188 0189 QStringList Hash::supportedTypes(const QString &provider) 0190 { 0191 return supportedHashTypes(provider); 0192 } 0193 0194 QString Hash::type() const 0195 { 0196 // algorithm type is the same as the hash type 0197 return Algorithm::type(); 0198 } 0199 0200 void Hash::clear() 0201 { 0202 static_cast<HashContext *>(context())->clear(); 0203 } 0204 0205 void Hash::update(const MemoryRegion &a) 0206 { 0207 static_cast<HashContext *>(context())->update(a); 0208 } 0209 0210 void Hash::update(const QByteArray &a) 0211 { 0212 update(MemoryRegion(a)); 0213 } 0214 0215 void Hash::update(const char *data, int len) 0216 { 0217 if (len < 0) 0218 len = qstrlen(data); 0219 if (len == 0) 0220 return; 0221 0222 update(MemoryRegion(QByteArray::fromRawData(data, len))); 0223 } 0224 0225 // Reworked from KMD5, from KDE's kdelibs 0226 void Hash::update(QIODevice *file) 0227 { 0228 char buffer[1024]; 0229 int len; 0230 0231 while ((len = file->read(reinterpret_cast<char *>(buffer), sizeof(buffer))) > 0) 0232 update(buffer, len); 0233 } 0234 0235 MemoryRegion Hash::final() 0236 { 0237 return static_cast<HashContext *>(context())->final(); 0238 } 0239 0240 MemoryRegion Hash::hash(const MemoryRegion &a) 0241 { 0242 return process(a); 0243 } 0244 0245 QString Hash::hashToString(const MemoryRegion &a) 0246 { 0247 return arrayToHex(hash(a).toByteArray()); 0248 } 0249 0250 //---------------------------------------------------------------------------- 0251 // Cipher 0252 //---------------------------------------------------------------------------- 0253 class Cipher::Private 0254 { 0255 public: 0256 QString type; 0257 Cipher::Mode mode; 0258 Cipher::Padding pad; 0259 Direction dir; 0260 SymmetricKey key; 0261 InitializationVector iv; 0262 AuthTag tag; 0263 0264 bool ok, done; 0265 }; 0266 0267 Cipher::Cipher(const QString &type, 0268 Mode mode, 0269 Padding pad, 0270 Direction dir, 0271 const SymmetricKey &key, 0272 const InitializationVector &iv, 0273 const QString &provider) 0274 : Algorithm(withAlgorithms(type, mode, pad), provider) 0275 { 0276 d = new Private; 0277 d->type = type; 0278 d->mode = mode; 0279 d->pad = pad; 0280 if (!key.isEmpty()) 0281 setup(dir, key, iv); 0282 } 0283 0284 Cipher::Cipher(const QString &type, 0285 Cipher::Mode mode, 0286 Cipher::Padding pad, 0287 Direction dir, 0288 const SymmetricKey &key, 0289 const InitializationVector &iv, 0290 const AuthTag &tag, 0291 const QString &provider) 0292 : Algorithm(withAlgorithms(type, mode, pad), provider) 0293 { 0294 d = new Private; 0295 d->type = type; 0296 d->mode = mode; 0297 d->pad = pad; 0298 d->tag = tag; 0299 if (!key.isEmpty()) 0300 setup(dir, key, iv, tag); 0301 } 0302 0303 Cipher::Cipher(const Cipher &from) 0304 : Algorithm(from) 0305 , Filter(from) 0306 { 0307 d = new Private(*from.d); 0308 } 0309 0310 Cipher::~Cipher() 0311 { 0312 delete d; 0313 } 0314 0315 Cipher &Cipher::operator=(const Cipher &from) 0316 { 0317 Algorithm::operator=(from); 0318 *d = *from.d; 0319 return *this; 0320 } 0321 0322 QStringList Cipher::supportedTypes(const QString &provider) 0323 { 0324 return supportedCipherTypes(provider); 0325 } 0326 0327 QString Cipher::type() const 0328 { 0329 return d->type; 0330 } 0331 0332 Cipher::Mode Cipher::mode() const 0333 { 0334 return d->mode; 0335 } 0336 0337 Cipher::Padding Cipher::padding() const 0338 { 0339 return d->pad; 0340 } 0341 0342 Direction Cipher::direction() const 0343 { 0344 return d->dir; 0345 } 0346 0347 KeyLength Cipher::keyLength() const 0348 { 0349 return static_cast<const CipherContext *>(context())->keyLength(); 0350 } 0351 0352 bool Cipher::validKeyLength(int n) const 0353 { 0354 const KeyLength len = keyLength(); 0355 return ((n >= len.minimum()) && (n <= len.maximum()) && (n % len.multiple() == 0)); 0356 } 0357 0358 int Cipher::blockSize() const 0359 { 0360 return static_cast<const CipherContext *>(context())->blockSize(); 0361 } 0362 0363 AuthTag Cipher::tag() const 0364 { 0365 return static_cast<const CipherContext *>(context())->tag(); 0366 } 0367 0368 void Cipher::clear() 0369 { 0370 d->done = false; 0371 static_cast<CipherContext *>(context())->setup(d->dir, d->key, d->iv, d->tag); 0372 } 0373 0374 MemoryRegion Cipher::update(const MemoryRegion &a) 0375 { 0376 SecureArray out; 0377 if (d->done) 0378 return out; 0379 d->ok = static_cast<CipherContext *>(context())->update(a, &out); 0380 return out; 0381 } 0382 0383 MemoryRegion Cipher::final() 0384 { 0385 SecureArray out; 0386 if (d->done) 0387 return out; 0388 d->done = true; 0389 d->ok = static_cast<CipherContext *>(context())->final(&out); 0390 return out; 0391 } 0392 0393 bool Cipher::ok() const 0394 { 0395 return d->ok; 0396 } 0397 0398 void Cipher::setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv) 0399 { 0400 setup(dir, key, iv, AuthTag()); 0401 } 0402 0403 void Cipher::setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv, const AuthTag &tag) 0404 { 0405 d->dir = dir; 0406 d->key = key; 0407 d->iv = iv; 0408 d->tag = tag; 0409 clear(); 0410 } 0411 0412 QString Cipher::withAlgorithms(const QString &cipherType, Mode modeType, Padding paddingType) 0413 { 0414 QString mode; 0415 switch (modeType) { 0416 case CBC: 0417 mode = QStringLiteral("cbc"); 0418 break; 0419 case CFB: 0420 mode = QStringLiteral("cfb"); 0421 break; 0422 case OFB: 0423 mode = QStringLiteral("ofb"); 0424 break; 0425 case ECB: 0426 mode = QStringLiteral("ecb"); 0427 break; 0428 case CTR: 0429 mode = QStringLiteral("ctr"); 0430 break; 0431 case GCM: 0432 mode = QStringLiteral("gcm"); 0433 break; 0434 case CCM: 0435 mode = QStringLiteral("ccm"); 0436 break; 0437 default: 0438 Q_ASSERT(0); 0439 } 0440 0441 // do the default 0442 if (paddingType == DefaultPadding) { 0443 // logic from Botan 0444 if (modeType == CBC) 0445 paddingType = PKCS7; 0446 else 0447 paddingType = NoPadding; 0448 } 0449 0450 QString pad; 0451 if (paddingType == NoPadding) 0452 pad = QLatin1String(""); 0453 else 0454 pad = QStringLiteral("pkcs7"); 0455 0456 QString result = cipherType + QLatin1Char('-') + mode; 0457 if (!pad.isEmpty()) 0458 result += QStringLiteral("-") + pad; 0459 0460 return result; 0461 } 0462 0463 //---------------------------------------------------------------------------- 0464 // MessageAuthenticationCode 0465 //---------------------------------------------------------------------------- 0466 class MessageAuthenticationCode::Private 0467 { 0468 public: 0469 SymmetricKey key; 0470 0471 bool done; 0472 MemoryRegion buf; 0473 }; 0474 0475 MessageAuthenticationCode::MessageAuthenticationCode(const QString &type, 0476 const SymmetricKey &key, 0477 const QString &provider) 0478 : Algorithm(type, provider) 0479 { 0480 d = new Private; 0481 setup(key); 0482 } 0483 0484 MessageAuthenticationCode::MessageAuthenticationCode(const MessageAuthenticationCode &from) 0485 : Algorithm(from) 0486 , BufferedComputation(from) 0487 { 0488 d = new Private(*from.d); 0489 } 0490 0491 MessageAuthenticationCode::~MessageAuthenticationCode() 0492 { 0493 delete d; 0494 } 0495 0496 MessageAuthenticationCode &MessageAuthenticationCode::operator=(const MessageAuthenticationCode &from) 0497 { 0498 Algorithm::operator=(from); 0499 *d = *from.d; 0500 return *this; 0501 } 0502 0503 QStringList MessageAuthenticationCode::supportedTypes(const QString &provider) 0504 { 0505 return supportedMACTypes(provider); 0506 } 0507 0508 QString MessageAuthenticationCode::type() const 0509 { 0510 // algorithm type is the same as the mac type 0511 return Algorithm::type(); 0512 } 0513 0514 KeyLength MessageAuthenticationCode::keyLength() const 0515 { 0516 return static_cast<const MACContext *>(context())->keyLength(); 0517 } 0518 0519 bool MessageAuthenticationCode::validKeyLength(int n) const 0520 { 0521 const KeyLength len = keyLength(); 0522 return ((n >= len.minimum()) && (n <= len.maximum()) && (n % len.multiple() == 0)); 0523 } 0524 0525 void MessageAuthenticationCode::clear() 0526 { 0527 d->done = false; 0528 static_cast<MACContext *>(context())->setup(d->key); 0529 } 0530 0531 void MessageAuthenticationCode::update(const MemoryRegion &a) 0532 { 0533 if (d->done) 0534 return; 0535 static_cast<MACContext *>(context())->update(a); 0536 } 0537 0538 MemoryRegion MessageAuthenticationCode::final() 0539 { 0540 if (!d->done) { 0541 d->done = true; 0542 static_cast<MACContext *>(context())->final(&d->buf); 0543 } 0544 return d->buf; 0545 } 0546 0547 void MessageAuthenticationCode::setup(const SymmetricKey &key) 0548 { 0549 d->key = key; 0550 clear(); 0551 } 0552 0553 //---------------------------------------------------------------------------- 0554 // Key Derivation Function 0555 //---------------------------------------------------------------------------- 0556 KeyDerivationFunction::KeyDerivationFunction(const QString &type, const QString &provider) 0557 : Algorithm(type, provider) 0558 { 0559 } 0560 0561 KeyDerivationFunction::KeyDerivationFunction(const KeyDerivationFunction &from) 0562 : Algorithm(from) 0563 { 0564 } 0565 0566 KeyDerivationFunction::~KeyDerivationFunction() 0567 { 0568 } 0569 0570 KeyDerivationFunction &KeyDerivationFunction::operator=(const KeyDerivationFunction &from) 0571 { 0572 Algorithm::operator=(from); 0573 return *this; 0574 } 0575 0576 SymmetricKey KeyDerivationFunction::makeKey(const SecureArray &secret, 0577 const InitializationVector &salt, 0578 unsigned int keyLength, 0579 unsigned int iterationCount) 0580 { 0581 return static_cast<KDFContext *>(context())->makeKey(secret, salt, keyLength, iterationCount); 0582 } 0583 0584 SymmetricKey KeyDerivationFunction::makeKey(const SecureArray &secret, 0585 const InitializationVector &salt, 0586 unsigned int keyLength, 0587 int msecInterval, 0588 unsigned int *iterationCount) 0589 { 0590 return static_cast<KDFContext *>(context())->makeKey(secret, salt, keyLength, msecInterval, iterationCount); 0591 } 0592 0593 QString KeyDerivationFunction::withAlgorithm(const QString &kdfType, const QString &algType) 0594 { 0595 return (kdfType + QLatin1Char('(') + algType + QLatin1Char(')')); 0596 } 0597 0598 //---------------------------------------------------------------------------- 0599 // HKDF 0600 //---------------------------------------------------------------------------- 0601 HKDF::HKDF(const QString &algorithm, const QString &provider) 0602 : Algorithm(QStringLiteral("hkdf(") + algorithm + QLatin1Char(')'), provider) 0603 { 0604 } 0605 0606 HKDF::HKDF(const HKDF &from) 0607 : Algorithm(from) 0608 { 0609 } 0610 0611 HKDF::~HKDF() 0612 { 0613 } 0614 0615 HKDF &HKDF::operator=(const HKDF &from) 0616 { 0617 Algorithm::operator=(from); 0618 return *this; 0619 } 0620 0621 SymmetricKey HKDF::makeKey(const SecureArray &secret, 0622 const InitializationVector &salt, 0623 const InitializationVector &info, 0624 unsigned int keyLength) 0625 { 0626 return static_cast<HKDFContext *>(context())->makeKey(secret, salt, info, keyLength); 0627 } 0628 0629 }