1/*
2 * Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com>
3 * Copyright (C) 2004,2005 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_tools.h"
23
24#include "qdebug.h"
25
26#ifdef Q_OS_UNIX
27#include <cstdlib>
28#include <sys/mman.h>
29#endif
30#include "botantools/botantools.h"
31
32namespace QCA {
33
34static bool can_lock()
35{
36#ifdef Q_OS_UNIX
37 bool ok = false;
38#ifdef MLOCK_NOT_VOID_PTR
39#define MLOCK_TYPE char *
40#define MLOCK_TYPE_CAST (MLOCK_TYPE)
41#else
42#define MLOCK_TYPE void *
43#define MLOCK_TYPE_CAST
44#endif
45
46 MLOCK_TYPE d = MLOCK_TYPE_CAST malloc(size: 256);
47 if (mlock(addr: d, len: 256) == 0) {
48 munlock(addr: d, len: 256);
49 ok = true;
50 }
51 free(ptr: d);
52 return ok;
53#else
54 return true;
55#endif
56}
57
58// Botan shouldn't throw any exceptions in our init/deinit.
59
60static Botan::Allocator *alloc = nullptr;
61
62void botan_throw_abort()
63{
64 fprintf(stderr, format: "QCA: Exception from internal Botan\n");
65 abort();
66}
67
68bool botan_init(int prealloc, bool mmap)
69{
70 // 64k minimum
71 if (prealloc < 64)
72 prealloc = 64;
73
74 bool secmem = false;
75
76 try {
77 Botan::Builtin_Modules modules;
78 Botan::Library_State *libstate = new Botan::Library_State(modules.mutex_factory());
79 libstate->prealloc_size = prealloc * 1024;
80 Botan::set_global_state(libstate);
81 Botan::global_state().load(modules);
82
83 if (can_lock()) {
84 Botan::global_state().set_default_allocator("locking");
85 secmem = true;
86 } else if (mmap) {
87 Botan::global_state().set_default_allocator("mmap");
88 secmem = true;
89 }
90 alloc = Botan::Allocator::get(true);
91 } catch (std::exception &) {
92 fprintf(stderr, format: "QCA: Error initializing internal Botan\n");
93 abort();
94 }
95
96 return secmem;
97}
98
99void botan_deinit()
100{
101 try {
102 alloc = nullptr;
103 Botan::set_global_state(nullptr);
104 } catch (std::exception &) {
105 botan_throw_abort();
106 }
107}
108
109void *botan_secure_alloc(int bytes)
110{
111 try {
112 return alloc->allocate((Botan::u32bit)bytes);
113 } catch (std::exception &) {
114 botan_throw_abort();
115 }
116 return nullptr; // never get here
117}
118
119void botan_secure_free(void *p, int bytes)
120{
121 try {
122 alloc->deallocate(p, (Botan::u32bit)bytes);
123 } catch (std::exception &) {
124 botan_throw_abort();
125 }
126}
127
128} // end namespace QCA
129
130void *qca_secure_alloc(int bytes)
131{
132 // allocate enough room to store a size value in front, return a pointer after it
133 char *c = (char *)QCA::botan_secure_alloc(bytes: bytes + sizeof(int));
134 reinterpret_cast<int *>(c)[0] = bytes + sizeof(int);
135 return c + sizeof(int);
136}
137
138void qca_secure_free(void *p)
139{
140 // backtrack to read the size value
141 char *c = (char *)p;
142 c -= sizeof(int);
143 const int bytes = reinterpret_cast<int *>(c)[0];
144 QCA::botan_secure_free(p: c, bytes);
145}
146
147void *qca_secure_realloc(void *p, int bytes)
148{
149 // if null, do a plain alloc (just like how realloc() works)
150 if (!p)
151 return qca_secure_alloc(bytes);
152
153 // backtrack to read the size value
154 char *c = (char *)p;
155 c -= sizeof(int);
156 const int oldsize = reinterpret_cast<int *>(c)[0] - sizeof(int);
157
158 // alloc the new chunk
159 char *new_p = (char *)qca_secure_alloc(bytes);
160 if (!new_p)
161 return nullptr;
162
163 // move over the memory from the original block
164 memmove(dest: new_p, src: p, n: qMin(a: oldsize, b: bytes));
165
166 // free the original
167 qca_secure_free(p);
168
169 // done
170 return new_p;
171}
172
173namespace QCA {
174
175// secure or non-secure buffer, with trailing 0-byte.
176// buffer size of 0 is okay (sbuf/qbuf will be 0).
177struct alloc_info
178{
179 bool sec;
180 char *data;
181 int size;
182
183 // internal
184 Botan::SecureVector<Botan::byte> *sbuf;
185 QByteArray *qbuf;
186};
187
188// note: these functions don't return error if memory allocation/resizing
189// fails.. maybe fix this someday?
190
191// ai: uninitialized
192// size: >= 0
193// note: memory will be initially zero'd out
194static bool ai_new(alloc_info *ai, int size, bool sec);
195
196// ai: uninitialized
197// from: initialized
198static bool ai_copy(alloc_info *ai, const alloc_info *from);
199
200// ai: initialized
201// new_size: >= 0
202static bool ai_resize(alloc_info *ai, int new_size);
203
204// ai: initialized
205static void ai_delete(alloc_info *ai);
206
207bool ai_new(alloc_info *ai, int size, bool sec)
208{
209 if (size < 0)
210 return false;
211
212 ai->size = size;
213 ai->sec = sec;
214
215 if (size == 0) {
216 ai->sbuf = nullptr;
217 ai->qbuf = nullptr;
218 ai->data = nullptr;
219 return true;
220 }
221
222 if (sec) {
223 try {
224 ai->sbuf = new Botan::SecureVector<Botan::byte>((Botan::u32bit)size + 1);
225 } catch (std::exception &) {
226 botan_throw_abort();
227 return false; // never get here
228 }
229
230 (*(ai->sbuf))[size] = 0;
231 ai->qbuf = nullptr;
232 Botan::byte *bp = (Botan::byte *)(*(ai->sbuf));
233 ai->data = (char *)bp;
234 } else {
235 ai->sbuf = nullptr;
236 ai->qbuf = new QByteArray(size, 0);
237 ai->data = ai->qbuf->data();
238 }
239
240 return true;
241}
242
243bool ai_copy(alloc_info *ai, const alloc_info *from)
244{
245 ai->size = from->size;
246 ai->sec = from->sec;
247
248 if (ai->size == 0) {
249 ai->sbuf = nullptr;
250 ai->qbuf = nullptr;
251 ai->data = nullptr;
252 return true;
253 }
254
255 if (ai->sec) {
256 try {
257 ai->sbuf = new Botan::SecureVector<Botan::byte>(*(from->sbuf));
258 } catch (std::exception &) {
259 botan_throw_abort();
260 return false; // never get here
261 }
262
263 ai->qbuf = nullptr;
264 Botan::byte *bp = (Botan::byte *)(*(ai->sbuf));
265 ai->data = (char *)bp;
266 } else {
267 ai->sbuf = nullptr;
268 ai->qbuf = new QByteArray(*(from->qbuf));
269 ai->data = ai->qbuf->data();
270 }
271
272 return true;
273}
274
275bool ai_resize(alloc_info *ai, int new_size)
276{
277 if (new_size < 0)
278 return false;
279
280 // new size is empty
281 if (new_size == 0) {
282 // we currently aren't empty
283 if (ai->size > 0) {
284 if (ai->sec) {
285 delete ai->sbuf;
286 ai->sbuf = nullptr;
287 } else {
288 delete ai->qbuf;
289 ai->qbuf = nullptr;
290 }
291
292 ai->size = 0;
293 ai->data = nullptr;
294 }
295
296 return true;
297 }
298
299 if (ai->sec) {
300 Botan::SecureVector<Botan::byte> *new_buf;
301 try {
302 new_buf = new Botan::SecureVector<Botan::byte>((Botan::u32bit)new_size + 1);
303 } catch (std::exception &) {
304 botan_throw_abort();
305 return false; // never get here
306 }
307
308 Botan::byte *new_p = (Botan::byte *)(*new_buf);
309 if (ai->size > 0) {
310 const Botan::byte *old_p = (const Botan::byte *)(*(ai->sbuf));
311 memcpy(dest: new_p, src: old_p, n: qMin(a: new_size, b: ai->size));
312 delete ai->sbuf;
313 }
314 ai->sbuf = new_buf;
315 ai->size = new_size;
316 (*(ai->sbuf))[new_size] = 0;
317 ai->data = (char *)new_p;
318 } else {
319 if (ai->size > 0)
320 ai->qbuf->resize(size: new_size);
321 else
322 ai->qbuf = new QByteArray(new_size, 0);
323
324 ai->size = new_size;
325 ai->data = ai->qbuf->data();
326 }
327
328 return true;
329}
330
331void ai_delete(alloc_info *ai)
332{
333 if (ai->size > 0) {
334 if (ai->sec)
335 delete ai->sbuf;
336 else
337 delete ai->qbuf;
338 }
339}
340
341//----------------------------------------------------------------------------
342// MemoryRegion
343//----------------------------------------------------------------------------
344static char blank[] = "";
345
346class MemoryRegion::Private : public QSharedData
347{
348public:
349 alloc_info ai;
350
351 Private(int size, bool sec)
352 {
353 ai_new(ai: &ai, size, sec);
354 }
355
356 Private(const QByteArray &from, bool sec)
357 {
358 ai_new(ai: &ai, size: from.size(), sec);
359 memcpy(dest: ai.data, src: from.data(), n: ai.size);
360 }
361
362 Private(const Private &from)
363 : QSharedData(from)
364 {
365 ai_copy(ai: &ai, from: &from.ai);
366 }
367
368 ~Private()
369 {
370 ai_delete(ai: &ai);
371 }
372
373 bool resize(int new_size)
374 {
375 return ai_resize(ai: &ai, new_size);
376 }
377
378 void setSecure(bool sec)
379 {
380 // if same mode, do nothing
381 if (ai.sec == sec)
382 return;
383
384 alloc_info other;
385 ai_new(ai: &other, size: ai.size, sec);
386 memcpy(dest: other.data, src: ai.data, n: ai.size);
387 ai_delete(ai: &ai);
388 ai = other;
389 }
390};
391
392MemoryRegion::MemoryRegion()
393 : _secure(false)
394 , d(nullptr)
395{
396}
397
398MemoryRegion::MemoryRegion(const char *str)
399 : _secure(false)
400 , d(new Private(QByteArray::fromRawData(data: str, size: strlen(s: str)), false))
401{
402}
403
404MemoryRegion::MemoryRegion(const QByteArray &from)
405 : _secure(false)
406 , d(new Private(from, false))
407{
408}
409
410MemoryRegion::MemoryRegion(const MemoryRegion &from)
411 : _secure(from._secure)
412 , d(from.d)
413{
414}
415
416MemoryRegion::~MemoryRegion()
417{
418}
419
420MemoryRegion &MemoryRegion::operator=(const MemoryRegion &from)
421{
422 _secure = from._secure;
423 d = from.d;
424 return *this;
425}
426
427MemoryRegion &MemoryRegion::operator=(const QByteArray &from)
428{
429 set(from, secure: false);
430 return *this;
431}
432
433bool MemoryRegion::isNull() const
434{
435 return (d ? false : true);
436}
437
438bool MemoryRegion::isSecure() const
439{
440 return _secure;
441}
442
443QByteArray MemoryRegion::toByteArray() const
444{
445 if (!d)
446 return QByteArray();
447
448 if (d->ai.sec) {
449 QByteArray buf(d->ai.size, 0);
450 memcpy(dest: buf.data(), src: d->ai.data, n: d->ai.size);
451 return buf;
452 } else {
453 if (d->ai.size > 0)
454 return *(d->ai.qbuf);
455 else
456 return QByteArray((int)0, (char)0);
457 }
458}
459
460MemoryRegion::MemoryRegion(bool secure)
461 : _secure(secure)
462 , d(nullptr)
463{
464}
465
466MemoryRegion::MemoryRegion(int size, bool secure)
467 : _secure(secure)
468 , d(new Private(size, secure))
469{
470}
471
472MemoryRegion::MemoryRegion(const QByteArray &from, bool secure)
473 : _secure(secure)
474 , d(new Private(from, secure))
475{
476}
477
478char *MemoryRegion::data()
479{
480 if (!d)
481 return blank;
482 return d->ai.data;
483}
484
485const char *MemoryRegion::data() const
486{
487 if (!d)
488 return blank;
489 return d->ai.data;
490}
491
492const char *MemoryRegion::constData() const
493{
494 if (!d)
495 return blank;
496 return d->ai.data;
497}
498
499char &MemoryRegion::at(int index)
500{
501 return *(d->ai.data + index);
502}
503
504const char &MemoryRegion::at(int index) const
505{
506 return *(d->ai.data + index);
507}
508
509int MemoryRegion::size() const
510{
511 if (!d)
512 return 0;
513 return d->ai.size;
514}
515
516bool MemoryRegion::isEmpty() const
517{
518 if (!d)
519 return true;
520 return (d->ai.size > 0 ? false : true);
521}
522
523bool MemoryRegion::resize(int size)
524{
525 if (!d) {
526 d = new Private(size, _secure);
527 return true;
528 }
529
530 if (d->ai.size == size)
531 return true;
532
533 return d->resize(new_size: size);
534}
535
536void MemoryRegion::set(const QByteArray &from, bool secure)
537{
538 _secure = secure;
539
540 if (!from.isEmpty())
541 d = new Private(from, secure);
542 else
543 d = new Private(0, secure);
544}
545
546void MemoryRegion::setSecure(bool secure)
547{
548 _secure = secure;
549
550 if (!d) {
551 d = new Private(0, secure);
552 return;
553 }
554
555 d->setSecure(secure);
556}
557
558//----------------------------------------------------------------------------
559// SecureArray
560//----------------------------------------------------------------------------
561SecureArray::SecureArray()
562 : MemoryRegion(true)
563{
564}
565
566SecureArray::SecureArray(int size, char ch)
567 : MemoryRegion(size, true)
568{
569 // ai_new fills with zeros for us
570 if (ch != 0)
571 fill(fillChar: ch, fillToPosition: size);
572}
573
574SecureArray::SecureArray(const char *str)
575 : MemoryRegion(QByteArray::fromRawData(data: str, size: strlen(s: str)), true)
576{
577}
578
579SecureArray::SecureArray(const QByteArray &a)
580 : MemoryRegion(a, true)
581{
582}
583
584SecureArray::SecureArray(const MemoryRegion &a)
585 : MemoryRegion(a)
586{
587 setSecure(true);
588}
589
590SecureArray::SecureArray(const SecureArray &from)
591 : MemoryRegion(from)
592{
593}
594
595SecureArray::~SecureArray()
596{
597}
598
599SecureArray &SecureArray::operator=(const SecureArray &from)
600{
601 MemoryRegion::operator=(from);
602 return *this;
603}
604
605SecureArray &SecureArray::operator=(const QByteArray &from)
606{
607 MemoryRegion::set(from, secure: true);
608 return *this;
609}
610
611void SecureArray::clear()
612{
613 MemoryRegion::resize(size: 0);
614}
615
616bool SecureArray::resize(int size)
617{
618 return MemoryRegion::resize(size);
619}
620
621char &SecureArray::operator[](int index)
622{
623 return at(index);
624}
625
626const char &SecureArray::operator[](int index) const
627{
628 return at(index);
629}
630
631char &SecureArray::at(int index)
632{
633 return MemoryRegion::at(index);
634}
635
636const char &SecureArray::at(int index) const
637{
638 return MemoryRegion::at(index);
639}
640
641char *SecureArray::data()
642{
643 return MemoryRegion::data();
644}
645
646const char *SecureArray::data() const
647{
648 return MemoryRegion::data();
649}
650
651const char *SecureArray::constData() const
652{
653 return MemoryRegion::constData();
654}
655
656int SecureArray::size() const
657{
658 return MemoryRegion::size();
659}
660
661bool SecureArray::isEmpty() const
662{
663 return MemoryRegion::isEmpty();
664}
665
666QByteArray SecureArray::toByteArray() const
667{
668 return MemoryRegion::toByteArray();
669}
670
671SecureArray &SecureArray::append(const SecureArray &a)
672{
673 const int oldsize = size();
674 resize(size: oldsize + a.size());
675 memcpy(dest: data() + oldsize, src: a.data(), n: a.size());
676 return *this;
677}
678
679bool SecureArray::operator==(const MemoryRegion &other) const
680{
681 if (this == &other)
682 return true;
683 if (size() == other.size() && memcmp(s1: data(), s2: other.data(), n: size()) == 0)
684 return true;
685 return false;
686}
687
688SecureArray &SecureArray::operator+=(const SecureArray &a)
689{
690 return append(a);
691}
692
693void SecureArray::fill(char fillChar, int fillToPosition)
694{
695 const int len = (fillToPosition == -1) ? size() : qMin(a: fillToPosition, b: size());
696 if (len > 0)
697 memset(s: data(), c: (int)fillChar, n: len);
698}
699
700void SecureArray::set(const SecureArray &from)
701{
702 *this = from;
703}
704
705void SecureArray::set(const QByteArray &from)
706{
707 *this = from;
708}
709
710const SecureArray operator+(const SecureArray &a, const SecureArray &b)
711{
712 SecureArray c = a;
713 return c.append(a: b);
714}
715
716//----------------------------------------------------------------------------
717// BigInteger
718//----------------------------------------------------------------------------
719static void negate_binary(char *a, int size)
720{
721 // negate = two's compliment + 1
722 bool done = false;
723 for (int n = size - 1; n >= 0; --n) {
724 a[n] = ~a[n];
725 if (!done) {
726 if ((unsigned char)a[n] < 0xff) {
727 ++a[n];
728 done = true;
729 } else
730 a[n] = 0;
731 }
732 }
733}
734
735class BigInteger::Private : public QSharedData
736{
737public:
738 Botan::BigInt n;
739};
740
741BigInteger::BigInteger()
742{
743 d = new Private;
744}
745
746BigInteger::BigInteger(int i)
747{
748 d = new Private;
749 if (i < 0) {
750 d->n = Botan::BigInt(i * (-1));
751 d->n.set_sign(Botan::BigInt::Negative);
752 } else {
753 d->n = Botan::BigInt(i);
754 d->n.set_sign(Botan::BigInt::Positive);
755 }
756}
757
758BigInteger::BigInteger(const char *c)
759{
760 d = new Private;
761 fromString(s: QString::fromLatin1(ba: c));
762}
763
764BigInteger::BigInteger(const QString &s)
765{
766 d = new Private;
767 fromString(s);
768}
769
770BigInteger::BigInteger(const SecureArray &a)
771{
772 d = new Private;
773 fromArray(a);
774}
775
776BigInteger::BigInteger(const BigInteger &from)
777{
778 *this = from;
779}
780
781BigInteger::~BigInteger()
782{
783}
784
785BigInteger &BigInteger::operator=(const BigInteger &from)
786{
787 d = from.d;
788 return *this;
789}
790
791BigInteger &BigInteger::operator+=(const BigInteger &i)
792{
793 d->n += i.d->n;
794 return *this;
795}
796
797BigInteger &BigInteger::operator-=(const BigInteger &i)
798{
799 d->n -= i.d->n;
800 return *this;
801}
802
803BigInteger &BigInteger::operator*=(const BigInteger &i)
804{
805 d->n *= i.d->n;
806 return *this;
807}
808
809BigInteger &BigInteger::operator/=(const BigInteger &i)
810{
811 try {
812 d->n /= i.d->n;
813 } catch (std::exception &) {
814 fprintf(stderr, format: "QCA: Botan integer division error\n");
815 abort();
816 }
817 return *this;
818}
819
820BigInteger &BigInteger::operator%=(const BigInteger &i)
821{
822 try {
823 d->n %= i.d->n;
824 } catch (std::exception &) {
825 fprintf(stderr, format: "QCA: Botan integer division error\n");
826 abort();
827 }
828 return *this;
829}
830
831BigInteger &BigInteger::operator=(const QString &s)
832{
833 fromString(s);
834 return *this;
835}
836
837int BigInteger::compare(const BigInteger &n) const
838{
839 return ((d->n).cmp(n.d->n, true));
840}
841
842QTextStream &operator<<(QTextStream &stream, const BigInteger &b)
843{
844 stream << b.toString();
845 return stream;
846}
847
848SecureArray BigInteger::toArray() const
849{
850 int size = d->n.encoded_size(Botan::BigInt::Binary);
851
852 // return at least 8 bits
853 if (size == 0) {
854 SecureArray a(1);
855 a[0] = 0;
856 return a;
857 }
858
859 int offset = 0;
860 SecureArray a;
861
862 // make room for a sign bit if needed
863 if (d->n.get_bit((size * 8) - 1)) {
864 ++size;
865 a.resize(size);
866 a[0] = 0;
867 ++offset;
868 } else
869 a.resize(size);
870
871 Botan::BigInt::encode((Botan::byte *)a.data() + offset, d->n, Botan::BigInt::Binary);
872
873 if (d->n.is_negative())
874 negate_binary(a: a.data(), size: a.size());
875
876 return a;
877}
878
879void BigInteger::fromArray(const SecureArray &_a)
880{
881 if (_a.isEmpty()) {
882 d->n = Botan::BigInt(0);
883 return;
884 }
885 SecureArray a = _a;
886
887 Botan::BigInt::Sign sign = Botan::BigInt::Positive;
888 if (a[0] & 0x80)
889 sign = Botan::BigInt::Negative;
890
891 if (sign == Botan::BigInt::Negative)
892 negate_binary(a: a.data(), size: a.size());
893
894 d->n = Botan::BigInt::decode((const Botan::byte *)a.data(), a.size(), Botan::BigInt::Binary);
895 d->n.set_sign(sign);
896}
897
898QString BigInteger::toString() const
899{
900 QByteArray cs;
901 try {
902 cs.resize(size: d->n.encoded_size(Botan::BigInt::Decimal));
903 Botan::BigInt::encode((Botan::byte *)cs.data(), d->n, Botan::BigInt::Decimal);
904 } catch (std::exception &) {
905 return QString();
906 }
907
908 QString str;
909 if (d->n.is_negative())
910 str += QLatin1Char('-');
911 str += QString::fromLatin1(ba: cs);
912 str.remove(c: QChar::Null);
913 return str;
914}
915
916bool BigInteger::fromString(const QString &s)
917{
918 if (s.isEmpty())
919 return false;
920 const QByteArray cs = s.toLatin1();
921
922 bool neg = false;
923 if (s[0] == QLatin1Char('-'))
924 neg = true;
925
926 try {
927 d->n = Botan::BigInt::decode(
928 (const Botan::byte *)cs.data() + (neg ? 1 : 0), cs.length() - (neg ? 1 : 0), Botan::BigInt::Decimal);
929 } catch (std::exception &) {
930 return false;
931 }
932
933 if (neg)
934 d->n.set_sign(Botan::BigInt::Negative);
935 else
936 d->n.set_sign(Botan::BigInt::Positive);
937 return true;
938}
939
940}
941

source code of qca/src/qca_tools.cpp