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