.. | .. |
---|
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); |
---|