blob: e468e2cbcf957f22133e14f1050d50820a22443f [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
Paul Bakker66d5d072014-06-17 16:39:18 +020088 n = ( slen << 3 ) / 6;
Paul Bakker5121ce52009-01-03 21:22:43 +000089
Paul Bakker66d5d072014-06-17 16:39:18 +020090 switch( ( slen << 3 ) - ( n * 6 ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000091 {
92 case 2: n += 3; break;
93 case 4: n += 2; break;
94 default: break;
95 }
96
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010097 if( dlen < n + 1 )
Paul Bakker5121ce52009-01-03 21:22:43 +000098 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010099 *olen = n + 1;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200100 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000101 }
102
Paul Bakker66d5d072014-06-17 16:39:18 +0200103 n = ( slen / 3 ) * 3;
Paul Bakker5121ce52009-01-03 21:22:43 +0000104
105 for( i = 0, p = dst; i < n; i += 3 )
106 {
107 C1 = *src++;
108 C2 = *src++;
109 C3 = *src++;
110
111 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
112 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
113 *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
114 *p++ = base64_enc_map[C3 & 0x3F];
115 }
116
117 if( i < slen )
118 {
119 C1 = *src++;
Paul Bakker66d5d072014-06-17 16:39:18 +0200120 C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000121
122 *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
123 *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
124
Paul Bakker66d5d072014-06-17 16:39:18 +0200125 if( ( i + 1 ) < slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000126 *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
127 else *p++ = '=';
128
129 *p++ = '=';
130 }
131
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100132 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000133 *p = 0;
134
135 return( 0 );
136}
137
138/*
139 * Decode a base64-formatted buffer
140 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100141int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +0000142 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +0000143{
Paul Bakker5c2364c2012-10-01 14:41:15 +0000144 size_t i, n;
145 uint32_t j, x;
Paul Bakker5121ce52009-01-03 21:22:43 +0000146 unsigned char *p;
147
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200148 /* First pass: check for validity and get output length */
Paul Bakkerb9cfaa02013-10-11 18:58:55 +0200149 for( i = n = j = 0; i < slen; i++ )
Paul Bakker5121ce52009-01-03 21:22:43 +0000150 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200151 /* Skip spaces before checking for EOL */
152 x = 0;
153 while( i < slen && src[i] == ' ' )
154 {
155 ++i;
156 ++x;
157 }
158
159 /* Spaces at end of buffer are OK */
160 if( i == slen )
161 break;
162
Paul Bakker5121ce52009-01-03 21:22:43 +0000163 if( ( slen - i ) >= 2 &&
164 src[i] == '\r' && src[i + 1] == '\n' )
165 continue;
166
167 if( src[i] == '\n' )
168 continue;
169
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200170 /* Space inside a line is an error */
171 if( x != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200172 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200173
Paul Bakker5121ce52009-01-03 21:22:43 +0000174 if( src[i] == '=' && ++j > 2 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200175 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000176
177 if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200178 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000179
180 if( base64_dec_map[src[i]] < 64 && j != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200181 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
Paul Bakker5121ce52009-01-03 21:22:43 +0000182
183 n++;
184 }
185
186 if( n == 0 )
Simon Butchera45aa132015-10-05 00:26:36 +0100187 {
188 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +0000189 return( 0 );
Simon Butchera45aa132015-10-05 00:26:36 +0100190 }
Paul Bakker5121ce52009-01-03 21:22:43 +0000191
Paul Bakker66d5d072014-06-17 16:39:18 +0200192 n = ( ( n * 6 ) + 7 ) >> 3;
Paul Bakkerd5983182014-07-04 13:50:31 +0200193 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000194
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100195 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000196 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100197 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200198 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000199 }
200
201 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
202 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200203 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000204 continue;
205
206 j -= ( base64_dec_map[*src] == 64 );
Paul Bakker66d5d072014-06-17 16:39:18 +0200207 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000208
209 if( ++n == 4 )
210 {
211 n = 0;
212 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
213 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
214 if( j > 2 ) *p++ = (unsigned char)( x );
215 }
216 }
217
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100218 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000219
220 return( 0 );
221}
222
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200223#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000224
Paul Bakker5121ce52009-01-03 21:22:43 +0000225static const unsigned char base64_test_dec[64] =
226{
227 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
228 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
229 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
230 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
231 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
232 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
233 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
234 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
235};
236
237static const unsigned char base64_test_enc[] =
238 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
239 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
240
241/*
242 * Checkup routine
243 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200244int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000245{
Paul Bakker23986e52011-04-24 08:57:21 +0000246 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200247 const unsigned char *src;
248 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000249
250 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200251 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000252
Paul Bakker3c2122f2013-06-24 19:03:14 +0200253 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000254
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100255 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200256 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000257 {
258 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200259 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000260
261 return( 1 );
262 }
263
264 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200265 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000266
Paul Bakker3c2122f2013-06-24 19:03:14 +0200267 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000268
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100269 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000270 memcmp( base64_test_dec, buffer, 64 ) != 0 )
271 {
272 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200273 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000274
275 return( 1 );
276 }
277
278 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200279 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000280
281 return( 0 );
282}
283
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200284#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000285
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200286#endif /* MBEDTLS_BASE64_C */