Coverage Report

Created: 2022-08-24 06:37

/src/wolfssl-normal-math/wolfcrypt/src/coding.c
Line
Count
Source (jump to first uncovered line)
1
/* coding.c
2
 *
3
 * Copyright (C) 2006-2022 wolfSSL Inc.
4
 *
5
 * This file is part of wolfSSL.
6
 *
7
 * wolfSSL is free software; you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation; either version 2 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * wolfSSL is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20
 */
21
22
23
#ifdef HAVE_CONFIG_H
24
    #include <config.h>
25
#endif
26
27
#include <wolfssl/wolfcrypt/settings.h>
28
29
#ifndef NO_CODING
30
31
#include <wolfssl/wolfcrypt/coding.h>
32
#include <wolfssl/wolfcrypt/error-crypt.h>
33
#include <wolfssl/wolfcrypt/logging.h>
34
#ifndef NO_ASN
35
    #include <wolfssl/wolfcrypt/asn.h> /* For PEM_LINE_SZ */
36
#endif
37
#ifdef NO_INLINE
38
    #include <wolfssl/wolfcrypt/misc.h>
39
#else
40
    #define WOLFSSL_MISC_INCLUDED
41
    #include <wolfcrypt/src/misc.c>
42
#endif
43
44
enum {
45
    BAD         = 0xFF,  /* invalid encoding */
46
    PAD         = '=',
47
    BASE64_MIN  = 0x2B,
48
    BASE16_MIN  = 0x30,
49
};
50
51
52
#ifndef BASE64_LINE_SZ
53
    #ifdef NO_ASN
54
        #define BASE64_LINE_SZ 64
55
    #else
56
24.7M
        #define BASE64_LINE_SZ PEM_LINE_SZ
57
    #endif
58
#endif
59
60
#ifdef WOLFSSL_BASE64_DECODE
61
62
#ifdef BASE64_NO_TABLE
63
static WC_INLINE byte Base64_Char2Val(byte c)
64
{
65
    word16 v = 0x0000;
66
67
    v |= 0xff3E & ctMask16Eq(c, 0x2b);
68
    v |= 0xff3F & ctMask16Eq(c, 0x2f);
69
    v |= (c + 0xff04) & ctMask16GTE(c, 0x30) & ctMask16LTE(c, 0x39);
70
    v |= (0xff00 + c - 0x41) & ctMask16GTE(c, 0x41) & ctMask16LTE(c, 0x5a);
71
    v |= (0xff00 + c - 0x47) & ctMask16GTE(c, 0x61) & ctMask16LTE(c, 0x7a);
72
    v |= ~(v >> 8);
73
74
    return (byte)v;
75
}
76
#else
77
static
78
ALIGN64 const byte base64Decode[] = {          /* + starts at 0x2B */
79
/* 0x28:       + , - . / */                   62, BAD, BAD, BAD,  63,
80
/* 0x30: 0 1 2 3 4 5 6 7 */    52,  53,  54,  55,  56,  57,  58,  59,
81
/* 0x38: 8 9 : ; < = > ? */    60,  61, BAD, BAD, BAD, BAD, BAD, BAD,
82
/* 0x40: @ A B C D E F G */   BAD,   0,   1,   2,   3,   4,   5,   6,
83
/* 0x48: H I J K L M N O */     7,   8,   9,  10,  11,  12,  13,  14,
84
/* 0x50: P Q R S T U V W */    15,  16,  17,  18,  19,  20,  21,  22,
85
/* 0x58: X Y Z [ \ ] ^ _ */    23,  24,  25, BAD, BAD, BAD, BAD, BAD,
86
/* 0x60: ` a b c d e f g */   BAD,  26,  27,  28,  29,  30,  31,  32,
87
/* 0x68: h i j k l m n o */    33,  34,  35,  36,  37,  38,  39,  40,
88
/* 0x70: p q r s t u v w */    41,  42,  43,  44,  45,  46,  47,  48,
89
/* 0x78: x y z           */    49,  50,  51
90
                            };
