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 <time.h>
00035
00036 #include "mbuf.h"
00037 #include "px.h"
00038 #include "pgp.h"
00039
00040
00041 #define MDC_DIGEST_LEN 20
00042 #define STREAM_ID 0xE0
00043 #define STREAM_BLOCK_SHIFT 14
00044
00045 static uint8 *
00046 render_newlen(uint8 *h, int len)
00047 {
00048 if (len <= 191)
00049 {
00050 *h++ = len & 255;
00051 }
00052 else if (len > 191 && len <= 8383)
00053 {
00054 *h++ = ((len - 192) >> 8) + 192;
00055 *h++ = (len - 192) & 255;
00056 }
00057 else
00058 {
00059 *h++ = 255;
00060 *h++ = (len >> 24) & 255;
00061 *h++ = (len >> 16) & 255;
00062 *h++ = (len >> 8) & 255;
00063 *h++ = len & 255;
00064 }
00065 return h;
00066 }
00067
00068 static int
00069 write_tag_only(PushFilter *dst, int tag)
00070 {
00071 uint8 hdr = 0xC0 | tag;
00072
00073 return pushf_write(dst, &hdr, 1);
00074 }
00075
00076 static int
00077 write_normal_header(PushFilter *dst, int tag, int len)
00078 {
00079 uint8 hdr[8];
00080 uint8 *h = hdr;
00081
00082 *h++ = 0xC0 | tag;
00083 h = render_newlen(h, len);
00084 return pushf_write(dst, hdr, h - hdr);
00085 }
00086
00087
00088
00089
00090
00091
00092 static int
00093 mdc_init(PushFilter *dst, void *init_arg, void **priv_p)
00094 {
00095 int res;
00096 PX_MD *md;
00097
00098 res = pgp_load_digest(PGP_DIGEST_SHA1, &md);
00099 if (res < 0)
00100 return res;
00101
00102 *priv_p = md;
00103 return 0;
00104 }
00105
00106 static int
00107 mdc_write(PushFilter *dst, void *priv, const uint8 *data, int len)
00108 {
00109 PX_MD *md = priv;
00110
00111 px_md_update(md, data, len);
00112 return pushf_write(dst, data, len);
00113 }
00114
00115 static int
00116 mdc_flush(PushFilter *dst, void *priv)
00117 {
00118 int res;
00119 uint8 pkt[2 + MDC_DIGEST_LEN];
00120 PX_MD *md = priv;
00121
00122
00123
00124
00125 pkt[0] = 0xD3;
00126 pkt[1] = 0x14;
00127 px_md_update(md, pkt, 2);
00128 px_md_finish(md, pkt + 2);
00129
00130 res = pushf_write(dst, pkt, 2 + MDC_DIGEST_LEN);
00131 memset(pkt, 0, 2 + MDC_DIGEST_LEN);
00132 return res;
00133 }
00134
00135 static void
00136 mdc_free(void *priv)
00137 {
00138 PX_MD *md = priv;
00139
00140 px_md_free(md);
00141 }
00142
00143 static const PushFilterOps mdc_filter = {
00144 mdc_init, mdc_write, mdc_flush, mdc_free
00145 };
00146
00147
00148
00149
00150
00151 #define ENCBUF 8192
00152 struct EncStat
00153 {
00154 PGP_CFB *ciph;
00155 uint8 buf[ENCBUF];
00156 };
00157
00158 static int
00159 encrypt_init(PushFilter *next, void *init_arg, void **priv_p)
00160 {
00161 struct EncStat *st;
00162 PGP_Context *ctx = init_arg;
00163 PGP_CFB *ciph;
00164 int resync = 1;
00165 int res;
00166
00167
00168 if (ctx->disable_mdc == 0)
00169 {
00170 uint8 ver = 1;
00171
00172 resync = 0;
00173 res = pushf_write(next, &ver, 1);
00174 if (res < 0)
00175 return res;
00176 }
00177 res = pgp_cfb_create(&ciph, ctx->cipher_algo,
00178 ctx->sess_key, ctx->sess_key_len, resync, NULL);
00179 if (res < 0)
00180 return res;
00181
00182 st = px_alloc(sizeof(*st));
00183 memset(st, 0, sizeof(*st));
00184 st->ciph = ciph;
00185
00186 *priv_p = st;
00187 return ENCBUF;
00188 }
00189
00190 static int
00191 encrypt_process(PushFilter *next, void *priv, const uint8 *data, int len)
00192 {
00193 int res;
00194 struct EncStat *st = priv;
00195 int avail = len;
00196
00197 while (avail > 0)
00198 {
00199 int tmplen = avail > ENCBUF ? ENCBUF : avail;
00200
00201 res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf);
00202 if (res < 0)
00203 return res;
00204
00205 res = pushf_write(next, st->buf, tmplen);
00206 if (res < 0)
00207 return res;
00208
00209 data += tmplen;
00210 avail -= tmplen;
00211 }
00212 return 0;
00213 }
00214
00215 static void
00216 encrypt_free(void *priv)
00217 {
00218 struct EncStat *st = priv;
00219
00220 memset(st, 0, sizeof(*st));
00221 px_free(st);
00222 }
00223
00224 static const PushFilterOps encrypt_filter = {
00225 encrypt_init, encrypt_process, NULL, encrypt_free
00226 };
00227
00228
00229
00230
00231
00232 struct PktStreamStat
00233 {
00234 int final_done;
00235 int pkt_block;
00236 };
00237
00238 static int
00239 pkt_stream_init(PushFilter *next, void *init_arg, void **priv_p)
00240 {
00241 struct PktStreamStat *st;
00242
00243 st = px_alloc(sizeof(*st));
00244 st->final_done = 0;
00245 st->pkt_block = 1 << STREAM_BLOCK_SHIFT;
00246 *priv_p = st;
00247
00248 return st->pkt_block;
00249 }
00250
00251 static int
00252 pkt_stream_process(PushFilter *next, void *priv, const uint8 *data, int len)
00253 {
00254 int res;
00255 uint8 hdr[8];
00256 uint8 *h = hdr;
00257 struct PktStreamStat *st = priv;
00258
00259 if (st->final_done)
00260 return PXE_BUG;
00261
00262 if (len == st->pkt_block)
00263 *h++ = STREAM_ID | STREAM_BLOCK_SHIFT;
00264 else
00265 {
00266 h = render_newlen(h, len);
00267 st->final_done = 1;
00268 }
00269
00270 res = pushf_write(next, hdr, h - hdr);
00271 if (res < 0)
00272 return res;
00273
00274 return pushf_write(next, data, len);
00275 }
00276
00277 static int
00278 pkt_stream_flush(PushFilter *next, void *priv)
00279 {
00280 int res;
00281 uint8 hdr[8];
00282 uint8 *h = hdr;
00283 struct PktStreamStat *st = priv;
00284
00285
00286 if (!st->final_done)
00287 {
00288 h = render_newlen(h, 0);
00289 res = pushf_write(next, hdr, h - hdr);
00290 if (res < 0)
00291 return res;
00292 st->final_done = 1;
00293 }
00294 return 0;
00295 }
00296
00297 static void
00298 pkt_stream_free(void *priv)
00299 {
00300 struct PktStreamStat *st = priv;
00301
00302 memset(st, 0, sizeof(*st));
00303 px_free(st);
00304 }
00305
00306 static const PushFilterOps pkt_stream_filter = {
00307 pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free
00308 };
00309
00310 int
00311 pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p)
00312 {
00313 int res;
00314
00315 res = write_tag_only(dst, tag);
00316 if (res < 0)
00317 return res;
00318
00319 return pushf_create(res_p, &pkt_stream_filter, NULL, dst);
00320 }
00321
00322
00323
00324
00325
00326 static int
00327 crlf_process(PushFilter *dst, void *priv, const uint8 *data, int len)
00328 {
00329 const uint8 *data_end = data + len;
00330 const uint8 *p2,
00331 *p1 = data;
00332 int line_len;
00333 static const uint8 crlf[] = {'\r', '\n'};
00334 int res = 0;
00335
00336 while (p1 < data_end)
00337 {
00338 p2 = memchr(p1, '\n', data_end - p1);
00339 if (p2 == NULL)
00340 p2 = data_end;
00341
00342 line_len = p2 - p1;
00343
00344
00345 res = 0;
00346 if (line_len > 0)
00347 {
00348 res = pushf_write(dst, p1, line_len);
00349 if (res < 0)
00350 break;
00351 p1 += line_len;
00352 }
00353
00354
00355 while (p1 < data_end && *p1 == '\n')
00356 {
00357 res = pushf_write(dst, crlf, 2);
00358 if (res < 0)
00359 break;
00360 p1++;
00361 }
00362 }
00363 return res;
00364 }
00365
00366 static const PushFilterOps crlf_filter = {
00367 NULL, crlf_process, NULL, NULL
00368 };
00369
00370
00371
00372
00373 static int
00374 init_litdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
00375 {
00376 int res;
00377 int hdrlen;
00378 uint8 hdr[6];
00379 uint32 t;
00380 PushFilter *pkt;
00381 int type;
00382
00383
00384
00385
00386
00387 if (ctx->text_mode)
00388 type = ctx->unicode_mode ? 'u' : 't';
00389 else
00390 type = 'b';
00391
00392
00393
00394
00395
00396 t = (uint32) time(NULL);
00397
00398 hdr[0] = type;
00399 hdr[1] = 0;
00400 hdr[2] = (t >> 24) & 255;
00401 hdr[3] = (t >> 16) & 255;
00402 hdr[4] = (t >> 8) & 255;
00403 hdr[5] = t & 255;
00404 hdrlen = 6;
00405
00406 res = write_tag_only(dst, PGP_PKT_LITERAL_DATA);
00407 if (res < 0)
00408 return res;
00409
00410 res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
00411 if (res < 0)
00412 return res;
00413
00414 res = pushf_write(pkt, hdr, hdrlen);
00415 if (res < 0)
00416 {
00417 pushf_free(pkt);
00418 return res;
00419 }
00420
00421 *pf_res = pkt;
00422 return 0;
00423 }
00424
00425
00426
00427
00428 static int
00429 init_compress(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
00430 {
00431 int res;
00432 uint8 type = ctx->compress_algo;
00433 PushFilter *pkt;
00434
00435 res = write_tag_only(dst, PGP_PKT_COMPRESSED_DATA);
00436 if (res < 0)
00437 return res;
00438
00439 res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
00440 if (res < 0)
00441 return res;
00442
00443 res = pushf_write(pkt, &type, 1);
00444 if (res >= 0)
00445 res = pgp_compress_filter(pf_res, ctx, pkt);
00446
00447 if (res < 0)
00448 pushf_free(pkt);
00449
00450 return res;
00451 }
00452
00453
00454
00455
00456 static int
00457 init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
00458 {
00459 int res;
00460 int tag;
00461
00462 if (ctx->disable_mdc)
00463 tag = PGP_PKT_SYMENCRYPTED_DATA;
00464 else
00465 tag = PGP_PKT_SYMENCRYPTED_DATA_MDC;
00466
00467 res = write_tag_only(dst, tag);
00468 if (res < 0)
00469 return res;
00470
00471 return pushf_create(pf_res, &pkt_stream_filter, ctx, dst);
00472 }
00473
00474
00475
00476
00477 static int
00478 write_prefix(PGP_Context *ctx, PushFilter *dst)
00479 {
00480 uint8 prefix[PGP_MAX_BLOCK + 2];
00481 int res,
00482 bs;
00483
00484 bs = pgp_get_cipher_block_size(ctx->cipher_algo);
00485 res = px_get_random_bytes(prefix, bs);
00486 if (res < 0)
00487 return res;
00488
00489 prefix[bs + 0] = prefix[bs - 2];
00490 prefix[bs + 1] = prefix[bs - 1];
00491
00492 res = pushf_write(dst, prefix, bs + 2);
00493 memset(prefix, 0, bs + 2);
00494 return res < 0 ? res : 0;
00495 }
00496
00497
00498
00499
00500
00501 static int
00502 symencrypt_sesskey(PGP_Context *ctx, uint8 *dst)
00503 {
00504 int res;
00505 PGP_CFB *cfb;
00506 uint8 algo = ctx->cipher_algo;
00507
00508 res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
00509 ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
00510 if (res < 0)
00511 return res;
00512
00513 pgp_cfb_encrypt(cfb, &algo, 1, dst);
00514 pgp_cfb_encrypt(cfb, ctx->sess_key, ctx->sess_key_len, dst + 1);
00515
00516 pgp_cfb_free(cfb);
00517 return ctx->sess_key_len + 1;
00518 }
00519
00520
00521 static int
00522 write_symenc_sesskey(PGP_Context *ctx, PushFilter *dst)
00523 {
00524 uint8 pkt[256];
00525 int pktlen;
00526 int res;
00527 uint8 *p = pkt;
00528
00529 *p++ = 4;
00530 *p++ = ctx->s2k_cipher_algo;
00531
00532 *p++ = ctx->s2k.mode;
00533 *p++ = ctx->s2k.digest_algo;
00534 if (ctx->s2k.mode > 0)
00535 {
00536 memcpy(p, ctx->s2k.salt, 8);
00537 p += 8;
00538 }
00539 if (ctx->s2k.mode == 3)
00540 *p++ = ctx->s2k.iter;
00541
00542 if (ctx->use_sess_key)
00543 {
00544 res = symencrypt_sesskey(ctx, p);
00545 if (res < 0)
00546 return res;
00547 p += res;
00548 }
00549
00550 pktlen = p - pkt;
00551 res = write_normal_header(dst, PGP_PKT_SYMENCRYPTED_SESSKEY, pktlen);
00552 if (res >= 0)
00553 res = pushf_write(dst, pkt, pktlen);
00554
00555 memset(pkt, 0, pktlen);
00556 return res;
00557 }
00558
00559
00560
00561
00562 static int
00563 init_s2k_key(PGP_Context *ctx)
00564 {
00565 int res;
00566
00567 if (ctx->s2k_cipher_algo < 0)
00568 ctx->s2k_cipher_algo = ctx->cipher_algo;
00569
00570 res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo);
00571 if (res < 0)
00572 return res;
00573
00574 return pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
00575 ctx->sym_key, ctx->sym_key_len);
00576 }
00577
00578 static int
00579 init_sess_key(PGP_Context *ctx)
00580 {
00581 int res;
00582
00583 if (ctx->use_sess_key || ctx->pub_key)
00584 {
00585 ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo);
00586 res = px_get_random_bytes(ctx->sess_key, ctx->sess_key_len);
00587 if (res < 0)
00588 return res;
00589 }
00590 else
00591 {
00592 ctx->sess_key_len = ctx->s2k.key_len;
00593 memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
00594 }
00595
00596 return 0;
00597 }
00598
00599
00600
00601
00602 int
00603 pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
00604 {
00605 int res;
00606 int len;
00607 uint8 *buf;
00608 PushFilter *pf,
00609 *pf_tmp;
00610
00611
00612
00613
00614 if (!ctx->sym_key && !ctx->pub_key)
00615 return PXE_ARGUMENT_ERROR;
00616
00617
00618 res = pushf_create_mbuf_writer(&pf, dst);
00619 if (res < 0)
00620 goto out;
00621
00622
00623
00624
00625 if (ctx->sym_key)
00626 {
00627 res = init_s2k_key(ctx);
00628 if (res < 0)
00629 goto out;
00630 }
00631
00632 res = init_sess_key(ctx);
00633 if (res < 0)
00634 goto out;
00635
00636
00637
00638
00639 if (ctx->pub_key)
00640 res = pgp_write_pubenc_sesskey(ctx, pf);
00641 else
00642 res = write_symenc_sesskey(ctx, pf);
00643 if (res < 0)
00644 goto out;
00645
00646
00647 res = init_encdata_packet(&pf_tmp, ctx, pf);
00648 if (res < 0)
00649 goto out;
00650 pf = pf_tmp;
00651
00652
00653 res = pushf_create(&pf_tmp, &encrypt_filter, ctx, pf);
00654 if (res < 0)
00655 goto out;
00656 pf = pf_tmp;
00657
00658
00659 if (ctx->disable_mdc == 0)
00660 {
00661 res = pushf_create(&pf_tmp, &mdc_filter, ctx, pf);
00662 if (res < 0)
00663 goto out;
00664 pf = pf_tmp;
00665 }
00666
00667
00668 res = write_prefix(ctx, pf);
00669 if (res < 0)
00670 goto out;
00671
00672
00673 if (ctx->compress_algo > 0 && ctx->compress_level > 0)
00674 {
00675 res = init_compress(&pf_tmp, ctx, pf);
00676 if (res < 0)
00677 goto out;
00678 pf = pf_tmp;
00679 }
00680
00681
00682 res = init_litdata_packet(&pf_tmp, ctx, pf);
00683 if (res < 0)
00684 goto out;
00685 pf = pf_tmp;
00686
00687
00688
00689 if (ctx->text_mode && ctx->convert_crlf)
00690 {
00691 res = pushf_create(&pf_tmp, &crlf_filter, ctx, pf);
00692 if (res < 0)
00693 goto out;
00694 pf = pf_tmp;
00695 }
00696
00697
00698
00699
00700
00701 len = mbuf_grab(src, mbuf_avail(src), &buf);
00702 res = pushf_write(pf, buf, len);
00703 if (res >= 0)
00704 res = pushf_flush(pf);
00705 out:
00706 pushf_free_all(pf);
00707 return res;
00708 }