1 /* $OpenBSD: bn_convert.c,v 1.15 2023/07/09 18:37:58 tb Exp $ */ 2 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 3 * All rights reserved. 4 * 5 * This package is an SSL implementation written 6 * by Eric Young (eay@cryptsoft.com). 7 * The implementation was written so as to conform with Netscapes SSL. 8 * 9 * This library is free for commercial and non-commercial use as long as 10 * the following conditions are aheared to. The following conditions 11 * apply to all code found in this distribution, be it the RC4, RSA, 12 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 13 * included with this distribution is covered by the same copyright terms 14 * except that the holder is Tim Hudson (tjh@cryptsoft.com). 15 * 16 * Copyright remains Eric Young's, and as such any Copyright notices in 17 * the code are not to be removed. 18 * If this package is used in a product, Eric Young should be given attribution 19 * as the author of the parts of the library used. 20 * This can be in the form of a textual message at program startup or 21 * in documentation (online or textual) provided with the package. 22 * 23 * Redistribution and use in source and binary forms, with or without 24 * modification, are permitted provided that the following conditions 25 * are met: 26 * 1. Redistributions of source code must retain the copyright 27 * notice, this list of conditions and the following disclaimer. 28 * 2. Redistributions in binary form must reproduce the above copyright 29 * notice, this list of conditions and the following disclaimer in the 30 * documentation and/or other materials provided with the distribution. 31 * 3. All advertising materials mentioning features or use of this software 32 * must display the following acknowledgement: 33 * "This product includes cryptographic software written by 34 * Eric Young (eay@cryptsoft.com)" 35 * The word 'cryptographic' can be left out if the rouines from the library 36 * being used are not cryptographic related :-). 37 * 4. If you include any Windows specific code (or a derivative thereof) from 38 * the apps directory (application code) you must include an acknowledgement: 39 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" 40 * 41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51 * SUCH DAMAGE. 52 * 53 * The licence and distribution terms for any publically available version or 54 * derivative of this code cannot be changed. i.e. this code cannot simply be 55 * copied and put under another distribution licence 56 * [including the GNU Public Licence.] 57 */ 58 59 #include <ctype.h> 60 #include <limits.h> 61 #include <stdio.h> 62 #include <string.h> 63 64 #include <openssl/opensslconf.h> 65 66 #include <openssl/bio.h> 67 #include <openssl/buffer.h> 68 #include <openssl/err.h> 69 70 #include "bn_local.h" 71 #include "bytestring.h" 72 73 static int bn_dec2bn_cbs(BIGNUM **bnp, CBS *cbs); 74 static int bn_hex2bn_cbs(BIGNUM **bnp, CBS *cbs); 75 76 static const char hex_digits[] = "0123456789ABCDEF"; 77 78 typedef enum { 79 big, 80 little, 81 } endianness_t; 82 83 /* ignore negative */ 84 static int 85 bn2binpad(const BIGNUM *a, unsigned char *to, int tolen, endianness_t endianness) 86 { 87 int n; 88 size_t i, lasti, j, atop, mask; 89 BN_ULONG l; 90 91 /* 92 * In case |a| is fixed-top, BN_num_bytes can return bogus length, 93 * but it's assumed that fixed-top inputs ought to be "nominated" 94 * even for padded output, so it works out... 95 */ 96 n = BN_num_bytes(a); 97 if (tolen == -1) 98 tolen = n; 99 else if (tolen < n) { /* uncommon/unlike case */ 100 BIGNUM temp = *a; 101 102 bn_correct_top(&temp); 103 104 n = BN_num_bytes(&temp); 105 if (tolen < n) 106 return -1; 107 } 108 109 /* Swipe through whole available data and don't give away padded zero. */ 110 atop = a->dmax * BN_BYTES; 111 if (atop == 0) { 112 explicit_bzero(to, tolen); 113 return tolen; 114 } 115 116 lasti = atop - 1; 117 atop = a->top * BN_BYTES; 118 119 if (endianness == big) 120 to += tolen; /* start from the end of the buffer */ 121 122 for (i = 0, j = 0; j < (size_t)tolen; j++) { 123 unsigned char val; 124 125 l = a->d[i / BN_BYTES]; 126 mask = 0 - ((j - atop) >> (8 * sizeof(i) - 1)); 127 val = (unsigned char)(l >> (8 * (i % BN_BYTES)) & mask); 128 129 if (endianness == big) 130 *--to = val; 131 else 132 *to++ = val; 133 134 i += (i - lasti) >> (8 * sizeof(i) - 1); /* stay on last limb */ 135 } 136 137 return tolen; 138 } 139 140 int 141 BN_bn2bin(const BIGNUM *a, unsigned char *to) 142 { 143 return bn2binpad(a, to, -1, big); 144 } 145 LCRYPTO_ALIAS(BN_bn2bin); 146 147 int 148 BN_bn2binpad(const BIGNUM *a, unsigned char *to, int tolen) 149 { 150 if (tolen < 0) 151 return -1; 152 return bn2binpad(a, to, tolen, big); 153 } 154 LCRYPTO_ALIAS(BN_bn2binpad); 155 156 BIGNUM * 157 BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret) 158 { 159 unsigned int i, m; 160 unsigned int n; 161 BN_ULONG l; 162 BIGNUM *bn = NULL; 163 164 if (len < 0) 165 return (NULL); 166 if (ret == NULL) 167 ret = bn = BN_new(); 168 if (ret == NULL) 169 return (NULL); 170 l = 0; 171 n = len; 172 if (n == 0) { 173 ret->top = 0; 174 return (ret); 175 } 176 i = ((n - 1) / BN_BYTES) + 1; 177 m = ((n - 1) % (BN_BYTES)); 178 if (!bn_wexpand(ret, (int)i)) { 179 BN_free(bn); 180 return NULL; 181 } 182 ret->top = i; 183 ret->neg = 0; 184 while (n--) { 185 l = (l << 8L) | *(s++); 186 if (m-- == 0) { 187 ret->d[--i] = l; 188 l = 0; 189 m = BN_BYTES - 1; 190 } 191 } 192 /* need to call this due to clear byte at top if avoiding 193 * having the top bit set (-ve number) */ 194 bn_correct_top(ret); 195 return (ret); 196 } 197 LCRYPTO_ALIAS(BN_bin2bn); 198 199 int 200 BN_bn2lebinpad(const BIGNUM *a, unsigned char *to, int tolen) 201 { 202 if (tolen < 0) 203 return -1; 204 205 return bn2binpad(a, to, tolen, little); 206 } 207 LCRYPTO_ALIAS(BN_bn2lebinpad); 208 209 BIGNUM * 210 BN_lebin2bn(const unsigned char *s, int len, BIGNUM *ret) 211 { 212 unsigned int i, m, n; 213 BN_ULONG l; 214 BIGNUM *bn = NULL; 215 216 if (ret == NULL) 217 ret = bn = BN_new(); 218 if (ret == NULL) 219 return NULL; 220 221 222 s += len; 223 /* Skip trailing zeroes. */ 224 for (; len > 0 && s[-1] == 0; s--, len--) 225 continue; 226 227 n = len; 228 if (n == 0) { 229 ret->top = 0; 230 return ret; 231 } 232 233 i = ((n - 1) / BN_BYTES) + 1; 234 m = (n - 1) % BN_BYTES; 235 if (!bn_wexpand(ret, (int)i)) { 236 BN_free(bn); 237 return NULL; 238 } 239 240 ret->top = i; 241 ret->neg = 0; 242 l = 0; 243 while (n-- > 0) { 244 s--; 245 l = (l << 8L) | *s; 246 if (m-- == 0) { 247 ret->d[--i] = l; 248 l = 0; 249 m = BN_BYTES - 1; 250 } 251 } 252 253 /* 254 * need to call this due to clear byte at top if avoiding having the 255 * top bit set (-ve number) 256 */ 257 bn_correct_top(ret); 258 259 return ret; 260 } 261 LCRYPTO_ALIAS(BN_lebin2bn); 262 263 int 264 BN_asc2bn(BIGNUM **bnp, const char *s) 265 { 266 CBS cbs, cbs_hex; 267 size_t s_len; 268 uint8_t v; 269 int neg; 270 271 if (bnp != NULL && *bnp != NULL) 272 BN_zero(*bnp); 273 274 if (s == NULL) 275 return 0; 276 if ((s_len = strlen(s)) == 0) 277 return 0; 278 279 CBS_init(&cbs, s, s_len); 280 281 /* Handle negative sign. */ 282 if (!CBS_peek_u8(&cbs, &v)) 283 return 0; 284 if ((neg = (v == '-'))) { 285 if (!CBS_skip(&cbs, 1)) 286 return 0; 287 } 288 289 /* Try parsing as hexadecimal with a 0x prefix. */ 290 CBS_dup(&cbs, &cbs_hex); 291 if (!CBS_get_u8(&cbs_hex, &v)) 292 goto decimal; 293 if (v != '0') 294 goto decimal; 295 if (!CBS_get_u8(&cbs_hex, &v)) 296 goto decimal; 297 if (v != 'X' && v != 'x') 298 goto decimal; 299 if (bn_hex2bn_cbs(bnp, &cbs_hex) == 0) 300 return 0; 301 302 goto done; 303 304 decimal: 305 if (bn_dec2bn_cbs(bnp, &cbs) == 0) 306 return 0; 307 308 done: 309 if (bnp != NULL && *bnp != NULL) 310 BN_set_negative(*bnp, neg); 311 312 return 1; 313 } 314 LCRYPTO_ALIAS(BN_asc2bn); 315 316 char * 317 BN_bn2dec(const BIGNUM *bn) 318 { 319 int started = 0; 320 BIGNUM *tmp = NULL; 321 uint8_t *data = NULL; 322 size_t data_len = 0; 323 uint8_t *s = NULL; 324 size_t s_len; 325 BN_ULONG v, w; 326 uint8_t c; 327 CBB cbb; 328 CBS cbs; 329 int i; 330 331 if (!CBB_init(&cbb, 0)) 332 goto err; 333 334 if ((tmp = BN_dup(bn)) == NULL) 335 goto err; 336 337 /* 338 * Divide the BIGNUM by a large multiple of 10, then break the remainder 339 * into decimal digits. This produces a reversed string of digits, 340 * potentially with leading zeroes. 341 */ 342 while (!BN_is_zero(tmp)) { 343 if ((w = BN_div_word(tmp, BN_DEC_CONV)) == -1) 344 goto err; 345 for (i = 0; i < BN_DEC_NUM; i++) { 346 v = w % 10; 347 if (!CBB_add_u8(&cbb, '0' + v)) 348 goto err; 349 w /= 10; 350 } 351 } 352 if (!CBB_finish(&cbb, &data, &data_len)) 353 goto err; 354 355 if (data_len > SIZE_MAX - 3) 356 goto err; 357 if (!CBB_init(&cbb, data_len + 3)) 358 goto err; 359 360 if (BN_is_negative(bn)) { 361 if (!CBB_add_u8(&cbb, '-')) 362 goto err; 363 } 364 365 /* Reverse digits and trim leading zeroes. */ 366 CBS_init(&cbs, data, data_len); 367 while (CBS_len(&cbs) > 0) { 368 if (!CBS_get_last_u8(&cbs, &c)) 369 goto err; 370 if (!started && c == '0') 371 continue; 372 if (!CBB_add_u8(&cbb, c)) 373 goto err; 374 started = 1; 375 } 376 377 if (!started) { 378 if (!CBB_add_u8(&cbb, '0')) 379 goto err; 380 } 381 if (!CBB_add_u8(&cbb, '\0')) 382 goto err; 383 if (!CBB_finish(&cbb, &s, &s_len)) 384 goto err; 385 386 err: 387 BN_free(tmp); 388 CBB_cleanup(&cbb); 389 freezero(data, data_len); 390 391 return s; 392 } 393 LCRYPTO_ALIAS(BN_bn2dec); 394 395 static int 396 bn_dec2bn_cbs(BIGNUM **bnp, CBS *cbs) 397 { 398 CBS cbs_digits; 399 BIGNUM *bn = NULL; 400 int d, neg, num; 401 size_t digits = 0; 402 BN_ULONG w; 403 uint8_t v; 404 405 /* Handle negative sign. */ 406 if (!CBS_peek_u8(cbs, &v)) 407 goto err; 408 if ((neg = (v == '-'))) { 409 if (!CBS_skip(cbs, 1)) 410 goto err; 411 } 412 413 /* Scan to find last decimal digit. */ 414 CBS_dup(cbs, &cbs_digits); 415 while (CBS_len(&cbs_digits) > 0) { 416 if (!CBS_get_u8(&cbs_digits, &v)) 417 goto err; 418 if (!isdigit(v)) 419 break; 420 digits++; 421 } 422 if (digits > INT_MAX / 4) 423 goto err; 424 425 num = digits + neg; 426 427 if (bnp == NULL) 428 return num; 429 430 if ((bn = *bnp) == NULL) 431 bn = BN_new(); 432 if (bn == NULL) 433 goto err; 434 if (!bn_expand(bn, digits * 4)) 435 goto err; 436 437 if ((d = digits % BN_DEC_NUM) == 0) 438 d = BN_DEC_NUM; 439 440 w = 0; 441 442 /* Work forwards from most significant digit. */ 443 while (digits-- > 0) { 444 if (!CBS_get_u8(cbs, &v)) 445 goto err; 446 447 if (v < '0' || v > '9') 448 goto err; 449 450 v -= '0'; 451 w = w * 10 + v; 452 d--; 453 454 if (d == 0) { 455 if (!BN_mul_word(bn, BN_DEC_CONV)) 456 goto err; 457 if (!BN_add_word(bn, w)) 458 goto err; 459 460 d = BN_DEC_NUM; 461 w = 0; 462 } 463 } 464 465 bn_correct_top(bn); 466 467 BN_set_negative(bn, neg); 468 469 *bnp = bn; 470 471 return num; 472 473 err: 474 if (bnp != NULL && *bnp == NULL) 475 BN_free(bn); 476 477 return 0; 478 } 479 480 int 481 BN_dec2bn(BIGNUM **bnp, const char *s) 482 { 483 size_t s_len; 484 CBS cbs; 485 486 if (bnp != NULL && *bnp != NULL) 487 BN_zero(*bnp); 488 489 if (s == NULL) 490 return 0; 491 if ((s_len = strlen(s)) == 0) 492 return 0; 493 494 CBS_init(&cbs, s, s_len); 495 496 return bn_dec2bn_cbs(bnp, &cbs); 497 } 498 LCRYPTO_ALIAS(BN_dec2bn); 499 500 static int 501 bn_bn2hex_internal(const BIGNUM *bn, int include_sign, int nibbles_only, 502 char **out, size_t *out_len) 503 { 504 int started = 0; 505 uint8_t *s = NULL; 506 size_t s_len = 0; 507 BN_ULONG v, w; 508 int i, j; 509 CBB cbb; 510 CBS cbs; 511 uint8_t nul; 512 int ret = 0; 513 514 *out = NULL; 515 *out_len = 0; 516 517 if (!CBB_init(&cbb, 0)) 518 goto err; 519 520 if (BN_is_negative(bn) && include_sign) { 521 if (!CBB_add_u8(&cbb, '-')) 522 goto err; 523 } 524 if (BN_is_zero(bn)) { 525 if (!CBB_add_u8(&cbb, '0')) 526 goto err; 527 } 528 for (i = bn->top - 1; i >= 0; i--) { 529 w = bn->d[i]; 530 for (j = BN_BITS2 - 8; j >= 0; j -= 8) { 531 v = (w >> j) & 0xff; 532 if (!started && v == 0) 533 continue; 534 if (started || !nibbles_only || (v >> 4) != 0) { 535 if (!CBB_add_u8(&cbb, hex_digits[v >> 4])) 536 goto err; 537 } 538 if (!CBB_add_u8(&cbb, hex_digits[v & 0xf])) 539 goto err; 540 started = 1; 541 } 542 } 543 if (!CBB_add_u8(&cbb, '\0')) 544 goto err; 545 if (!CBB_finish(&cbb, &s, &s_len)) 546 goto err; 547 548 /* The length of a C string does not include the terminating NUL. */ 549 CBS_init(&cbs, s, s_len); 550 if (!CBS_get_last_u8(&cbs, &nul)) 551 goto err; 552 553 *out = (char *)CBS_data(&cbs); 554 *out_len = CBS_len(&cbs); 555 s = NULL; 556 s_len = 0; 557 558 ret = 1; 559 560 err: 561 CBB_cleanup(&cbb); 562 freezero(s, s_len); 563 564 return ret; 565 } 566 567 int 568 bn_bn2hex_nosign(const BIGNUM *bn, char **out, size_t *out_len) 569 { 570 return bn_bn2hex_internal(bn, 0, 0, out, out_len); 571 } 572 573 int 574 bn_bn2hex_nibbles(const BIGNUM *bn, char **out, size_t *out_len) 575 { 576 return bn_bn2hex_internal(bn, 1, 1, out, out_len); 577 } 578 579 char * 580 BN_bn2hex(const BIGNUM *bn) 581 { 582 char *s; 583 size_t s_len; 584 585 if (!bn_bn2hex_internal(bn, 1, 0, &s, &s_len)) 586 return NULL; 587 588 return s; 589 } 590 LCRYPTO_ALIAS(BN_bn2hex); 591 592 static int 593 bn_hex2bn_cbs(BIGNUM **bnp, CBS *cbs) 594 { 595 CBS cbs_digits; 596 BIGNUM *bn = NULL; 597 int b, i, neg, num; 598 size_t digits = 0; 599 BN_ULONG w; 600 uint8_t v; 601 602 /* Handle negative sign. */ 603 if (!CBS_peek_u8(cbs, &v)) 604 goto err; 605 if ((neg = (v == '-'))) { 606 if (!CBS_skip(cbs, 1)) 607 goto err; 608 } 609 610 /* Scan to find last hexadecimal digit. */ 611 CBS_dup(cbs, &cbs_digits); 612 while (CBS_len(&cbs_digits) > 0) { 613 if (!CBS_get_u8(&cbs_digits, &v)) 614 goto err; 615 if (!isxdigit(v)) 616 break; 617 digits++; 618 } 619 if (digits > INT_MAX / 4) 620 goto err; 621 622 num = digits + neg; 623 624 if (bnp == NULL) 625 return num; 626 627 if ((bn = *bnp) == NULL) 628 bn = BN_new(); 629 if (bn == NULL) 630 goto err; 631 if (!bn_expand(bn, digits * 4)) 632 goto err; 633 634 if (!CBS_get_bytes(cbs, cbs, digits)) 635 goto err; 636 637 b = BN_BITS2; 638 i = 0; 639 w = 0; 640 641 /* Work backwards from least significant digit. */ 642 while (digits-- > 0) { 643 if (!CBS_get_last_u8(cbs, &v)) 644 goto err; 645 646 if (v >= '0' && v <= '9') 647 v -= '0'; 648 else if (v >= 'a' && v <= 'f') 649 v -= 'a' - 10; 650 else if (v >= 'A' && v <= 'F') 651 v -= 'A' - 10; 652 else 653 goto err; 654 655 w |= (BN_ULONG)v << (BN_BITS2 - b); 656 b -= 4; 657 658 if (b == 0 || digits == 0) { 659 b = BN_BITS2; 660 bn->d[i++] = w; 661 w = 0; 662 } 663 } 664 665 bn->top = i; 666 bn_correct_top(bn); 667 668 BN_set_negative(bn, neg); 669 670 *bnp = bn; 671 672 return num; 673 674 err: 675 if (bnp != NULL && *bnp == NULL) 676 BN_free(bn); 677 678 return 0; 679 } 680 681 int 682 BN_hex2bn(BIGNUM **bnp, const char *s) 683 { 684 size_t s_len; 685 CBS cbs; 686 687 if (bnp != NULL && *bnp != NULL) 688 BN_zero(*bnp); 689 690 if (s == NULL) 691 return 0; 692 if ((s_len = strlen(s)) == 0) 693 return 0; 694 695 CBS_init(&cbs, s, s_len); 696 697 return bn_hex2bn_cbs(bnp, &cbs); 698 } 699 LCRYPTO_ALIAS(BN_hex2bn); 700 701 int 702 BN_bn2mpi(const BIGNUM *a, unsigned char *d) 703 { 704 int bits; 705 int num = 0; 706 int ext = 0; 707 long l; 708 709 bits = BN_num_bits(a); 710 num = (bits + 7) / 8; 711 if (bits > 0) { 712 ext = ((bits & 0x07) == 0); 713 } 714 if (d == NULL) 715 return (num + 4 + ext); 716 717 l = num + ext; 718 d[0] = (unsigned char)(l >> 24) & 0xff; 719 d[1] = (unsigned char)(l >> 16) & 0xff; 720 d[2] = (unsigned char)(l >> 8) & 0xff; 721 d[3] = (unsigned char)(l) & 0xff; 722 if (ext) 723 d[4] = 0; 724 num = BN_bn2bin(a, &(d[4 + ext])); 725 if (a->neg) 726 d[4] |= 0x80; 727 return (num + 4 + ext); 728 } 729 LCRYPTO_ALIAS(BN_bn2mpi); 730 731 BIGNUM * 732 BN_mpi2bn(const unsigned char *d, int n, BIGNUM *ain) 733 { 734 BIGNUM *a = ain; 735 long len; 736 int neg = 0; 737 738 if (n < 4) { 739 BNerror(BN_R_INVALID_LENGTH); 740 return (NULL); 741 } 742 len = ((long)d[0] << 24) | ((long)d[1] << 16) | ((int)d[2] << 8) | 743 (int)d[3]; 744 if ((len + 4) != n) { 745 BNerror(BN_R_ENCODING_ERROR); 746 return (NULL); 747 } 748 749 if (a == NULL) 750 a = BN_new(); 751 if (a == NULL) 752 return (NULL); 753 754 if (len == 0) { 755 a->neg = 0; 756 a->top = 0; 757 return (a); 758 } 759 d += 4; 760 if ((*d) & 0x80) 761 neg = 1; 762 if (BN_bin2bn(d, (int)len, a) == NULL) { 763 if (ain == NULL) 764 BN_free(a); 765 return (NULL); 766 } 767 BN_set_negative(a, neg); 768 if (neg) { 769 BN_clear_bit(a, BN_num_bits(a) - 1); 770 } 771 return (a); 772 } 773 LCRYPTO_ALIAS(BN_mpi2bn); 774