91
44.0k
#define BASE64DECODE_SZ    (byte)(sizeof(base64Decode))
92
93
static WC_INLINE byte Base64_Char2Val(byte c)
94
15.9M
{
95
15.9M
#ifndef WC_NO_CACHE_RESISTANT
96
    /* 80 characters in table.
97
     * 64 bytes in a cache line - first line has 64, second has 16
98
     */
99
15.9M
    byte v;
100
15.9M
    byte mask;
101
102
15.9M
    c -= BASE64_MIN;
103
15.9M
    mask = (((byte)(0x3f - c)) >> 7) - 1;
104
    /* Load a value from the first cache line and use when mask set. */
105
15.9M
    v  = base64Decode[ c & 0x3f        ] &   mask ;
106
    /* Load a value from the second cache line and use when mask not set. */
107
15.9M
    v |= base64Decode[(c & 0x0f) | 0x40] & (~mask);
108
109
15.9M
    return v;
110
#else
111
    return base64Decode[c - BASE64_MIN];
112
#endif
113
15.9M
}
114
#endif
115
116
int Base64_SkipNewline(const byte* in, word32 *inLen,
117
  word32 *outJ)
118
15.9M
{
119
15.9M
    word32 len = *inLen;
120
15.9M
    word32 j = *outJ;
121
15.9M
    byte curChar;
122
123
15.9M
    if (len == 0) {
124
713
        return BUFFER_E;
125
713
    }
126
15.9M
    curChar = in[j];
127
128
15.9M
    while (len > 1 && curChar == ' ') {
129
        /* skip whitespace in the middle or end of line */
130
64.3k
        curChar = in[++j];
131
64.3k
        len--;
132
64.3k
    }
133
15.9M
    if (len && (curChar == '\r' || curChar == '\n')) {
134
84.9k
        j++;
135
84.9k
        len--;
136
84.9k
        if (curChar == '\r') {
137
10.7k
            if (len) {
138
9.96k
                curChar = in[j++];
139
9.96k
                len--;
140
9.96k
            }
141
10.7k
        }
142
84.9k
        if (curChar != '\n') {
143
1.48k
            WOLFSSL_MSG("Bad end of line in Base64 Decode");
144
1.48k
            return ASN_INPUT_E;
145
1.48k
        }
146
147
83.4k
        if (len) {
148
82.6k
            curChar = in[j];
149
82.6k
        }
150
83.4k
    }
151
15.9M
    while (len && curChar == ' ') {
152
5.00k
        if (--len > 0) {
153
4.12k
            curChar = in[++j];
154
4.12k
        }
155
5.00k
    }
156
15.9M
    if (!len) {
157
1.73k
        return BUFFER_E;
158
1.73k
    }
159
15.9M
    *inLen = len;
160
15.9M
    *outJ = j;
161
15.9M
    return 0;
162
15.9M
}
163
164
int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
165
44.0k
{
166
44.0k
    word32 i = 0;
167
44.0k
    word32 j = 0;
168
44.0k
    word32 plainSz = inLen - ((inLen + (BASE64_LINE_SZ - 1)) / BASE64_LINE_SZ );
169
44.0k
    int ret;
170
44.0k
#ifndef BASE64_NO_TABLE
171
44.0k
    const byte maxIdx = BASE64DECODE_SZ + BASE64_MIN - 1;
172
44.0k
#endif
173
174
44.0k
    plainSz = (plainSz * 3 + 3) / 4;
175
44.0k
    if (plainSz > *outLen) return BAD_FUNC_ARG;
176
177
4.01M
    while (inLen > 3) {
178
3.98M
        int pad3 = 0;
179
3.98M
        int pad4 = 0;
180
3.98M
        byte b1, b2, b3;
181
3.98M
        byte e1, e2, e3, e4;
182
183
3.98M
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
184
853
            if (ret == BUFFER_E) {
185
                /* Running out of buffer here is not an error */
186
412
                break;
187
412
            }
188
441
            return ret;
189
853
        }
190
3.98M
        e1 = in[j++];
191
3.98M
        if (e1 == '\0') {
192
12
            break;
193
12
        }
194
3.98M
        inLen--;
195
3.98M
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
196
876
            return ret;
197
876
        }
