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