Coverage Report

Created: 2025-09-01 06:47

/src/wolfssl/wolfcrypt/src/coding.c
Line
Count
Source (jump to first uncovered line)
1
/* coding.c
2
 *
3
 * Copyright (C) 2006-2025 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 3 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
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
23
24
#ifndef NO_CODING
25
26
#include <wolfssl/wolfcrypt/coding.h>
27
#ifndef NO_ASN
28
    #include <wolfssl/wolfcrypt/asn.h> /* For PEM_LINE_SZ */
29
#endif
30
#ifdef NO_INLINE
31
    #include <wolfssl/wolfcrypt/misc.h>
32
#else
33
    #define WOLFSSL_MISC_INCLUDED
34
    #include <wolfcrypt/src/misc.c>
35
#endif
36
37
enum {
38
    BAD         = 0xFF,  /* invalid encoding */
39
    PAD         = '=',
40
    BASE64_MIN  = 0x2B,
41
    BASE16_MIN  = 0x30
42
};
43
44
45
#ifndef BASE64_LINE_SZ
46
    #ifdef NO_ASN
47
        #define BASE64_LINE_SZ 64
48
    #else
49
0
        #define BASE64_LINE_SZ PEM_LINE_SZ
50
    #endif
51
#endif
52
53
#ifdef WOLFSSL_BASE64_DECODE
54
55
static WC_INLINE byte Base64_Char2Val_CT(byte c)
56
0
{
57
0
    int v;
58
0
    int smallEnd   = (int)c - 0x7b;
59
0
    int smallStart = (int)c - 0x61;
60
0
    int bigEnd     = (int)c - 0x5b;
61
0
    int bigStart   = (int)c - 0x41;
62
0
    int numEnd     = (int)c - 0x3a;
63
0
    int numStart   = (int)c - 0x30;
64
0
    int slashEnd   = (int)c - 0x30;
65
0
    int slashStart = (int)c - 0x2f;
66
0
    int plusEnd    = (int)c - 0x2c;
67
0
    int plusStart  = (int)c - 0x2b;
68
69
0
    v  = ((smallStart >> 8) ^ (smallEnd >> 8)) & (smallStart + 26 + 1);
70
0
    v |= ((bigStart   >> 8) ^ (bigEnd   >> 8)) & (bigStart   +  0 + 1);
71
0
    v |= ((numStart   >> 8) ^ (numEnd   >> 8)) & (numStart   + 52 + 1);
72
0
    v |= ((slashStart >> 8) ^ (slashEnd >> 8)) & (slashStart + 63 + 1);
73
0
    v |= ((plusStart  >> 8) ^ (plusEnd  >> 8)) & (plusStart  + 62 + 1);
74
75
0
    return (byte)(v - 1);
76
0
}
77
78
#ifndef BASE64_NO_TABLE
79
80
static
81
ALIGN64 const byte base64Decode_table[] = {    /* + starts at 0x2B */
82
/* 0x28:       + , - . / */                   62, BAD, BAD, BAD,  63,
83
/* 0x30: 0 1 2 3 4 5 6 7 */    52,  53,  54,  55,  56,  57,  58,  59,
84
/* 0x38: 8 9 : ; < = > ? */    60,  61, BAD, BAD, BAD, BAD, BAD, BAD,
85
/* 0x40: @ A B C D E F G */   BAD,   0,   1,   2,   3,   4,   5,   6,
86
/* 0x48: H I J K L M N O */     7,   8,   9,  10,  11,  12,  13,  14,
87
/* 0x50: P Q R S T U V W */    15,  16,  17,  18,  19,  20,  21,  22,
88
/* 0x58: X Y Z [ \ ] ^ _ */    23,  24,  25, BAD, BAD, BAD, BAD, BAD,
89
/* 0x60: ` a b c d e f g */   BAD,  26,  27,  28,  29,  30,  31,  32,
90
/* 0x68: h i j k l m n o */    33,  34,  35,  36,  37,  38,  39,  40,
91
/* 0x70: p q r s t u v w */    41,  42,  43,  44,  45,  46,  47,  48,
92
/* 0x78: x y z           */    49,  50,  51
93
                            };