198
3.98M
        e2 = in[j++];
199
3.98M
        inLen--;
200
3.98M
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
201
1.09k
            return ret;
202
1.09k
        }
203
3.98M
        e3 = in[j++];
204
3.98M
        inLen--;
205
3.98M
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
206
1.10k
            return ret;
207
1.10k
        }
208
3.98M
        e4 = in[j++];
209
3.98M
        inLen--;
210
211
3.98M
        if (e3 == PAD)
212
1.30k
            pad3 = 1;
213
3.98M
        if (e4 == PAD)
214
1.96k
            pad4 = 1;
215
216
3.98M
        if (pad3 && !pad4)
217
201
            return ASN_INPUT_E;
218
219
3.98M
#ifndef BASE64_NO_TABLE
220
3.98M
        if (e1 < BASE64_MIN || e2 < BASE64_MIN || e3 < BASE64_MIN ||
221
3.98M
                                                              e4 < BASE64_MIN) {
222
1.19k
            WOLFSSL_MSG("Bad Base64 Decode data, too small");
223
1.19k
            return ASN_INPUT_E;
224
1.19k
        }
225
226
3.97M
        if (e1 > maxIdx || e2 > maxIdx || e3 > maxIdx || e4 > maxIdx) {
227
1.76k
            WOLFSSL_MSG("Bad Base64 Decode data, too big");
228
1.76k
            return ASN_INPUT_E;
229
1.76k
        }
230
3.97M
#endif
231
232
3.97M
        if (i + 1 + !pad3 + !pad4 > *outLen) {
233
3
            WOLFSSL_MSG("Bad Base64 Decode out buffer, too small");
234
3
            return BAD_FUNC_ARG;
235
3
        }
236
237
3.97M
        e1 = Base64_Char2Val(e1);
238
3.97M
        e2 = Base64_Char2Val(e2);
239
3.97M
        e3 = (e3 == PAD) ? 0 : Base64_Char2Val(e3);
240
3.97M
        e4 = (e4 == PAD) ? 0 : Base64_Char2Val(e4);
241
242
3.97M
        if (e1 == BAD || e2 == BAD || e3 == BAD || e4 == BAD) {
243
1.73k
            WOLFSSL_MSG("Bad Base64 Decode bad character");
244
1.73k
            return ASN_INPUT_E;
245
1.73k
        }
246
247
3.97M
        b1 = (byte)((e1 << 2) | (e2 >> 4));
248
3.97M
        b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2));
249
3.97M
        b3 = (byte)(((e3 & 0x3) << 6) | e4);
250
251
3.97M
        out[i++] = b1;
252
3.97M
        if (!pad3)
253
3.97M
            out[i++] = b2;
254
3.97M
        if (!pad4)
255
3.97M
            out[i++] = b3;
256
1.76k
        else
257
1.76k
            break;
258
3.97M
    }
259
/* If the output buffer has a room for an extra byte, add a null terminator */
260
35.5k
    if (out && *outLen > i)
261
35.5k
        out[i]= '\0';
262
263
35.5k
    *outLen = i;
264
265
35.5k
    return 0;
266
43.9k
}
267
268
#endif /* WOLFSSL_BASE64_DECODE */
269
270
#if defined(WOLFSSL_BASE64_ENCODE)
271
272
static
273
const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
274
                              'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
275
                              'U', 'V', 'W', 'X', 'Y', 'Z',
276
                              'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
277
                              'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
278
                              'u', 'v', 'w', 'x', 'y', 'z',
279
                              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
280
                              '+', '/'
281
                            };
