1/*
2 *  RFC 1521 base64 encoding/decoding
3 *
4 *  Based on XySSL: Copyright (C) 2006-2008  Christophe Devine
5 *
6 *  Copyright (C) 2009  Paul Bakker <polarssl_maintainer at polarssl dot org>
7 *
8 *  All rights reserved.
9 *
10 *  Redistribution and use in source and binary forms, with or without
11 *  modification, are permitted provided that the following conditions
12 *  are met:
13 *
14 *    * Redistributions of source code must retain the above copyright
15 *      notice, this list of conditions and the following disclaimer.
16 *    * Redistributions in binary form must reproduce the above copyright
17 *      notice, this list of conditions and the following disclaimer in the
18 *      documentation and/or other materials provided with the distribution.
19 *    * Neither the names of PolarSSL or XySSL nor the names of its contributors
20 *      may be used to endorse or promote products derived from this software
21 *      without specific prior written permission.
22 *
23 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 *  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include "polarssl/config.h"
37
38#if defined(POLARSSL_BASE64_C)
39
40#include "polarssl/base64.h"
41
42static const unsigned char base64_enc_map[64] =
43{
44    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
45    'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
46    'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
47    'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
48    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
49    'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
50    '8', '9', '+', '/'
51};
52
53static const unsigned char base64_dec_map[128] =
54{
55    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
56    127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
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,  62, 127, 127, 127,  63,  52,  53,
60     54,  55,  56,  57,  58,  59,  60,  61, 127, 127,
61    127,  64, 127, 127, 127,   0,   1,   2,   3,   4,
62      5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
63     15,  16,  17,  18,  19,  20,  21,  22,  23,  24,
64     25, 127, 127, 127, 127, 127, 127,  26,  27,  28,
65     29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
66     39,  40,  41,  42,  43,  44,  45,  46,  47,  48,
67     49,  50,  51, 127, 127, 127, 127, 127
68};
69
70/*
71 * Encode a buffer into base64 format
72 */
73int base64_encode( unsigned char *dst, int *dlen,
74                   unsigned char *src, int  slen )
75{
76    int i, n;
77    int C1, C2, C3;
78    unsigned char *p;
79
80    if( slen == 0 )
81        return( 0 );
82
83    n = (slen << 3) / 6;
84
85    switch( (slen << 3) - (n * 6) )
86    {
87        case  2: n += 3; break;
88        case  4: n += 2; break;
89        default: break;
90    }
91
92    if( *dlen < n + 1 )
93    {
94        *dlen = n + 1;
95        return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
96    }
97
98    n = (slen / 3) * 3;
99
100    for( i = 0, p = dst; i < n; i += 3 )
101    {
102        C1 = *src++;
103        C2 = *src++;
104        C3 = *src++;
105
106        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
107        *p++ = base64_enc_map[(((C1 &  3) << 4) + (C2 >> 4)) & 0x3F];
108        *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
109        *p++ = base64_enc_map[C3 & 0x3F];
110    }
111
112    if( i < slen )
113    {
114        C1 = *src++;
115        C2 = ((i + 1) < slen) ? *src++ : 0;
116
117        *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
118        *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
119
120        if( (i + 1) < slen )
121             *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
122        else *p++ = '=';
123
124        *p++ = '=';
125    }
126
127    *dlen = p - dst;
128    *p = 0;
129
130    return( 0 );
131}
132
133/*
134 * Decode a base64-formatted buffer
135 */
136int base64_decode( unsigned char *dst, int *dlen,
137                   unsigned char *src, int  slen )
138{
139    int i, j, n;
140    unsigned long x;
141    unsigned char *p;
142
143    for( i = j = n = 0; i < slen; i++ )
144    {
145        if( ( slen - i ) >= 2 &&
146            src[i] == '\r' && src[i + 1] == '\n' )
147            continue;
148
149        if( src[i] == '\n' )
150            continue;
151
152        if( src[i] == '=' && ++j > 2 )
153            return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
154
155        if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
156            return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
157
158        if( base64_dec_map[src[i]] < 64 && j != 0 )
159            return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
160
161        n++;
162    }
163
164    if( n == 0 )
165        return( 0 );
166
167    n = ((n * 6) + 7) >> 3;
168
169    if( *dlen < n )
170    {
171        *dlen = n;
172        return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL );
173    }
174
175   for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
176   {
177        if( *src == '\r' || *src == '\n' )
178            continue;
179
180        j -= ( base64_dec_map[*src] == 64 );
181        x  = (x << 6) | ( base64_dec_map[*src] & 0x3F );
182
183        if( ++n == 4 )
184        {
185            n = 0;
186            if( j > 0 ) *p++ = (unsigned char)( x >> 16 );
187            if( j > 1 ) *p++ = (unsigned char)( x >>  8 );
188            if( j > 2 ) *p++ = (unsigned char)( x       );
189        }
190    }
191
192    *dlen = p - dst;
193
194    return( 0 );
195}
196
197#if defined(POLARSSL_SELF_TEST)
198
199#include <string.h>
200#include <stdio.h>
201
202static const unsigned char base64_test_dec[64] =
203{
204    0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
205    0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
206    0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
207    0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
208    0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
209    0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
210    0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
211    0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
212};
213
214static const unsigned char base64_test_enc[] =
215    "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
216    "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
217
218/*
219 * Checkup routine
220 */
221int base64_self_test( int verbose )
222{
223    int len;
224    unsigned char *src, buffer[128];
225
226    if( verbose != 0 )
227        printf( "  Base64 encoding test: " );
228
229    len = sizeof( buffer );
230    src = (unsigned char *) base64_test_dec;
231
232    if( base64_encode( buffer, &len, src, 64 ) != 0 ||
233         memcmp( base64_test_enc, buffer, 88 ) != 0 )
234    {
235        if( verbose != 0 )
236            printf( "failed\n" );
237
238        return( 1 );
239    }
240
241    if( verbose != 0 )
242        printf( "passed\n  Base64 decoding test: " );
243
244    len = sizeof( buffer );
245    src = (unsigned char *) base64_test_enc;
246
247    if( base64_decode( buffer, &len, src, 88 ) != 0 ||
248         memcmp( base64_test_dec, buffer, 64 ) != 0 )
249    {
250        if( verbose != 0 )
251            printf( "failed\n" );
252
253        return( 1 );
254    }
255
256    if( verbose != 0 )
257        printf( "passed\n\n" );
258
259    return( 0 );
260}
261
262#endif
263
264#endif
265