94
0
#define BASE64DECODE_TABLE_SZ    (byte)(sizeof(base64Decode_table))
95
96
static WC_INLINE byte Base64_Char2Val_by_table(byte c)
97
0
{
98
#ifdef WC_CACHE_RESISTANT_BASE64_TABLE
99
    /* 80 characters in table.
100
     * 64 bytes in a cache line - first line has 64, second has 16
101
     */
102
    byte v;
103
    byte mask;
104
105
    c = (byte)(c - BASE64_MIN);
106
    mask = (byte)((((byte)(0x3f - c)) >> 7) - 1);
107
    /* Load a value from the first cache line and use when mask set. */
108
    v  = (byte)(base64Decode_table[ c & 0x3f        ] &   mask);
109
    /* Load a value from the second cache line and use when mask not set. */
110
    v |= (byte)(base64Decode_table[(c & 0x0f) | 0x40] & (~mask));
111
112
    return v;
113
#else
114
0
    return base64Decode_table[c - BASE64_MIN];
115
0
#endif
116
0
}
117
118
#endif /* !BASE64_NO_TABLE */
119
120
int Base64_SkipNewline(const byte* in, word32 *inLen,
121
  word32 *outJ)
122
0
{
123
0
    word32 len = *inLen;
124
0
    word32 j = *outJ;
125
0
    byte curChar;
126
127
0
    if (len == 0) {
128
0
        return BUFFER_E;
129
0
    }
130
0
    curChar = in[j];
131
132
0
    while (len > 1 && curChar == ' ') {
133
        /* skip whitespace in the middle or end of line */
134
0
        curChar = in[++j];
135
0
        len--;
136
0
    }
137
0
    if (len && (curChar == '\r' || curChar == '\n')) {
138
0
        j++;
139
0
        len--;
140
0
        if (curChar == '\r') {
141
0
            if (len) {
142
0
                curChar = in[j++];
143
0
                len--;
144
0
            }
145
0
        }
146
0
        if (curChar != '\n') {
147
0
            WOLFSSL_MSG("Bad end of line in Base64 Decode");
148
0
            return ASN_INPUT_E;
149
0
        }
150
151
0
        if (len) {
152
0
            curChar = in[j];
153
0
        }
154
0
    }
155
0
    while (len && curChar == ' ') {
156
0
        if (--len > 0) {
157
0
            curChar = in[++j];
158
0
        }
159
0
    }
160
0
    if (!len) {
161
0
        return BUFFER_E;
162
0
    }
163
0
    *inLen = len;
164
0
    *outJ = j;
165
0
    return 0;
166
0
}
167
168
#ifndef BASE64_NO_TABLE
169
170
int Base64_Decode_nonCT(const byte* in, word32 inLen, byte* out, word32* outLen)
171
0
{
172
0
    word32 i = 0;
173
0
    word32 j = 0;
174
0
    int ret;
175
0
    const byte maxIdx = BASE64DECODE_TABLE_SZ + BASE64_MIN - 1;
176
177
0
    while (inLen > 3) {
178
0
        int pad3 = 0;
179
0
        int pad4 = 0;
180
0
        byte b1, b2, b3;
181
0
        byte e1, e2, e3, e4;
182
183
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
184
0
            if (ret == WC_NO_ERR_TRACE(BUFFER_E)) {
185
                /* Running out of buffer here is not an error */
186
0
                break;
187
0
            }
188
0
            return ret;
189
0
        }
190
0
        e1 = in[j++];
191
0
        if (e1 == '\0') {
192
0
            break;
193
0
        }
194
0
        inLen--;
195
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
196
0
            return ret;
197
0
        }
198
0
        e2 = in[j++];
199
0
        inLen--;
200
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
201
0
            return ret;
202
0
        }
203
0
        e3 = in[j++];
204
0
        inLen--;
205
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
206
0
            return ret;
207
0
        }
208
0
        e4 = in[j++];
209
0
        inLen--;
210
211
0
        if (e3 == PAD)
212
0
            pad3 = 1;
213
0
        if (e4 == PAD)
214
0
            pad4 = 1;
215
216
0
        if (pad3 && !pad4)
217
0
            return ASN_INPUT_E;
218
219
0
        if (e1 < BASE64_MIN || e2 < BASE64_MIN || e3 < BASE64_MIN ||
220
0
                                                              e4 < BASE64_MIN) {
221
0
            WOLFSSL_MSG("Bad Base64 Decode data, too small");
222
0
            return ASN_INPUT_E;
223
0
        }
