1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6   @file base64_decode.c
7   Compliant base64 code donated by Wayne Scott (wscott@bitmover.com)
8   base64 URL Safe variant (RFC 4648 section 5) by Karel Miko
9 */
10 
11 
12 #if defined(LTC_BASE64) || defined (LTC_BASE64_URL)
13 
14 /* 253 - ignored in "relaxed" + "insane" mode: TAB(9), CR(13), LF(10), space(32)
15  * 254 - padding character '=' (allowed only at the end)
16  * 255 - ignored in "insane" mode, but not allowed in "relaxed" + "strict" mode
17  */
18 
19 #if defined(LTC_BASE64)
20 static const unsigned char map_base64[256] = {
21 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 253, 255,
22 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
23 255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
24 255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
25  52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
26 255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
27   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
28  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,
29 255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
30  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
31  49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
32 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
33 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
34 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
35 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
36 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
37 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
38 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
39 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
40 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
41 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
42 255, 255, 255, 255 };
43 #endif /* LTC_BASE64 */
44 
45 static const unsigned char map_base64url[] = {
46 #if defined(LTC_BASE64_URL)
47 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 253, 255,
48 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
49 255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
50 255, 255, 255, 255, 255, 255, 255, 255, 255,  62, 255, 255,
51  52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
52 255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
53   7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,
54  19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255,  63,
55 255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
56  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
57  49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
58 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
59 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
60 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
61 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
62 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
63 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
64 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
65 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
66 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
67 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
68 255, 255, 255, 255
69 #endif /* LTC_BASE64_URL */
70 };
71 
72 enum {
73    insane = 0,
74    strict = 1,
75    relaxed = 2
76 };
77 
s_base64_decode_internal(const char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen,const unsigned char * map,int mode)78 static int s_base64_decode_internal(const char *in,  unsigned long inlen,
79                                  unsigned char *out, unsigned long *outlen,
80                            const unsigned char *map, int mode)
81 {
82    unsigned long t, x, y, z;
83    unsigned char c;
84    int           g;
85 
86    LTC_ARGCHK(in     != NULL);
87    LTC_ARGCHK(out    != NULL);
88    LTC_ARGCHK(outlen != NULL);
89 
90    g = 0; /* '=' counter */
91    for (x = y = z = t = 0; x < inlen; x++) {
92        if ((in[x] == 0) && (x == (inlen - 1)) && (mode != strict)) {
93           continue; /* allow the last byte to be NUL (relaxed+insane) */
94        }
95        c = map[(unsigned char)in[x]&0xFF];
96        if (c == 254) {
97           g++;
98           continue;
99        }
100        if (c == 253) {
101           if (mode == strict) {
102              return CRYPT_INVALID_PACKET;
103           }
104           continue; /* allow to ignore white-spaces (relaxed+insane) */
105        }
106        if (c == 255) {
107           if (mode == insane) {
108              continue; /* allow to ignore invalid garbage (insane) */
109           }
110           return CRYPT_INVALID_PACKET;
111        }
112        if ((g > 0) && (mode != insane)) {
113           /* we only allow '=' to be at the end (strict+relaxed) */
114           return CRYPT_INVALID_PACKET;
115        }
116 
117        t = (t<<6)|c;
118 
119        if (++y == 4) {
120           if (z + 3 > *outlen) return CRYPT_BUFFER_OVERFLOW;
121           out[z++] = (unsigned char)((t>>16)&255);
122           out[z++] = (unsigned char)((t>>8)&255);
123           out[z++] = (unsigned char)(t&255);
124           y = t = 0;
125        }
126    }
127 
128    if (y != 0) {
129       if (y == 1) return CRYPT_INVALID_PACKET;
130       if (((y + g) != 4) && (mode == strict) && (map != map_base64url)) return CRYPT_INVALID_PACKET;
131       t = t << (6 * (4 - y));
132       if (z + y - 1 > *outlen) return CRYPT_BUFFER_OVERFLOW;
133       if (y >= 2) out[z++] = (unsigned char) ((t >> 16) & 255);
134       if (y == 3) out[z++] = (unsigned char) ((t >> 8) & 255);
135    }
136    *outlen = z;
137    return CRYPT_OK;
138 }
139 
140 #if defined(LTC_BASE64)
141 /**
142    Dangerously relaxed base64 decode a block of memory
143    @param in       The base64 data to decode
144    @param inlen    The length of the base64 data
145    @param out      [out] The destination of the binary decoded data
146    @param outlen   [in/out] The max size and resulting size of the decoded data
147    @return CRYPT_OK if successful
148 */
base64_decode(const char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen)149 int base64_decode(const char *in,  unsigned long inlen,
150                         unsigned char *out, unsigned long *outlen)
151 {
152     return s_base64_decode_internal(in, inlen, out, outlen, map_base64, insane);
153 }
154 
155 /**
156    Strict base64 decode a block of memory
157    @param in       The base64 data to decode
158    @param inlen    The length of the base64 data
159    @param out      [out] The destination of the binary decoded data
160    @param outlen   [in/out] The max size and resulting size of the decoded data
161    @return CRYPT_OK if successful
162 */
base64_strict_decode(const char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen)163 int base64_strict_decode(const char *in,  unsigned long inlen,
164                         unsigned char *out, unsigned long *outlen)
165 {
166    return s_base64_decode_internal(in, inlen, out, outlen, map_base64, strict);
167 }
168 
169 /**
170    Sane base64 decode a block of memory
171    @param in       The base64 data to decode
172    @param inlen    The length of the base64 data
173    @param out      [out] The destination of the binary decoded data
174    @param outlen   [in/out] The max size and resulting size of the decoded data
175    @return CRYPT_OK if successful
176 */
base64_sane_decode(const char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen)177 int base64_sane_decode(const char *in,  unsigned long inlen,
178                         unsigned char *out, unsigned long *outlen)
179 {
180    return s_base64_decode_internal(in, inlen, out, outlen, map_base64, relaxed);
181 }
182 #endif /* LTC_BASE64 */
183 
184 #if defined(LTC_BASE64_URL)
185 /**
186    Dangerously relaxed base64 (URL Safe, RFC 4648 section 5) decode a block of memory
187    @param in       The base64 data to decode
188    @param inlen    The length of the base64 data
189    @param out      [out] The destination of the binary decoded data
190    @param outlen   [in/out] The max size and resulting size of the decoded data
191    @return CRYPT_OK if successful
192 */
base64url_decode(const char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen)193 int base64url_decode(const char *in,  unsigned long inlen,
194                            unsigned char *out, unsigned long *outlen)
195 {
196     return s_base64_decode_internal(in, inlen, out, outlen, map_base64url, insane);
197 }
198 
199 /**
200    Strict base64 (URL Safe, RFC 4648 section 5) decode a block of memory
201    @param in       The base64 data to decode
202    @param inlen    The length of the base64 data
203    @param out      [out] The destination of the binary decoded data
204    @param outlen   [in/out] The max size and resulting size of the decoded data
205    @return CRYPT_OK if successful
206 */
base64url_strict_decode(const char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen)207 int base64url_strict_decode(const char *in,  unsigned long inlen,
208                            unsigned char *out, unsigned long *outlen)
209 {
210     return s_base64_decode_internal(in, inlen, out, outlen, map_base64url, strict);
211 }
212 
213 /**
214    Sane base64 (URL Safe, RFC 4648 section 5) decode a block of memory
215    @param in       The base64 data to decode
216    @param inlen    The length of the base64 data
217    @param out      [out] The destination of the binary decoded data
218    @param outlen   [in/out] The max size and resulting size of the decoded data
219    @return CRYPT_OK if successful
220 */
base64url_sane_decode(const char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen)221 int base64url_sane_decode(const char *in,  unsigned long inlen,
222                            unsigned char *out, unsigned long *outlen)
223 {
224     return s_base64_decode_internal(in, inlen, out, outlen, map_base64url, relaxed);
225 }
226 #endif /* LTC_BASE64_URL */
227 
228 #endif
229 
230