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