5 * Copyright (c) 2005 Marko Kreen
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
41 #define MDC_DIGEST_LEN 20
42 #define STREAM_ID 0xE0
43 #define STREAM_BLOCK_SHIFT 14
46 render_newlen(uint8
*h
, int len
)
52 else if (len
> 191 && len
<= 8383)
54 *h
++ = ((len
- 192) >> 8) + 192;
55 *h
++ = (len
- 192) & 255;
60 *h
++ = (len
>> 24) & 255;
61 *h
++ = (len
>> 16) & 255;
62 *h
++ = (len
>> 8) & 255;
69 write_tag_only(PushFilter
* dst
, int tag
)
71 uint8 hdr
= 0xC0 | tag
;
73 return pushf_write(dst
, &hdr
, 1);
77 write_normal_header(PushFilter
* dst
, int tag
, int len
)
83 h
= render_newlen(h
, len
);
84 return pushf_write(dst
, hdr
, h
- hdr
);
93 mdc_init(PushFilter
* dst
, void *init_arg
, void **priv_p
)
98 res
= pgp_load_digest(PGP_DIGEST_SHA1
, &md
);
107 mdc_write(PushFilter
* dst
, void *priv
, const uint8
*data
, int len
)
111 px_md_update(md
, data
, len
);
112 return pushf_write(dst
, data
, len
);
116 mdc_flush(PushFilter
* dst
, void *priv
)
119 uint8 pkt
[2 + MDC_DIGEST_LEN
];
126 pkt
[1] = 0x14; /* MDC_DIGEST_LEN */
127 px_md_update(md
, pkt
, 2);
128 px_md_finish(md
, pkt
+ 2);
130 res
= pushf_write(dst
, pkt
, 2 + MDC_DIGEST_LEN
);
131 memset(pkt
, 0, 2 + MDC_DIGEST_LEN
);
143 static const PushFilterOps mdc_filter
= {
144 mdc_init
, mdc_write
, mdc_flush
, mdc_free
149 * Encrypted pkt writer
159 encrypt_init(PushFilter
* next
, void *init_arg
, void **priv_p
)
162 PGP_Context
*ctx
= init_arg
;
167 /* should we use newer packet format? */
168 if (ctx
->disable_mdc
== 0)
173 res
= pushf_write(next
, &ver
, 1);
177 res
= pgp_cfb_create(&ciph
, ctx
->cipher_algo
,
178 ctx
->sess_key
, ctx
->sess_key_len
, resync
, NULL
);
182 st
= px_alloc(sizeof(*st
));
183 memset(st
, 0, sizeof(*st
));
191 encrypt_process(PushFilter
* next
, void *priv
, const uint8
*data
, int len
)
194 struct EncStat
*st
= priv
;
199 int tmplen
= avail
> ENCBUF
? ENCBUF
: avail
;
201 res
= pgp_cfb_encrypt(st
->ciph
, data
, tmplen
, st
->buf
);
205 res
= pushf_write(next
, st
->buf
, tmplen
);
216 encrypt_free(void *priv
)
218 struct EncStat
*st
= priv
;
220 memset(st
, 0, sizeof(*st
));
224 static const PushFilterOps encrypt_filter
= {
225 encrypt_init
, encrypt_process
, NULL
, encrypt_free
229 * Write Streamable pkts
239 pkt_stream_init(PushFilter
* next
, void *init_arg
, void **priv_p
)
241 struct PktStreamStat
*st
;
243 st
= px_alloc(sizeof(*st
));
245 st
->pkt_block
= 1 << STREAM_BLOCK_SHIFT
;
248 return st
->pkt_block
;
252 pkt_stream_process(PushFilter
* next
, void *priv
, const uint8
*data
, int len
)
257 struct PktStreamStat
*st
= priv
;
262 if (len
== st
->pkt_block
)
263 *h
++ = STREAM_ID
| STREAM_BLOCK_SHIFT
;
266 h
= render_newlen(h
, len
);
270 res
= pushf_write(next
, hdr
, h
- hdr
);
274 return pushf_write(next
, data
, len
);
278 pkt_stream_flush(PushFilter
* next
, void *priv
)
283 struct PktStreamStat
*st
= priv
;
285 /* stream MUST end with normal packet. */
288 h
= render_newlen(h
, 0);
289 res
= pushf_write(next
, hdr
, h
- hdr
);
298 pkt_stream_free(void *priv
)
300 struct PktStreamStat
*st
= priv
;
302 memset(st
, 0, sizeof(*st
));
306 static const PushFilterOps pkt_stream_filter
= {
307 pkt_stream_init
, pkt_stream_process
, pkt_stream_flush
, pkt_stream_free
311 pgp_create_pkt_writer(PushFilter
* dst
, int tag
, PushFilter
** res_p
)
315 res
= write_tag_only(dst
, tag
);
319 return pushf_create(res_p
, &pkt_stream_filter
, NULL
, dst
);
323 * Text conversion filter
327 crlf_process(PushFilter
* dst
, void *priv
, const uint8
*data
, int len
)
329 const uint8
*data_end
= data
+ len
;
333 static const uint8 crlf
[] = {'\r', '\n'};
336 while (p1
< data_end
)
338 p2
= memchr(p1
, '\n', data_end
- p1
);
348 res
= pushf_write(dst
, p1
, line_len
);
355 while (p1
< data_end
&& *p1
== '\n')
357 res
= pushf_write(dst
, crlf
, 2);
366 static const PushFilterOps crlf_filter
= {
367 NULL
, crlf_process
, NULL
, NULL
371 * Initialize literal data packet
374 init_litdata_packet(PushFilter
** pf_res
, PGP_Context
* ctx
, PushFilter
* dst
)
388 type
= ctx
->unicode_mode
? 'u' : 't';
393 * Store the creation time into packet. The goal is to have as few known
396 t
= (uint32
) time(NULL
);
400 hdr
[2] = (t
>> 24) & 255;
401 hdr
[3] = (t
>> 16) & 255;
402 hdr
[4] = (t
>> 8) & 255;
406 res
= write_tag_only(dst
, PGP_PKT_LITERAL_DATA
);
410 res
= pushf_create(&pkt
, &pkt_stream_filter
, ctx
, dst
);
414 res
= pushf_write(pkt
, hdr
, hdrlen
);
426 * Initialize compression filter
429 init_compress(PushFilter
** pf_res
, PGP_Context
* ctx
, PushFilter
* dst
)
432 uint8 type
= ctx
->compress_algo
;
435 res
= write_tag_only(dst
, PGP_PKT_COMPRESSED_DATA
);
439 res
= pushf_create(&pkt
, &pkt_stream_filter
, ctx
, dst
);
443 res
= pushf_write(pkt
, &type
, 1);
445 res
= pgp_compress_filter(pf_res
, ctx
, pkt
);
454 * Initialize encdata packet
457 init_encdata_packet(PushFilter
** pf_res
, PGP_Context
* ctx
, PushFilter
* dst
)
462 if (ctx
->disable_mdc
)
463 tag
= PGP_PKT_SYMENCRYPTED_DATA
;
465 tag
= PGP_PKT_SYMENCRYPTED_DATA_MDC
;
467 res
= write_tag_only(dst
, tag
);
471 return pushf_create(pf_res
, &pkt_stream_filter
, ctx
, dst
);
478 write_prefix(PGP_Context
* ctx
, PushFilter
* dst
)
480 uint8 prefix
[PGP_MAX_BLOCK
+ 2];
484 bs
= pgp_get_cipher_block_size(ctx
->cipher_algo
);
485 res
= px_get_random_bytes(prefix
, bs
);
489 prefix
[bs
+ 0] = prefix
[bs
- 2];
490 prefix
[bs
+ 1] = prefix
[bs
- 1];
492 res
= pushf_write(dst
, prefix
, bs
+ 2);
493 memset(prefix
, 0, bs
+ 2);
494 return res
< 0 ? res
: 0;
498 * write symmetrically encrypted session key packet
502 symencrypt_sesskey(PGP_Context
* ctx
, uint8
*dst
)
506 uint8 algo
= ctx
->cipher_algo
;
508 res
= pgp_cfb_create(&cfb
, ctx
->s2k_cipher_algo
,
509 ctx
->s2k
.key
, ctx
->s2k
.key_len
, 0, NULL
);
513 pgp_cfb_encrypt(cfb
, &algo
, 1, dst
);
514 pgp_cfb_encrypt(cfb
, ctx
->sess_key
, ctx
->sess_key_len
, dst
+ 1);
517 return ctx
->sess_key_len
+ 1;
520 /* 5.3: Symmetric-Key Encrypted Session-Key */
522 write_symenc_sesskey(PGP_Context
* ctx
, PushFilter
* dst
)
529 *p
++ = 4; /* 5.3 - version number */
530 *p
++ = ctx
->s2k_cipher_algo
;
532 *p
++ = ctx
->s2k
.mode
;
533 *p
++ = ctx
->s2k
.digest_algo
;
534 if (ctx
->s2k
.mode
> 0)
536 memcpy(p
, ctx
->s2k
.salt
, 8);
539 if (ctx
->s2k
.mode
== 3)
540 *p
++ = ctx
->s2k
.iter
;
542 if (ctx
->use_sess_key
)
544 res
= symencrypt_sesskey(ctx
, p
);
551 res
= write_normal_header(dst
, PGP_PKT_SYMENCRYPTED_SESSKEY
, pktlen
);
553 res
= pushf_write(dst
, pkt
, pktlen
);
555 memset(pkt
, 0, pktlen
);
563 init_s2k_key(PGP_Context
* ctx
)
567 if (ctx
->s2k_cipher_algo
< 0)
568 ctx
->s2k_cipher_algo
= ctx
->cipher_algo
;
570 res
= pgp_s2k_fill(&ctx
->s2k
, ctx
->s2k_mode
, ctx
->s2k_digest_algo
);
574 return pgp_s2k_process(&ctx
->s2k
, ctx
->s2k_cipher_algo
,
575 ctx
->sym_key
, ctx
->sym_key_len
);
579 init_sess_key(PGP_Context
* ctx
)
583 if (ctx
->use_sess_key
|| ctx
->pub_key
)
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
);
592 ctx
->sess_key_len
= ctx
->s2k
.key_len
;
593 memcpy(ctx
->sess_key
, ctx
->s2k
.key
, ctx
->s2k
.key_len
);
603 pgp_encrypt(PGP_Context
* ctx
, MBuf
* src
, MBuf
* dst
)
614 if (!ctx
->sym_key
&& !ctx
->pub_key
)
615 return PXE_ARGUMENT_ERROR
;
618 res
= pushf_create_mbuf_writer(&pf
, dst
);
627 res
= init_s2k_key(ctx
);
632 res
= init_sess_key(ctx
);
640 res
= pgp_write_pubenc_sesskey(ctx
, pf
);
642 res
= write_symenc_sesskey(ctx
, pf
);
646 /* encrypted data pkt */
647 res
= init_encdata_packet(&pf_tmp
, ctx
, pf
);
653 res
= pushf_create(&pf_tmp
, &encrypt_filter
, ctx
, pf
);
659 if (ctx
->disable_mdc
== 0)
661 res
= pushf_create(&pf_tmp
, &mdc_filter
, ctx
, pf
);
668 res
= write_prefix(ctx
, pf
);
673 if (ctx
->compress_algo
> 0 && ctx
->compress_level
> 0)
675 res
= init_compress(&pf_tmp
, ctx
, pf
);
682 res
= init_litdata_packet(&pf_tmp
, ctx
, pf
);
688 /* text conversion? */
689 if (ctx
->text_mode
&& ctx
->convert_crlf
)
691 res
= pushf_create(&pf_tmp
, &crlf_filter
, ctx
, pf
);
701 len
= mbuf_grab(src
, mbuf_avail(src
), &buf
);
702 res
= pushf_write(pf
, buf
, len
);
704 res
= pushf_flush(pf
);