1/*
2 * Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com>
3 * Copyright (C) 2004,2005,2007 Brad Hards <bradh@frogmouth.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 *
20 */
21
22#include "qca_basic.h"
23
24#include "qcaprovider.h"
25
26#include <QMutexLocker>
27#include <QtGlobal>
28
29namespace QCA {
30
31// from qca_core.cpp
32QMutex *global_random_mutex();
33Random *global_random();
34Provider::Context *getContext(const QString &type, Provider *p);
35
36// from qca_publickey.cpp
37ProviderList allProviders();
38Provider *providerForName(const QString &name);
39
40static void mergeList(QStringList *a, const QStringList &b)
41{
42 foreach (const QString &s, b) {
43 if (!a->contains(str: s))
44 a->append(t: s);
45 }
46}
47
48static QStringList get_hash_types(Provider *p)
49{
50 QStringList out;
51 InfoContext *c = static_cast<InfoContext *>(getContext(QStringLiteral("info"), p));
52 if (!c)
53 return out;
54 out = c->supportedHashTypes();
55 delete c;
56 return out;
57}
58
59static QStringList get_cipher_types(Provider *p)
60{
61 QStringList out;
62 InfoContext *c = static_cast<InfoContext *>(getContext(QStringLiteral("info"), p));
63 if (!c)
64 return out;
65 out = c->supportedCipherTypes();
66 delete c;
67 return out;
68}
69
70static QStringList get_mac_types(Provider *p)
71{
72 QStringList out;
73 InfoContext *c = static_cast<InfoContext *>(getContext(QStringLiteral("info"), p));
74 if (!c)
75 return out;
76 out = c->supportedMACTypes();
77 delete c;
78 return out;
79}
80
81static QStringList get_types(QStringList (*get_func)(Provider *p), const QString &provider)
82{
83 QStringList out;
84 if (!provider.isEmpty()) {
85 Provider *p = providerForName(name: provider);
86 if (p)
87 out = get_func(p);
88 } else {
89 const ProviderList pl = allProviders();
90 foreach (Provider *p, pl)
91 mergeList(a: &out, b: get_func(p));
92 }
93 return out;
94}
95
96static QStringList supportedHashTypes(const QString &provider)
97{
98 return get_types(get_func: get_hash_types, provider);
99}
100
101static QStringList supportedCipherTypes(const QString &provider)
102{
103 return get_types(get_func: get_cipher_types, provider);
104}
105
106static QStringList supportedMACTypes(const QString &provider)
107{
108 return get_types(get_func: get_mac_types, provider);
109}
110
111//----------------------------------------------------------------------------
112// Random
113//----------------------------------------------------------------------------
114Random::Random(const QString &provider)
115 : Algorithm(QStringLiteral("random"), provider)
116{
117}
118
119Random::Random(const Random &from)
120 : Algorithm(from)
121{
122}
123
124Random::~Random()
125{
126}
127
128Random &Random::operator=(const Random &from)
129{
130 Algorithm::operator=(from);
131 return *this;
132}
133
134uchar Random::nextByte()
135{
136 return (uchar)(nextBytes(size: 1)[0]);
137}
138
139SecureArray Random::nextBytes(int size)
140{
141 return static_cast<RandomContext *>(context())->nextBytes(size);
142}
143
144uchar Random::randomChar()
145{
146 QMutexLocker locker(global_random_mutex());
147 return global_random()->nextByte();
148}
149
150int Random::randomInt()
151{
152 QMutexLocker locker(global_random_mutex());
153 const SecureArray a = global_random()->nextBytes(size: sizeof(int));
154 int x;
155 memcpy(dest: &x, src: a.data(), n: a.size());
156 return x;
157}
158
159SecureArray Random::randomArray(int size)
160{
161 QMutexLocker locker(global_random_mutex());
162 return global_random()->nextBytes(size);
163}
164
165//----------------------------------------------------------------------------
166// Hash
167//----------------------------------------------------------------------------
168Hash::Hash(const QString &type, const QString &provider)
169 : Algorithm(type, provider)
170{
171}
172
173Hash::Hash(const Hash &from)
174 : Algorithm(from)
175 , BufferedComputation(from)
176{
177}
178
179Hash::~Hash()
180{
181}
182
183Hash &Hash::operator=(const Hash &from)
184{
185 Algorithm::operator=(from);
186 return *this;
187}
188
189QStringList Hash::supportedTypes(const QString &provider)
190{
191 return supportedHashTypes(provider);
192}
193
194QString Hash::type() const
195{
196 // algorithm type is the same as the hash type
197 return Algorithm::type();
198}
199
200void Hash::clear()
201{
202 static_cast<HashContext *>(context())->clear();
203}
204
205void Hash::update(const MemoryRegion &a)
206{
207 static_cast<HashContext *>(context())->update(a);
208}
209
210void Hash::update(const QByteArray &a)
211{
212 update(a: MemoryRegion(a));
213}
214
215void Hash::update(const char *data, int len)
216{
217 if (len < 0)
218 len = qstrlen(str: data);
219 if (len == 0)
220 return;
221
222 update(a: MemoryRegion(QByteArray::fromRawData(data, size: len)));
223}
224
225// Reworked from KMD5, from KDE's kdelibs
226void Hash::update(QIODevice *file)
227{
228 char buffer[1024];
229 int len;
230
231 while ((len = file->read(data: reinterpret_cast<char *>(buffer), maxlen: sizeof(buffer))) > 0)
232 update(data: buffer, len);
233}
234
235MemoryRegion Hash::final()
236{
237 return static_cast<HashContext *>(context())->final();
238}
239
240MemoryRegion Hash::hash(const MemoryRegion &a)
241{
242 return process(a);
243}
244
245QString Hash::hashToString(const MemoryRegion &a)
246{
247 return arrayToHex(array: hash(a).toByteArray());
248}
249
250//----------------------------------------------------------------------------
251// Cipher
252//----------------------------------------------------------------------------
253class Cipher::Private
254{
255public:
256 QString type;
257 Cipher::Mode mode;
258 Cipher::Padding pad;
259 Direction dir;
260 SymmetricKey key;
261 InitializationVector iv;
262 AuthTag tag;
263
264 bool ok, done;
265};
266
267Cipher::Cipher(const QString &type,
268 Mode mode,
269 Padding pad,
270 Direction dir,
271 const SymmetricKey &key,
272 const InitializationVector &iv,
273 const QString &provider)
274 : Algorithm(withAlgorithms(cipherType: type, modeType: mode, paddingType: pad), provider)
275{
276 d = new Private;
277 d->type = type;
278 d->mode = mode;
279 d->pad = pad;
280 if (!key.isEmpty())
281 setup(dir, key, iv);
282}
283
284Cipher::Cipher(const QString &type,
285 Cipher::Mode mode,
286 Cipher::Padding pad,
287 Direction dir,
288 const SymmetricKey &key,
289 const InitializationVector &iv,
290 const AuthTag &tag,
291 const QString &provider)
292 : Algorithm(withAlgorithms(cipherType: type, modeType: mode, paddingType: pad), provider)
293{
294 d = new Private;
295 d->type = type;
296 d->mode = mode;
297 d->pad = pad;
298 d->tag = tag;
299 if (!key.isEmpty())
300 setup(dir, key, iv, tag);
301}
302
303Cipher::Cipher(const Cipher &from)
304 : Algorithm(from)
305 , Filter(from)
306{
307 d = new Private(*from.d);
308}
309
310Cipher::~Cipher()
311{
312 delete d;
313}
314
315Cipher &Cipher::operator=(const Cipher &from)
316{
317 Algorithm::operator=(from);
318 *d = *from.d;
319 return *this;
320}
321
322QStringList Cipher::supportedTypes(const QString &provider)
323{
324 return supportedCipherTypes(provider);
325}
326
327QString Cipher::type() const
328{
329 return d->type;
330}
331
332Cipher::Mode Cipher::mode() const
333{
334 return d->mode;
335}
336
337Cipher::Padding Cipher::padding() const
338{
339 return d->pad;
340}
341
342Direction Cipher::direction() const
343{
344 return d->dir;
345}
346
347KeyLength Cipher::keyLength() const
348{
349 return static_cast<const CipherContext *>(context())->keyLength();
350}
351
352bool Cipher::validKeyLength(int n) const
353{
354 const KeyLength len = keyLength();
355 return ((n >= len.minimum()) && (n <= len.maximum()) && (n % len.multiple() == 0));
356}
357
358int Cipher::blockSize() const
359{
360 return static_cast<const CipherContext *>(context())->blockSize();
361}
362
363AuthTag Cipher::tag() const
364{
365 return static_cast<const CipherContext *>(context())->tag();
366}
367
368void Cipher::clear()
369{
370 d->done = false;
371 static_cast<CipherContext *>(context())->setup(dir: d->dir, key: d->key, iv: d->iv, tag: d->tag);
372}
373
374MemoryRegion Cipher::update(const MemoryRegion &a)
375{
376 SecureArray out;
377 if (d->done)
378 return out;
379 d->ok = static_cast<CipherContext *>(context())->update(in: a, out: &out);
380 return out;
381}
382
383MemoryRegion Cipher::final()
384{
385 SecureArray out;
386 if (d->done)
387 return out;
388 d->done = true;
389 d->ok = static_cast<CipherContext *>(context())->final(out: &out);
390 return out;
391}
392
393bool Cipher::ok() const
394{
395 return d->ok;
396}
397
398void Cipher::setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv)
399{
400 setup(dir, key, iv, tag: AuthTag());
401}
402
403void Cipher::setup(Direction dir, const SymmetricKey &key, const InitializationVector &iv, const AuthTag &tag)
404{
405 d->dir = dir;
406 d->key = key;
407 d->iv = iv;
408 d->tag = tag;
409 clear();
410}
411
412QString Cipher::withAlgorithms(const QString &cipherType, Mode modeType, Padding paddingType)
413{
414 QString mode;
415 switch (modeType) {
416 case CBC:
417 mode = QStringLiteral("cbc");
418 break;
419 case CFB:
420 mode = QStringLiteral("cfb");
421 break;
422 case OFB:
423 mode = QStringLiteral("ofb");
424 break;
425 case ECB:
426 mode = QStringLiteral("ecb");
427 break;
428 case CTR:
429 mode = QStringLiteral("ctr");
430 break;
431 case GCM:
432 mode = QStringLiteral("gcm");
433 break;
434 case CCM:
435 mode = QStringLiteral("ccm");
436 break;
437 default:
438 Q_ASSERT(0);
439 }
440
441 // do the default
442 if (paddingType == DefaultPadding) {
443 // logic from Botan
444 if (modeType == CBC)
445 paddingType = PKCS7;
446 else
447 paddingType = NoPadding;
448 }
449
450 QString pad;
451 if (paddingType == NoPadding)
452 pad = QLatin1String("");
453 else
454 pad = QStringLiteral("pkcs7");
455
456 QString result = cipherType + QLatin1Char('-') + mode;
457 if (!pad.isEmpty())
458 result += QStringLiteral("-") + pad;
459
460 return result;
461}
462
463//----------------------------------------------------------------------------
464// MessageAuthenticationCode
465//----------------------------------------------------------------------------
466class MessageAuthenticationCode::Private
467{
468public:
469 SymmetricKey key;
470
471 bool done;
472 MemoryRegion buf;
473};
474
475MessageAuthenticationCode::MessageAuthenticationCode(const QString &type,
476 const SymmetricKey &key,
477 const QString &provider)
478 : Algorithm(type, provider)
479{
480 d = new Private;
481 setup(key);
482}
483
484MessageAuthenticationCode::MessageAuthenticationCode(const MessageAuthenticationCode &from)
485 : Algorithm(from)
486 , BufferedComputation(from)
487{
488 d = new Private(*from.d);
489}
490
491MessageAuthenticationCode::~MessageAuthenticationCode()
492{
493 delete d;
494}
495
496MessageAuthenticationCode &MessageAuthenticationCode::operator=(const MessageAuthenticationCode &from)
497{
498 Algorithm::operator=(from);
499 *d = *from.d;
500 return *this;
501}
502
503QStringList MessageAuthenticationCode::supportedTypes(const QString &provider)
504{
505 return supportedMACTypes(provider);
506}
507
508QString MessageAuthenticationCode::type() const
509{
510 // algorithm type is the same as the mac type
511 return Algorithm::type();
512}
513
514KeyLength MessageAuthenticationCode::keyLength() const
515{
516 return static_cast<const MACContext *>(context())->keyLength();
517}
518
519bool MessageAuthenticationCode::validKeyLength(int n) const
520{
521 const KeyLength len = keyLength();
522 return ((n >= len.minimum()) && (n <= len.maximum()) && (n % len.multiple() == 0));
523}
524
525void MessageAuthenticationCode::clear()
526{
527 d->done = false;
528 static_cast<MACContext *>(context())->setup(d->key);
529}
530
531void MessageAuthenticationCode::update(const MemoryRegion &a)
532{
533 if (d->done)
534 return;
535 static_cast<MACContext *>(context())->update(in: a);
536}
537
538MemoryRegion MessageAuthenticationCode::final()
539{
540 if (!d->done) {
541 d->done = true;
542 static_cast<MACContext *>(context())->final(out: &d->buf);
543 }
544 return d->buf;
545}
546
547void MessageAuthenticationCode::setup(const SymmetricKey &key)
548{
549 d->key = key;
550 clear();
551}
552
553//----------------------------------------------------------------------------
554// Key Derivation Function
555//----------------------------------------------------------------------------
556KeyDerivationFunction::KeyDerivationFunction(const QString &type, const QString &provider)
557 : Algorithm(type, provider)
558{
559}
560
561KeyDerivationFunction::KeyDerivationFunction(const KeyDerivationFunction &from)
562 : Algorithm(from)
563{
564}
565
566KeyDerivationFunction::~KeyDerivationFunction()
567{
568}
569
570KeyDerivationFunction &KeyDerivationFunction::operator=(const KeyDerivationFunction &from)
571{
572 Algorithm::operator=(from);
573 return *this;
574}
575
576SymmetricKey KeyDerivationFunction::makeKey(const SecureArray &secret,
577 const InitializationVector &salt,
578 unsigned int keyLength,
579 unsigned int iterationCount)
580{
581 return static_cast<KDFContext *>(context())->makeKey(secret, salt, keyLength, iterationCount);
582}
583
584SymmetricKey KeyDerivationFunction::makeKey(const SecureArray &secret,
585 const InitializationVector &salt,
586 unsigned int keyLength,
587 int msecInterval,
588 unsigned int *iterationCount)
589{
590 return static_cast<KDFContext *>(context())->makeKey(secret, salt, keyLength, msecInterval, iterationCount);
591}
592
593QString KeyDerivationFunction::withAlgorithm(const QString &kdfType, const QString &algType)
594{
595 return (kdfType + QLatin1Char('(') + algType + QLatin1Char(')'));
596}
597
598//----------------------------------------------------------------------------
599// HKDF
600//----------------------------------------------------------------------------
601HKDF::HKDF(const QString &algorithm, const QString &provider)
602 : Algorithm(QStringLiteral("hkdf(") + algorithm + QLatin1Char(')'), provider)
603{
604}
605
606HKDF::HKDF(const HKDF &from)
607 : Algorithm(from)
608{
609}
610
611HKDF::~HKDF()
612{
613}
614
615HKDF &HKDF::operator=(const HKDF &from)
616{
617 Algorithm::operator=(from);
618 return *this;
619}
620
621SymmetricKey HKDF::makeKey(const SecureArray &secret,
622 const InitializationVector &salt,
623 const InitializationVector &info,
624 unsigned int keyLength)
625{
626 return static_cast<HKDFContext *>(context())->makeKey(secret, salt, info, keyLength);
627}
628
629}
630

source code of qca/src/qca_basic.cpp