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 | |
32 | namespace QCA { |
33 | |
34 | static 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 | |
60 | static Botan::Allocator *alloc = nullptr; |
61 | |
62 | void botan_throw_abort() |
63 | { |
64 | fprintf(stderr, format: "QCA: Exception from internal Botan\n" ); |
65 | abort(); |
66 | } |
67 | |
68 | bool 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 | |
99 | void 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 | |
109 | void *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 | |
119 | void 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 | |
130 | void *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 | |
138 | void 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 | |
147 | void *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 | |
173 | namespace QCA { |
174 | |
175 | // secure or non-secure buffer, with trailing 0-byte. |
176 | // buffer size of 0 is okay (sbuf/qbuf will be 0). |
177 | struct 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 |
194 | static bool ai_new(alloc_info *ai, int size, bool sec); |
195 | |
196 | // ai: uninitialized |
197 | // from: initialized |
198 | static bool ai_copy(alloc_info *ai, const alloc_info *from); |
199 | |
200 | // ai: initialized |
201 | // new_size: >= 0 |
202 | static bool ai_resize(alloc_info *ai, int new_size); |
203 | |
204 | // ai: initialized |
205 | static void ai_delete(alloc_info *ai); |
206 | |
207 | bool 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 | |
243 | bool 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 | |
275 | bool 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 | |
331 | void 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 | //---------------------------------------------------------------------------- |
344 | static char blank[] = "" ; |
345 | |
346 | class MemoryRegion::Private : public QSharedData |
347 | { |
348 | public: |
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 | |
392 | MemoryRegion::MemoryRegion() |
393 | : _secure(false) |
394 | , d(nullptr) |
395 | { |
396 | } |
397 | |
398 | MemoryRegion::MemoryRegion(const char *str) |
399 | : _secure(false) |
400 | , d(new Private(QByteArray::fromRawData(data: str, size: strlen(s: str)), false)) |
401 | { |
402 | } |
403 | |
404 | MemoryRegion::MemoryRegion(const QByteArray &from) |
405 | : _secure(false) |
406 | , d(new Private(from, false)) |
407 | { |
408 | } |
409 | |
410 | MemoryRegion::MemoryRegion(const MemoryRegion &from) |
411 | : _secure(from._secure) |
412 | , d(from.d) |
413 | { |
414 | } |
415 | |
416 | MemoryRegion::~MemoryRegion() |
417 | { |
418 | } |
419 | |
420 | MemoryRegion &MemoryRegion::operator=(const MemoryRegion &from) |
421 | { |
422 | _secure = from._secure; |
423 | d = from.d; |
424 | return *this; |
425 | } |
426 | |
427 | MemoryRegion &MemoryRegion::operator=(const QByteArray &from) |
428 | { |
429 | set(from, secure: false); |
430 | return *this; |
431 | } |
432 | |
433 | bool MemoryRegion::isNull() const |
434 | { |
435 | return (d ? false : true); |
436 | } |
437 | |
438 | bool MemoryRegion::isSecure() const |
439 | { |
440 | return _secure; |
441 | } |
442 | |
443 | QByteArray 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 | |
460 | MemoryRegion::MemoryRegion(bool secure) |
461 | : _secure(secure) |
462 | , d(nullptr) |
463 | { |
464 | } |
465 | |
466 | MemoryRegion::MemoryRegion(int size, bool secure) |
467 | : _secure(secure) |
468 | , d(new Private(size, secure)) |
469 | { |
470 | } |
471 | |
472 | MemoryRegion::MemoryRegion(const QByteArray &from, bool secure) |
473 | : _secure(secure) |
474 | , d(new Private(from, secure)) |
475 | { |
476 | } |
477 | |
478 | char *MemoryRegion::data() |
479 | { |
480 | if (!d) |
481 | return blank; |
482 | return d->ai.data; |
483 | } |
484 | |
485 | const char *MemoryRegion::data() const |
486 | { |
487 | if (!d) |
488 | return blank; |
489 | return d->ai.data; |
490 | } |
491 | |
492 | const char *MemoryRegion::constData() const |
493 | { |
494 | if (!d) |
495 | return blank; |
496 | return d->ai.data; |
497 | } |
498 | |
499 | char &MemoryRegion::at(int index) |
500 | { |
501 | return *(d->ai.data + index); |
502 | } |
503 | |
504 | const char &MemoryRegion::at(int index) const |
505 | { |
506 | return *(d->ai.data + index); |
507 | } |
508 | |
509 | int MemoryRegion::size() const |
510 | { |
511 | if (!d) |
512 | return 0; |
513 | return d->ai.size; |
514 | } |
515 | |
516 | bool MemoryRegion::isEmpty() const |
517 | { |
518 | if (!d) |
519 | return true; |
520 | return (d->ai.size > 0 ? false : true); |
521 | } |
522 | |
523 | bool 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 | |
536 | void 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 | |
546 | void 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 | //---------------------------------------------------------------------------- |
561 | SecureArray::SecureArray() |
562 | : MemoryRegion(true) |
563 | { |
564 | } |
565 | |
566 | SecureArray::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 | |
574 | SecureArray::SecureArray(const char *str) |
575 | : MemoryRegion(QByteArray::fromRawData(data: str, size: strlen(s: str)), true) |
576 | { |
577 | } |
578 | |
579 | SecureArray::SecureArray(const QByteArray &a) |
580 | : MemoryRegion(a, true) |
581 | { |
582 | } |
583 | |
584 | SecureArray::SecureArray(const MemoryRegion &a) |
585 | : MemoryRegion(a) |
586 | { |
587 | setSecure(true); |
588 | } |
589 | |
590 | SecureArray::SecureArray(const SecureArray &from) |
591 | : MemoryRegion(from) |
592 | { |
593 | } |
594 | |
595 | SecureArray::~SecureArray() |
596 | { |
597 | } |
598 | |
599 | SecureArray &SecureArray::operator=(const SecureArray &from) |
600 | { |
601 | MemoryRegion::operator=(from); |
602 | return *this; |
603 | } |
604 | |
605 | SecureArray &SecureArray::operator=(const QByteArray &from) |
606 | { |
607 | MemoryRegion::set(from, secure: true); |
608 | return *this; |
609 | } |
610 | |
611 | void SecureArray::clear() |
612 | { |
613 | MemoryRegion::resize(size: 0); |
614 | } |
615 | |
616 | bool SecureArray::resize(int size) |
617 | { |
618 | return MemoryRegion::resize(size); |
619 | } |
620 | |
621 | char &SecureArray::operator[](int index) |
622 | { |
623 | return at(index); |
624 | } |
625 | |
626 | const char &SecureArray::operator[](int index) const |
627 | { |
628 | return at(index); |
629 | } |
630 | |
631 | char &SecureArray::at(int index) |
632 | { |
633 | return MemoryRegion::at(index); |
634 | } |
635 | |
636 | const char &SecureArray::at(int index) const |
637 | { |
638 | return MemoryRegion::at(index); |
639 | } |
640 | |
641 | char *SecureArray::data() |
642 | { |
643 | return MemoryRegion::data(); |
644 | } |
645 | |
646 | const char *SecureArray::data() const |
647 | { |
648 | return MemoryRegion::data(); |
649 | } |
650 | |
651 | const char *SecureArray::constData() const |
652 | { |
653 | return MemoryRegion::constData(); |
654 | } |
655 | |
656 | int SecureArray::size() const |
657 | { |
658 | return MemoryRegion::size(); |
659 | } |
660 | |
661 | bool SecureArray::isEmpty() const |
662 | { |
663 | return MemoryRegion::isEmpty(); |
664 | } |
665 | |
666 | QByteArray SecureArray::toByteArray() const |
667 | { |
668 | return MemoryRegion::toByteArray(); |
669 | } |
670 | |
671 | SecureArray &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 | |
679 | bool 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 | |
688 | SecureArray &SecureArray::operator+=(const SecureArray &a) |
689 | { |
690 | return append(a); |
691 | } |
692 | |
693 | void 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 | |
700 | void SecureArray::set(const SecureArray &from) |
701 | { |
702 | *this = from; |
703 | } |
704 | |
705 | void SecureArray::set(const QByteArray &from) |
706 | { |
707 | *this = from; |
708 | } |
709 | |
710 | const 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 | //---------------------------------------------------------------------------- |
719 | static 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 | |
735 | class BigInteger::Private : public QSharedData |
736 | { |
737 | public: |
738 | Botan::BigInt n; |
739 | }; |
740 | |
741 | BigInteger::BigInteger() |
742 | { |
743 | d = new Private; |
744 | } |
745 | |
746 | BigInteger::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 | |
758 | BigInteger::BigInteger(const char *c) |
759 | { |
760 | d = new Private; |
761 | fromString(s: QString::fromLatin1(ba: c)); |
762 | } |
763 | |
764 | BigInteger::BigInteger(const QString &s) |
765 | { |
766 | d = new Private; |
767 | fromString(s); |
768 | } |
769 | |
770 | BigInteger::BigInteger(const SecureArray &a) |
771 | { |
772 | d = new Private; |
773 | fromArray(a); |
774 | } |
775 | |
776 | BigInteger::BigInteger(const BigInteger &from) |
777 | { |
778 | *this = from; |
779 | } |
780 | |
781 | BigInteger::~BigInteger() |
782 | { |
783 | } |
784 | |
785 | BigInteger &BigInteger::operator=(const BigInteger &from) |
786 | { |
787 | d = from.d; |
788 | return *this; |
789 | } |
790 | |
791 | BigInteger &BigInteger::operator+=(const BigInteger &i) |
792 | { |
793 | d->n += i.d->n; |
794 | return *this; |
795 | } |
796 | |
797 | BigInteger &BigInteger::operator-=(const BigInteger &i) |
798 | { |
799 | d->n -= i.d->n; |
800 | return *this; |
801 | } |
802 | |
803 | BigInteger &BigInteger::operator*=(const BigInteger &i) |
804 | { |
805 | d->n *= i.d->n; |
806 | return *this; |
807 | } |
808 | |
809 | BigInteger &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 | |
820 | BigInteger &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 | |
831 | BigInteger &BigInteger::operator=(const QString &s) |
832 | { |
833 | fromString(s); |
834 | return *this; |
835 | } |
836 | |
837 | int BigInteger::compare(const BigInteger &n) const |
838 | { |
839 | return ((d->n).cmp(n.d->n, true)); |
840 | } |
841 | |
842 | QTextStream &operator<<(QTextStream &stream, const BigInteger &b) |
843 | { |
844 | stream << b.toString(); |
845 | return stream; |
846 | } |
847 | |
848 | SecureArray 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 | |
879 | void 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 | |
898 | QString 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 | |
916 | bool 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 | |