xref: /optee_os/lib/libmbedtls/mbedtls/library/base64.c (revision 039e02df2716a0ed886b56e1e07b7ac1d8597228)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  RFC 1521 base64 encoding/decoding
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
57901324dSJerome Forissier  *  SPDX-License-Identifier: Apache-2.0
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  */
19817466cbSJens Wiklander 
207901324dSJerome Forissier #include "common.h"
21817466cbSJens Wiklander 
22817466cbSJens Wiklander #if defined(MBEDTLS_BASE64_C)
23817466cbSJens Wiklander 
24817466cbSJens Wiklander #include "mbedtls/base64.h"
25*039e02dfSJerome Forissier #include "constant_time_internal.h"
26817466cbSJens Wiklander 
27817466cbSJens Wiklander #include <stdint.h>
28817466cbSJens Wiklander 
29817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
30817466cbSJens Wiklander #include <string.h>
31817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
32817466cbSJens Wiklander #include "mbedtls/platform.h"
33817466cbSJens Wiklander #else
34817466cbSJens Wiklander #include <stdio.h>
35817466cbSJens Wiklander #define mbedtls_printf printf
36817466cbSJens Wiklander #endif /* MBEDTLS_PLATFORM_C */
37817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
38817466cbSJens Wiklander 
39817466cbSJens Wiklander #define BASE64_SIZE_T_MAX   ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
40817466cbSJens Wiklander 
41817466cbSJens Wiklander /*
42817466cbSJens Wiklander  * Encode a buffer into base64 format
43817466cbSJens Wiklander  */
44817466cbSJens Wiklander int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen,
45817466cbSJens Wiklander                    const unsigned char *src, size_t slen )
46817466cbSJens Wiklander {
47817466cbSJens Wiklander     size_t i, n;
48817466cbSJens Wiklander     int C1, C2, C3;
49817466cbSJens Wiklander     unsigned char *p;
50817466cbSJens Wiklander 
51817466cbSJens Wiklander     if( slen == 0 )
52817466cbSJens Wiklander     {
53817466cbSJens Wiklander         *olen = 0;
54817466cbSJens Wiklander         return( 0 );
55817466cbSJens Wiklander     }
56817466cbSJens Wiklander 
57817466cbSJens Wiklander     n = slen / 3 + ( slen % 3 != 0 );
58817466cbSJens Wiklander 
59817466cbSJens Wiklander     if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
60817466cbSJens Wiklander     {
61817466cbSJens Wiklander         *olen = BASE64_SIZE_T_MAX;
62817466cbSJens Wiklander         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
63817466cbSJens Wiklander     }
64817466cbSJens Wiklander 
65817466cbSJens Wiklander     n *= 4;
66817466cbSJens Wiklander 
67817466cbSJens Wiklander     if( ( dlen < n + 1 ) || ( NULL == dst ) )
68817466cbSJens Wiklander     {
69817466cbSJens Wiklander         *olen = n + 1;
70817466cbSJens Wiklander         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
71817466cbSJens Wiklander     }
72817466cbSJens Wiklander 
73817466cbSJens Wiklander     n = ( slen / 3 ) * 3;
74817466cbSJens Wiklander 
75817466cbSJens Wiklander     for( i = 0, p = dst; i < n; i += 3 )
76817466cbSJens Wiklander     {
77817466cbSJens Wiklander         C1 = *src++;
78817466cbSJens Wiklander         C2 = *src++;
79817466cbSJens Wiklander         C3 = *src++;
80817466cbSJens Wiklander 
81*039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
82*039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 &  3 ) << 4 ) + ( C2 >> 4 ) )
83*039e02dfSJerome Forissier                                         & 0x3F );
84*039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char( ( ( ( C2 & 15 ) << 2 ) + ( C3 >> 6 ) )
85*039e02dfSJerome Forissier                                         & 0x3F );
86*039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char( C3 & 0x3F );
87817466cbSJens Wiklander     }
88817466cbSJens Wiklander 
89817466cbSJens Wiklander     if( i < slen )
90817466cbSJens Wiklander     {
91817466cbSJens Wiklander         C1 = *src++;
92817466cbSJens Wiklander         C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
93817466cbSJens Wiklander 
94*039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char( ( C1 >> 2 ) & 0x3F );
95*039e02dfSJerome Forissier         *p++ = mbedtls_ct_base64_enc_char( ( ( ( C1 & 3 ) << 4 ) + ( C2 >> 4 ) )
96*039e02dfSJerome Forissier                                         & 0x3F );
97817466cbSJens Wiklander 
98817466cbSJens Wiklander         if( ( i + 1 ) < slen )
99*039e02dfSJerome Forissier              *p++ = mbedtls_ct_base64_enc_char( ( ( C2 & 15 ) << 2 ) & 0x3F );
100817466cbSJens Wiklander         else *p++ = '=';
101817466cbSJens Wiklander 
102817466cbSJens Wiklander         *p++ = '=';
103817466cbSJens Wiklander     }
104817466cbSJens Wiklander 
105817466cbSJens Wiklander     *olen = p - dst;
106817466cbSJens Wiklander     *p = 0;
107817466cbSJens Wiklander 
108817466cbSJens Wiklander     return( 0 );
109817466cbSJens Wiklander }
110817466cbSJens Wiklander 
111817466cbSJens Wiklander /*
112817466cbSJens Wiklander  * Decode a base64-formatted buffer
113817466cbSJens Wiklander  */
114817466cbSJens Wiklander int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen,
115817466cbSJens Wiklander                    const unsigned char *src, size_t slen )
116817466cbSJens Wiklander {
117*039e02dfSJerome Forissier     size_t i; /* index in source */
118*039e02dfSJerome Forissier     size_t n; /* number of digits or trailing = in source */
119*039e02dfSJerome Forissier     uint32_t x; /* value accumulator */
120*039e02dfSJerome Forissier     unsigned accumulated_digits = 0;
121*039e02dfSJerome Forissier     unsigned equals = 0;
122*039e02dfSJerome Forissier     int spaces_present = 0;
123817466cbSJens Wiklander     unsigned char *p;
124817466cbSJens Wiklander 
125817466cbSJens Wiklander     /* First pass: check for validity and get output length */
126*039e02dfSJerome Forissier     for( i = n = 0; i < slen; i++ )
127817466cbSJens Wiklander     {
128817466cbSJens Wiklander         /* Skip spaces before checking for EOL */
129*039e02dfSJerome Forissier         spaces_present = 0;
130817466cbSJens Wiklander         while( i < slen && src[i] == ' ' )
131817466cbSJens Wiklander         {
132817466cbSJens Wiklander             ++i;
133*039e02dfSJerome Forissier             spaces_present = 1;
134817466cbSJens Wiklander         }
135817466cbSJens Wiklander 
136817466cbSJens Wiklander         /* Spaces at end of buffer are OK */
137817466cbSJens Wiklander         if( i == slen )
138817466cbSJens Wiklander             break;
139817466cbSJens Wiklander 
140817466cbSJens Wiklander         if( ( slen - i ) >= 2 &&
141817466cbSJens Wiklander             src[i] == '\r' && src[i + 1] == '\n' )
142817466cbSJens Wiklander             continue;
143817466cbSJens Wiklander 
144817466cbSJens Wiklander         if( src[i] == '\n' )
145817466cbSJens Wiklander             continue;
146817466cbSJens Wiklander 
147817466cbSJens Wiklander         /* Space inside a line is an error */
148*039e02dfSJerome Forissier         if( spaces_present )
149817466cbSJens Wiklander             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
150817466cbSJens Wiklander 
151*039e02dfSJerome Forissier         if( src[i] > 127 )
152817466cbSJens Wiklander             return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
153817466cbSJens Wiklander 
154*039e02dfSJerome Forissier         if( src[i] == '=' )
155*039e02dfSJerome Forissier         {
156*039e02dfSJerome Forissier             if( ++equals > 2 )
157817466cbSJens Wiklander                 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
158*039e02dfSJerome Forissier         }
159*039e02dfSJerome Forissier         else
160*039e02dfSJerome Forissier         {
161*039e02dfSJerome Forissier             if( equals != 0 )
162817466cbSJens Wiklander                 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
163*039e02dfSJerome Forissier             if( mbedtls_ct_base64_dec_value( src[i] ) < 0 )
164*039e02dfSJerome Forissier                 return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER );
165*039e02dfSJerome Forissier         }
166817466cbSJens Wiklander         n++;
167817466cbSJens Wiklander     }
168817466cbSJens Wiklander 
169817466cbSJens Wiklander     if( n == 0 )
170817466cbSJens Wiklander     {
171817466cbSJens Wiklander         *olen = 0;
172817466cbSJens Wiklander         return( 0 );
173817466cbSJens Wiklander     }
174817466cbSJens Wiklander 
175817466cbSJens Wiklander     /* The following expression is to calculate the following formula without
176817466cbSJens Wiklander      * risk of integer overflow in n:
177817466cbSJens Wiklander      *     n = ( ( n * 6 ) + 7 ) >> 3;
178817466cbSJens Wiklander      */
179817466cbSJens Wiklander     n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 );
180*039e02dfSJerome Forissier     n -= equals;
181817466cbSJens Wiklander 
182817466cbSJens Wiklander     if( dst == NULL || dlen < n )
183817466cbSJens Wiklander     {
184817466cbSJens Wiklander         *olen = n;
185817466cbSJens Wiklander         return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL );
186817466cbSJens Wiklander     }
187817466cbSJens Wiklander 
188*039e02dfSJerome Forissier     equals = 0;
189*039e02dfSJerome Forissier     for( x = 0, p = dst; i > 0; i--, src++ )
190817466cbSJens Wiklander     {
191817466cbSJens Wiklander         if( *src == '\r' || *src == '\n' || *src == ' ' )
192817466cbSJens Wiklander             continue;
193817466cbSJens Wiklander 
194*039e02dfSJerome Forissier         x = x << 6;
195*039e02dfSJerome Forissier         if( *src == '=' )
196*039e02dfSJerome Forissier             ++equals;
197*039e02dfSJerome Forissier         else
198*039e02dfSJerome Forissier             x |= mbedtls_ct_base64_dec_value( *src );
1997901324dSJerome Forissier 
200*039e02dfSJerome Forissier         if( ++accumulated_digits == 4 )
201817466cbSJens Wiklander         {
202*039e02dfSJerome Forissier             accumulated_digits = 0;
203*039e02dfSJerome Forissier             *p++ = MBEDTLS_BYTE_2( x );
204*039e02dfSJerome Forissier             if( equals <= 1 ) *p++ = MBEDTLS_BYTE_1( x );
205*039e02dfSJerome Forissier             if( equals <= 0 ) *p++ = MBEDTLS_BYTE_0( x );
206817466cbSJens Wiklander         }
207817466cbSJens Wiklander     }
208817466cbSJens Wiklander 
209817466cbSJens Wiklander     *olen = p - dst;
210817466cbSJens Wiklander 
211817466cbSJens Wiklander     return( 0 );
212817466cbSJens Wiklander }
213817466cbSJens Wiklander 
214817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
215817466cbSJens Wiklander 
216817466cbSJens Wiklander static const unsigned char base64_test_dec[64] =
217817466cbSJens Wiklander {
218817466cbSJens Wiklander     0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
219817466cbSJens Wiklander     0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
220817466cbSJens Wiklander     0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
221817466cbSJens Wiklander     0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
222817466cbSJens Wiklander     0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
223817466cbSJens Wiklander     0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
224817466cbSJens Wiklander     0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
225817466cbSJens Wiklander     0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
226817466cbSJens Wiklander };
227817466cbSJens Wiklander 
228817466cbSJens Wiklander static const unsigned char base64_test_enc[] =
229817466cbSJens Wiklander     "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
230817466cbSJens Wiklander     "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
231817466cbSJens Wiklander 
232817466cbSJens Wiklander /*
233817466cbSJens Wiklander  * Checkup routine
234817466cbSJens Wiklander  */
235817466cbSJens Wiklander int mbedtls_base64_self_test( int verbose )
236817466cbSJens Wiklander {
237817466cbSJens Wiklander     size_t len;
238817466cbSJens Wiklander     const unsigned char *src;
239817466cbSJens Wiklander     unsigned char buffer[128];
240817466cbSJens Wiklander 
241817466cbSJens Wiklander     if( verbose != 0 )
242817466cbSJens Wiklander         mbedtls_printf( "  Base64 encoding test: " );
243817466cbSJens Wiklander 
244817466cbSJens Wiklander     src = base64_test_dec;
245817466cbSJens Wiklander 
246817466cbSJens Wiklander     if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 ||
247817466cbSJens Wiklander          memcmp( base64_test_enc, buffer, 88 ) != 0 )
248817466cbSJens Wiklander     {
249817466cbSJens Wiklander         if( verbose != 0 )
250817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
251817466cbSJens Wiklander 
252817466cbSJens Wiklander         return( 1 );
253817466cbSJens Wiklander     }
254817466cbSJens Wiklander 
255817466cbSJens Wiklander     if( verbose != 0 )
256817466cbSJens Wiklander         mbedtls_printf( "passed\n  Base64 decoding test: " );
257817466cbSJens Wiklander 
258817466cbSJens Wiklander     src = base64_test_enc;
259817466cbSJens Wiklander 
260817466cbSJens Wiklander     if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 ||
261817466cbSJens Wiklander          memcmp( base64_test_dec, buffer, 64 ) != 0 )
262817466cbSJens Wiklander     {
263817466cbSJens Wiklander         if( verbose != 0 )
264817466cbSJens Wiklander             mbedtls_printf( "failed\n" );
265817466cbSJens Wiklander 
266817466cbSJens Wiklander         return( 1 );
267817466cbSJens Wiklander     }
268817466cbSJens Wiklander 
269817466cbSJens Wiklander     if( verbose != 0 )
270817466cbSJens Wiklander         mbedtls_printf( "passed\n\n" );
271817466cbSJens Wiklander 
272817466cbSJens Wiklander     return( 0 );
273817466cbSJens Wiklander }
274817466cbSJens Wiklander 
275817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
276817466cbSJens Wiklander 
277817466cbSJens Wiklander #endif /* MBEDTLS_BASE64_C */
278