NeoMutt  2025-12-11-1052-ga8f1ca
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
base64.c
Go to the documentation of this file.
1
23
32
33#include "config.h"
34#include "base64.h"
35#include "buffer.h"
36#include "memory.h"
37#include "string2.h"
38
39#define BAD -1
40
44static const char B64Chars[64] = {
45 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
46 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
47 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
48 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
49 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
50};
51
57static const char B64CharsUrlSafe[64] = {
58 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
59 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
60 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
61 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
62 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
63};
64
74const int Index64[128] = {
75 // clang-format off
76 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
77 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
78 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
79 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
80 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
81 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
82 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
83 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
84 // clang-format on
85};
86
101static size_t b64_encode_common(const char *in, size_t inlen, char *out,
102 size_t outlen, const char *alpha)
103{
104 if (!out)
105 return 0;
106
107 if (!in || inlen == 0)
108 {
109 *out = '\0';
110 return 0;
111 }
112
113 unsigned char *begin = (unsigned char *) out;
114 const unsigned char *inu = (const unsigned char *) in;
115
116 while ((inlen >= 3) && (outlen > 4))
117 {
118 *out++ = alpha[inu[0] >> 2];
119 *out++ = alpha[((inu[0] << 4) & 0x30) | (inu[1] >> 4)];
120 *out++ = alpha[((inu[1] << 2) & 0x3c) | (inu[2] >> 6)];
121 *out++ = alpha[inu[2] & 0x3f];
122 outlen -= 4;
123 inlen -= 3;
124 inu += 3;
125 }
126
127 /* clean up remainder */
128 if ((inlen > 0) && (outlen > 4))
129 {
130 unsigned char fragment;
131
132 *out++ = alpha[inu[0] >> 2];
133 fragment = (inu[0] << 4) & 0x30;
134 if (inlen > 1)
135 fragment |= inu[1] >> 4;
136 *out++ = alpha[fragment];
137 *out++ = (inlen < 2) ? '=' : alpha[(inu[1] << 2) & 0x3c];
138 *out++ = '=';
139 }
140 *out = '\0';
141 return out - (char *) begin;
142}
143
154size_t mutt_b64_encode(const char *in, size_t inlen, char *out, size_t outlen)
155{
156 return b64_encode_common(in, inlen, out, outlen, B64Chars);
157}
158
169size_t mutt_b64_encode_urlsafe(const char *in, size_t inlen, char *out, size_t outlen)
170{
171 return b64_encode_common(in, inlen, out, outlen, B64CharsUrlSafe);
172}
173
186int mutt_b64_decode(const char *in, char *out, size_t olen)
187{
188 if (!in || !*in || !out)
189 return -1;
190
191 int len = 0;
192
193 for (; *in; in += 4)
194 {
195 const unsigned char digit1 = in[0];
196 if ((digit1 > 127) || (base64val(digit1) == BAD))
197 return -1;
198 const unsigned char digit2 = in[1];
199 if ((digit2 > 127) || (base64val(digit2) == BAD))
200 return -1;
201
202 /* The 3rd and 4th bytes can be terminating padding chars ('='). Some
203 * mailers don't properly terminate base64-encoded strings, so we allow for
204 * the input string to terminate without padding. */
205 const unsigned char digit3 = in[2] ? in[2] : '=';
206 if ((digit3 > 127) || ((digit3 != '=') && (base64val(digit3) == BAD)))
207 return -1;
208 const unsigned char digit4 = (digit3 == '=') ? '=' : in[3];
209 if ((digit4 > 127) || ((digit4 != '=') && (base64val(digit4) == BAD)))
210 return -1;
211
212 /* digits are already sanity-checked */
213 if (len == olen)
214 return len;
215 *out++ = (base64val(digit1) << 2) | (base64val(digit2) >> 4);
216 len++;
217 if (digit3 != '=')
218 {
219 if (len == olen)
220 return len;
221 *out++ = ((base64val(digit2) << 4) & 0xf0) | (base64val(digit3) >> 2);
222 len++;
223 if (digit4 != '=')
224 {
225 if (len == olen)
226 return len;
227 *out++ = ((base64val(digit3) << 6) & 0xc0) | base64val(digit4);
228 len++;
229 }
230 }
231
232 /* did we reach the end? */
233 if (digit4 == '=')
234 {
235 break;
236 }
237 }
238
239 return len;
240}
241
249size_t mutt_b64_buffer_encode(struct Buffer *buf, const char *in, size_t len)
250{
251 if (!buf)
252 return 0;
253
254 buf_alloc(buf, MAX((len * 2), 1024));
255 size_t num = mutt_b64_encode(in, len, buf->data, buf->dsize);
256 buf_fix_dptr(buf);
257 return num;
258}
259
267int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
268{
269 if (!buf)
270 return -1;
271
272 buf_alloc(buf, mutt_str_len(in));
273 int olen = mutt_b64_decode(in, buf->data, buf->dsize);
274 // mutt_b64_decode returns raw bytes, so don't terminate the buffer either
275 if (olen > 0)
276 buf_seek(buf, olen);
277 else
278 buf_seek(buf, 0);
279
280 return olen;
281}
size_t mutt_b64_encode(const char *in, size_t inlen, char *out, size_t outlen)
Convert raw bytes to a base64 string.
Definition base64.c:154
size_t mutt_b64_encode_urlsafe(const char *in, size_t inlen, char *out, size_t outlen)
Convert raw bytes to a URL-safe base64 string.
Definition base64.c:169
size_t mutt_b64_buffer_encode(struct Buffer *buf, const char *in, size_t len)
Convert raw bytes to NUL-terminated base64 string.
Definition base64.c:249
int mutt_b64_decode(const char *in, char *out, size_t olen)
Convert NUL-terminated base64 string to raw bytes.
Definition base64.c:186
static const char B64CharsUrlSafe[64]
URL-Safe Characters of the Base64 encoding.
Definition base64.c:57
const int Index64[128]
Lookup table for Base64 encoding characters.
Definition base64.c:74
int mutt_b64_buffer_decode(struct Buffer *buf, const char *in)
Convert NUL-terminated base64 string to raw bytes.
Definition base64.c:267
static size_t b64_encode_common(const char *in, size_t inlen, char *out, size_t outlen, const char *alpha)
Convert raw bytes to NUL-terminated base64 string.
Definition base64.c:101
#define BAD
Definition base64.c:39
Conversion to/from base64 encoding.
#define base64val(ch)
Convert base64 character to its numeric value.
Definition base64.h:33
void buf_seek(struct Buffer *buf, size_t offset)
Set current read/write position to offset from beginning.
Definition buffer.c:628
void buf_fix_dptr(struct Buffer *buf)
Move the dptr to end of the Buffer.
Definition buffer.c:189
void buf_alloc(struct Buffer *buf, size_t new_size)
Make sure a buffer can store at least new_size bytes.
Definition buffer.c:342
General purpose object for storing and parsing strings.
Memory management wrappers.
#define MAX(a, b)
Return the maximum of two values.
Definition memory.h:38
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition string.c:503
String manipulation functions.
String manipulation buffer.
Definition buffer.h:37
size_t dsize
Length of data.
Definition buffer.h:40
char * data
Pointer to data.
Definition buffer.h:38
static const char B64Chars[64]
Characters of the Base64 encoding.
Definition utf7.c:82