282
283
284
/* make sure *i (idx) won't exceed max, store and possibly escape to out,
285
 * raw means use e w/o decode,  0 on success */
286
static int CEscape(int escaped, byte e, byte* out, word32* i, word32 maxSz,
287
                  int raw, int getSzOnly)
288
100M
{
289
100M
    int    doEscape = 0;
290
100M
    word32 needed = 1;
291
100M
    word32 idx = *i;
292
293
100M
    byte basic;
294
100M
    byte plus    = 0;
295
100M
    byte equals  = 0;
296
100M
    byte newline = 0;
297
298
100M
    if (raw)
299
1.55M
        basic = e;
300
99.1M
    else
301
99.1M
        basic = base64Encode[e];
302
303
    /* check whether to escape. Only escape for EncodeEsc */
304
100M
    if (escaped == WC_ESC_NL_ENC) {
305
3.94M
        switch ((char)basic) {
306
1.68M
            case '+' :
307
1.68M
                plus     = 1;
308
1.68M
                doEscape = 1;
309
1.68M
                needed  += 2;
310
1.68M
                break;
311
100
            case '=' :
312
100
                equals   = 1;
313
100
                doEscape = 1;
314
100
                needed  += 2;
315
100
                break;
316
60.7k
            case '\n' :
317
60.7k
                newline  = 1;
318
60.7k
                doEscape = 1;
319
60.7k
                needed  += 2;
320
60.7k
                break;
321
2.20M
            default:
322
                /* do nothing */
323
2.20M
                break;
324
3.94M
        }
325
3.94M
    }
326
327
    /* check size */
328
100M
    if ( (idx+needed) > maxSz && !getSzOnly) {
329
37
        WOLFSSL_MSG("Escape buffer max too small");
330
37
        return BUFFER_E;
331
37
    }
332
333
    /* store it */
334
100M
    if (doEscape == 0) {
335
98.9M
        if(getSzOnly)
336
45.4M
            idx++;
337
53.5M
        else
338
53.5M
            out[idx++] = basic;
339
98.9M
    }
340
1.74M
    else {
341
1.74M
        if(getSzOnly)
342
0
            idx+=3;
343
1.74M
        else {
344
1.74M
            out[idx++] = '%';  /* start escape */
345
346
1.74M
            if (plus) {
347
1.68M
                out[idx++] = '2';
348
1.68M
                out[idx++] = 'B';
349
1.68M
            }
350
60.8k
            else if (equals) {
351
96
                out[idx++] = '3';
352
96
                out[idx++] = 'D';
353
96
            }
354
60.7k
            else if (newline) {
355
60.7k
                out[idx++] = '0';
356
60.7k
                out[idx++] = 'A';
357
60.7k
            }
358
1.74M
        }
359
1.74M
    }
360
100M
    *i = idx;
361
362
100M
    return 0;
363
100M
}
364
365
366
/* internal worker, handles both escaped and normal line endings.
367
   If out buffer is NULL, will return sz needed in outLen */
368
static int DoBase64_Encode(const byte* in, word32 inLen, byte* out,
369
                           word32* outLen, int escaped)
