| .. | .. |
|---|
| 25 | 25 | #include <linux/string.h> |
|---|
| 26 | 26 | #include "mpi-internal.h" |
|---|
| 27 | 27 | |
|---|
| 28 | +#define MAX_EXTERN_SCAN_BYTES (16*1024*1024) |
|---|
| 28 | 29 | #define MAX_EXTERN_MPI_BITS 16384 |
|---|
| 29 | 30 | |
|---|
| 30 | 31 | /** |
|---|
| .. | .. |
|---|
| 108 | 109 | return val; |
|---|
| 109 | 110 | } |
|---|
| 110 | 111 | EXPORT_SYMBOL_GPL(mpi_read_from_buffer); |
|---|
| 112 | + |
|---|
| 113 | +/**************** |
|---|
| 114 | + * Fill the mpi VAL from the hex string in STR. |
|---|
| 115 | + */ |
|---|
| 116 | +int mpi_fromstr(MPI val, const char *str) |
|---|
| 117 | +{ |
|---|
| 118 | + int sign = 0; |
|---|
| 119 | + int prepend_zero = 0; |
|---|
| 120 | + int i, j, c, c1, c2; |
|---|
| 121 | + unsigned int nbits, nbytes, nlimbs; |
|---|
| 122 | + mpi_limb_t a; |
|---|
| 123 | + |
|---|
| 124 | + if (*str == '-') { |
|---|
| 125 | + sign = 1; |
|---|
| 126 | + str++; |
|---|
| 127 | + } |
|---|
| 128 | + |
|---|
| 129 | + /* Skip optional hex prefix. */ |
|---|
| 130 | + if (*str == '0' && str[1] == 'x') |
|---|
| 131 | + str += 2; |
|---|
| 132 | + |
|---|
| 133 | + nbits = strlen(str); |
|---|
| 134 | + if (nbits > MAX_EXTERN_SCAN_BYTES) { |
|---|
| 135 | + mpi_clear(val); |
|---|
| 136 | + return -EINVAL; |
|---|
| 137 | + } |
|---|
| 138 | + nbits *= 4; |
|---|
| 139 | + if ((nbits % 8)) |
|---|
| 140 | + prepend_zero = 1; |
|---|
| 141 | + |
|---|
| 142 | + nbytes = (nbits+7) / 8; |
|---|
| 143 | + nlimbs = (nbytes+BYTES_PER_MPI_LIMB-1) / BYTES_PER_MPI_LIMB; |
|---|
| 144 | + |
|---|
| 145 | + if (val->alloced < nlimbs) |
|---|
| 146 | + mpi_resize(val, nlimbs); |
|---|
| 147 | + |
|---|
| 148 | + i = BYTES_PER_MPI_LIMB - (nbytes % BYTES_PER_MPI_LIMB); |
|---|
| 149 | + i %= BYTES_PER_MPI_LIMB; |
|---|
| 150 | + j = val->nlimbs = nlimbs; |
|---|
| 151 | + val->sign = sign; |
|---|
| 152 | + for (; j > 0; j--) { |
|---|
| 153 | + a = 0; |
|---|
| 154 | + for (; i < BYTES_PER_MPI_LIMB; i++) { |
|---|
| 155 | + if (prepend_zero) { |
|---|
| 156 | + c1 = '0'; |
|---|
| 157 | + prepend_zero = 0; |
|---|
| 158 | + } else |
|---|
| 159 | + c1 = *str++; |
|---|
| 160 | + |
|---|
| 161 | + if (!c1) { |
|---|
| 162 | + mpi_clear(val); |
|---|
| 163 | + return -EINVAL; |
|---|
| 164 | + } |
|---|
| 165 | + c2 = *str++; |
|---|
| 166 | + if (!c2) { |
|---|
| 167 | + mpi_clear(val); |
|---|
| 168 | + return -EINVAL; |
|---|
| 169 | + } |
|---|
| 170 | + if (c1 >= '0' && c1 <= '9') |
|---|
| 171 | + c = c1 - '0'; |
|---|
| 172 | + else if (c1 >= 'a' && c1 <= 'f') |
|---|
| 173 | + c = c1 - 'a' + 10; |
|---|
| 174 | + else if (c1 >= 'A' && c1 <= 'F') |
|---|
| 175 | + c = c1 - 'A' + 10; |
|---|
| 176 | + else { |
|---|
| 177 | + mpi_clear(val); |
|---|
| 178 | + return -EINVAL; |
|---|
| 179 | + } |
|---|
| 180 | + c <<= 4; |
|---|
| 181 | + if (c2 >= '0' && c2 <= '9') |
|---|
| 182 | + c |= c2 - '0'; |
|---|
| 183 | + else if (c2 >= 'a' && c2 <= 'f') |
|---|
| 184 | + c |= c2 - 'a' + 10; |
|---|
| 185 | + else if (c2 >= 'A' && c2 <= 'F') |
|---|
| 186 | + c |= c2 - 'A' + 10; |
|---|
| 187 | + else { |
|---|
| 188 | + mpi_clear(val); |
|---|
| 189 | + return -EINVAL; |
|---|
| 190 | + } |
|---|
| 191 | + a <<= 8; |
|---|
| 192 | + a |= c; |
|---|
| 193 | + } |
|---|
| 194 | + i = 0; |
|---|
| 195 | + val->d[j-1] = a; |
|---|
| 196 | + } |
|---|
| 197 | + |
|---|
| 198 | + return 0; |
|---|
| 199 | +} |
|---|
| 200 | +EXPORT_SYMBOL_GPL(mpi_fromstr); |
|---|
| 201 | + |
|---|
| 202 | +MPI mpi_scanval(const char *string) |
|---|
| 203 | +{ |
|---|
| 204 | + MPI a; |
|---|
| 205 | + |
|---|
| 206 | + a = mpi_alloc(0); |
|---|
| 207 | + if (!a) |
|---|
| 208 | + return NULL; |
|---|
| 209 | + |
|---|
| 210 | + if (mpi_fromstr(a, string)) { |
|---|
| 211 | + mpi_free(a); |
|---|
| 212 | + return NULL; |
|---|
| 213 | + } |
|---|
| 214 | + mpi_normalize(a); |
|---|
| 215 | + return a; |
|---|
| 216 | +} |
|---|
| 217 | +EXPORT_SYMBOL_GPL(mpi_scanval); |
|---|
| 111 | 218 | |
|---|
| 112 | 219 | static int count_lzeros(MPI a) |
|---|
| 113 | 220 | { |
|---|
| .. | .. |
|---|
| 413 | 520 | return val; |
|---|
| 414 | 521 | } |
|---|
| 415 | 522 | EXPORT_SYMBOL_GPL(mpi_read_raw_from_sgl); |
|---|
| 523 | + |
|---|
| 524 | +/* Perform a two's complement operation on buffer P of size N bytes. */ |
|---|
| 525 | +static void twocompl(unsigned char *p, unsigned int n) |
|---|
| 526 | +{ |
|---|
| 527 | + int i; |
|---|
| 528 | + |
|---|
| 529 | + for (i = n-1; i >= 0 && !p[i]; i--) |
|---|
| 530 | + ; |
|---|
| 531 | + if (i >= 0) { |
|---|
| 532 | + if ((p[i] & 0x01)) |
|---|
| 533 | + p[i] = (((p[i] ^ 0xfe) | 0x01) & 0xff); |
|---|
| 534 | + else if ((p[i] & 0x02)) |
|---|
| 535 | + p[i] = (((p[i] ^ 0xfc) | 0x02) & 0xfe); |
|---|
| 536 | + else if ((p[i] & 0x04)) |
|---|
| 537 | + p[i] = (((p[i] ^ 0xf8) | 0x04) & 0xfc); |
|---|
| 538 | + else if ((p[i] & 0x08)) |
|---|
| 539 | + p[i] = (((p[i] ^ 0xf0) | 0x08) & 0xf8); |
|---|
| 540 | + else if ((p[i] & 0x10)) |
|---|
| 541 | + p[i] = (((p[i] ^ 0xe0) | 0x10) & 0xf0); |
|---|
| 542 | + else if ((p[i] & 0x20)) |
|---|
| 543 | + p[i] = (((p[i] ^ 0xc0) | 0x20) & 0xe0); |
|---|
| 544 | + else if ((p[i] & 0x40)) |
|---|
| 545 | + p[i] = (((p[i] ^ 0x80) | 0x40) & 0xc0); |
|---|
| 546 | + else |
|---|
| 547 | + p[i] = 0x80; |
|---|
| 548 | + |
|---|
| 549 | + for (i--; i >= 0; i--) |
|---|
| 550 | + p[i] ^= 0xff; |
|---|
| 551 | + } |
|---|
| 552 | +} |
|---|
| 553 | + |
|---|
| 554 | +int mpi_print(enum gcry_mpi_format format, unsigned char *buffer, |
|---|
| 555 | + size_t buflen, size_t *nwritten, MPI a) |
|---|
| 556 | +{ |
|---|
| 557 | + unsigned int nbits = mpi_get_nbits(a); |
|---|
| 558 | + size_t len; |
|---|
| 559 | + size_t dummy_nwritten; |
|---|
| 560 | + int negative; |
|---|
| 561 | + |
|---|
| 562 | + if (!nwritten) |
|---|
| 563 | + nwritten = &dummy_nwritten; |
|---|
| 564 | + |
|---|
| 565 | + /* Libgcrypt does no always care to set clear the sign if the value |
|---|
| 566 | + * is 0. For printing this is a bit of a surprise, in particular |
|---|
| 567 | + * because if some of the formats don't support negative numbers but |
|---|
| 568 | + * should be able to print a zero. Thus we need this extra test |
|---|
| 569 | + * for a negative number. |
|---|
| 570 | + */ |
|---|
| 571 | + if (a->sign && mpi_cmp_ui(a, 0)) |
|---|
| 572 | + negative = 1; |
|---|
| 573 | + else |
|---|
| 574 | + negative = 0; |
|---|
| 575 | + |
|---|
| 576 | + len = buflen; |
|---|
| 577 | + *nwritten = 0; |
|---|
| 578 | + if (format == GCRYMPI_FMT_STD) { |
|---|
| 579 | + unsigned char *tmp; |
|---|
| 580 | + int extra = 0; |
|---|
| 581 | + unsigned int n; |
|---|
| 582 | + |
|---|
| 583 | + tmp = mpi_get_buffer(a, &n, NULL); |
|---|
| 584 | + if (!tmp) |
|---|
| 585 | + return -EINVAL; |
|---|
| 586 | + |
|---|
| 587 | + if (negative) { |
|---|
| 588 | + twocompl(tmp, n); |
|---|
| 589 | + if (!(*tmp & 0x80)) { |
|---|
| 590 | + /* Need to extend the sign. */ |
|---|
| 591 | + n++; |
|---|
| 592 | + extra = 2; |
|---|
| 593 | + } |
|---|
| 594 | + } else if (n && (*tmp & 0x80)) { |
|---|
| 595 | + /* Positive but the high bit of the returned buffer is set. |
|---|
| 596 | + * Thus we need to print an extra leading 0x00 so that the |
|---|
| 597 | + * output is interpreted as a positive number. |
|---|
| 598 | + */ |
|---|
| 599 | + n++; |
|---|
| 600 | + extra = 1; |
|---|
| 601 | + } |
|---|
| 602 | + |
|---|
| 603 | + if (buffer && n > len) { |
|---|
| 604 | + /* The provided buffer is too short. */ |
|---|
| 605 | + kfree(tmp); |
|---|
| 606 | + return -E2BIG; |
|---|
| 607 | + } |
|---|
| 608 | + if (buffer) { |
|---|
| 609 | + unsigned char *s = buffer; |
|---|
| 610 | + |
|---|
| 611 | + if (extra == 1) |
|---|
| 612 | + *s++ = 0; |
|---|
| 613 | + else if (extra) |
|---|
| 614 | + *s++ = 0xff; |
|---|
| 615 | + memcpy(s, tmp, n-!!extra); |
|---|
| 616 | + } |
|---|
| 617 | + kfree(tmp); |
|---|
| 618 | + *nwritten = n; |
|---|
| 619 | + return 0; |
|---|
| 620 | + } else if (format == GCRYMPI_FMT_USG) { |
|---|
| 621 | + unsigned int n = (nbits + 7)/8; |
|---|
| 622 | + |
|---|
| 623 | + /* Note: We ignore the sign for this format. */ |
|---|
| 624 | + /* FIXME: for performance reasons we should put this into |
|---|
| 625 | + * mpi_aprint because we can then use the buffer directly. |
|---|
| 626 | + */ |
|---|
| 627 | + |
|---|
| 628 | + if (buffer && n > len) |
|---|
| 629 | + return -E2BIG; |
|---|
| 630 | + if (buffer) { |
|---|
| 631 | + unsigned char *tmp; |
|---|
| 632 | + |
|---|
| 633 | + tmp = mpi_get_buffer(a, &n, NULL); |
|---|
| 634 | + if (!tmp) |
|---|
| 635 | + return -EINVAL; |
|---|
| 636 | + memcpy(buffer, tmp, n); |
|---|
| 637 | + kfree(tmp); |
|---|
| 638 | + } |
|---|
| 639 | + *nwritten = n; |
|---|
| 640 | + return 0; |
|---|
| 641 | + } else if (format == GCRYMPI_FMT_PGP) { |
|---|
| 642 | + unsigned int n = (nbits + 7)/8; |
|---|
| 643 | + |
|---|
| 644 | + /* The PGP format can only handle unsigned integers. */ |
|---|
| 645 | + if (negative) |
|---|
| 646 | + return -EINVAL; |
|---|
| 647 | + |
|---|
| 648 | + if (buffer && n+2 > len) |
|---|
| 649 | + return -E2BIG; |
|---|
| 650 | + |
|---|
| 651 | + if (buffer) { |
|---|
| 652 | + unsigned char *tmp; |
|---|
| 653 | + unsigned char *s = buffer; |
|---|
| 654 | + |
|---|
| 655 | + s[0] = nbits >> 8; |
|---|
| 656 | + s[1] = nbits; |
|---|
| 657 | + |
|---|
| 658 | + tmp = mpi_get_buffer(a, &n, NULL); |
|---|
| 659 | + if (!tmp) |
|---|
| 660 | + return -EINVAL; |
|---|
| 661 | + memcpy(s+2, tmp, n); |
|---|
| 662 | + kfree(tmp); |
|---|
| 663 | + } |
|---|
| 664 | + *nwritten = n+2; |
|---|
| 665 | + return 0; |
|---|
| 666 | + } else if (format == GCRYMPI_FMT_SSH) { |
|---|
| 667 | + unsigned char *tmp; |
|---|
| 668 | + int extra = 0; |
|---|
| 669 | + unsigned int n; |
|---|
| 670 | + |
|---|
| 671 | + tmp = mpi_get_buffer(a, &n, NULL); |
|---|
| 672 | + if (!tmp) |
|---|
| 673 | + return -EINVAL; |
|---|
| 674 | + |
|---|
| 675 | + if (negative) { |
|---|
| 676 | + twocompl(tmp, n); |
|---|
| 677 | + if (!(*tmp & 0x80)) { |
|---|
| 678 | + /* Need to extend the sign. */ |
|---|
| 679 | + n++; |
|---|
| 680 | + extra = 2; |
|---|
| 681 | + } |
|---|
| 682 | + } else if (n && (*tmp & 0x80)) { |
|---|
| 683 | + n++; |
|---|
| 684 | + extra = 1; |
|---|
| 685 | + } |
|---|
| 686 | + |
|---|
| 687 | + if (buffer && n+4 > len) { |
|---|
| 688 | + kfree(tmp); |
|---|
| 689 | + return -E2BIG; |
|---|
| 690 | + } |
|---|
| 691 | + |
|---|
| 692 | + if (buffer) { |
|---|
| 693 | + unsigned char *s = buffer; |
|---|
| 694 | + |
|---|
| 695 | + *s++ = n >> 24; |
|---|
| 696 | + *s++ = n >> 16; |
|---|
| 697 | + *s++ = n >> 8; |
|---|
| 698 | + *s++ = n; |
|---|
| 699 | + if (extra == 1) |
|---|
| 700 | + *s++ = 0; |
|---|
| 701 | + else if (extra) |
|---|
| 702 | + *s++ = 0xff; |
|---|
| 703 | + memcpy(s, tmp, n-!!extra); |
|---|
| 704 | + } |
|---|
| 705 | + kfree(tmp); |
|---|
| 706 | + *nwritten = 4+n; |
|---|
| 707 | + return 0; |
|---|
| 708 | + } else if (format == GCRYMPI_FMT_HEX) { |
|---|
| 709 | + unsigned char *tmp; |
|---|
| 710 | + int i; |
|---|
| 711 | + int extra = 0; |
|---|
| 712 | + unsigned int n = 0; |
|---|
| 713 | + |
|---|
| 714 | + tmp = mpi_get_buffer(a, &n, NULL); |
|---|
| 715 | + if (!tmp) |
|---|
| 716 | + return -EINVAL; |
|---|
| 717 | + if (!n || (*tmp & 0x80)) |
|---|
| 718 | + extra = 2; |
|---|
| 719 | + |
|---|
| 720 | + if (buffer && 2*n + extra + negative + 1 > len) { |
|---|
| 721 | + kfree(tmp); |
|---|
| 722 | + return -E2BIG; |
|---|
| 723 | + } |
|---|
| 724 | + if (buffer) { |
|---|
| 725 | + unsigned char *s = buffer; |
|---|
| 726 | + |
|---|
| 727 | + if (negative) |
|---|
| 728 | + *s++ = '-'; |
|---|
| 729 | + if (extra) { |
|---|
| 730 | + *s++ = '0'; |
|---|
| 731 | + *s++ = '0'; |
|---|
| 732 | + } |
|---|
| 733 | + |
|---|
| 734 | + for (i = 0; i < n; i++) { |
|---|
| 735 | + unsigned int c = tmp[i]; |
|---|
| 736 | + |
|---|
| 737 | + *s++ = (c >> 4) < 10 ? '0'+(c>>4) : 'A'+(c>>4)-10; |
|---|
| 738 | + c &= 15; |
|---|
| 739 | + *s++ = c < 10 ? '0'+c : 'A'+c-10; |
|---|
| 740 | + } |
|---|
| 741 | + *s++ = 0; |
|---|
| 742 | + *nwritten = s - buffer; |
|---|
| 743 | + } else { |
|---|
| 744 | + *nwritten = 2*n + extra + negative + 1; |
|---|
| 745 | + } |
|---|
| 746 | + kfree(tmp); |
|---|
| 747 | + return 0; |
|---|
| 748 | + } else |
|---|
| 749 | + return -EINVAL; |
|---|
| 750 | +} |
|---|
| 751 | +EXPORT_SYMBOL_GPL(mpi_print); |
|---|