File indexing completed on 2024-04-21 04:43:47

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 }