Coverage Report

Created: 2026-05-14 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/tvbuff_base64.c
Line
Count
Source
1
/* tvbuff_base64.c
2
 * Base-64 tvbuff implementation (based on real tvb)
3
 *
4
 * Wireshark - Network traffic analyzer
5
 * By Gerald Combs <gerald@wireshark.org>
6
 * Copyright 1998 Gerald Combs
7
 *
8
 * SPDX-License-Identifier: GPL-2.0-or-later
9
 */
10
11
#include "config.h"
12
13
#include <glib.h>
14
15
#include <epan/tvbuff.h>
16
#include "proto.h"
17
18
/* Copy of glib function modified for base64uri */
19
20
static const unsigned char mime_base64uri_rank[256] = {
21
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
22
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
23
  255,255,255,255,255,255,255,255,255,255,255, 255,255,63,255,255,
24
   52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,  0,255,255,
25
  255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
26
   15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255, 63,
27
  255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
28
   41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
29
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
30
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
31
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
32
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
33
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
34
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
35
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
36
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
37
};
38
 /**
39
  * Copy of glib function modified for base64uri
40
  * g_base64uri_decode_step: (skip)
41
  * @in: (array length=len) (element-type uint8_t): binary input data
42
  * @len: max length of @in data to decode
43
  * @out: (out caller-allocates) (array) (element-type uint8_t): output buffer
44
  * @state: (inout): Saved state between steps, initialize to 0
45
  * @save: (inout): Saved state between steps, initialize to 0
46
  *
47
  * Incrementally decode a sequence of binary data from its Base-64 stringified
48
  * representation. By calling this function multiple times you can convert
49
  * data in chunks to avoid having to have the full encoded data in memory.
50
  *
51
  * The output buffer must be large enough to fit all the data that will
52
  * be written to it. Since base64 encodes 3 bytes in 4 chars you need
53
  * at least: (@len / 4) * 3 + 3 bytes (+ 3 may be needed in case of non-zero
54
  * state).
55
  *
56
  * Returns: The number of bytes of output that was written
57
  *
58
  * Since: 2.12
59
  **/
60
static size_t
61
g_base64uri_decode_step(const char* in,
62
    size_t        len,
63
    unsigned char* out,
64
    int* state,
65
    unsigned* save)
66
0
{
67
0
    const unsigned char* inptr;
68
0
    unsigned char* outptr;
69
0
    const unsigned char* inend;
70
0
    unsigned char c, rank;
71
0
    unsigned char last[2];
72
0
    unsigned int v;
73
0
    int i;
74
75
0
    g_return_val_if_fail(in != NULL || len == 0, 0);
76
0
    g_return_val_if_fail(out != NULL, 0);
77
0
    g_return_val_if_fail(state != NULL, 0);
78
0
    g_return_val_if_fail(save != NULL, 0);
79
80
0
    if (len == 0)
81
0
        return 0;
82
83
0
    inend = (const unsigned char*)in + len;
84
0
    outptr = out;
85
86
    /* convert 4 base64 bytes to 3 normal bytes */
87
0
    v = *save;
88
0
    i = *state;
89
90
0
    last[0] = last[1] = 0;
91
92
    /* we use the sign in the state to determine if we got a padding character
93
       in the previous sequence */
94
0
    if (i < 0)
95
0
    {
96
0
        i = -i;
97
0
        last[0] = '=';
98
0
    }
99
100
0
    inptr = (const unsigned char*)in;
101
0
    while (inptr < inend)
102
0
    {
103
0
        c = *inptr++;
104
0
        rank = mime_base64uri_rank[c];
105
0
        if (rank != 0xff)
106
0
        {
107
0
            last[1] = last[0];
108
0
            last[0] = c;
109
0
            v = (v << 6) | rank;
110
0
            i++;
111
0
            if (i == 4)
112
0
            {
113
0
                *outptr++ = v >> 16;
114
0
                if (last[1] != '=')
115
0
                    *outptr++ = v >> 8;
116
0
                if (last[0] != '=')
117
0
                    *outptr++ = v;
118
0
                i = 0;
119
0
            }
120
0
        }
121
0
    }
122
123
0
    *save = v;
124
0
    *state = last[0] == '=' ? -i : i;
125
126
0
    return outptr - out;
127
0
}
128
 /**
129
  * Copy of glib function modified for base64uri
130
  * g_base64uri_decode:
131
  * @text: (not nullable): zero-terminated string with base64 text to decode
132
  * @out_len: (out): The length of the decoded data is written here
133
  *
134
  * Decode a sequence of Base-64 encoded text into binary data.  Note
135
  * that the returned binary data is not necessarily zero-terminated,
136
  * so it should not be used as a character string.
137
  *
138
  * Returns: (transfer full) (array length=out_len) (element-type uint8_t):
139
  *               newly allocated buffer containing the binary data
140
  *               that @text represents. The returned buffer must
141
  *               be freed with g_free().
142
  *
143
  * Since: 2.12
144
  */
