/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 | | */ |