Start background writer during archive recovery. Background writer now performs
[PostgreSQL.git] / contrib / pgcrypto / pgp-armor.c
blobb2e3ce00b08c61ad746f876cc9d3d9127a62041b
1 /*
2 * pgp-armor.c
3 * PGP ascii-armor.
5 * Copyright (c) 2005 Marko Kreen
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
29 * $PostgreSQL$
32 #include "postgres.h"
34 #include "px.h"
35 #include "mbuf.h"
36 #include "pgp.h"
39 * BASE64 - duplicated :(
42 static const unsigned char _base64[] =
43 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
45 static int
46 b64_encode(const uint8 *src, unsigned len, uint8 *dst)
48 uint8 *p,
49 *lend = dst + 76;
50 const uint8 *s,
51 *end = src + len;
52 int pos = 2;
53 unsigned long buf = 0;
55 s = src;
56 p = dst;
58 while (s < end)
60 buf |= *s << (pos << 3);
61 pos--;
62 s++;
65 * write it out
67 if (pos < 0)
69 *p++ = _base64[(buf >> 18) & 0x3f];
70 *p++ = _base64[(buf >> 12) & 0x3f];
71 *p++ = _base64[(buf >> 6) & 0x3f];
72 *p++ = _base64[buf & 0x3f];
74 pos = 2;
75 buf = 0;
77 if (p >= lend)
79 *p++ = '\n';
80 lend = p + 76;
83 if (pos != 2)
85 *p++ = _base64[(buf >> 18) & 0x3f];
86 *p++ = _base64[(buf >> 12) & 0x3f];
87 *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
88 *p++ = '=';
91 return p - dst;
94 /* probably should use lookup table */
95 static int
96 b64_decode(const uint8 *src, unsigned len, uint8 *dst)
98 const uint8 *srcend = src + len,
99 *s = src;
100 uint8 *p = dst;
101 char c;
102 unsigned b = 0;
103 unsigned long buf = 0;
104 int pos = 0,
105 end = 0;
107 while (s < srcend)
109 c = *s++;
110 if (c >= 'A' && c <= 'Z')
111 b = c - 'A';
112 else if (c >= 'a' && c <= 'z')
113 b = c - 'a' + 26;
114 else if (c >= '0' && c <= '9')
115 b = c - '0' + 52;
116 else if (c == '+')
117 b = 62;
118 else if (c == '/')
119 b = 63;
120 else if (c == '=')
123 * end sequence
125 if (!end)
127 if (pos == 2)
128 end = 1;
129 else if (pos == 3)
130 end = 2;
131 else
132 return PXE_PGP_CORRUPT_ARMOR;
134 b = 0;
136 else if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
137 continue;
138 else
139 return PXE_PGP_CORRUPT_ARMOR;
142 * add it to buffer
144 buf = (buf << 6) + b;
145 pos++;
146 if (pos == 4)
148 *p++ = (buf >> 16) & 255;
149 if (end == 0 || end > 1)
150 *p++ = (buf >> 8) & 255;
151 if (end == 0 || end > 2)
152 *p++ = buf & 255;
153 buf = 0;
154 pos = 0;
158 if (pos != 0)
159 return PXE_PGP_CORRUPT_ARMOR;
160 return p - dst;
163 static unsigned
164 b64_enc_len(unsigned srclen)
167 * 3 bytes will be converted to 4, linefeed after 76 chars
169 return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
172 static unsigned
173 b64_dec_len(unsigned srclen)
175 return (srclen * 3) >> 2;
179 * PGP armor
182 static const char *armor_header = "-----BEGIN PGP MESSAGE-----\n\n";
183 static const char *armor_footer = "\n-----END PGP MESSAGE-----\n";
185 /* CRC24 implementation from rfc2440 */
186 #define CRC24_INIT 0x00b704ceL
187 #define CRC24_POLY 0x01864cfbL
188 static long
189 crc24(const uint8 *data, unsigned len)
191 unsigned crc = CRC24_INIT;
192 int i;
194 while (len--)
196 crc ^= (*data++) << 16;
197 for (i = 0; i < 8; i++)
199 crc <<= 1;
200 if (crc & 0x1000000)
201 crc ^= CRC24_POLY;
204 return crc & 0xffffffL;
208 pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst)
210 int n;
211 uint8 *pos = dst;
212 unsigned crc = crc24(src, len);
214 n = strlen(armor_header);
215 memcpy(pos, armor_header, n);
216 pos += n;
218 n = b64_encode(src, len, pos);
219 pos += n;
221 if (*(pos - 1) != '\n')
222 *pos++ = '\n';
224 *pos++ = '=';
225 pos[3] = _base64[crc & 0x3f];
226 crc >>= 6;
227 pos[2] = _base64[crc & 0x3f];
228 crc >>= 6;
229 pos[1] = _base64[crc & 0x3f];
230 crc >>= 6;
231 pos[0] = _base64[crc & 0x3f];
232 pos += 4;
234 n = strlen(armor_footer);
235 memcpy(pos, armor_footer, n);
236 pos += n;
238 return pos - dst;
241 static const uint8 *
242 find_str(const uint8 *data, const uint8 *data_end, const char *str, int strlen)
244 const uint8 *p = data;
246 if (!strlen)
247 return NULL;
248 if (data_end - data < strlen)
249 return NULL;
250 while (p < data_end)
252 p = memchr(p, str[0], data_end - p);
253 if (p == NULL)
254 return NULL;
255 if (p + strlen > data_end)
256 return NULL;
257 if (memcmp(p, str, strlen) == 0)
258 return p;
259 p++;
261 return NULL;
264 static int
265 find_header(const uint8 *data, const uint8 *datend,
266 const uint8 **start_p, int is_end)
268 const uint8 *p = data;
269 static const char *start_sep = "-----BEGIN";
270 static const char *end_sep = "-----END";
271 const char *sep = is_end ? end_sep : start_sep;
273 /* find header line */
274 while (1)
276 p = find_str(p, datend, sep, strlen(sep));
277 if (p == NULL)
278 return PXE_PGP_CORRUPT_ARMOR;
279 /* it must start at beginning of line */
280 if (p == data || *(p - 1) == '\n')
281 break;
282 p += strlen(sep);
284 *start_p = p;
285 p += strlen(sep);
287 /* check if header text ok */
288 for (; p < datend && *p != '-'; p++)
290 /* various junk can be there, but definitely not line-feed */
291 if (*p >= ' ')
292 continue;
293 return PXE_PGP_CORRUPT_ARMOR;
295 if (datend - p < 5 || memcmp(p, sep, 5) != 0)
296 return PXE_PGP_CORRUPT_ARMOR;
297 p += 5;
299 /* check if at end of line */
300 if (p < datend)
302 if (*p != '\n' && *p != '\r')
303 return PXE_PGP_CORRUPT_ARMOR;
304 if (*p == '\r')
305 p++;
306 if (p < datend && *p == '\n')
307 p++;
309 return p - *start_p;
313 pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
315 const uint8 *p = src;
316 const uint8 *data_end = src + len;
317 long crc;
318 const uint8 *base64_start,
319 *armor_end;
320 const uint8 *base64_end = NULL;
321 uint8 buf[4];
322 int hlen;
323 int res = PXE_PGP_CORRUPT_ARMOR;
325 /* armor start */
326 hlen = find_header(src, data_end, &p, 0);
327 if (hlen <= 0)
328 goto out;
329 p += hlen;
331 /* armor end */
332 hlen = find_header(p, data_end, &armor_end, 1);
333 if (hlen <= 0)
334 goto out;
336 /* skip comments - find empty line */
337 while (p < armor_end && *p != '\n' && *p != '\r')
339 p = memchr(p, '\n', armor_end - p);
340 if (!p)
341 goto out;
343 /* step to start of next line */
344 p++;
346 base64_start = p;
348 /* find crc pos */
349 for (p = armor_end; p >= base64_start; p--)
350 if (*p == '=')
352 base64_end = p - 1;
353 break;
355 if (base64_end == NULL)
356 goto out;
358 /* decode crc */
359 if (b64_decode(p + 1, 4, buf) != 3)
360 goto out;
361 crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2];
363 /* decode data */
364 res = b64_decode(base64_start, base64_end - base64_start, dst);
366 /* check crc */
367 if (res >= 0 && crc24(dst, res) != crc)
368 res = PXE_PGP_CORRUPT_ARMOR;
369 out:
370 return res;
373 unsigned
374 pgp_armor_enc_len(unsigned len)
376 return b64_enc_len(len) + strlen(armor_header) + strlen(armor_footer) + 16;
379 unsigned
380 pgp_armor_dec_len(unsigned len)
382 return b64_dec_len(len);