1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /**
36  *  @defgroup base Base conversion functions
37  *  @ingroup dnscore
38  *  @brief Base 64 codec
39  *
40  * Base 64 codec functions
41  *
42  *----------------------------------------------------------------------------*/
43 
44 #include "dnscore/dnscore-config.h"
45 
46 #include <stdio.h>
47 
48 #include "dnscore/base64.h"
49 
50 /*
51  *
52  */
53 
54 #define BASE64_PADDING '='
55 
56 static const char __BASE64__[256] ={
57     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
58     'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
59     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
60     'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
61     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
62     'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
63     'w', 'x', 'y', 'z', '0', '1', '2', '3',
64     '4', '5', '6', '7', '8', '9', '+', '/',
65 
66     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
67     'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
68     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
69     'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
70     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
71     'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
72     'w', 'x', 'y', 'z', '0', '1', '2', '3',
73     '4', '5', '6', '7', '8', '9', '+', '/',
74 
75     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
76     'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
77     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
78     'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
79     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
80     'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
81     'w', 'x', 'y', 'z', '0', '1', '2', '3',
82     '4', '5', '6', '7', '8', '9', '+', '/',
83 
84     'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
85     'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
86     'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
87     'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
88     'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
89     'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
90     'w', 'x', 'y', 'z', '0', '1', '2', '3',
91     '4', '5', '6', '7', '8', '9', '+', '/'
92 };
93 
94 /**
95  * Encodes bytes into base64
96  * The output size must be at least size_in * 8/5
97  *
98  * @param buffer_in     bytes to convert
99  * @param size_in       number of bytes
100  * @param buffer_out    output buffer of a size >= size_in * 4/3
101  *
102  * @return output size
103  */
104 
105 u32
base64_encode(const u8 * buffer_in,u32 size_in,char * buffer_out)106 base64_encode(const u8* buffer_in, u32 size_in, char* buffer_out)
107 {
108     char* ptr = buffer_out;
109 
110     while(size_in >= 3)
111     {
112         u8 b0 = *buffer_in++;
113         u8 b1 = *buffer_in++;
114         u8 b2 = *buffer_in++;
115 
116         *ptr++ = __BASE64__[ b0 >> 2 ];
117         *ptr++ = __BASE64__[(u8)((b0 << 4) | (b1 >> 4))];
118         *ptr++ = __BASE64__[(u8)((b1 << 2) | (b2 >> 6))];
119         *ptr++ = __BASE64__[ b2 ];
120 
121         size_in -= 3;
122     }
123 
124     switch(size_in)
125     {
126         case 2:
127         {
128             u8 b0 = *buffer_in++;
129             u8 b1 = *buffer_in;
130             *ptr++ = __BASE64__[ b0 >> 2 ];
131             *ptr++ = __BASE64__[(u8)((b0 << 4) | (b1 >> 4))];
132             *ptr++ = __BASE64__[(u8)(b1 << 2) ];
133             *ptr++ = BASE64_PADDING;
134             break;
135         }
136         case 1:
137         {
138             u8 b0 = *buffer_in;
139             *ptr++ = __BASE64__[ b0 >> 2 ];
140             *ptr++ = __BASE64__[ (u8)(b0 << 4) ];
141             *ptr++ = BASE64_PADDING;
142             *ptr++ = BASE64_PADDING;
143             break;
144         }
145     }
146 
147     return (u32)(ptr - buffer_out);
148 }
149 
150 #define __DEBASE64__STOP__ 0x80
151 
152 static const u8 __DEBASE64__[256] ={
153     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*  0 -  7 */
154     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /*  8 - 15 */
155     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 16 - 23 */
156     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 24 - 31 */
157     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 32 - 39 */
158     0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, /* 40 - 47 ...+.../ */
159     0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, /* 01234567 */
160     0x3c, 0x3d, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, /* 89...=.. */
161 
162     0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* .ABCDEFG */
163     0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, /* HIJKLMNO */
164     0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* PQRSTUVW */
165     0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, /* XYZ..... */
166     0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, /* .abcdefg */
167     0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, /* hijklmno */
168     0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, /* pqrstuvw */
169     0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, /* xyz..... */
170 
171     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
172     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
173     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
174     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
175     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
176     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
177     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
178     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
179 
180     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
181     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
182     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
183     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
184     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
185     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
186     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
187     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
188 };
189 
190 bool
base64_character_set_contains(char c)191 base64_character_set_contains(char c)
192 {
193     return __DEBASE64__[(u8)c] != (u8)0xff;
194 }
195 
196 /**
197  * Decodes base64 into bytes
198  * The output size must be at least size_in * 3/4
199  *
200  * @param buffer_in     base64 text
201  * @param size_in       number of chars
202  * @param buffer_out    output buffer of a size >= size_in * 3/4
203  *
204  * @return output size
205  */
206 
207 ya_result
base64_decode(const char * buffer_in,u32 size_in,u8 * buffer_out)208 base64_decode(const char* buffer_in, u32 size_in, u8* buffer_out)
209 {
210     if((size_in & 3) != 0)
211     {
212         return PARSEB64_ERROR; // wrong number of bytes
213     }
214 
215     u8* in = (u8*)buffer_in;
216     u8* out = buffer_out;
217 
218     while(size_in > 4)
219     {
220         u8 a = __DEBASE64__[*in++];
221         u8 b = __DEBASE64__[*in++];
222         u8 c = __DEBASE64__[*in++];
223         u8 d = __DEBASE64__[*in++];
224 
225         if(((a | b | c | d)&0x80) != 0x00)
226         {
227             /* PARSE ERROR */
228 
229             return PARSEB64_ERROR;
230         }
231 
232         *out++ = (a << 2) | (b >> 4);
233         *out++ = (b << 4) | (c >> 2);
234         *out++ = (c << 6) | d;
235 
236         size_in -= 4;
237     }
238 
239     if(size_in != 0) /* It's either 0 or 4 */
240     {
241         u8 a = __DEBASE64__[*in++];
242         u8 b = __DEBASE64__[*in++];
243 
244         if(((a | b)&0xc0) != 0x00)
245         {
246             /* PARSE ERROR */
247 
248             return PARSEB64_ERROR;
249         }
250 
251         *out++ = (a << 2) | (b >> 4);
252 
253         u8 c = __DEBASE64__[*in++];
254         if(c != __DEBASE64__STOP__)
255         {
256             if((c & 0xc0) != 0)
257             {
258                 return PARSEB64_ERROR;
259             }
260 
261             *out++ = (b << 4) | (c >> 2);
262 
263             u8 d = __DEBASE64__[*in++];
264 
265             if(d != __DEBASE64__STOP__)
266             {
267                 if((d & 0xc0) != 0)
268                 {
269                     return PARSEB64_ERROR;
270                 }
271 
272                 *out++ = (c << 6) | d;
273             }
274         }
275     }
276 
277     return out - buffer_out;
278 }
279