blob: 8c99538053eb05e861d8a0c197cd69c648997d25 [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 )
188 return( 0 );
189
Paul Bakker66d5d072014-06-17 16:39:18 +0200190 n = ( ( n * 6 ) + 7 ) >> 3;
Paul Bakkerd5983182014-07-04 13:50:31 +0200191 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000192
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100193 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000194 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100195 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200196 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000197 }
198
199 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
200 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200201 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000202 continue;
203
204 j -= ( base64_dec_map[*src] == 64 );
Paul Bakker66d5d072014-06-17 16:39:18 +0200205 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000206
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
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100216 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000217
218 return( 0 );
219}
220
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200221#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000222
Paul Bakker5121ce52009-01-03 21:22:43 +0000223static 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 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200242int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000243{
Paul Bakker23986e52011-04-24 08:57:21 +0000244 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200245 const unsigned char *src;
246 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000247
248 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200249 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000250
Paul Bakker3c2122f2013-06-24 19:03:14 +0200251 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000252
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100253 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200254 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000255 {
256 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200257 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000258
259 return( 1 );
260 }
261
262 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200263 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000264
Paul Bakker3c2122f2013-06-24 19:03:14 +0200265 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000266
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100267 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000268 memcmp( base64_test_dec, buffer, 64 ) != 0 )
269 {
270 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200271 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000272
273 return( 1 );
274 }
275
276 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200277 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000278
279 return( 0 );
280}
281
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200282#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000283
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200284#endif /* MBEDTLS_BASE64_C */