Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * base64.c
4 : * Encoding and decoding routines for base64 without whitespace.
5 : *
6 : * Copyright (c) 2001-2026, PostgreSQL Global Development Group
7 : *
8 : *
9 : * IDENTIFICATION
10 : * src/common/base64.c
11 : *
12 : *-------------------------------------------------------------------------
13 : */
14 :
15 : #ifndef FRONTEND
16 : #include "postgres.h"
17 : #else
18 : #include "postgres_fe.h"
19 : #endif
20 :
21 : #include "common/base64.h"
22 :
23 : /*
24 : * BASE64
25 : */
26 :
27 : static const char _base64[] =
28 : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
29 :
30 : static const int8 b64lookup[128] = {
31 : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
34 : 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
35 : -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
36 : 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
37 : -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
38 : 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
39 : };
40 :
41 : /*
42 : * pg_b64_encode
43 : *
44 : * Encode the 'src' byte array into base64. Returns the length of the encoded
45 : * string, and -1 in the event of an error with the result buffer zeroed for
46 : * safety.
47 : */
48 : int
49 455 : pg_b64_encode(const uint8 *src, int len, char *dst, int dstlen)
50 : {
51 : char *p;
52 : const uint8 *s,
53 455 : *end = src + len;
54 455 : int pos = 2;
55 455 : uint32 buf = 0;
56 :
57 455 : s = src;
58 455 : p = dst;
59 :
60 12517 : while (s < end)
61 : {
62 12062 : buf |= *s << (pos << 3);
63 12062 : pos--;
64 12062 : s++;
65 :
66 : /* write it out */
67 12062 : if (pos < 0)
68 : {
69 : /*
70 : * Leave if there is an overflow in the area allocated for the
71 : * encoded string.
72 : */
73 3822 : if ((p - dst + 4) > dstlen)
74 0 : goto error;
75 :
76 3822 : *p++ = _base64[(buf >> 18) & 0x3f];
77 3822 : *p++ = _base64[(buf >> 12) & 0x3f];
78 3822 : *p++ = _base64[(buf >> 6) & 0x3f];
79 3822 : *p++ = _base64[buf & 0x3f];
80 :
81 3822 : pos = 2;
82 3822 : buf = 0;
83 : }
84 : }
85 455 : if (pos != 2)
86 : {
87 : /*
88 : * Leave if there is an overflow in the area allocated for the encoded
89 : * string.
90 : */
91 328 : if ((p - dst + 4) > dstlen)
92 0 : goto error;
93 :
94 328 : *p++ = _base64[(buf >> 18) & 0x3f];
95 328 : *p++ = _base64[(buf >> 12) & 0x3f];
96 328 : *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
97 328 : *p++ = '=';
98 : }
99 :
100 : Assert((p - dst) <= dstlen);
101 455 : return p - dst;
102 :
103 0 : error:
104 0 : memset(dst, 0, dstlen);
105 0 : return -1;
106 : }
107 :
108 : /*
109 : * pg_b64_decode
110 : *
111 : * Decode the given base64 string. Returns the length of the decoded
112 : * string on success, and -1 in the event of an error with the result
113 : * buffer zeroed for safety.
114 : */
115 : int
116 1238 : pg_b64_decode(const char *src, int len, uint8 *dst, int dstlen)
117 : {
118 1238 : const char *srcend = src + len,
119 1238 : *s = src;
120 1238 : uint8 *p = dst;
121 : char c;
122 1238 : int b = 0;
123 1238 : uint32 buf = 0;
124 1238 : int pos = 0,
125 1238 : end = 0;
126 :
127 47734 : while (s < srcend)
128 : {
129 46496 : c = *s++;
130 :
131 : /* Leave if a whitespace is found */
132 46496 : if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
133 0 : goto error;
134 :
135 46496 : if (c == '=')
136 : {
137 : /* end sequence */
138 1650 : if (!end)
139 : {
140 1229 : if (pos == 2)
141 421 : end = 1;
142 808 : else if (pos == 3)
143 808 : end = 2;
144 : else
145 : {
146 : /*
147 : * Unexpected "=" character found while decoding base64
148 : * sequence.
149 : */
150 0 : goto error;
151 : }
152 : }
153 1650 : b = 0;
154 : }
155 : else
156 : {
157 44846 : b = -1;
158 44846 : if (c > 0 && c < 127)
159 44846 : b = b64lookup[(unsigned char) c];
160 44846 : if (b < 0)
161 : {
162 : /* invalid symbol found */
163 0 : goto error;
164 : }
165 : }
166 : /* add it to buffer */
167 46496 : buf = (buf << 6) + b;
168 46496 : pos++;
169 46496 : if (pos == 4)
170 : {
171 : /*
172 : * Leave if there is an overflow in the area allocated for the
173 : * decoded string.
174 : */
175 11624 : if ((p - dst + 1) > dstlen)
176 0 : goto error;
177 11624 : *p++ = (buf >> 16) & 255;
178 :
179 11624 : if (end == 0 || end > 1)
180 : {
181 : /* overflow check */
182 11203 : if ((p - dst + 1) > dstlen)
183 0 : goto error;
184 11203 : *p++ = (buf >> 8) & 255;
185 : }
186 11624 : if (end == 0 || end > 2)
187 : {
188 : /* overflow check */
189 10395 : if ((p - dst + 1) > dstlen)
190 0 : goto error;
191 10395 : *p++ = buf & 255;
192 : }
193 11624 : buf = 0;
194 11624 : pos = 0;
195 : }
196 : }
197 :
198 1238 : if (pos != 0)
199 : {
200 : /*
201 : * base64 end sequence is invalid. Input data is missing padding, is
202 : * truncated or is otherwise corrupted.
203 : */
204 0 : goto error;
205 : }
206 :
207 : Assert((p - dst) <= dstlen);
208 1238 : return p - dst;
209 :
210 0 : error:
211 0 : memset(dst, 0, dstlen);
212 0 : return -1;
213 : }
214 :
215 : /*
216 : * pg_b64_enc_len
217 : *
218 : * Returns to caller the length of the string if it were encoded with
219 : * base64 based on the length provided by caller. This is useful to
220 : * estimate how large a buffer allocation needs to be done before doing
221 : * the actual encoding.
222 : */
223 : int
224 455 : pg_b64_enc_len(int srclen)
225 : {
226 : /* 3 bytes will be converted to 4 */
227 455 : return (srclen + 2) / 3 * 4;
228 : }
229 :
230 : /*
231 : * pg_b64_dec_len
232 : *
233 : * Returns to caller the length of the string if it were to be decoded
234 : * with base64, based on the length given by caller. This is useful to
235 : * estimate how large a buffer allocation needs to be done before doing
236 : * the actual decoding.
237 : */
238 : int
239 1238 : pg_b64_dec_len(int srclen)
240 : {
241 1238 : return (srclen * 3) >> 2;
242 : }
|