145
static unsigned char*
146
g_base64uri_decode(const char* text,
147
    size_t* out_len)
148
0
{
149
0
    unsigned char* ret;
150
0
    size_t input_length;
151
0
    int state = 0;
152
0
    unsigned save = 0;
153
154
0
    g_return_val_if_fail(text != NULL, NULL);
155
0
    g_return_val_if_fail(out_len != NULL, NULL);
156
157
0
    input_length = strlen(text);
158
159
    /* We can use a smaller limit here, since we know the saved state is 0,
160
       +1 used to avoid calling g_malloc0(0), and hence returning NULL */
161
0
    ret = (unsigned char * )g_malloc0((input_length / 4) * 3 + 1);
162
163
0
    *out_len = g_base64uri_decode_step(text, input_length, ret, &state, &save);
164
165
0
    return ret;
166
0
}
167
168
tvbuff_t *
169
base64_to_tvb(tvbuff_t *parent, const char *base64)
170
0
{
171
0
  tvbuff_t *tvb;
172
0
  uint8_t *data;
173
0
  size_t len;
174
175
0
  data = g_base64_decode(base64, &len);
176
0
  tvb = tvb_new_child_real_data(parent, data, (unsigned)len, (unsigned)len);
177
178
0
  tvb_set_free_cb(tvb, g_free);
179
180
0
  return tvb;
181
0
}
182
183
tvbuff_t*
184
base64_tvb_to_new_tvb(tvbuff_t* parent, unsigned offset, unsigned length)
185
1
{
186
1
    tvbuff_t* tvb;
187
1
    uint8_t* data, *tmp;
188
1
    size_t len;
189
190
    /* g_base64_decode only requires NULL termination, not a valid UTF-8
191
     * or ASCII string (it silently skips over invalid bytes, we don't
192
     * check that either). So tvb_get_raw_bytes_as_string() would work,
193
     * but we would need to check the length before allocating the buffer
194
     * to avoid a memory leak (or push a CLEANUP function on exception).
195
     *
196
     * We could also implement our own function that took a length and
197
     * didn't require NULL termination.
198
     */
199
1
    tmp = tvb_get_string_enc(NULL, parent, offset, length, ENC_ASCII);
200
1
    data = g_base64_decode((const char*)tmp, &len);
201
1
    wmem_free(NULL, tmp);
202
203
1
    tvb = tvb_new_child_real_data(parent, data, (unsigned)len, (unsigned)len);
204
205
1
    tvb_set_free_cb(tvb, g_free);
206
207
1
    return tvb;
208
1
}
209
210
tvbuff_t*
211
base64uri_tvb_to_new_tvb(tvbuff_t* parent, unsigned offset, unsigned length)
212
0
{
213
0
    tvbuff_t* tvb;
214
0
    uint8_t* data, *tmp;
215
0
    size_t len = 0;
216
217
0
    tmp = tvb_get_string_enc(NULL, parent, offset, length, ENC_ASCII);
218
0
    data = g_base64uri_decode((const char*)tmp, &len);
219
0
    wmem_free(NULL, tmp);
220
221
0
    tvb = tvb_new_child_real_data(parent, data, (unsigned)len, (unsigned)len);
222
223
0
    tvb_set_free_cb(tvb, g_free);
224
225
0
    return tvb;
226
0
}
227
/*
228
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
229
 *
230
 * Local Variables:
231
 * c-basic-offset: 2
232
 * tab-width: 8
233
 * indent-tabs-mode: nil
234
 * End:
235
 *
236
 * ex: set shiftwidth=2 tabstop=8 expandtab:
237
 * :indentSize=2:tabSize=8:noTabs=true:
238
 */