xref: /openssl/crypto/bn/bn_conv.c (revision 7ed6de99)
1 /*
2  * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <openssl/err.h>
11 #include "crypto/ctype.h"
12 #include "bn_local.h"
13 
14 /* Must 'OPENSSL_free' the returned data */
BN_bn2hex(const BIGNUM * a)15 char *BN_bn2hex(const BIGNUM *a)
16 {
17     int i, j, v, z = 0;
18     char *buf;
19     char *p;
20 
21     if (BN_is_zero(a))
22         return OPENSSL_strdup("0");
23     buf = OPENSSL_malloc(a->top * BN_BYTES * 2 + 2);
24     if (buf == NULL)
25         goto err;
26     p = buf;
27     if (a->neg)
28         *p++ = '-';
29     for (i = a->top - 1; i >= 0; i--) {
30         for (j = BN_BITS2 - 8; j >= 0; j -= 8) {
31             /* strip leading zeros */
32             v = (int)((a->d[i] >> j) & 0xff);
33             if (z || v != 0) {
34                 p += ossl_to_hex(p, v);
35                 z = 1;
36             }
37         }
38     }
39     *p = '\0';
40  err:
41     return buf;
42 }
43 
44 #ifndef FIPS_MODULE
45 /* No BIO_snprintf in FIPS_MODULE */
46 /* Must 'OPENSSL_free' the returned data */
BN_bn2dec(const BIGNUM * a)47 char *BN_bn2dec(const BIGNUM *a)
48 {
49     int i = 0, num, ok = 0, n, tbytes;
50     char *buf = NULL;
51     char *p;
52     BIGNUM *t = NULL;
53     BN_ULONG *bn_data = NULL, *lp;
54     int bn_data_num;
55 
56     /*-
57      * get an upper bound for the length of the decimal integer
58      * num <= (BN_num_bits(a) + 1) * log(2)
59      *     <= 3 * BN_num_bits(a) * 0.101 + log(2) + 1     (rounding error)
60      *     <= 3 * BN_num_bits(a) / 10 + 3 * BN_num_bits / 1000 + 1 + 1
61      */
62     i = BN_num_bits(a) * 3;
63     num = (i / 10 + i / 1000 + 1) + 1;
64     tbytes = num + 3;   /* negative and terminator and one spare? */
65     bn_data_num = num / BN_DEC_NUM + 1;
66     bn_data = OPENSSL_malloc(bn_data_num * sizeof(BN_ULONG));
67     buf = OPENSSL_malloc(tbytes);
68     if (buf == NULL || bn_data == NULL)
69         goto err;
70     if ((t = BN_dup(a)) == NULL)
71         goto err;
72 
73     p = buf;
74     lp = bn_data;
75     if (BN_is_zero(t)) {
76         *p++ = '0';
77         *p++ = '\0';
78     } else {
79         if (BN_is_negative(t))
80             *p++ = '-';
81 
82         while (!BN_is_zero(t)) {
83             if (lp - bn_data >= bn_data_num)
84                 goto err;
85             *lp = BN_div_word(t, BN_DEC_CONV);
86             if (*lp == (BN_ULONG)-1)
87                 goto err;
88             lp++;
89         }
90         lp--;
91         /*
92          * We now have a series of blocks, BN_DEC_NUM chars in length, where
93          * the last one needs truncation. The blocks need to be reversed in
94          * order.
95          */
96         n = BIO_snprintf(p, tbytes - (size_t)(p - buf), BN_DEC_FMT1, *lp);
97         if (n < 0)
98             goto err;
99         p += n;
100         while (lp != bn_data) {
101             lp--;
102             n = BIO_snprintf(p, tbytes - (size_t)(p - buf), BN_DEC_FMT2, *lp);
103             if (n < 0)
104                 goto err;
105             p += n;
106         }
107     }
108     ok = 1;
109  err:
110     OPENSSL_free(bn_data);
111     BN_free(t);
112     if (ok)
113         return buf;
114     OPENSSL_free(buf);
115     return NULL;
116 }
117 #endif
118 
BN_hex2bn(BIGNUM ** bn,const char * a)119 int BN_hex2bn(BIGNUM **bn, const char *a)
120 {
121     BIGNUM *ret = NULL;
122     BN_ULONG l = 0;
123     int neg = 0, h, m, i, j, k, c;
124     int num;
125 
126     if (a == NULL || *a == '\0')
127         return 0;
128 
129     if (*a == '-') {
130         neg = 1;
131         a++;
132     }
133 
134     for (i = 0; i <= INT_MAX / 4 && ossl_isxdigit(a[i]); i++)
135         continue;
136 
137     if (i == 0 || i > INT_MAX / 4)
138         return 0;
139 
140     num = i + neg;
141     if (bn == NULL)
142         return num;
143 
144     /* a is the start of the hex digits, and it is 'i' long */
145     if (*bn == NULL) {
146         if ((ret = BN_new()) == NULL)
147             return 0;
148     } else {
149         ret = *bn;
150         if (BN_get_flags(ret, BN_FLG_STATIC_DATA)) {
151             ERR_raise(ERR_LIB_BN, ERR_R_PASSED_INVALID_ARGUMENT);
152             return 0;
153         }
154         BN_zero(ret);
155     }
156 
157     /* i is the number of hex digits */
158     if (bn_expand(ret, i * 4) == NULL)
159         goto err;
160 
161     j = i;                      /* least significant 'hex' */
162     m = 0;
163     h = 0;
164     while (j > 0) {
165         m = (BN_BYTES * 2 <= j) ? BN_BYTES * 2 : j;
166         l = 0;
167         for (;;) {
168             c = a[j - m];
169             k = OPENSSL_hexchar2int(c);
170             if (k < 0)
171                 k = 0;          /* paranoia */
172             l = (l << 4) | k;
173 
174             if (--m <= 0) {
175                 ret->d[h++] = l;
176                 break;
177             }
178         }
179         j -= BN_BYTES * 2;
180     }
181     ret->top = h;
182     bn_correct_top(ret);
183 
184     *bn = ret;
185     bn_check_top(ret);
186     /* Don't set the negative flag if it's zero. */
187     if (ret->top != 0)
188         ret->neg = neg;
189     return num;
190  err:
191     if (*bn == NULL)
192         BN_free(ret);
193     return 0;
194 }
195 
BN_dec2bn(BIGNUM ** bn,const char * a)196 int BN_dec2bn(BIGNUM **bn, const char *a)
197 {
198     BIGNUM *ret = NULL;
199     BN_ULONG l = 0;
200     int neg = 0, i, j;
201     int num;
202 
203     if (a == NULL || *a == '\0')
204         return 0;
205     if (*a == '-') {
206         neg = 1;
207         a++;
208     }
209 
210     for (i = 0; i <= INT_MAX / 4 && ossl_isdigit(a[i]); i++)
211         continue;
212 
213     if (i == 0 || i > INT_MAX / 4)
214         goto err;
215 
216     num = i + neg;
217     if (bn == NULL)
218         return num;
219 
220     /*
221      * a is the start of the digits, and it is 'i' long. We chop it into
222      * BN_DEC_NUM digits at a time
223      */
224     if (*bn == NULL) {
225         if ((ret = BN_new()) == NULL)
226             return 0;
227     } else {
228         ret = *bn;
229         BN_zero(ret);
230     }
231 
232     /* i is the number of digits, a bit of an over expand */
233     if (bn_expand(ret, i * 4) == NULL)
234         goto err;
235 
236     j = BN_DEC_NUM - i % BN_DEC_NUM;
237     if (j == BN_DEC_NUM)
238         j = 0;
239     l = 0;
240     while (--i >= 0) {
241         l *= 10;
242         l += *a - '0';
243         a++;
244         if (++j == BN_DEC_NUM) {
245             if (!BN_mul_word(ret, BN_DEC_CONV)
246                 || !BN_add_word(ret, l))
247                 goto err;
248             l = 0;
249             j = 0;
250         }
251     }
252 
253     bn_correct_top(ret);
254     *bn = ret;
255     bn_check_top(ret);
256     /* Don't set the negative flag if it's zero. */
257     if (ret->top != 0)
258         ret->neg = neg;
259     return num;
260  err:
261     if (*bn == NULL)
262         BN_free(ret);
263     return 0;
264 }
265 
BN_asc2bn(BIGNUM ** bn,const char * a)266 int BN_asc2bn(BIGNUM **bn, const char *a)
267 {
268     const char *p = a;
269 
270     if (*p == '-')
271         p++;
272 
273     if (p[0] == '0' && (p[1] == 'X' || p[1] == 'x')) {
274         if (!BN_hex2bn(bn, p + 2))
275             return 0;
276     } else {
277         if (!BN_dec2bn(bn, p))
278             return 0;
279     }
280     /* Don't set the negative flag if it's zero. */
281     if (*a == '-' && (*bn)->top != 0)
282         (*bn)->neg = 1;
283     return 1;
284 }
285