370
12.3k
{
371
12.3k
    int    ret = 0;
372
12.3k
    word32 i = 0,
373
12.3k
           j = 0,
374
12.3k
           n = 0;   /* new line counter */
375
376
12.3k
    int    getSzOnly = (out == NULL);
377
378
12.3k
    word32 outSz = (inLen + 3 - 1) / 3 * 4;
379
12.3k
    word32 addSz = (outSz + BASE64_LINE_SZ - 1) / BASE64_LINE_SZ;  /* new lines */
380
381
12.3k
    if (escaped == WC_ESC_NL_ENC)
382
187
        addSz *= 3;   /* instead of just \n, we're doing %0A triplet */
383
12.1k
    else if (escaped == WC_NO_NL_ENC)
384
42
        addSz = 0;    /* encode without \n */
385
386
12.3k
    outSz += addSz;
387
388
    /* if escaped we can't predetermine size for one pass encoding, but
389
     * make sure we have enough if no escapes are in input
390
     * Also need to ensure outLen valid before dereference */
391
12.3k
    if (!outLen || (outSz > *outLen && !getSzOnly)) return BAD_FUNC_ARG;
392
393
24.7M
    while (inLen > 2) {
394
24.7M
        byte b1 = in[j++];
395
24.7M
        byte b2 = in[j++];
396
24.7M
        byte b3 = in[j++];
397
398
        /* encoded idx */
399
24.7M
        byte e1 = b1 >> 2;
400
24.7M
        byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
401
24.7M
        byte e3 = (byte)(((b2 & 0xF) << 2) | (b3 >> 6));
402
24.7M
        byte e4 = b3 & 0x3F;
403
404
        /* store */
405
24.7M
        ret = CEscape(escaped, e1, out, &i, *outLen, 0, getSzOnly);
406
24.7M
        if (ret != 0) break;
407
24.7M
        ret = CEscape(escaped, e2, out, &i, *outLen, 0, getSzOnly);
408
24.7M
        if (ret != 0) break;
409
24.7M
        ret = CEscape(escaped, e3, out, &i, *outLen, 0, getSzOnly);
410
24.7M
        if (ret != 0) break;
411
24.7M
        ret = CEscape(escaped, e4, out, &i, *outLen, 0, getSzOnly);
412
24.7M
        if (ret != 0) break;
413
414
24.7M
        inLen -= 3;
415
416
        /* Insert newline after BASE64_LINE_SZ, unless no \n requested */
417
24.7M
        if (escaped != WC_NO_NL_ENC && (++n % (BASE64_LINE_SZ/4)) == 0 && inLen) {
418
1.53M
            ret = CEscape(escaped, '\n', out, &i, *outLen, 1, getSzOnly);
419
1.53M
            if (ret != 0) break;
420
1.53M
        }
421
24.7M
    }
422
423
    /* last integral */
424
12.3k
    if (inLen && ret == 0) {
425
7.55k
        int twoBytes = (inLen == 2);
426
427
7.55k
        byte b1 = in[j++];
428
7.55k
        byte b2 = (twoBytes) ? in[j++] : 0;
429
430
7.55k
        byte e1 = b1 >> 2;
431
7.55k
        byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
432
7.55k
        byte e3 = (byte)((b2 & 0xF) << 2);
433
434
7.55k
        ret = CEscape(escaped, e1, out, &i, *outLen, 0, getSzOnly);
435
7.55k
        if (ret == 0)
436
7.55k
            ret = CEscape(escaped, e2, out, &i, *outLen, 0, getSzOnly);
437
7.55k
        if (ret == 0) {
438
            /* third */
439
7.55k
            if (twoBytes)
440
3.39k
                ret = CEscape(escaped, e3, out, &i, *outLen, 0, getSzOnly);
441
4.15k
            else
442
4.15k
                ret = CEscape(escaped, '=', out, &i, *outLen, 1, getSzOnly);
443
7.55k
        }
444
        /* fourth always pad */
445
7.55k
        if (ret == 0)
446
7.55k
            ret = CEscape(escaped, '=', out, &i, *outLen, 1, getSzOnly);
447
7.55k
    }
448
449
12.3k
    if (ret == 0 && escaped != WC_NO_NL_ENC)
450
12.2k
        ret = CEscape(escaped, '\n', out, &i, *outLen, 1, getSzOnly);
451
452
12.3k
    if (i != outSz && escaped != 1 && ret == 0)
453
9
        return ASN_INPUT_E;
454
/* If the output buffer has a room for an extra byte, add a null terminator */
455
12.3k
    if (out && *outLen > i)
456
254
        out[i]= '\0';
457
458
12.3k
    *outLen = i;
459
460
12.3k
    if (ret == 0)
461
12.2k
        return getSzOnly ? LENGTH_ONLY_E : 0;
462
463
37
    return ret;
464
12.3k
}
465
466
467
/* Base64 Encode, PEM style, with \n line endings */
468
int Base64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
469
12.1k
{
470
12.1k
    return DoBase64_Encode(in, inLen, out, outLen, WC_STD_ENC);
471
12.1k
}
472
473
474
/* Base64 Encode, with %0A escaped line endings instead of \n */
475
int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out, word32* outLen)
476
187
{
477
187
    return DoBase64_Encode(in, inLen, out, outLen, WC_ESC_NL_ENC);
478
187
}
479
480
int Base64_Encode_NoNl(const byte* in, word32 inLen, byte* out, word32* outLen)
481
42
{
482
42
    return DoBase64_Encode(in, inLen, out, outLen, WC_NO_NL_ENC);
483
42
}
484
485
#endif /* WOLFSSL_BASE64_ENCODE */
486
487
488
#ifdef WOLFSSL_BASE16
489
490
static
491
const byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
492
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD,
493
                           10, 11, 12, 13, 14, 15,  /* upper case A-F */
