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