224
225
0
        if (e1 > maxIdx || e2 > maxIdx || e3 > maxIdx || e4 > maxIdx) {
226
0
            WOLFSSL_MSG("Bad Base64 Decode data, too big");
227
0
            return ASN_INPUT_E;
228
0
        }
229
230
0
        if (i + 1 + !pad3 + !pad4 > *outLen) {
231
0
            WOLFSSL_MSG("Bad Base64 Decode out buffer, too small");
232
0
            return BUFFER_E;
233
0
        }
234
235
0
        e1 = Base64_Char2Val_by_table(e1);
236
0
        e2 = Base64_Char2Val_by_table(e2);
237
0
        e3 = (byte)((e3 == PAD) ? 0 : Base64_Char2Val_by_table(e3));
238
0
        e4 = (byte)((e4 == PAD) ? 0 : Base64_Char2Val_by_table(e4));
239
240
0
        if (e1 == BAD || e2 == BAD || e3 == BAD || e4 == BAD) {
241
0
            WOLFSSL_MSG("Bad Base64 Decode bad character");
242
0
            return ASN_INPUT_E;
243
0
        }
244
245
0
        b1 = (byte)((e1 << 2) | (e2 >> 4));
246
0
        b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2));
247
0
        b3 = (byte)(((e3 & 0x3) << 6) | e4);
248
249
0
        out[i++] = b1;
250
0
        if (!pad3)
251
0
            out[i++] = b2;
252
0
        if (!pad4)
253
0
            out[i++] = b3;
254
0
        else
255
0
            break;
256
0
    }
257
258
    /* If the output buffer has a room for an extra byte, add a null terminator */
259
0
    if (out && *outLen > i)
260
0
        out[i]= '\0';
261
262
    /* Note, *outLen won't reflect the optional terminating null. */
263
0
    *outLen = i;
264
265
0
    return 0;
266
0
}
267
268
#endif /* !BASE64_NO_TABLE */
269
270
int Base64_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
271
0
{
272
0
    word32 i = 0;
273
0
    word32 j = 0;
274
0
    int ret;
275
276
0
    while (inLen > 3) {
277
0
        int pad3 = 0;
278
0
        int pad4 = 0;
279
0
        byte b1, b2, b3;
280
0
        byte e1, e2, e3, e4;
281
282
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
283
0
            if (ret == WC_NO_ERR_TRACE(BUFFER_E)) {
284
                /* Running out of buffer here is not an error */
285
0
                break;
286
0
            }
287
0
            return ret;
288
0
        }
289
0
        e1 = in[j++];
290
0
        if (e1 == '\0') {
291
0
            break;
292
0
        }
293
0
        inLen--;
294
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
295
0
            return ret;
296
0
        }
297
0
        e2 = in[j++];
298
0
        inLen--;
299
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
300
0
            return ret;
301
0
        }
302
0
        e3 = in[j++];
303
0
        inLen--;
304
0
        if ((ret = Base64_SkipNewline(in, &inLen, &j)) != 0) {
305
0
            return ret;
306
0
        }
307
0
        e4 = in[j++];
308
0
        inLen--;
309
310
0
        if (e3 == PAD)
311
0
            pad3 = 1;
312
0
        if (e4 == PAD)
313
0
            pad4 = 1;
314
315
0
        if (pad3 && !pad4)
316
0
            return ASN_INPUT_E;
317
318
0
        if (i + 1 + !pad3 + !pad4 > *outLen) {
319
0
            WOLFSSL_MSG("Bad Base64 Decode out buffer, too small");
320
0
            return BUFFER_E;
321
0
        }
322
323
0
        e1 = Base64_Char2Val_CT(e1);
324
0
        e2 = Base64_Char2Val_CT(e2);
325
0
        e3 = (byte)((e3 == PAD) ? 0 : Base64_Char2Val_CT(e3));
326
0
        e4 = (byte)((e4 == PAD) ? 0 : Base64_Char2Val_CT(e4));
327
328
0
        if (e1 == BAD || e2 == BAD || e3 == BAD || e4 == BAD) {
329
0
            WOLFSSL_MSG("Bad Base64 Decode bad character");
330
0
            return ASN_INPUT_E;
331
0
        }
332
333
0
        b1 = (byte)((e1 << 2) | (e2 >> 4));
334
0
        b2 = (byte)(((e2 & 0xF) << 4) | (e3 >> 2));
335
0
        b3 = (byte)(((e3 & 0x3) << 6) | e4);
