blob: 16c254da92cee6c9478f0b2a957c42e32e59d99f [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 )
187 return( 0 );
188
Paul Bakker66d5d072014-06-17 16:39:18 +0200189 n = ( ( n * 6 ) + 7 ) >> 3;
Paul Bakkerd5983182014-07-04 13:50:31 +0200190 n -= j;
Paul Bakker5121ce52009-01-03 21:22:43 +0000191
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100192 if( dst == NULL || dlen < n )
Paul Bakker5121ce52009-01-03 21:22:43 +0000193 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100194 *olen = n;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200195 return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
Paul Bakker5121ce52009-01-03 21:22:43 +0000196 }
197
198 for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
199 {
Manuel Pégourié-Gonnard64938c62014-10-15 21:45:39 +0200200 if( *src == '\r' || *src == '\n' || *src == ' ' )
Paul Bakker5121ce52009-01-03 21:22:43 +0000201 continue;
202
203 j -= ( base64_dec_map[*src] == 64 );
Paul Bakker66d5d072014-06-17 16:39:18 +0200204 x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F );
Paul Bakker5121ce52009-01-03 21:22:43 +0000205
206 if( ++n == 4 )
207 {
208 n = 0;
209 if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
210 if( j > 1 ) *p++ = (unsigned char)( x >> 8 );
211 if( j > 2 ) *p++ = (unsigned char)( x );
212 }
213 }
214
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100215 *olen = p - dst;
Paul Bakker5121ce52009-01-03 21:22:43 +0000216
217 return( 0 );
218}
219
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200220#if defined(MBEDTLS_SELF_TEST)
Paul Bakker5121ce52009-01-03 21:22:43 +0000221
Paul Bakker5121ce52009-01-03 21:22:43 +0000222static const unsigned char base64_test_dec[64] =
223{
224 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
225 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
226 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
227 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
228 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
229 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
230 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
231 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
232};
233
234static const unsigned char base64_test_enc[] =
235 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
236 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
237
238/*
239 * Checkup routine
240 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200241int mbedtls_base64_self_test( int verbose )
Paul Bakker5121ce52009-01-03 21:22:43 +0000242{
Paul Bakker23986e52011-04-24 08:57:21 +0000243 size_t len;
Paul Bakker3c2122f2013-06-24 19:03:14 +0200244 const unsigned char *src;
245 unsigned char buffer[128];
Paul Bakker5121ce52009-01-03 21:22:43 +0000246
247 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200248 mbedtls_printf( " Base64 encoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000249
Paul Bakker3c2122f2013-06-24 19:03:14 +0200250 src = base64_test_dec;
Paul Bakker5121ce52009-01-03 21:22:43 +0000251
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100252 if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
Paul Bakker3c2122f2013-06-24 19:03:14 +0200253 memcmp( base64_test_enc, buffer, 88 ) != 0 )
Paul Bakker5121ce52009-01-03 21:22:43 +0000254 {
255 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200256 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000257
258 return( 1 );
259 }
260
261 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200262 mbedtls_printf( "passed\n Base64 decoding test: " );
Paul Bakker5121ce52009-01-03 21:22:43 +0000263
Paul Bakker3c2122f2013-06-24 19:03:14 +0200264 src = base64_test_enc;
Paul Bakker5121ce52009-01-03 21:22:43 +0000265
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +0100266 if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
Paul Bakker5121ce52009-01-03 21:22:43 +0000267 memcmp( base64_test_dec, buffer, 64 ) != 0 )
268 {
269 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200270 mbedtls_printf( "failed\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000271
272 return( 1 );
273 }
274
275 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200276 mbedtls_printf( "passed\n\n" );
Paul Bakker5121ce52009-01-03 21:22:43 +0000277
278 return( 0 );
279}
280
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200281#endif /* MBEDTLS_SELF_TEST */
Paul Bakker5121ce52009-01-03 21:22:43 +0000282
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200283#endif /* MBEDTLS_BASE64_C */