Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * base64.c
4 : * Encoding and decoding routines for base64 without whitespace.
5 : *
6 : * Copyright (c) 2001-2024, 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 into base64 the given string. Returns the length of the encoded
45 : * string, and -1 in the event of an error with the result buffer zeroed
46 : * for safety.
47 : */
48 : int
49 624 : pg_b64_encode(const char *src, int len, char *dst, int dstlen)
50 : {
51 : char *p;
52 : const char *s,
53 624 : *end = src + len;
54 624 : int pos = 2;
55 624 : uint32 buf = 0;
56 :
57 624 : s = src;
58 624 : p = dst;
59 :
60 17232 : while (s < end)
61 : {
62 16608 : buf |= (unsigned char) *s << (pos << 3);
63 16608 : pos--;
64 16608 : s++;
65 :
66 : /* write it out */
67 16608 : if (pos < 0)
68 : {
69 : /*
70 : * Leave if there is an overflow in the area allocated for the
71 : * encoded string.
72 : */
73 5260 : if ((p - dst + 4) > dstlen)
74 0 : goto error;
75 :
76 5260 : *p++ = _base64[(buf >> 18) & 0x3f];
77 5260 : *p++ = _base64[(buf >> 12) & 0x3f];
78 5260 : *p++ = _base64[(buf >> 6) & 0x3f];
79 5260 : *p++ = _base64[buf & 0x3f];
80 :
81 5260 : pos = 2;
82 5260 : buf = 0;
83 : }
84 : }
85 624 : if (pos != 2)
86 : {
87 : /*
88 : * Leave if there is an overflow in the area allocated for the encoded
89 : * string.
90 : */
91 464 : if ((p - dst + 4) > dstlen)
92 0 : goto error;
93 :
94 464 : *p++ = _base64[(buf >> 18) & 0x3f];
95 464 : *p++ = _base64[(buf >> 12) & 0x3f];
96 464 : *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
97 464 : *p++ = '=';
98 : }
99 :
100 : Assert((p - dst) <= dstlen);
101 624 : 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 1484 : pg_b64_decode(const char *src, int len, char *dst, int dstlen)
117 : {
118 1484 : const char *srcend = src + len,
119 1484 : *s = src;
120 1484 : char *p = dst;
121 : char c;
122 1484 : int b = 0;
123 1484 : uint32 buf = 0;
124 1484 : int pos = 0,
125 1484 : end = 0;
126 :
127 57356 : while (s < srcend)
128 : {
129 55872 : c = *s++;
130 :
131 : /* Leave if a whitespace is found */
132 55872 : if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
133 0 : goto error;
134 :
135 55872 : if (c == '=')
136 : {
137 : /* end sequence */
138 1984 : if (!end)
139 : {
140 1466 : if (pos == 2)
141 518 : end = 1;
142 948 : else if (pos == 3)
143 948 : end = 2;
144 : else
145 : {
146 : /*
147 : * Unexpected "=" character found while decoding base64
148 : * sequence.
149 : */
150 0 : goto error;
151 : }
152 : }
153 1984 : b = 0;
154 : }
155 : else
156 : {
157 53888 : b = -1;
158 53888 : if (c > 0 && c < 127)
159 53888 : b = b64lookup[(unsigned char) c];
160 53888 : if (b < 0)
161 : {
162 : /* invalid symbol found */
163 0 : goto error;
164 : }
165 : }
166 : /* add it to buffer */
167 55872 : buf = (buf << 6) + b;
168 55872 : pos++;
169 55872 : if (pos == 4)
170 : {
171 : /*
172 : * Leave if there is an overflow in the area allocated for the
173 : * decoded string.
174 : */
175 13968 : if ((p - dst + 1) > dstlen)
176 0 : goto error;
177 13968 : *p++ = (buf >> 16) & 255;
178 :
179 13968 : if (end == 0 || end > 1)
180 : {
181 : /* overflow check */
182 13450 : if ((p - dst + 1) > dstlen)
183 0 : goto error;
184 13450 : *p++ = (buf >> 8) & 255;
185 : }
186 13968 : if (end == 0 || end > 2)
187 : {
188 : /* overflow check */
189 12502 : if ((p - dst + 1) > dstlen)
190 0 : goto error;
191 12502 : *p++ = buf & 255;
192 : }
193 13968 : buf = 0;
194 13968 : pos = 0;
195 : }
196 : }
197 :
198 1484 : 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 1484 : 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 624 : pg_b64_enc_len(int srclen)
225 : {
226 : /* 3 bytes will be converted to 4 */
227 624 : 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 1484 : pg_b64_dec_len(int srclen)
240 : {
241 1484 : return (srclen * 3) >> 2;
242 : }
|