336
337
0
        out[i++] = b1;
338
0
        if (!pad3)
339
0
            out[i++] = b2;
340
0
        if (!pad4)
341
0
            out[i++] = b3;
342
0
        else
343
0
            break;
344
0
    }
345
346
    /* If the output buffer has a room for an extra byte, add a null terminator */
347
0
    if (out && *outLen > i)
348
0
        out[i]= '\0';
349
350
    /* Note, *outLen won't reflect the optional terminating null. */
351
0
    *outLen = i;
352
353
0
    return 0;
354
0
}
355
356
#ifdef BASE64_NO_TABLE
357
int Base64_Decode_nonCT(const byte* in, word32 inLen, byte* out, word32* outLen) {
358
    return Base64_Decode(in, inLen, out, outLen);
359
}
360
#endif /* BASE64_NO_TABLE */
361
362
#endif /* WOLFSSL_BASE64_DECODE */
363
364
#if defined(WOLFSSL_BASE64_ENCODE)
365
366
static
367
const byte base64Encode[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
368
                              'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
369
                              'U', 'V', 'W', 'X', 'Y', 'Z',
370
                              'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
371
                              'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
372
                              'u', 'v', 'w', 'x', 'y', 'z',
373
                              '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
374
                              '+', '/'
375
                            };
376
377
378
/* make sure *i (idx) won't exceed max, store and possibly escape to out,
379
 * raw means use e w/o decode,  0 on success */
380
static int CEscape(int escaped, byte e, byte* out, word32* i, word32 maxSz,
381
                  int raw, int getSzOnly)
382
0
{
383
0
    int    doEscape = 0;
384
0
    word32 needed = 1;
385
0
    word32 idx = *i;
386
387
0
    byte basic;
388
0
    byte plus    = 0;
389
0
    byte equals  = 0;
390
0
    byte newline = 0;
391
392
0
    if (raw)
393
0
        basic = e;
394
0
    else if (e < sizeof(base64Encode))
395
0
        basic = base64Encode[e];
396
0
    else
397
0
        return BAD_FUNC_ARG;
398
399
    /* check whether to escape. Only escape for EncodeEsc */
400
0
    if (escaped == WC_ESC_NL_ENC) {
401
0
        switch ((char)basic) {
402
0
            case '+' :
403
0
                plus     = 1;
404
0
                doEscape = 1;
405
0
                needed  += 2;
406
0
                break;
407
0
            case '=' :
408
0
                equals   = 1;
409
0
                doEscape = 1;
410
0
                needed  += 2;
411
0
                break;
412
0
            case '\n' :
413
0
                newline  = 1;
414
0
                doEscape = 1;
415
0
                needed  += 2;
416
0
                break;
417
0
            default:
418
                /* do nothing */
419
0
                break;
420
0
        }
421
0
    }
422
423
    /* check size */
424
0
    if ( (idx+needed) > maxSz && !getSzOnly) {
425
0
        WOLFSSL_MSG("Escape buffer max too small");
426
0
        return BUFFER_E;
427
0
    }
428
429
    /* store it */
430
0
    if (doEscape == 0) {
431
0
        if(getSzOnly)
432
0
            idx++;
433
0
        else
434
0
            out[idx++] = basic;
435
0
    }
436
0
    else {
437
0
        if(getSzOnly)
438
0
            idx+=3;
439
0
        else {
440
0
            out[idx++] = '%';  /* start escape */
441
442
0
            if (plus) {
443
0
                out[idx++] = '2';
444
0
                out[idx++] = 'B';
445
0
            }
446
0
            else if (equals) {
447
0
                out[idx++] = '3';
448
0
                out[idx++] = 'D';
449
0
            }
450
0
            else if (newline) {
451
0
                out[idx++] = '0';
452
0
                out[idx++] = 'A';
453
0
            }
454
0
        }
455
0
    }
456
0
    *i = idx;
457
458
0
    return 0;
459
0
}
460
461
462
/* internal worker, handles both escaped and normal line endings.
463
   If out buffer is NULL, will return sz needed in outLen */
464
static int DoBase64_Encode(const byte* in, word32 inLen, byte* out,
465
                           word32* outLen, int escaped)
