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