1 /* 2 * pgp-encrypt.c 3 * OpenPGP encrypt. 4 * 5 * Copyright (c) 2005 Marko Kreen 6 * All rights reserved. 7 * 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. 16 * 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. 28 * 29 * contrib/pgcrypto/pgp-encrypt.c 30 */ 31 32 #include "postgres.h" 33 34 #include <time.h> 35 36 #include "mbuf.h" 37 #include "px.h" 38 #include "pgp.h" 39 40 41 #define MDC_DIGEST_LEN 20 42 #define STREAM_ID 0xE0 43 #define STREAM_BLOCK_SHIFT 14 44 45 static uint8 * 46 render_newlen(uint8 *h, int len) 47 { 48 if (len <= 191) 49 { 50 *h++ = len & 255; 51 } 52 else if (len > 191 && len <= 8383) 53 { 54 *h++ = ((len - 192) >> 8) + 192; 55 *h++ = (len - 192) & 255; 56 } 57 else 58 { 59 *h++ = 255; 60 *h++ = (len >> 24) & 255; 61 *h++ = (len >> 16) & 255; 62 *h++ = (len >> 8) & 255; 63 *h++ = len & 255; 64 } 65 return h; 66 } 67 68 static int 69 write_tag_only(PushFilter *dst, int tag) 70 { 71 uint8 hdr = 0xC0 | tag; 72 73 return pushf_write(dst, &hdr, 1); 74 } 75 76 static int 77 write_normal_header(PushFilter *dst, int tag, int len) 78 { 79 uint8 hdr[8]; 80 uint8 *h = hdr; 81 82 *h++ = 0xC0 | tag; 83 h = render_newlen(h, len); 84 return pushf_write(dst, hdr, h - hdr); 85 } 86 87 88 /* 89 * MAC writer 90 */ 91 92 static int 93 mdc_init(PushFilter *dst, void *init_arg, void **priv_p) 94 { 95 int res; 96 PX_MD *md; 97 98 res = pgp_load_digest(PGP_DIGEST_SHA1, &md); 99 if (res < 0) 100 return res; 101 102 *priv_p = md; 103 return 0; 104 } 105 106 static int 107 mdc_write(PushFilter *dst, void *priv, const uint8 *data, int len) 108 { 109 PX_MD *md = priv; 110 111 px_md_update(md, data, len); 112 return pushf_write(dst, data, len); 113 } 114 115 static int 116 mdc_flush(PushFilter *dst, void *priv) 117 { 118 int res; 119 uint8 pkt[2 + MDC_DIGEST_LEN]; 120 PX_MD *md = priv; 121 122 /* 123 * create mdc pkt 124 */ 125 pkt[0] = 0xD3; 126 pkt[1] = 0x14; /* MDC_DIGEST_LEN */ 127 px_md_update(md, pkt, 2); 128 px_md_finish(md, pkt + 2); 129 130 res = pushf_write(dst, pkt, 2 + MDC_DIGEST_LEN); 131 px_memset(pkt, 0, 2 + MDC_DIGEST_LEN); 132 return res; 133 } 134 135 static void 136 mdc_free(void *priv) 137 { 138 PX_MD *md = priv; 139 140 px_md_free(md); 141 } 142 143 static const PushFilterOps mdc_filter = { 144 mdc_init, mdc_write, mdc_flush, mdc_free 145 }; 146 147 148 /* 149 * Encrypted pkt writer 150 */ 151 #define ENCBUF 8192 152 struct EncStat 153 { 154 PGP_CFB *ciph; 155 uint8 buf[ENCBUF]; 156 }; 157 158 static int 159 encrypt_init(PushFilter *next, void *init_arg, void **priv_p) 160 { 161 struct EncStat *st; 162 PGP_Context *ctx = init_arg; 163 PGP_CFB *ciph; 164 int resync = 1; 165 int res; 166 167 /* should we use newer packet format? */ 168 if (ctx->disable_mdc == 0) 169 { 170 uint8 ver = 1; 171 172 resync = 0; 173 res = pushf_write(next, &ver, 1); 174 if (res < 0) 175 return res; 176 } 177 res = pgp_cfb_create(&ciph, ctx->cipher_algo, 178 ctx->sess_key, ctx->sess_key_len, resync, NULL); 179 if (res < 0) 180 return res; 181 182 st = px_alloc(sizeof(*st)); 183 memset(st, 0, sizeof(*st)); 184 st->ciph = ciph; 185 186 *priv_p = st; 187 return ENCBUF; 188 } 189 190 static int 191 encrypt_process(PushFilter *next, void *priv, const uint8 *data, int len) 192 { 193 int res; 194 struct EncStat *st = priv; 195 int avail = len; 196 197 while (avail > 0) 198 { 199 int tmplen = avail > ENCBUF ? ENCBUF : avail; 200 201 res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf); 202 if (res < 0) 203 return res; 204 205 res = pushf_write(next, st->buf, tmplen); 206 if (res < 0) 207 return res; 208 209 data += tmplen; 210 avail -= tmplen; 211 } 212 return 0; 213 } 214 215 static void 216 encrypt_free(void *priv) 217 { 218 struct EncStat *st = priv; 219 220 if (st->ciph) 221 pgp_cfb_free(st->ciph); 222 px_memset(st, 0, sizeof(*st)); 223 px_free(st); 224 } 225 226 static const PushFilterOps encrypt_filter = { 227 encrypt_init, encrypt_process, NULL, encrypt_free 228 }; 229 230 /* 231 * Write Streamable pkts 232 */ 233 234 struct PktStreamStat 235 { 236 int final_done; 237 int pkt_block; 238 }; 239 240 static int 241 pkt_stream_init(PushFilter *next, void *init_arg, void **priv_p) 242 { 243 struct PktStreamStat *st; 244 245 st = px_alloc(sizeof(*st)); 246 st->final_done = 0; 247 st->pkt_block = 1 << STREAM_BLOCK_SHIFT; 248 *priv_p = st; 249 250 return st->pkt_block; 251 } 252 253 static int 254 pkt_stream_process(PushFilter *next, void *priv, const uint8 *data, int len) 255 { 256 int res; 257 uint8 hdr[8]; 258 uint8 *h = hdr; 259 struct PktStreamStat *st = priv; 260 261 if (st->final_done) 262 return PXE_BUG; 263 264 if (len == st->pkt_block) 265 *h++ = STREAM_ID | STREAM_BLOCK_SHIFT; 266 else 267 { 268 h = render_newlen(h, len); 269 st->final_done = 1; 270 } 271 272 res = pushf_write(next, hdr, h - hdr); 273 if (res < 0) 274 return res; 275 276 return pushf_write(next, data, len); 277 } 278 279 static int 280 pkt_stream_flush(PushFilter *next, void *priv) 281 { 282 int res; 283 uint8 hdr[8]; 284 uint8 *h = hdr; 285 struct PktStreamStat *st = priv; 286 287 /* stream MUST end with normal packet. */ 288 if (!st->final_done) 289 { 290 h = render_newlen(h, 0); 291 res = pushf_write(next, hdr, h - hdr); 292 if (res < 0) 293 return res; 294 st->final_done = 1; 295 } 296 return 0; 297 } 298 299 static void 300 pkt_stream_free(void *priv) 301 { 302 struct PktStreamStat *st = priv; 303 304 px_memset(st, 0, sizeof(*st)); 305 px_free(st); 306 } 307 308 static const PushFilterOps pkt_stream_filter = { 309 pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free 310 }; 311 312 int 313 pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p) 314 { 315 int res; 316 317 res = write_tag_only(dst, tag); 318 if (res < 0) 319 return res; 320 321 return pushf_create(res_p, &pkt_stream_filter, NULL, dst); 322 } 323 324 /* 325 * Text conversion filter 326 */ 327 328 static int 329 crlf_process(PushFilter *dst, void *priv, const uint8 *data, int len) 330 { 331 const uint8 *data_end = data + len; 332 const uint8 *p2, 333 *p1 = data; 334 int line_len; 335 static const uint8 crlf[] = {'\r', '\n'}; 336 int res = 0; 337 338 while (p1 < data_end) 339 { 340 p2 = memchr(p1, '\n', data_end - p1); 341 if (p2 == NULL) 342 p2 = data_end; 343 344 line_len = p2 - p1; 345 346 /* write data */ 347 res = 0; 348 if (line_len > 0) 349 { 350 res = pushf_write(dst, p1, line_len); 351 if (res < 0) 352 break; 353 p1 += line_len; 354 } 355 356 /* write crlf */ 357 while (p1 < data_end && *p1 == '\n') 358 { 359 res = pushf_write(dst, crlf, 2); 360 if (res < 0) 361 break; 362 p1++; 363 } 364 } 365 return res; 366 } 367 368 static const PushFilterOps crlf_filter = { 369 NULL, crlf_process, NULL, NULL 370 }; 371 372 /* 373 * Initialize literal data packet 374 */ 375 static int 376 init_litdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst) 377 { 378 int res; 379 int hdrlen; 380 uint8 hdr[6]; 381 uint32 t; 382 PushFilter *pkt; 383 int type; 384 385 /* 386 * Create header 387 */ 388 389 if (ctx->text_mode) 390 type = ctx->unicode_mode ? 'u' : 't'; 391 else 392 type = 'b'; 393 394 /* 395 * Store the creation time into packet. The goal is to have as few known 396 * bytes as possible. 397 */ 398 t = (uint32) time(NULL); 399 400 hdr[0] = type; 401 hdr[1] = 0; 402 hdr[2] = (t >> 24) & 255; 403 hdr[3] = (t >> 16) & 255; 404 hdr[4] = (t >> 8) & 255; 405 hdr[5] = t & 255; 406 hdrlen = 6; 407 408 res = write_tag_only(dst, PGP_PKT_LITERAL_DATA); 409 if (res < 0) 410 return res; 411 412 res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst); 413 if (res < 0) 414 return res; 415 416 res = pushf_write(pkt, hdr, hdrlen); 417 if (res < 0) 418 { 419 pushf_free(pkt); 420 return res; 421 } 422 423 *pf_res = pkt; 424 return 0; 425 } 426 427 /* 428 * Initialize compression filter 429 */ 430 static int 431 init_compress(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst) 432 { 433 int res; 434 uint8 type = ctx->compress_algo; 435 PushFilter *pkt; 436 437 res = write_tag_only(dst, PGP_PKT_COMPRESSED_DATA); 438 if (res < 0) 439 return res; 440 441 res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst); 442 if (res < 0) 443 return res; 444 445 res = pushf_write(pkt, &type, 1); 446 if (res >= 0) 447 res = pgp_compress_filter(pf_res, ctx, pkt); 448 449 if (res < 0) 450 pushf_free(pkt); 451 452 return res; 453 } 454 455 /* 456 * Initialize encdata packet 457 */ 458 static int 459 init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst) 460 { 461 int res; 462 int tag; 463 464 if (ctx->disable_mdc) 465 tag = PGP_PKT_SYMENCRYPTED_DATA; 466 else 467 tag = PGP_PKT_SYMENCRYPTED_DATA_MDC; 468 469 res = write_tag_only(dst, tag); 470 if (res < 0) 471 return res; 472 473 return pushf_create(pf_res, &pkt_stream_filter, ctx, dst); 474 } 475 476 /* 477 * write prefix 478 */ 479 static int 480 write_prefix(PGP_Context *ctx, PushFilter *dst) 481 { 482 uint8 prefix[PGP_MAX_BLOCK + 2]; 483 int res, 484 bs; 485 486 bs = pgp_get_cipher_block_size(ctx->cipher_algo); 487 if (!pg_strong_random(prefix, bs)) 488 return PXE_NO_RANDOM; 489 490 prefix[bs + 0] = prefix[bs - 2]; 491 prefix[bs + 1] = prefix[bs - 1]; 492 493 res = pushf_write(dst, prefix, bs + 2); 494 px_memset(prefix, 0, bs + 2); 495 return res < 0 ? res : 0; 496 } 497 498 /* 499 * write symmetrically encrypted session key packet 500 */ 501 502 static int 503 symencrypt_sesskey(PGP_Context *ctx, uint8 *dst) 504 { 505 int res; 506 PGP_CFB *cfb; 507 uint8 algo = ctx->cipher_algo; 508 509 res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo, 510 ctx->s2k.key, ctx->s2k.key_len, 0, NULL); 511 if (res < 0) 512 return res; 513 514 pgp_cfb_encrypt(cfb, &algo, 1, dst); 515 pgp_cfb_encrypt(cfb, ctx->sess_key, ctx->sess_key_len, dst + 1); 516 517 pgp_cfb_free(cfb); 518 return ctx->sess_key_len + 1; 519 } 520 521 /* 5.3: Symmetric-Key Encrypted Session-Key */ 522 static int 523 write_symenc_sesskey(PGP_Context *ctx, PushFilter *dst) 524 { 525 uint8 pkt[256]; 526 int pktlen; 527 int res; 528 uint8 *p = pkt; 529 530 *p++ = 4; /* 5.3 - version number */ 531 *p++ = ctx->s2k_cipher_algo; 532 533 *p++ = ctx->s2k.mode; 534 *p++ = ctx->s2k.digest_algo; 535 if (ctx->s2k.mode > 0) 536 { 537 memcpy(p, ctx->s2k.salt, 8); 538 p += 8; 539 } 540 if (ctx->s2k.mode == 3) 541 *p++ = ctx->s2k.iter; 542 543 if (ctx->use_sess_key) 544 { 545 res = symencrypt_sesskey(ctx, p); 546 if (res < 0) 547 return res; 548 p += res; 549 } 550 551 pktlen = p - pkt; 552 res = write_normal_header(dst, PGP_PKT_SYMENCRYPTED_SESSKEY, pktlen); 553 if (res >= 0) 554 res = pushf_write(dst, pkt, pktlen); 555 556 px_memset(pkt, 0, pktlen); 557 return res; 558 } 559 560 /* 561 * key setup 562 */ 563 static int 564 init_s2k_key(PGP_Context *ctx) 565 { 566 int res; 567 568 if (ctx->s2k_cipher_algo < 0) 569 ctx->s2k_cipher_algo = ctx->cipher_algo; 570 571 res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo, ctx->s2k_count); 572 if (res < 0) 573 return res; 574 575 return pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo, 576 ctx->sym_key, ctx->sym_key_len); 577 } 578 579 static int 580 init_sess_key(PGP_Context *ctx) 581 { 582 if (ctx->use_sess_key || ctx->pub_key) 583 { 584 ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo); 585 if (!pg_strong_random(ctx->sess_key, ctx->sess_key_len)) 586 return PXE_NO_RANDOM; 587 } 588 else 589 { 590 ctx->sess_key_len = ctx->s2k.key_len; 591 memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len); 592 } 593 594 return 0; 595 } 596 597 /* 598 * combine 599 */ 600 int 601 pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst) 602 { 603 int res; 604 int len; 605 uint8 *buf; 606 PushFilter *pf, 607 *pf_tmp; 608 609 /* 610 * do we have any key 611 */ 612 if (!ctx->sym_key && !ctx->pub_key) 613 return PXE_ARGUMENT_ERROR; 614 615 /* MBuf writer */ 616 res = pushf_create_mbuf_writer(&pf, dst); 617 if (res < 0) 618 goto out; 619 620 /* 621 * initialize symkey 622 */ 623 if (ctx->sym_key) 624 { 625 res = init_s2k_key(ctx); 626 if (res < 0) 627 goto out; 628 } 629 630 res = init_sess_key(ctx); 631 if (res < 0) 632 goto out; 633 634 /* 635 * write keypkt 636 */ 637 if (ctx->pub_key) 638 res = pgp_write_pubenc_sesskey(ctx, pf); 639 else 640 res = write_symenc_sesskey(ctx, pf); 641 if (res < 0) 642 goto out; 643 644 /* encrypted data pkt */ 645 res = init_encdata_packet(&pf_tmp, ctx, pf); 646 if (res < 0) 647 goto out; 648 pf = pf_tmp; 649 650 /* encrypter */ 651 res = pushf_create(&pf_tmp, &encrypt_filter, ctx, pf); 652 if (res < 0) 653 goto out; 654 pf = pf_tmp; 655 656 /* hasher */ 657 if (ctx->disable_mdc == 0) 658 { 659 res = pushf_create(&pf_tmp, &mdc_filter, ctx, pf); 660 if (res < 0) 661 goto out; 662 pf = pf_tmp; 663 } 664 665 /* prefix */ 666 res = write_prefix(ctx, pf); 667 if (res < 0) 668 goto out; 669 670 /* compressor */ 671 if (ctx->compress_algo > 0 && ctx->compress_level > 0) 672 { 673 res = init_compress(&pf_tmp, ctx, pf); 674 if (res < 0) 675 goto out; 676 pf = pf_tmp; 677 } 678 679 /* data streamer */ 680 res = init_litdata_packet(&pf_tmp, ctx, pf); 681 if (res < 0) 682 goto out; 683 pf = pf_tmp; 684 685 686 /* text conversion? */ 687 if (ctx->text_mode && ctx->convert_crlf) 688 { 689 res = pushf_create(&pf_tmp, &crlf_filter, ctx, pf); 690 if (res < 0) 691 goto out; 692 pf = pf_tmp; 693 } 694 695 /* 696 * chain complete 697 */ 698 699 len = mbuf_grab(src, mbuf_avail(src), &buf); 700 res = pushf_write(pf, buf, len); 701 if (res >= 0) 702 res = pushf_flush(pf); 703 out: 704 pushf_free_all(pf); 705 return res; 706 } 707