blob: 4fa434d18615540c0fc235e628fe2c4d5bb040f5 [file] [log] [blame]
Paul Bakker5121ce52009-01-03 21:22:43 +00001/*
2 * RFC 1521 base64 encoding/decoding
3 *
Manuel Pégourié-Gonnarda658a402015-01-23 09:45:19 +00004 * Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
Paul Bakkerb96f1542010-07-18 20:36:00 +00005 *
Manuel Pégourié-Gonnardfe446432015-03-06 13:17:10 +00006 * This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakkerb96f1542010-07-18 20:36:00 +00007 *
Paul Bakker5121ce52009-01-03 21:22:43 +00008 * 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
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020023#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000024#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020025#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020026#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020027#endif
Paul Bakker5121ce52009-01-03 21:22:43 +000028
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020029#if defined(MBEDTLS_BASE64_C)
Paul Bakker5121ce52009-01-03 21:22:43 +000030
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000031#include "mbedtls/base64.h"
Paul Bakker5121ce52009-01-03 21:22:43 +000032
Manuel Pégourié-Gonnard93866642015-06-22 19:21:23 +020033#include <stdint.h>
Paul Bakker5c2364c2012-10-01 14:41:15 +000034
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020035#if defined(MBEDTLS_SELF_TEST)
Rich Evans00ab4702015-02-06 13:43:58 +000036#include <string.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020037#if defined(MBEDTLS_PLATFORM_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000038#include "mbedtls/platform.h"
Paul Bakker7dc4c442014-02-01 22:50:26 +010039#else
Rich Evans00ab4702015-02-06 13:43:58 +000040#include <stdio.h>
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020041#define mbedtls_printf printf
42#endif /* MBEDTLS_PLATFORM_C */
43#endif /* MBEDTLS_SELF_TEST */
Paul Bakker7dc4c442014-02-01 22:50:26 +010044
Paul Bakker5121ce52009-01-03 21:22:43 +000045static 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 */
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010076int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
Paul Bakker23986e52011-04-24 08:57:21 +000077 const unsigned char *src, size_t slen )
Paul Bakker5121ce52009-01-03 21:22:43 +000078{
Paul Bakker23986e52011-04-24 08:57:21 +000079 size_t i, n;
Paul Bakker5121ce52009-01-03 21:22:43 +000080 int C1, C2, C3;
81 unsigned char *p;
82
83 if( slen == 0 )
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000084 {
Manuel Pégourié-Gonnardba561362015-06-02 16:30:35 +010085 *olen = 0;
Paul Bakker5121ce52009-01-03 21:22:43 +000086 return( 0 );
Manuel Pégourié-Gonnard65fc6a82015-01-28 16:49:26 +000087 }
Paul Bakker5121ce52009-01-03 21:22:43 +000088
Paul Bakker66d5d072014-06-17 16:39:18 +020089 n = ( slen << 3 ) / 6;
Paul Bakker5121ce52009-01-03 21:22:43 +000090
Paul Bakker66d5d072014-06-17 16:39:18 +020091 switch( ( slen << 3 ) - ( n * 6 ) )
Paul Bakker5121ce52009-01-03 21:22:43 +000092 {
93 case 2: n += 3; break;
94 case 4: n += 2; break;
95 default: break;
96 }
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 */