|
56 | 56 |
|
57 | 57 | #include <openssl/bn.h>
|
58 | 58 |
|
| 59 | +#include <assert.h> |
59 | 60 | #include <ctype.h>
|
60 | 61 | #include <stdio.h>
|
61 | 62 | #include <string.h>
|
62 | 63 |
|
63 | 64 | #include <openssl/bio.h>
|
| 65 | +#include <openssl/bytestring.h> |
64 | 66 | #include <openssl/err.h>
|
65 | 67 | #include <openssl/mem.h>
|
66 | 68 |
|
@@ -348,73 +350,71 @@ int BN_hex2bn(BIGNUM **outp, const char *in) {
|
348 | 350 | }
|
349 | 351 |
|
350 | 352 | char *BN_bn2dec(const BIGNUM *a) {
|
351 |
| - int i = 0, num, ok = 0; |
352 |
| - char *buf = NULL; |
353 |
| - char *p; |
354 |
| - BIGNUM *t = NULL; |
355 |
| - BN_ULONG *bn_data = NULL, *lp; |
356 |
| - |
357 |
| - /* get an upper bound for the length of the decimal integer |
358 |
| - * num <= (BN_num_bits(a) + 1) * log(2) |
359 |
| - * <= 3 * BN_num_bits(a) * 0.1001 + log(2) + 1 (rounding error) |
360 |
| - * <= BN_num_bits(a)/10 + BN_num_bits/1000 + 1 + 1 |
361 |
| - */ |
362 |
| - i = BN_num_bits(a) * 3; |
363 |
| - num = i / 10 + i / 1000 + 1 + 1; |
364 |
| - bn_data = |
365 |
| - (BN_ULONG *)OPENSSL_malloc((num / BN_DEC_NUM + 1) * sizeof(BN_ULONG)); |
366 |
| - buf = (char *)OPENSSL_malloc(num + 3); |
367 |
| - if ((buf == NULL) || (bn_data == NULL)) { |
368 |
| - OPENSSL_PUT_ERROR(BN, BN_bn2dec, ERR_R_MALLOC_FAILURE); |
369 |
| - goto err; |
370 |
| - } |
371 |
| - t = BN_dup(a); |
372 |
| - if (t == NULL) { |
373 |
| - goto err; |
374 |
| - } |
375 |
| - |
376 |
| -#define BUF_REMAIN (num + 3 - (size_t)(p - buf)) |
377 |
| - p = buf; |
378 |
| - lp = bn_data; |
379 |
| - if (BN_is_zero(t)) { |
380 |
| - *(p++) = '0'; |
381 |
| - *(p++) = '\0'; |
| 353 | + /* It is easier to print strings little-endian, so we assemble it in reverse |
| 354 | + * and fix at the end. */ |
| 355 | + BIGNUM *copy = NULL; |
| 356 | + CBB cbb; |
| 357 | + if (!CBB_init(&cbb, 16) || |
| 358 | + !CBB_add_u8(&cbb, 0 /* trailing NUL */)) { |
| 359 | + goto cbb_err; |
| 360 | + } |
| 361 | + |
| 362 | + if (BN_is_zero(a)) { |
| 363 | + if (!CBB_add_u8(&cbb, '0')) { |
| 364 | + goto cbb_err; |
| 365 | + } |
382 | 366 | } else {
|
383 |
| - if (BN_is_negative(t)) { |
384 |
| - *p++ = '-'; |
| 367 | + copy = BN_dup(a); |
| 368 | + if (copy == NULL) { |
| 369 | + goto err; |
385 | 370 | }
|
386 | 371 |
|
387 |
| - while (!BN_is_zero(t)) { |
388 |
| - *lp = BN_div_word(t, BN_DEC_CONV); |
389 |
| - lp++; |
390 |
| - } |
391 |
| - lp--; |
392 |
| - /* We now have a series of blocks, BN_DEC_NUM chars |
393 |
| - * in length, where the last one needs truncation. |
394 |
| - * The blocks need to be reversed in order. */ |
395 |
| - BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT1, *lp); |
396 |
| - while (*p) { |
397 |
| - p++; |
398 |
| - } |
399 |
| - while (lp != bn_data) { |
400 |
| - lp--; |
401 |
| - BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT2, *lp); |
402 |
| - while (*p) { |
403 |
| - p++; |
| 372 | + while (!BN_is_zero(copy)) { |
| 373 | + BN_ULONG word = BN_div_word(copy, BN_DEC_CONV); |
| 374 | + if (word == (BN_ULONG)-1) { |
| 375 | + goto err; |
404 | 376 | }
|
| 377 | + |
| 378 | + const int add_leading_zeros = !BN_is_zero(copy); |
| 379 | + int i; |
| 380 | + for (i = 0; i < BN_DEC_NUM && (add_leading_zeros || word != 0); i++) { |
| 381 | + if (!CBB_add_u8(&cbb, '0' + word % 10)) { |
| 382 | + goto cbb_err; |
| 383 | + } |
| 384 | + word /= 10; |
| 385 | + } |
| 386 | + assert(word == 0); |
405 | 387 | }
|
406 | 388 | }
|
407 |
| - ok = 1; |
408 | 389 |
|
409 |
| -err: |
410 |
| - OPENSSL_free(bn_data); |
411 |
| - BN_free(t); |
412 |
| - if (!ok) { |
413 |
| - OPENSSL_free(buf); |
414 |
| - buf = NULL; |
| 390 | + if (BN_is_negative(a) && |
| 391 | + !CBB_add_u8(&cbb, '-')) { |
| 392 | + goto cbb_err; |
415 | 393 | }
|
416 | 394 |
|
417 |
| - return buf; |
| 395 | + uint8_t *data; |
| 396 | + size_t len; |
| 397 | + if (!CBB_finish(&cbb, &data, &len)) { |
| 398 | + goto cbb_err; |
| 399 | + } |
| 400 | + |
| 401 | + /* Reverse the buffer. */ |
| 402 | + size_t i; |
| 403 | + for (i = 0; i < len/2; i++) { |
| 404 | + uint8_t tmp = data[i]; |
| 405 | + data[i] = data[len - 1 - i]; |
| 406 | + data[len - 1 - i] = tmp; |
| 407 | + } |
| 408 | + |
| 409 | + BN_free(copy); |
| 410 | + return (char *)data; |
| 411 | + |
| 412 | +cbb_err: |
| 413 | + OPENSSL_PUT_ERROR(BN, BN_bn2dec, ERR_R_MALLOC_FAILURE); |
| 414 | +err: |
| 415 | + BN_free(copy); |
| 416 | + CBB_cleanup(&cbb); |
| 417 | + return NULL; |
418 | 418 | }
|
419 | 419 |
|
420 | 420 | int BN_dec2bn(BIGNUM **outp, const char *in) {
|
|
0 commit comments