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