2 * RFC 1521 base64 encoding/decoding
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #if defined(MBEDTLS_BASE64_C)
24 #include "mbedtls/base64.h"
28 #if defined(MBEDTLS_SELF_TEST)
30 #if defined(MBEDTLS_PLATFORM_C)
31 #include "mbedtls/platform.h"
34 #define mbedtls_printf printf
35 #endif /* MBEDTLS_PLATFORM_C */
36 #endif /* MBEDTLS_SELF_TEST */
38 static const unsigned char base64_enc_map
[64] = {
39 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
40 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
41 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
42 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
43 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
44 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
48 static const unsigned char base64_dec_map
[128] = {
49 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
50 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
51 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
52 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
53 127, 127, 127, 62, 127, 127, 127, 63, 52, 53,
54 54, 55, 56, 57, 58, 59, 60, 61, 127, 127,
55 127, 64, 127, 127, 127, 0, 1, 2, 3, 4,
56 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
57 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
58 25, 127, 127, 127, 127, 127, 127, 26, 27, 28,
59 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
60 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
61 49, 50, 51, 127, 127, 127, 127, 127
64 #define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
67 * Constant flow conditional assignment to unsigned char
69 static void mbedtls_base64_cond_assign_uchar(unsigned char *dest
, const unsigned char *const src
,
70 unsigned char condition
) {
71 /* MSVC has a warning about unary minus on unsigned integer types,
72 * but this is well-defined and precisely what we want to do here. */
74 #pragma warning( push )
75 #pragma warning( disable : 4146 )
78 /* Generate bitmask from condition, mask will either be 0xFF or 0 */
79 unsigned char mask
= (condition
| -condition
);
84 #pragma warning( pop )
87 *dest
= ((*src
) & mask
) | ((*dest
) & ~mask
);
91 * Constant flow conditional assignment to uint_32
93 static void mbedtls_base64_cond_assign_uint32(uint32_t *dest
, const uint32_t src
,
95 /* MSVC has a warning about unary minus on unsigned integer types,
96 * but this is well-defined and precisely what we want to do here. */
98 #pragma warning( push )
99 #pragma warning( disable : 4146 )
102 /* Generate bitmask from condition, mask will either be 0xFFFFFFFF or 0 */
103 uint32_t mask
= (condition
| -condition
);
107 #if defined(_MSC_VER)
108 #pragma warning( pop )
111 *dest
= (src
& mask
) | ((*dest
) & ~mask
);
115 * Constant flow check for equality
117 static unsigned char mbedtls_base64_eq(size_t in_a
, size_t in_b
) {
118 size_t difference
= in_a
^ in_b
;
120 /* MSVC has a warning about unary minus on unsigned integer types,
121 * but this is well-defined and precisely what we want to do here. */
122 #if defined(_MSC_VER)
123 #pragma warning( push )
124 #pragma warning( disable : 4146 )
127 difference
|= -difference
;
129 #if defined(_MSC_VER)
130 #pragma warning( pop )
133 /* cope with the varying size of size_t per platform */
134 difference
>>= (sizeof(difference
) * 8 - 1);
136 return (unsigned char)(1 ^ difference
);
140 * Constant flow lookup into table.
142 static unsigned char mbedtls_base64_table_lookup(const unsigned char *const table
,
143 const size_t table_size
, const size_t table_index
) {
145 unsigned char result
= 0;
147 for (i
= 0; i
< table_size
; ++i
) {
148 mbedtls_base64_cond_assign_uchar(&result
, &table
[i
], mbedtls_base64_eq(i
, table_index
));
155 * Encode a buffer into base64 format
157 int mbedtls_base64_encode(unsigned char *dst
, size_t dlen
, size_t *olen
,
158 const unsigned char *src
, size_t slen
) {
168 n
= slen
/ 3 + (slen
% 3 != 0);
170 if (n
> (BASE64_SIZE_T_MAX
- 1) / 4) {
171 *olen
= BASE64_SIZE_T_MAX
;
172 return (MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL
);
177 if ((dlen
< n
+ 1) || (NULL
== dst
)) {
179 return (MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL
);
184 for (i
= 0, p
= dst
; i
< n
; i
+= 3) {
189 *p
++ = mbedtls_base64_table_lookup(base64_enc_map
, sizeof(base64_enc_map
),
192 *p
++ = mbedtls_base64_table_lookup(base64_enc_map
, sizeof(base64_enc_map
),
193 ((((C1
& 3) << 4) + (C2
>> 4)) & 0x3F));
195 *p
++ = mbedtls_base64_table_lookup(base64_enc_map
, sizeof(base64_enc_map
),
196 ((((C2
& 15) << 2) + (C3
>> 6)) & 0x3F));
198 *p
++ = mbedtls_base64_table_lookup(base64_enc_map
, sizeof(base64_enc_map
),
204 C2
= ((i
+ 1) < slen
) ? *src
++ : 0;
206 *p
++ = mbedtls_base64_table_lookup(base64_enc_map
, sizeof(base64_enc_map
),
209 *p
++ = mbedtls_base64_table_lookup(base64_enc_map
, sizeof(base64_enc_map
),
210 ((((C1
& 3) << 4) + (C2
>> 4)) & 0x3F));
213 *p
++ = mbedtls_base64_table_lookup(base64_enc_map
, sizeof(base64_enc_map
),
214 (((C2
& 15) << 2) & 0x3F));
227 * Decode a base64-formatted buffer
229 int mbedtls_base64_decode(unsigned char *dst
, size_t dlen
, size_t *olen
,
230 const unsigned char *src
, size_t slen
) {
234 unsigned char dec_map_lookup
;
236 /* First pass: check for validity and get output length */
237 for (i
= n
= j
= 0; i
< slen
; i
++) {
238 /* Skip spaces before checking for EOL */
240 while (i
< slen
&& src
[i
] == ' ') {
245 /* Spaces at end of buffer are OK */
249 if ((slen
- i
) >= 2 &&
250 src
[i
] == '\r' && src
[i
+ 1] == '\n')
256 /* Space inside a line is an error */
258 return (MBEDTLS_ERR_BASE64_INVALID_CHARACTER
);
260 if (src
[i
] == '=' && ++j
> 2)
261 return (MBEDTLS_ERR_BASE64_INVALID_CHARACTER
);
263 dec_map_lookup
= mbedtls_base64_table_lookup(base64_dec_map
, sizeof(base64_dec_map
), src
[i
]);
265 if (src
[i
] > 127 || dec_map_lookup
== 127)
266 return (MBEDTLS_ERR_BASE64_INVALID_CHARACTER
);
268 if (dec_map_lookup
< 64 && j
!= 0)
269 return (MBEDTLS_ERR_BASE64_INVALID_CHARACTER
);
279 /* The following expression is to calculate the following formula without
280 * risk of integer overflow in n:
281 * n = ( ( n * 6 ) + 7 ) >> 3;
283 n
= (6 * (n
>> 3)) + ((6 * (n
& 0x7) + 7) >> 3);
286 if (dst
== NULL
|| dlen
< n
) {
288 return (MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL
);
291 for (j
= 3, n
= x
= 0, p
= dst
; i
> 0; i
--, src
++) {
292 if (*src
== '\r' || *src
== '\n' || *src
== ' ')
295 dec_map_lookup
= mbedtls_base64_table_lookup(base64_dec_map
, sizeof(base64_dec_map
), *src
);
297 mbedtls_base64_cond_assign_uint32(&j
, j
- 1, mbedtls_base64_eq(dec_map_lookup
, 64));
298 x
= (x
<< 6) | (dec_map_lookup
& 0x3F);
302 if (j
> 0) *p
++ = (unsigned char)(x
>> 16);
303 if (j
> 1) *p
++ = (unsigned char)(x
>> 8);
304 if (j
> 2) *p
++ = (unsigned char)(x
);
313 #if defined(MBEDTLS_SELF_TEST)
315 static const unsigned char base64_test_dec
[64] = {
316 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
317 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
318 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
319 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
320 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
321 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
322 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
323 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
326 static const unsigned char base64_test_enc
[] =
327 "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
328 "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
333 int mbedtls_base64_self_test(int verbose
) {
335 const unsigned char *src
;
336 unsigned char buffer
[128];
339 mbedtls_printf(" Base64 encoding test: ");
341 src
= base64_test_dec
;
343 if (mbedtls_base64_encode(buffer
, sizeof(buffer
), &len
, src
, 64) != 0 ||
344 memcmp(base64_test_enc
, buffer
, 88) != 0) {
346 mbedtls_printf("failed\n");
352 mbedtls_printf("passed\n Base64 decoding test: ");
354 src
= base64_test_enc
;
356 if (mbedtls_base64_decode(buffer
, sizeof(buffer
), &len
, src
, 88) != 0 ||
357 memcmp(base64_test_dec
, buffer
, 64) != 0) {
359 mbedtls_printf("failed\n");
365 mbedtls_printf("passed\n\n");
370 #endif /* MBEDTLS_SELF_TEST */
372 #endif /* MBEDTLS_BASE64_C */