494
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
495
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
496
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
497
                           BAD, BAD,  /* G - ` */
498
                           10, 11, 12, 13, 14, 15   /* lower case a-f */
499
                         };  /* A starts at 0x41 not 0x3A */
500
501
int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
502
{
503
    word32 inIdx  = 0;
504
    word32 outIdx = 0;
505
506
    if (in == NULL || out == NULL || outLen == NULL)
507
        return BAD_FUNC_ARG;
508
509
    if (inLen == 1 && *outLen && in) {
510
        byte b = in[inIdx++] - BASE16_MIN;  /* 0 starts at 0x30 */
511
512
        /* sanity check */
513
        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
514
            return ASN_INPUT_E;
515
516
        b  = hexDecode[b];
517
518
        if (b == BAD)
519
            return ASN_INPUT_E;
520
521
        out[outIdx++] = b;
522
523
        *outLen = outIdx;
524
        return 0;
525
    }
526
527
    if (inLen % 2)
528
        return BAD_FUNC_ARG;
529
530
    if (*outLen < (inLen / 2))
531
        return BAD_FUNC_ARG;
532
533
    while (inLen) {
534
        byte b  = in[inIdx++] - BASE16_MIN;  /* 0 starts at 0x30 */
535
        byte b2 = in[inIdx++] - BASE16_MIN;
536
537
        /* sanity checks */
538
        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
539
            return ASN_INPUT_E;
540
        if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0]))
541
            return ASN_INPUT_E;
542
543
        b  = hexDecode[b];
544
        b2 = hexDecode[b2];
545
546
        if (b == BAD || b2 == BAD)
547
            return ASN_INPUT_E;
548
549
        out[outIdx++] = (byte)((b << 4) | b2);
550
        inLen -= 2;
551
    }
552
553
    *outLen = outIdx;
554
    return 0;
555
}
556
557
int Base16_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
558
{
559
    word32 outIdx = 0;
560
    word32 i;
561
    byte   hb, lb;
562
563
    if (in == NULL || out == NULL || outLen == NULL)
564
        return BAD_FUNC_ARG;
565
566
    if (*outLen < (2 * inLen + 1))
567
        return BAD_FUNC_ARG;
568
569
    for (i = 0; i < inLen; i++) {
570
        hb = in[i] >> 4;
571
        lb = in[i] & 0x0f;
572
573
        /* ASCII value */
574
        hb += '0';
575
        if (hb > '9')
576
            hb += 7;
577
578
        /* ASCII value */
579
        lb += '0';
580
        if (lb>'9')
581
            lb += 7;
582
583
        out[outIdx++] = hb;
584
        out[outIdx++] = lb;
585
    }
586
587
    /* force 0 at this end */
588
    out[outIdx++] = 0;
589
590
    *outLen = outIdx;
591
    return 0;
592
}
593
594
#endif /* WOLFSSL_BASE16 */
595
596
#endif /* !NO_CODING */