466
0
{
467
0
    int    ret = 0;
468
0
    word32 i = 0,
469
0
           j = 0,
470
0
           n = 0;   /* new line counter */
471
472
0
    int    getSzOnly = (out == NULL);
473
474
0
    word32 outSz = (inLen + 3 - 1) / 3 * 4;
475
0
    word32 addSz = (outSz + BASE64_LINE_SZ - 1) / BASE64_LINE_SZ;  /* new lines */
476
477
0
    if (escaped == WC_ESC_NL_ENC)
478
0
        addSz *= 3;   /* instead of just \n, we're doing %0A triplet */
479
0
    else if (escaped == WC_NO_NL_ENC)
480
0
        addSz = 0;    /* encode without \n */
481
482
0
    outSz += addSz;
483
484
    /* if escaped we can't predetermine size for one pass encoding, but
485
     * make sure we have enough if no escapes are in input
486
     * Also need to ensure outLen valid before dereference */
487
0
    if (!outLen || (outSz > *outLen && !getSzOnly)) return BAD_FUNC_ARG;
488
489
0
    while (inLen > 2) {
490
0
        byte b1 = in[j++];
491
0
        byte b2 = in[j++];
492
0
        byte b3 = in[j++];
493
494
        /* encoded idx */
495
0
        byte e1 = b1 >> 2;
496
0
        byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
497
0
        byte e3 = (byte)(((b2 & 0xF) << 2) | (b3 >> 6));
498
0
        byte e4 = b3 & 0x3F;
499
500
        /* store */
501
0
        ret = CEscape(escaped, e1, out, &i, *outLen, 0, getSzOnly);
502
0
        if (ret != 0) break;
503
0
        ret = CEscape(escaped, e2, out, &i, *outLen, 0, getSzOnly);
504
0
        if (ret != 0) break;
505
0
        ret = CEscape(escaped, e3, out, &i, *outLen, 0, getSzOnly);
506
0
        if (ret != 0) break;
507
0
        ret = CEscape(escaped, e4, out, &i, *outLen, 0, getSzOnly);
508
0
        if (ret != 0) break;
509
510
0
        inLen -= 3;
511
512
        /* Insert newline after BASE64_LINE_SZ, unless no \n requested */
513
0
        if (escaped != WC_NO_NL_ENC && (++n % (BASE64_LINE_SZ/4)) == 0 && inLen) {
514
0
            ret = CEscape(escaped, '\n', out, &i, *outLen, 1, getSzOnly);
515
0
            if (ret != 0) break;
516
0
        }
517
0
    }
518
519
    /* last integral */
520
0
    if (inLen && ret == 0) {
521
0
        int twoBytes = (inLen == 2);
522
523
0
        byte b1 = in[j++];
524
0
        byte b2 = (twoBytes) ? in[j++] : 0;
525
526
0
        byte e1 = b1 >> 2;
527
0
        byte e2 = (byte)(((b1 & 0x3) << 4) | (b2 >> 4));
528
0
        byte e3 = (byte)((b2 & 0xF) << 2);
529
530
0
        ret = CEscape(escaped, e1, out, &i, *outLen, 0, getSzOnly);
531
0
        if (ret == 0)
532
0
            ret = CEscape(escaped, e2, out, &i, *outLen, 0, getSzOnly);
533
0
        if (ret == 0) {
534
            /* third */
535
0
            if (twoBytes)
536
0
                ret = CEscape(escaped, e3, out, &i, *outLen, 0, getSzOnly);
537
0
            else
538
0
                ret = CEscape(escaped, '=', out, &i, *outLen, 1, getSzOnly);
539
0
        }
540
        /* fourth always pad */
541
0
        if (ret == 0)
542
0
            ret = CEscape(escaped, '=', out, &i, *outLen, 1, getSzOnly);
543
0
    }
544
545
0
    if (ret == 0 && escaped != WC_NO_NL_ENC)
546
0
        ret = CEscape(escaped, '\n', out, &i, *outLen, 1, getSzOnly);
547
548
0
    if (i != outSz && escaped != 1 && ret == 0)
549
0
        return ASN_INPUT_E;
550
/* If the output buffer has a room for an extra byte, add a null terminator */
551
0
    if (out && *outLen > i)
552
0
        out[i]= '\0';
553
554
0
    *outLen = i;
555
556
0
    if (ret == 0)
557
0
        return getSzOnly ? WC_NO_ERR_TRACE(LENGTH_ONLY_E) : 0;
558
559
0
    return ret;
560
0
}
561
562
563
/* Base64 Encode, PEM style, with \n line endings */
564
int Base64_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
565
0
{
566
0
    return DoBase64_Encode(in, inLen, out, outLen, WC_STD_ENC);
567
0
}
568
569
570
/* Base64 Encode, with %0A escaped line endings instead of \n */
571
int Base64_EncodeEsc(const byte* in, word32 inLen, byte* out, word32* outLen)
572
0
{
573
0
    return DoBase64_Encode(in, inLen, out, outLen, WC_ESC_NL_ENC);
574
0
}
575
576
int Base64_Encode_NoNl(const byte* in, word32 inLen, byte* out, word32* outLen)
577
0
{
578
0
    return DoBase64_Encode(in, inLen, out, outLen, WC_NO_NL_ENC);
579
0
}
580
581
#endif /* WOLFSSL_BASE64_ENCODE */
582
583
584
#ifdef WOLFSSL_BASE16
585
586
static
587
const ALIGN64 byte hexDecode[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
588
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD,
589
                           10, 11, 12, 13, 14, 15,  /* upper case A-F */
590
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
591
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
592
                           BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
593
                           BAD, BAD,  /* G - ` */
594
                           10, 11, 12, 13, 14, 15   /* lower case a-f */
595
                         };  /* A starts at 0x41 not 0x3A */
