Coverage Report

Created: 2025-07-01 06:54

/work/mbedtls-2.28.8/library/base64.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *  RFC 1521 base64 encoding/decoding
3
 *
4
 *  Copyright The Mbed TLS Contributors
5
 *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6
 */
7
8
#include "common.h"
9
10
#if defined(MBEDTLS_BASE64_C)
11
12
#include "mbedtls/base64.h"
13
#include "constant_time_internal.h"
14
15
#include <stdint.h>
16
17
#if defined(MBEDTLS_SELF_TEST)
18
#include <string.h>
19
#include "mbedtls/platform.h"
20
#endif /* MBEDTLS_SELF_TEST */
21
22
0
#define BASE64_SIZE_T_MAX   ((size_t) -1)   /* SIZE_T_MAX is not standard */
23
24
/*
25
 * Encode a buffer into base64 format
26
 */
27
int mbedtls_base64_encode(unsigned char *dst, size_t dlen, size_t *olen,
28
                          const unsigned char *src, size_t slen)
29
0
{
30
0
    size_t i, n;
31
0
    int C1, C2, C3;
32
0
    unsigned char *p;
33
34
0
    if (slen == 0) {
35
0
        *olen = 0;
36
0
        return 0;
37
0
    }
38
39
0
    n = slen / 3 + (slen % 3 != 0);
40
41
0
    if (n > (BASE64_SIZE_T_MAX - 1) / 4) {
42
0
        *olen = BASE64_SIZE_T_MAX;
43
0
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
44
0
    }
45
46
0
    n *= 4;
47
48
0
    if ((dlen < n + 1) || (NULL == dst)) {
49
0
        *olen = n + 1;
50
0
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
51
0
    }
52
53
0
    n = (slen / 3) * 3;
54
55
0
    for (i = 0, p = dst; i < n; i += 3) {
56
0
        C1 = *src++;
57
0
        C2 = *src++;
58
0
        C3 = *src++;
59
60
0
        *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
61
0
        *p++ = mbedtls_ct_base64_enc_char((((C1 &  3) << 4) + (C2 >> 4))
62
0
                                          & 0x3F);
63
0
        *p++ = mbedtls_ct_base64_enc_char((((C2 & 15) << 2) + (C3 >> 6))
64
0
                                          & 0x3F);
65
0
        *p++ = mbedtls_ct_base64_enc_char(C3 & 0x3F);
66
0
    }
67
68
0
    if (i < slen) {
69
0
        C1 = *src++;
70
0
        C2 = ((i + 1) < slen) ? *src++ : 0;
71
72
0
        *p++ = mbedtls_ct_base64_enc_char((C1 >> 2) & 0x3F);
73
0
        *p++ = mbedtls_ct_base64_enc_char((((C1 & 3) << 4) + (C2 >> 4))
74
0
                                          & 0x3F);
75
76
0
        if ((i + 1) < slen) {
77
0
            *p++ = mbedtls_ct_base64_enc_char(((C2 & 15) << 2) & 0x3F);
78
0
        } else {
79
0
            *p++ = '=';
80
0
        }
81
82
0
        *p++ = '=';
83
0
    }
84
85
0
    *olen = p - dst;
86
0
    *p = 0;
87
88
0
    return 0;
89
0
}
90
91
/*
92
 * Decode a base64-formatted buffer
93
 */
94
int mbedtls_base64_decode(unsigned char *dst, size_t dlen, size_t *olen,
95
                          const unsigned char *src, size_t slen)
