Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * base64.c
4 : * Encoding and decoding routines for base64 without whitespace.
5 : *
6 : * Copyright (c) 2001-2023, 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
1375 michael 49 CBC 267 : pg_b64_encode(const char *src, int len, char *dst, int dstlen)
50 : {
51 : char *p;
52 : const char *s,
2224 heikki.linnakangas 53 267 : *end = src + len;
54 267 : int pos = 2;
55 267 : uint32 buf = 0;
56 :
57 267 : s = src;
58 267 : p = dst;
59 :
60 7385 : while (s < end)
61 : {
62 7118 : buf |= (unsigned char) *s << (pos << 3);
63 7118 : pos--;
64 7118 : s++;
65 :
66 : /* write it out */
67 7118 : if (pos < 0)
68 : {
69 : /*
70 : * Leave if there is an overflow in the area allocated for the
71 : * encoded string.
72 : */
1375 michael 73 2254 : if ((p - dst + 4) > dstlen)
1375 michael 74 UBC 0 : goto error;
75 :
2224 heikki.linnakangas 76 CBC 2254 : *p++ = _base64[(buf >> 18) & 0x3f];
77 2254 : *p++ = _base64[(buf >> 12) & 0x3f];
78 2254 : *p++ = _base64[(buf >> 6) & 0x3f];
79 2254 : *p++ = _base64[buf & 0x3f];
80 :
81 2254 : pos = 2;
82 2254 : buf = 0;
83 : }
84 : }
85 267 : if (pos != 2)
86 : {
87 : /*
88 : * Leave if there is an overflow in the area allocated for the encoded
89 : * string.
90 : */
1375 michael 91 200 : if ((p - dst + 4) > dstlen)
1375 michael 92 UBC 0 : goto error;
93 :
2224 heikki.linnakangas 94 CBC 200 : *p++ = _base64[(buf >> 18) & 0x3f];
95 200 : *p++ = _base64[(buf >> 12) & 0x3f];
96 200 : *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
97 200 : *p++ = '=';
98 : }
99 :
1375 michael 100 267 : Assert((p - dst) <= dstlen);
2224 heikki.linnakangas 101 267 : return p - dst;
102 :
1375 michael 103 UBC 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
1375 michael 116 CBC 557 : pg_b64_decode(const char *src, int len, char *dst, int dstlen)
117 : {
2224 heikki.linnakangas 118 557 : const char *srcend = src + len,
119 557 : *s = src;
120 557 : char *p = dst;
121 : char c;
122 557 : int b = 0;
123 557 : uint32 buf = 0;
124 557 : int pos = 0,
125 557 : end = 0;
126 :
127 21713 : while (s < srcend)
128 : {
129 21156 : c = *s++;
130 :
131 : /* Leave if a whitespace is found */
132 21156 : if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
1375 michael 133 UBC 0 : goto error;
134 :
2224 heikki.linnakangas 135 CBC 21156 : if (c == '=')
136 : {
137 : /* end sequence */
138 739 : if (!end)
139 : {
140 548 : if (pos == 2)
141 191 : end = 1;
142 357 : else if (pos == 3)
143 357 : end = 2;
144 : else
145 : {
146 : /*
147 : * Unexpected "=" character found while decoding base64
148 : * sequence.
149 : */
1375 michael 150 UBC 0 : goto error;
151 : }
152 : }
2224 heikki.linnakangas 153 CBC 739 : b = 0;
154 : }
155 : else
156 : {
157 20417 : b = -1;
158 20417 : if (c > 0 && c < 127)
159 20417 : b = b64lookup[(unsigned char) c];
160 20417 : if (b < 0)
161 : {
162 : /* invalid symbol found */
1375 michael 163 UBC 0 : goto error;
164 : }
165 : }
166 : /* add it to buffer */
2224 heikki.linnakangas 167 CBC 21156 : buf = (buf << 6) + b;
168 21156 : pos++;
169 21156 : if (pos == 4)
170 : {
171 : /*
172 : * Leave if there is an overflow in the area allocated for the
173 : * decoded string.
174 : */
1375 michael 175 5289 : if ((p - dst + 1) > dstlen)
1375 michael 176 UBC 0 : goto error;
2224 heikki.linnakangas 177 CBC 5289 : *p++ = (buf >> 16) & 255;
178 :
179 5289 : if (end == 0 || end > 1)
180 : {
181 : /* overflow check */
1375 michael 182 5098 : if ((p - dst + 1) > dstlen)
1375 michael 183 UBC 0 : goto error;
2224 heikki.linnakangas 184 CBC 5098 : *p++ = (buf >> 8) & 255;
185 : }
186 5289 : if (end == 0 || end > 2)
187 : {
188 : /* overflow check */
1375 michael 189 4741 : if ((p - dst + 1) > dstlen)
1375 michael 190 UBC 0 : goto error;
2224 heikki.linnakangas 191 CBC 4741 : *p++ = buf & 255;
192 : }
193 5289 : buf = 0;
194 5289 : pos = 0;
195 : }
196 : }
197 :
198 557 : if (pos != 0)
199 : {
200 : /*
201 : * base64 end sequence is invalid. Input data is missing padding, is
202 : * truncated or is otherwise corrupted.
203 : */
1375 michael 204 UBC 0 : goto error;
205 : }
206 :
1375 michael 207 CBC 557 : Assert((p - dst) <= dstlen);
2224 heikki.linnakangas 208 557 : return p - dst;
209 :
1375 michael 210 UBC 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
2224 heikki.linnakangas 224 CBC 267 : pg_b64_enc_len(int srclen)
225 : {
226 : /* 3 bytes will be converted to 4 */
227 267 : return (srclen + 2) * 4 / 3;
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 557 : pg_b64_dec_len(int srclen)
240 : {
241 557 : return (srclen * 3) >> 2;
242 : }
|