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 *
render_newlen(uint8 * h,int len)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
write_tag_only(PushFilter * dst,int tag)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
write_normal_header(PushFilter * dst,int tag,int len)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
mdc_init(PushFilter * dst,void * init_arg,void ** priv_p)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
mdc_write(PushFilter * dst,void * priv,const uint8 * data,int len)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
mdc_flush(PushFilter * dst,void * priv)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
mdc_free(void * priv)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
encrypt_init(PushFilter * next,void * init_arg,void ** priv_p)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
encrypt_process(PushFilter * next,void * priv,const uint8 * data,int len)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
encrypt_free(void * priv)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
pkt_stream_init(PushFilter * next,void * init_arg,void ** priv_p)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
pkt_stream_process(PushFilter * next,void * priv,const uint8 * data,int len)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
pkt_stream_flush(PushFilter * next,void * priv)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
pkt_stream_free(void * priv)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
pgp_create_pkt_writer(PushFilter * dst,int tag,PushFilter ** res_p)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
crlf_process(PushFilter * dst,void * priv,const uint8 * data,int len)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
init_litdata_packet(PushFilter ** pf_res,PGP_Context * ctx,PushFilter * dst)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
init_compress(PushFilter ** pf_res,PGP_Context * ctx,PushFilter * dst)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
init_encdata_packet(PushFilter ** pf_res,PGP_Context * ctx,PushFilter * dst)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
write_prefix(PGP_Context * ctx,PushFilter * dst)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
symencrypt_sesskey(PGP_Context * ctx,uint8 * dst)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
write_symenc_sesskey(PGP_Context * ctx,PushFilter * dst)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
init_s2k_key(PGP_Context * ctx)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
init_sess_key(PGP_Context * ctx)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
pgp_encrypt(PGP_Context * ctx,MBuf * src,MBuf * dst)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