00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "postgres.h"
00033
00034 #include "px.h"
00035 #include "mbuf.h"
00036 #include "pgp.h"
00037
00038
00039
00040
00041
00042 static const unsigned char _base64[] =
00043 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00044
00045 static int
00046 b64_encode(const uint8 *src, unsigned len, uint8 *dst)
00047 {
00048 uint8 *p,
00049 *lend = dst + 76;
00050 const uint8 *s,
00051 *end = src + len;
00052 int pos = 2;
00053 unsigned long buf = 0;
00054
00055 s = src;
00056 p = dst;
00057
00058 while (s < end)
00059 {
00060 buf |= *s << (pos << 3);
00061 pos--;
00062 s++;
00063
00064
00065
00066
00067 if (pos < 0)
00068 {
00069 *p++ = _base64[(buf >> 18) & 0x3f];
00070 *p++ = _base64[(buf >> 12) & 0x3f];
00071 *p++ = _base64[(buf >> 6) & 0x3f];
00072 *p++ = _base64[buf & 0x3f];
00073
00074 pos = 2;
00075 buf = 0;
00076 }
00077 if (p >= lend)
00078 {
00079 *p++ = '\n';
00080 lend = p + 76;
00081 }
00082 }
00083 if (pos != 2)
00084 {
00085 *p++ = _base64[(buf >> 18) & 0x3f];
00086 *p++ = _base64[(buf >> 12) & 0x3f];
00087 *p++ = (pos == 0) ? _base64[(buf >> 6) & 0x3f] : '=';
00088 *p++ = '=';
00089 }
00090
00091 return p - dst;
00092 }
00093
00094
00095 static int
00096 b64_decode(const uint8 *src, unsigned len, uint8 *dst)
00097 {
00098 const uint8 *srcend = src + len,
00099 *s = src;
00100 uint8 *p = dst;
00101 char c;
00102 unsigned b = 0;
00103 unsigned long buf = 0;
00104 int pos = 0,
00105 end = 0;
00106
00107 while (s < srcend)
00108 {
00109 c = *s++;
00110 if (c >= 'A' && c <= 'Z')
00111 b = c - 'A';
00112 else if (c >= 'a' && c <= 'z')
00113 b = c - 'a' + 26;
00114 else if (c >= '0' && c <= '9')
00115 b = c - '0' + 52;
00116 else if (c == '+')
00117 b = 62;
00118 else if (c == '/')
00119 b = 63;
00120 else if (c == '=')
00121 {
00122
00123
00124
00125 if (!end)
00126 {
00127 if (pos == 2)
00128 end = 1;
00129 else if (pos == 3)
00130 end = 2;
00131 else
00132 return PXE_PGP_CORRUPT_ARMOR;
00133 }
00134 b = 0;
00135 }
00136 else if (c == ' ' || c == '\t' || c == '\n' || c == '\r')
00137 continue;
00138 else
00139 return PXE_PGP_CORRUPT_ARMOR;
00140
00141
00142
00143
00144 buf = (buf << 6) + b;
00145 pos++;
00146 if (pos == 4)
00147 {
00148 *p++ = (buf >> 16) & 255;
00149 if (end == 0 || end > 1)
00150 *p++ = (buf >> 8) & 255;
00151 if (end == 0 || end > 2)
00152 *p++ = buf & 255;
00153 buf = 0;
00154 pos = 0;
00155 }
00156 }
00157
00158 if (pos != 0)
00159 return PXE_PGP_CORRUPT_ARMOR;
00160 return p - dst;
00161 }
00162
00163 static unsigned
00164 b64_enc_len(unsigned srclen)
00165 {
00166
00167
00168
00169 return (srclen + 2) * 4 / 3 + srclen / (76 * 3 / 4);
00170 }
00171
00172 static unsigned
00173 b64_dec_len(unsigned srclen)
00174 {
00175 return (srclen * 3) >> 2;
00176 }
00177
00178
00179
00180
00181
00182 static const char *armor_header = "-----BEGIN PGP MESSAGE-----\n\n";
00183 static const char *armor_footer = "\n-----END PGP MESSAGE-----\n";
00184
00185
00186 #define CRC24_INIT 0x00b704ceL
00187 #define CRC24_POLY 0x01864cfbL
00188 static long
00189 crc24(const uint8 *data, unsigned len)
00190 {
00191 unsigned crc = CRC24_INIT;
00192 int i;
00193
00194 while (len--)
00195 {
00196 crc ^= (*data++) << 16;
00197 for (i = 0; i < 8; i++)
00198 {
00199 crc <<= 1;
00200 if (crc & 0x1000000)
00201 crc ^= CRC24_POLY;
00202 }
00203 }
00204 return crc & 0xffffffL;
00205 }
00206
00207 int
00208 pgp_armor_encode(const uint8 *src, unsigned len, uint8 *dst)
00209 {
00210 int n;
00211 uint8 *pos = dst;
00212 unsigned crc = crc24(src, len);
00213
00214 n = strlen(armor_header);
00215 memcpy(pos, armor_header, n);
00216 pos += n;
00217
00218 n = b64_encode(src, len, pos);
00219 pos += n;
00220
00221 if (*(pos - 1) != '\n')
00222 *pos++ = '\n';
00223
00224 *pos++ = '=';
00225 pos[3] = _base64[crc & 0x3f];
00226 crc >>= 6;
00227 pos[2] = _base64[crc & 0x3f];
00228 crc >>= 6;
00229 pos[1] = _base64[crc & 0x3f];
00230 crc >>= 6;
00231 pos[0] = _base64[crc & 0x3f];
00232 pos += 4;
00233
00234 n = strlen(armor_footer);
00235 memcpy(pos, armor_footer, n);
00236 pos += n;
00237
00238 return pos - dst;
00239 }
00240
00241 static const uint8 *
00242 find_str(const uint8 *data, const uint8 *data_end, const char *str, int strlen)
00243 {
00244 const uint8 *p = data;
00245
00246 if (!strlen)
00247 return NULL;
00248 if (data_end - data < strlen)
00249 return NULL;
00250 while (p < data_end)
00251 {
00252 p = memchr(p, str[0], data_end - p);
00253 if (p == NULL)
00254 return NULL;
00255 if (p + strlen > data_end)
00256 return NULL;
00257 if (memcmp(p, str, strlen) == 0)
00258 return p;
00259 p++;
00260 }
00261 return NULL;
00262 }
00263
00264 static int
00265 find_header(const uint8 *data, const uint8 *datend,
00266 const uint8 **start_p, int is_end)
00267 {
00268 const uint8 *p = data;
00269 static const char *start_sep = "-----BEGIN";
00270 static const char *end_sep = "-----END";
00271 const char *sep = is_end ? end_sep : start_sep;
00272
00273
00274 while (1)
00275 {
00276 p = find_str(p, datend, sep, strlen(sep));
00277 if (p == NULL)
00278 return PXE_PGP_CORRUPT_ARMOR;
00279
00280 if (p == data || *(p - 1) == '\n')
00281 break;
00282 p += strlen(sep);
00283 }
00284 *start_p = p;
00285 p += strlen(sep);
00286
00287
00288 for (; p < datend && *p != '-'; p++)
00289 {
00290
00291 if (*p >= ' ')
00292 continue;
00293 return PXE_PGP_CORRUPT_ARMOR;
00294 }
00295 if (datend - p < 5 || memcmp(p, sep, 5) != 0)
00296 return PXE_PGP_CORRUPT_ARMOR;
00297 p += 5;
00298
00299
00300 if (p < datend)
00301 {
00302 if (*p != '\n' && *p != '\r')
00303 return PXE_PGP_CORRUPT_ARMOR;
00304 if (*p == '\r')
00305 p++;
00306 if (p < datend && *p == '\n')
00307 p++;
00308 }
00309 return p - *start_p;
00310 }
00311
00312 int
00313 pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
00314 {
00315 const uint8 *p = src;
00316 const uint8 *data_end = src + len;
00317 long crc;
00318 const uint8 *base64_start,
00319 *armor_end;
00320 const uint8 *base64_end = NULL;
00321 uint8 buf[4];
00322 int hlen;
00323 int res = PXE_PGP_CORRUPT_ARMOR;
00324
00325
00326 hlen = find_header(src, data_end, &p, 0);
00327 if (hlen <= 0)
00328 goto out;
00329 p += hlen;
00330
00331
00332 hlen = find_header(p, data_end, &armor_end, 1);
00333 if (hlen <= 0)
00334 goto out;
00335
00336
00337 while (p < armor_end && *p != '\n' && *p != '\r')
00338 {
00339 p = memchr(p, '\n', armor_end - p);
00340 if (!p)
00341 goto out;
00342
00343
00344 p++;
00345 }
00346 base64_start = p;
00347
00348
00349 for (p = armor_end; p >= base64_start; p--)
00350 if (*p == '=')
00351 {
00352 base64_end = p - 1;
00353 break;
00354 }
00355 if (base64_end == NULL)
00356 goto out;
00357
00358
00359 if (b64_decode(p + 1, 4, buf) != 3)
00360 goto out;
00361 crc = (((long) buf[0]) << 16) + (((long) buf[1]) << 8) + (long) buf[2];
00362
00363
00364 res = b64_decode(base64_start, base64_end - base64_start, dst);
00365
00366
00367 if (res >= 0 && crc24(dst, res) != crc)
00368 res = PXE_PGP_CORRUPT_ARMOR;
00369 out:
00370 return res;
00371 }
00372
00373 unsigned
00374 pgp_armor_enc_len(unsigned len)
00375 {
00376 return b64_enc_len(len) + strlen(armor_header) + strlen(armor_footer) + 16;
00377 }
00378
00379 unsigned
00380 pgp_armor_dec_len(unsigned len)
00381 {
00382 return b64_dec_len(len);
00383 }