blob: fc44c15ae82fcffca61d805791ed7e72f10a49f9 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Manuel Pégourié-Gonnard6fb81872015-07-27 11:11:48 +02004 * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * 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.
Paul Bakkerb96f1542010-07-18 20:36:00 +000018 *
Manuel Pégourié-Gonnardfe446432015-03-06 13:17:10 +000019 * This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakker5121ce52009-01-03 21:22:43 +000020 */
21
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020022#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000023#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020024#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020025#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020026#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000027
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020028#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000029
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000030#include "mbedtls/base64.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000031
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020032#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000033
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020034#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000035#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020036#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000037#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010038#else
Rich Evans00ab4702015-02-06 13:43:58 +000039#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020040#define mbedtls_printf printf
41#endif /* MBEDTLS_PLATFORM_C */
42#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010043
Paul Bakker5121ce52009-01-03 21:22:43 +000044static 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
55static 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/*
73 * Encode a buffer into base64 format
74 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010075int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000076 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000077{
Paul Bakker23986e52011-04-24 08:57:21 +000078 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000079 int C1, C2, C3;
80 unsigned char *p;
81
82 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000083 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010084 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000085 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000086 }
Paul Bakker5121ce52009-01-03 21:22:43 +000087
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020088 n = slen / 3 + ( slen % 3 != 0 );
Paul Bakker5121ce52009-01-03 21:22:43 +000089
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020090 if( n > ( SIZE_T_MAX - 1 ) / 4 )
Paul Bakker5121ce52009-01-03 21:22:43 +000091 {
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020092 *olen = SIZE_T_MAX;
93 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +000094 }
95
Manuel Pégourié-Gonnard0aa45c22015-09-30 16:30:28 +020096 n *= 4;
97
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010098 if( dlen < n + 1 )
Paul Bakker5121ce52009-01-03 21:22:43 +000099 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100100 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200101 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000102 }
103
Paul Bakker66d5d072014-06-17 16:39:18 +0200104 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000105
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++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200121 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000122
123 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
124 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
125
Paul Bakker66d5d072014-06-17 16:39:18 +0200126 if( ( i + 1 ) < slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000127 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
128 else *p++ = '=';
129
130 *p++ = '=';
131 }
132
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100133 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000134 *p = 0;
135
136 return( 0 );
137}
138
139/*
140 * Decode a base64-formatted buffer
141 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100142int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000143 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000144{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000145 size_t i, n;
146 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000147 unsigned char *p;
148
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200149 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200150 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000151 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200152 /* 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
Paul Bakker5121ce52009-01-03 21:22:43 +0000164 if( ( slen - i ) >= 2 &&
165 src[i] == '\r' && src[i + 1] == '\n' )
166 continue;
167
168 if( src[i] == '\n' )
169 continue;
170
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200171 /* Space inside a line is an error */
172 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200173 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200174
Paul Bakker5121ce52009-01-03 21:22:43 +0000175 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200176 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000177
178 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200179 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000180
181 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200182 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000183
184 n++;
185 }
186
187 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100188 {
189 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000190 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100191 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000192
Paul Bakker66d5d072014-06-17 16:39:18 +0200193 n = ( ( n * 6 ) + 7 ) >> 3;
Paul Bakkerd5983182014-07-04 13:50:31 +0200194 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000195
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100196 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000197 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100198 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200199 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000200 }
201
202 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
203 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200204 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000205 continue;
206
207 j -= ( base64_dec_map[*src] == 64 );
Paul Bakker66d5d072014-06-17 16:39:18 +0200208 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000209
210 if( ++n == 4 )
211 {
212 n = 0;
213 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
214 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
215 if( j > 2 ) *p++ = (unsigned char)( x );
216 }
217 }
218
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100219 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000220
221 return( 0 );
222}
223
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200224#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000225
Paul Bakker5121ce52009-01-03 21:22:43 +0000226static const unsigned char base64_test_dec[64] =
227{
228 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
229 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
230 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
231 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
232 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
233 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
234 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
235 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
236};
237
238static const unsigned char base64_test_enc[] =
239 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
240 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
241
242/*
243 * Checkup routine
244 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200245int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000246{
Paul Bakker23986e52011-04-24 08:57:21 +0000247 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200248 const unsigned char *src;
249 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000250
251 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200252 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000253
Paul Bakker3c2122f2013-06-24 19:03:14 +0200254 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000255
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100256 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200257 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000258 {
259 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200260 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000261
262 return( 1 );
263 }
264
265 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200266 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000267
Paul Bakker3c2122f2013-06-24 19:03:14 +0200268 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000269
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100270 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000271 memcmp( base64_test_dec, buffer, 64 ) != 0 )
272 {
273 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200274 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000275
276 return( 1 );
277 }
278
279 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200280 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000281
282 return( 0 );
283}
284
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200285#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000286
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200287#endif /* MBEDTLS_BASE64_C */