1 /*
2 * RFC 1521 base64 encoding/decoding
3 *
4 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 * This file is part of mbed TLS (https://tls.mbed.org)
20 */
21
22 #if !defined(MBEDTLS_CONFIG_FILE)
23 #include "mbedtls/config.h"
24 #else
25 #include MBEDTLS_CONFIG_FILE
26 #endif
27
28 #if defined(MBEDTLS_BASE64_C)
29
30 #include "mbedtls/base64.h"
31
32 #include <stdint.h>
33
34 #if defined(MBEDTLS_SELF_TEST)
35 #include <string.h>
36 #if defined(MBEDTLS_PLATFORM_C)
37 #include "mbedtls/platform.h"
38 #else
39 #include <stdio.h>
40 #define mbedtls_printf printf
41 #endif /* MBEDTLS_PLATFORM_C */
42 #endif /* MBEDTLS_SELF_TEST */
43
44 static const unsigned char base64_enc_map[64] =
45 {
46 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
47 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
48 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
49 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
50 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
51 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
52 '8', '9', '+', '/'
53 };
54
55 static const unsigned char base64_dec_map[128] =
56 {
57 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
58 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
59 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
60 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
61 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
62 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
63 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
64 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
65 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
66 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
67 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
68 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
69 49, 50, 51, 127, 127, 127, 127, 127
70 };
71
72 #define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
73
74 /*
75 * Encode a buffer into base64 format
76 */
mbedtls_base64_encode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)77 int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
78 const unsigned char *src, size_t slen )
79 {
80 size_t i, n;
81 int C1, C2, C3;
82 unsigned char *p;
83
84 if( slen == 0 )
85 {
86 *olen = 0;
87 return( 0 );
88 }
89
90 n = slen / 3 + ( slen % 3 != 0 );
91
92 if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
93 {
94 *olen = BASE64_SIZE_T_MAX;
95 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
96 }
97
98 n *= 4;
99
100 if( ( dlen < n + 1 ) || ( NULL == dst ) )
101 {
102 *olen = n + 1;
103 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
104 }
105
106 n = ( slen / 3 ) * 3;
107
108 for( i = 0, p = dst; i < n; i += 3 )
109 {
110 C1 = *src++;
111 C2 = *src++;
112 C3 = *src++;
113
114 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
115 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
116 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
117 *p++ = base64_enc_map[C3 & 0x3F];
118 }
119
120 if( i < slen )
121 {
122 C1 = *src++;
123 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
124
125 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
126 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
127
128 if( ( i + 1 ) < slen )
129 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
130 else *p++ = '=';
131
132 *p++ = '=';
133 }
134
135 *olen = p - dst;
136 *p = 0;
137
138 return( 0 );
139 }
140
141 /*
142 * Decode a base64-formatted buffer
143 */
mbedtls_base64_decode(unsigned char * dst,size_t dlen,size_t * olen,const unsigned char * src,size_t slen)144 int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
145 const unsigned char *src, size_t slen )
146 {
147 size_t i, n;
148 uint32_t j, x;
149 unsigned char *p;
150
151 /* First pass: check for validity and get output length */
152 for( i = n = j = 0; i < slen; i++ )
153 {
154 /* Skip spaces before checking for EOL */
155 x = 0;
156 while( i < slen && src[i] == ' ' )
157 {
158 ++i;
159 ++x;
160 }
161
162 /* Spaces at end of buffer are OK */
163 if( i == slen )
164 break;
165
166 if( ( slen - i ) >= 2 &&
167 src[i] == '\r' && src[i + 1] == '\n' )
168 continue;
169
170 if( src[i] == '\n' )
171 continue;
172
173 /* Space inside a line is an error */
174 if( x != 0 )
175 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
176
177 if( src[i] == '=' && ++j > 2 )
178 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
179
180 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
181 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
182
183 if( base64_dec_map[src[i]] < 64 && j != 0 )
184 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
185
186 n++;
187 }
188
189 if( n == 0 )
190 {
191 *olen = 0;
192 return( 0 );
193 }
194
195 n = ( ( n * 6 ) + 7 ) >> 3;
196 n -= j;
197
198 if( dst == NULL || dlen < n )
199 {
200 *olen = n;
201 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
202 }
203
204 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
205 {
206 if( *src == '\r' || *src == '\n' || *src == ' ' )
207 continue;
208
209 j -= ( base64_dec_map[*src] == 64 );
210 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
211
212 if( ++n == 4 )
213 {
214 n = 0;
215 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
216 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
217 if( j > 2 ) *p++ = (unsigned char)( x );
218 }
219 }
220
221 *olen = p - dst;
222
223 return( 0 );
224 }
225
226 #if defined(MBEDTLS_SELF_TEST)
227
228 static const unsigned char base64_test_dec[64] =
229 {
230 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
231 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
232 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
233 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
234 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
235 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
236 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
237 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
238 };
239
240 static const unsigned char base64_test_enc[] =
241 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
242 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
243
244 /*
245 * Checkup routine
246 */
mbedtls_base64_self_test(int verbose)247 int mbedtls_base64_self_test( int verbose )
248 {
249 size_t len;
250 const unsigned char *src;
251 unsigned char buffer[128];
252
253 if( verbose != 0 )
254 mbedtls_printf( " Base64 encoding test: " );
255
256 src = base64_test_dec;
257
258 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
259 memcmp( base64_test_enc, buffer, 88 ) != 0 )
260 {
261 if( verbose != 0 )
262 mbedtls_printf( "failed\n" );
263
264 return( 1 );
265 }
266
267 if( verbose != 0 )
268 mbedtls_printf( "passed\n Base64 decoding test: " );
269
270 src = base64_test_enc;
271
272 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
273 memcmp( base64_test_dec, buffer, 64 ) != 0 )
274 {
275 if( verbose != 0 )
276 mbedtls_printf( "failed\n" );
277
278 return( 1 );
279 }
280
281 if( verbose != 0 )
282 mbedtls_printf( "passed\n\n" );
283
284 return( 0 );
285 }
286
287 #endif /* MBEDTLS_SELF_TEST */
288
289 #endif /* MBEDTLS_BASE64_C */
290