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 	px_memset(st, 0, sizeof(*st));
221 	px_free(st);
222 }
223 
224 static const PushFilterOps encrypt_filter = {
225 	encrypt_init, encrypt_process, NULL, encrypt_free
226 };
227 
228 /*
229  * Write Streamable pkts
230  */
231 
232 struct PktStreamStat
233 {
234 	int			final_done;
235 	int			pkt_block;
236 };
237 
238 static int
pkt_stream_init(PushFilter * next,void * init_arg,void ** priv_p)239 pkt_stream_init(PushFilter *next, void *init_arg, void **priv_p)
240 {
241 	struct PktStreamStat *st;
242 
243 	st = px_alloc(sizeof(*st));
244 	st->final_done = 0;
245 	st->pkt_block = 1 << STREAM_BLOCK_SHIFT;
246 	*priv_p = st;
247 
248 	return st->pkt_block;
249 }
250 
251 static int
pkt_stream_process(PushFilter * next,void * priv,const uint8 * data,int len)252 pkt_stream_process(PushFilter *next, void *priv, const uint8 *data, int len)
253 {
254 	int			res;
255 	uint8		hdr[8];
256 	uint8	   *h = hdr;
257 	struct PktStreamStat *st = priv;
258 
259 	if (st->final_done)
260 		return PXE_BUG;
261 
262 	if (len == st->pkt_block)
263 		*h++ = STREAM_ID | STREAM_BLOCK_SHIFT;
264 	else
265 	{
266 		h = render_newlen(h, len);
267 		st->final_done = 1;
268 	}
269 
270 	res = pushf_write(next, hdr, h - hdr);
271 	if (res < 0)
272 		return res;
273 
274 	return pushf_write(next, data, len);
275 }
276 
277 static int
pkt_stream_flush(PushFilter * next,void * priv)278 pkt_stream_flush(PushFilter *next, void *priv)
279 {
280 	int			res;
281 	uint8		hdr[8];
282 	uint8	   *h = hdr;
283 	struct PktStreamStat *st = priv;
284 
285 	/* stream MUST end with normal packet. */
286 	if (!st->final_done)
287 	{
288 		h = render_newlen(h, 0);
289 		res = pushf_write(next, hdr, h - hdr);
290 		if (res < 0)
291 			return res;
292 		st->final_done = 1;
293 	}
294 	return 0;
295 }
296 
297 static void
pkt_stream_free(void * priv)298 pkt_stream_free(void *priv)
299 {
300 	struct PktStreamStat *st = priv;
301 
302 	px_memset(st, 0, sizeof(*st));
303 	px_free(st);
304 }
305 
306 static const PushFilterOps pkt_stream_filter = {
307 	pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free
308 };
309 
310 int
pgp_create_pkt_writer(PushFilter * dst,int tag,PushFilter ** res_p)311 pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p)
312 {
313 	int			res;
314 
315 	res = write_tag_only(dst, tag);
316 	if (res < 0)
317 		return res;
318 
319 	return pushf_create(res_p, &pkt_stream_filter, NULL, dst);
320 }
321 
322 /*
323  * Text conversion filter
324  */
325 
326 static int
crlf_process(PushFilter * dst,void * priv,const uint8 * data,int len)327 crlf_process(PushFilter *dst, void *priv, const uint8 *data, int len)
328 {
329 	const uint8 *data_end = data + len;
330 	const uint8 *p2,
331 			   *p1 = data;
332 	int			line_len;
333 	static const uint8 crlf[] = {'\r', '\n'};
334 	int			res = 0;
335 
336 	while (p1 < data_end)
337 	{
338 		p2 = memchr(p1, '\n', data_end - p1);
339 		if (p2 == NULL)
340 			p2 = data_end;
341 
342 		line_len = p2 - p1;
343 
344 		/* write data */
345 		res = 0;
346 		if (line_len > 0)
347 		{
348 			res = pushf_write(dst, p1, line_len);
349 			if (res < 0)
350 				break;
351 			p1 += line_len;
352 		}
353 
354 		/* write crlf */
355 		while (p1 < data_end && *p1 == '\n')
356 		{
357 			res = pushf_write(dst, crlf, 2);
358 			if (res < 0)
359 				break;
360 			p1++;
361 		}
362 	}
363 	return res;
364 }
365 
366 static const PushFilterOps crlf_filter = {
367 	NULL, crlf_process, NULL, NULL
368 };
369 
370 /*
371  * Initialize literal data packet
372  */
373 static int
init_litdata_packet(PushFilter ** pf_res,PGP_Context * ctx,PushFilter * dst)374 init_litdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
375 {
376 	int			res;
377 	int			hdrlen;
378 	uint8		hdr[6];
379 	uint32		t;
380 	PushFilter *pkt;
381 	int			type;
382 
383 	/*
384 	 * Create header
385 	 */
386 
387 	if (ctx->text_mode)
388 		type = ctx->unicode_mode ? 'u' : 't';
389 	else
390 		type = 'b';
391 
392 	/*
393 	 * Store the creation time into packet. The goal is to have as few known
394 	 * bytes as possible.
395 	 */
396 	t = (uint32) time(NULL);
397 
398 	hdr[0] = type;
399 	hdr[1] = 0;
400 	hdr[2] = (t >> 24) & 255;
401 	hdr[3] = (t >> 16) & 255;
402 	hdr[4] = (t >> 8) & 255;
403 	hdr[5] = t & 255;
404 	hdrlen = 6;
405 
406 	res = write_tag_only(dst, PGP_PKT_LITERAL_DATA);
407 	if (res < 0)
408 		return res;
409 
410 	res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
411 	if (res < 0)
412 		return res;
413 
414 	res = pushf_write(pkt, hdr, hdrlen);
415 	if (res < 0)
416 	{
417 		pushf_free(pkt);
418 		return res;
419 	}
420 
421 	*pf_res = pkt;
422 	return 0;
423 }
424 
425 /*
426  * Initialize compression filter
427  */
428 static int
init_compress(PushFilter ** pf_res,PGP_Context * ctx,PushFilter * dst)429 init_compress(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
430 {
431 	int			res;
432 	uint8		type = ctx->compress_algo;
433 	PushFilter *pkt;
434 
435 	res = write_tag_only(dst, PGP_PKT_COMPRESSED_DATA);
436 	if (res < 0)
437 		return res;
438 
439 	res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
440 	if (res < 0)
441 		return res;
442 
443 	res = pushf_write(pkt, &type, 1);
444 	if (res >= 0)
445 		res = pgp_compress_filter(pf_res, ctx, pkt);
446 
447 	if (res < 0)
448 		pushf_free(pkt);
449 
450 	return res;
451 }
452 
453 /*
454  * Initialize encdata packet
455  */
456 static int
init_encdata_packet(PushFilter ** pf_res,PGP_Context * ctx,PushFilter * dst)457 init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
458 {
459 	int			res;
460 	int			tag;
461 
462 	if (ctx->disable_mdc)
463 		tag = PGP_PKT_SYMENCRYPTED_DATA;
464 	else
465 		tag = PGP_PKT_SYMENCRYPTED_DATA_MDC;
466 
467 	res = write_tag_only(dst, tag);
468 	if (res < 0)
469 		return res;
470 
471 	return pushf_create(pf_res, &pkt_stream_filter, ctx, dst);
472 }
473 
474 /*
475  * write prefix
476  */
477 static int
write_prefix(PGP_Context * ctx,PushFilter * dst)478 write_prefix(PGP_Context *ctx, PushFilter *dst)
479 {
480 	uint8		prefix[PGP_MAX_BLOCK + 2];
481 	int			res,
482 				bs;
483 
484 	bs = pgp_get_cipher_block_size(ctx->cipher_algo);
485 	res = px_get_random_bytes(prefix, bs);
486 	if (res < 0)
487 		return res;
488 
489 	prefix[bs + 0] = prefix[bs - 2];
490 	prefix[bs + 1] = prefix[bs - 1];
491 
492 	res = pushf_write(dst, prefix, bs + 2);
493 	px_memset(prefix, 0, bs + 2);
494 	return res < 0 ? res : 0;
495 }
496 
497 /*
498  * write symmetrically encrypted session key packet
499  */
500 
501 static int
symencrypt_sesskey(PGP_Context * ctx,uint8 * dst)502 symencrypt_sesskey(PGP_Context *ctx, uint8 *dst)
503 {
504 	int			res;
505 	PGP_CFB    *cfb;
506 	uint8		algo = ctx->cipher_algo;
507 
508 	res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
509 						 ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
510 	if (res < 0)
511 		return res;
512 
513 	pgp_cfb_encrypt(cfb, &algo, 1, dst);
514 	pgp_cfb_encrypt(cfb, ctx->sess_key, ctx->sess_key_len, dst + 1);
515 
516 	pgp_cfb_free(cfb);
517 	return ctx->sess_key_len + 1;
518 }
519 
520 /* 5.3: Symmetric-Key Encrypted Session-Key */
521 static int
write_symenc_sesskey(PGP_Context * ctx,PushFilter * dst)522 write_symenc_sesskey(PGP_Context *ctx, PushFilter *dst)
523 {
524 	uint8		pkt[256];
525 	int			pktlen;
526 	int			res;
527 	uint8	   *p = pkt;
528 
529 	*p++ = 4;					/* 5.3 - version number  */
530 	*p++ = ctx->s2k_cipher_algo;
531 
532 	*p++ = ctx->s2k.mode;
533 	*p++ = ctx->s2k.digest_algo;
534 	if (ctx->s2k.mode > 0)
535 	{
536 		memcpy(p, ctx->s2k.salt, 8);
537 		p += 8;
538 	}
539 	if (ctx->s2k.mode == 3)
540 		*p++ = ctx->s2k.iter;
541 
542 	if (ctx->use_sess_key)
543 	{
544 		res = symencrypt_sesskey(ctx, p);
545 		if (res < 0)
546 			return res;
547 		p += res;
548 	}
549 
550 	pktlen = p - pkt;
551 	res = write_normal_header(dst, PGP_PKT_SYMENCRYPTED_SESSKEY, pktlen);
552 	if (res >= 0)
553 		res = pushf_write(dst, pkt, pktlen);
554 
555 	px_memset(pkt, 0, pktlen);
556 	return res;
557 }
558 
559 /*
560  * key setup
561  */
562 static int
init_s2k_key(PGP_Context * ctx)563 init_s2k_key(PGP_Context *ctx)
564 {
565 	int			res;
566 
567 	if (ctx->s2k_cipher_algo < 0)
568 		ctx->s2k_cipher_algo = ctx->cipher_algo;
569 
570 	res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo, ctx->s2k_count);
571 	if (res < 0)
572 		return res;
573 
574 	return pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
575 						   ctx->sym_key, ctx->sym_key_len);
576 }
577 
578 static int
init_sess_key(PGP_Context * ctx)579 init_sess_key(PGP_Context *ctx)
580 {
581 	int			res;
582 
583 	if (ctx->use_sess_key || ctx->pub_key)
584 	{
585 		ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo);
586 		res = px_get_random_bytes(ctx->sess_key, ctx->sess_key_len);
587 		if (res < 0)
588 			return res;
589 	}
590 	else
591 	{
592 		ctx->sess_key_len = ctx->s2k.key_len;
593 		memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
594 	}
595 
596 	return 0;
597 }
598 
599 /*
600  * combine
601  */
602 int
pgp_encrypt(PGP_Context * ctx,MBuf * src,MBuf * dst)603 pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
604 {
605 	int			res;
606 	int			len;
607 	uint8	   *buf;
608 	PushFilter *pf,
609 			   *pf_tmp;
610 
611 	/*
612 	 * do we have any key
613 	 */
614 	if (!ctx->sym_key && !ctx->pub_key)
615 		return PXE_ARGUMENT_ERROR;
616 
617 	/* MBuf writer */
618 	res = pushf_create_mbuf_writer(&pf, dst);
619 	if (res < 0)
620 		goto out;
621 
622 	/*
623 	 * initialize symkey
624 	 */
625 	if (ctx->sym_key)
626 	{
627 		res = init_s2k_key(ctx);
628 		if (res < 0)
629 			goto out;
630 	}
631 
632 	res = init_sess_key(ctx);
633 	if (res < 0)
634 		goto out;
635 
636 	/*
637 	 * write keypkt
638 	 */
639 	if (ctx->pub_key)
640 		res = pgp_write_pubenc_sesskey(ctx, pf);
641 	else
642 		res = write_symenc_sesskey(ctx, pf);
643 	if (res < 0)
644 		goto out;
645 
646 	/* encrypted data pkt */
647 	res = init_encdata_packet(&pf_tmp, ctx, pf);
648 	if (res < 0)
649 		goto out;
650 	pf = pf_tmp;
651 
652 	/* encrypter */
653 	res = pushf_create(&pf_tmp, &encrypt_filter, ctx, pf);
654 	if (res < 0)
655 		goto out;
656 	pf = pf_tmp;
657 
658 	/* hasher */
659 	if (ctx->disable_mdc == 0)
660 	{
661 		res = pushf_create(&pf_tmp, &mdc_filter, ctx, pf);
662 		if (res < 0)
663 			goto out;
664 		pf = pf_tmp;
665 	}
666 
667 	/* prefix */
668 	res = write_prefix(ctx, pf);
669 	if (res < 0)
670 		goto out;
671 
672 	/* compressor */
673 	if (ctx->compress_algo > 0 && ctx->compress_level > 0)
674 	{
675 		res = init_compress(&pf_tmp, ctx, pf);
676 		if (res < 0)
677 			goto out;
678 		pf = pf_tmp;
679 	}
680 
681 	/* data streamer */
682 	res = init_litdata_packet(&pf_tmp, ctx, pf);
683 	if (res < 0)
684 		goto out;
685 	pf = pf_tmp;
686 
687 
688 	/* text conversion? */
689 	if (ctx->text_mode && ctx->convert_crlf)
690 	{
691 		res = pushf_create(&pf_tmp, &crlf_filter, ctx, pf);
692 		if (res < 0)
693 			goto out;
694 		pf = pf_tmp;
695 	}
696 
697 	/*
698 	 * chain complete
699 	 */
700 
701 	len = mbuf_grab(src, mbuf_avail(src), &buf);
702 	res = pushf_write(pf, buf, len);
703 	if (res >= 0)
704 		res = pushf_flush(pf);
705 out:
706 	pushf_free_all(pf);
707 	return res;
708 }
709