596
597
int Base16_Decode(const byte* in, word32 inLen, byte* out, word32* outLen)
598
{
599
    word32 inIdx  = 0;
600
    word32 outIdx = 0;
601
602
    if (in == NULL || out == NULL || outLen == NULL)
603
        return BAD_FUNC_ARG;
604
605
    if (inLen == 1 && *outLen && in) {
606
        byte b = (byte)(in[inIdx++] - BASE16_MIN);  /* 0 starts at 0x30 */
607
608
        /* sanity check */
609
        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
610
            return ASN_INPUT_E;
611
612
        b  = hexDecode[b];
613
614
        if (b == BAD)
615
            return ASN_INPUT_E;
616
617
        out[outIdx++] = b;
618
619
        *outLen = outIdx;
620
        return 0;
621
    }
622
623
    if (inLen % 2)
624
        return BAD_FUNC_ARG;
625
626
    if (*outLen < (inLen / 2))
627
        return BUFFER_E;
628
629
    while (inLen) {
630
        byte b  = (byte)(in[inIdx++] - BASE16_MIN);  /* 0 starts at 0x30 */
631
        byte b2 = (byte)(in[inIdx++] - BASE16_MIN);
632
633
        /* sanity checks */
634
        if (b >=  sizeof(hexDecode)/sizeof(hexDecode[0]))
635
            return ASN_INPUT_E;
636
        if (b2 >= sizeof(hexDecode)/sizeof(hexDecode[0]))
637
            return ASN_INPUT_E;
638
639
        b  = hexDecode[b];
640
        b2 = hexDecode[b2];
641
642
        if (b == BAD || b2 == BAD)
643
            return ASN_INPUT_E;
644
645
        out[outIdx++] = (byte)((b << 4) | b2);
646
        inLen -= 2;
647
    }
648
649
    *outLen = outIdx;
650
    return 0;
651
}
652
653
static
654
const ALIGN64 byte hexEncode[] = { '0', '1', '2', '3', '4', '5', '6', '7',
655
                                   '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
656
};
657
658
int Base16_Encode(const byte* in, word32 inLen, byte* out, word32* outLen)
659
{
660
    word32 outIdx = 0;
661
    word32 i;
662
663
    if (in == NULL || out == NULL || outLen == NULL)
664
        return BAD_FUNC_ARG;
665
666
    if (*outLen < (2 * inLen))
667
        return BAD_FUNC_ARG;
668
669
    for (i = 0; i < inLen; i++) {
670
        byte hb = in[i] >> 4;
671
        byte lb = in[i] & 0x0f;
672
673
        hb = hexEncode[hb];
674
        lb = hexEncode[lb];
675
676
        out[outIdx++] = hb;
677
        out[outIdx++] = lb;
678
    }
679
680
    /* If the output buffer has a room for an extra byte, add a null terminator */
681
    if (*outLen > outIdx)
682
        out[outIdx++]= '\0';
683
684
    *outLen = outIdx;
685
    return 0;
686
}
687
688
#endif /* WOLFSSL_BASE16 */
689
690
#endif /* !NO_CODING */