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