96
0
{
97
0
    size_t i; /* index in source */
98
0
    size_t n; /* number of digits or trailing = in source */
99
0
    uint32_t x; /* value accumulator */
100
0
    unsigned accumulated_digits = 0;
101
0
    unsigned equals = 0;
102
0
    int spaces_present = 0;
103
0
    unsigned char *p;
104
105
    /* First pass: check for validity and get output length */
106
0
    for (i = n = 0; i < slen; i++) {
107
        /* Skip spaces before checking for EOL */
108
0
        spaces_present = 0;
109
0
        while (i < slen && src[i] == ' ') {
110
0
            ++i;
111
0
            spaces_present = 1;
112
0
        }
113
114
        /* Spaces at end of buffer are OK */
115
0
        if (i == slen) {
116
0
            break;
117
0
        }
118
119
0
        if ((slen - i) >= 2 &&
120
0
            src[i] == '\r' && src[i + 1] == '\n') {
121
0
            continue;
122
0
        }
123
124
0
        if (src[i] == '\n') {
125
0
            continue;
126
0
        }
127
128
        /* Space inside a line is an error */
129
0
        if (spaces_present) {
130
0
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
131
0
        }
132
133
0
        if (src[i] > 127) {
134
0
            return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
135
0
        }
136
137
0
        if (src[i] == '=') {
138
0
            if (++equals > 2) {
139
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
140
0
            }
141
0
        } else {
142
0
            if (equals != 0) {
143
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
144
0
            }
145
0
            if (mbedtls_ct_base64_dec_value(src[i]) < 0) {
146
0
                return MBEDTLS_ERR_BASE64_INVALID_CHARACTER;
147
0
            }
148
0
        }
149
0
        n++;
150
0
    }
151
152
0
    if (n == 0) {
153
0
        *olen = 0;
154
0
        return 0;
155
0
    }
156
157
    /* The following expression is to calculate the following formula without
158
     * risk of integer overflow in n:
159
     *     n = ( ( n * 6 ) + 7 ) >> 3;
160
     */
161
0
    n = (6 * (n >> 3)) + ((6 * (n & 0x7) + 7) >> 3);
162
0
    n -= equals;
163
164
0
    if (dst == NULL || dlen < n) {
165
0
        *olen = n;
166
0
        return MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL;
167
0
    }
168
169
0
    equals = 0;
170
0
    for (x = 0, p = dst; i > 0; i--, src++) {
171
0
        if (*src == '\r' || *src == '\n' || *src == ' ') {
172
0
            continue;
173
0
        }
174
175
0
        x = x << 6;
176
0
        if (*src == '=') {
177
0
            ++equals;
178
0
        } else {
179
0
            x |= mbedtls_ct_base64_dec_value(*src);
180
0
        }
181
182
0
        if (++accumulated_digits == 4) {
183
0
            accumulated_digits = 0;
184
0
            *p++ = MBEDTLS_BYTE_2(x);
185
0
            if (equals <= 1) {
186
0
                *p++ = MBEDTLS_BYTE_1(x);
187
0
            }
188
0
            if (equals <= 0) {
189
0
                *p++ = MBEDTLS_BYTE_0(x);
190
0
            }
191
0
        }
192
0
    }
193
194
0
    *olen = p - dst;
195
196
0
    return 0;
197
0
}
198
199
#if defined(MBEDTLS_SELF_TEST)
200
201
static const unsigned char base64_test_dec[64] =
202
{
203
    0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD,
204
    0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01,
205
    0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09,
206
    0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13,
207
    0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31,
208
    0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38,
209
    0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B,
210
    0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97
211
};
212
213
static const unsigned char base64_test_enc[] =
214
    "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK"
215
    "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw==";
216
217
/*
218
 * Checkup routine
219
 */
220
int mbedtls_base64_self_test(int verbose)
221
0
{
222
0
    size_t len;
223
0
    const unsigned char *src;
224
0
    unsigned char buffer[128];
225
226
0
    if (verbose != 0) {
227
0
        mbedtls_printf("  Base64 encoding test: ");
228
0
    }
229
230
0
    src = base64_test_dec;
231
232
0
    if (mbedtls_base64_encode(buffer, sizeof(buffer), &len, src, 64) != 0 ||
233
0
        memcmp(base64_test_enc, buffer, 88) != 0) {
234
0
        if (verbose != 0) {
235
0
            mbedtls_printf("failed\n");
236
0
        }
237
238
0
        return 1;
239
0
    }
240
241
0
    if (verbose != 0) {
242
0
        mbedtls_printf("passed\n  Base64 decoding test: ");
243
0
    }
244
245
0
    src = base64_test_enc;
246
247
0
    if (mbedtls_base64_decode(buffer, sizeof(buffer), &len, src, 88) != 0 ||
248
0
        memcmp(base64_test_dec, buffer, 64) != 0) {
249
0
        if (verbose != 0) {
250
0
            mbedtls_printf("failed\n");
251
0
        }
252
253
0
        return 1;
254
0
    }
255
256
0
    if (verbose != 0) {
257
0
        mbedtls_printf("passed\n\n");
258
0
    }
259
260
0
    return 0;
261
0
}
262
263
#endif /* MBEDTLS_SELF_TEST */
264
265
#endif /* MBEDTLS_BASE64_C */