mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			709 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			709 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * pgp-encrypt.c
 | 
						|
 *	  OpenPGP encrypt.
 | 
						|
 *
 | 
						|
 * Copyright (c) 2005 Marko Kreen
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *	  notice, this list of conditions and the following disclaimer.
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *	  notice, this list of conditions and the following disclaimer in the
 | 
						|
 *	  documentation and/or other materials provided with the distribution.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 | 
						|
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
 * ARE DISCLAIMED.	IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 | 
						|
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
						|
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
						|
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
						|
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
 * SUCH DAMAGE.
 | 
						|
 *
 | 
						|
 * contrib/pgcrypto/pgp-encrypt.c
 | 
						|
 */
 | 
						|
 | 
						|
#include "postgres.h"
 | 
						|
 | 
						|
#include <time.h>
 | 
						|
 | 
						|
#include "mbuf.h"
 | 
						|
#include "px.h"
 | 
						|
#include "pgp.h"
 | 
						|
 | 
						|
 | 
						|
#define MDC_DIGEST_LEN 20
 | 
						|
#define STREAM_ID 0xE0
 | 
						|
#define STREAM_BLOCK_SHIFT	14
 | 
						|
 | 
						|
static uint8 *
 | 
						|
render_newlen(uint8 *h, int len)
 | 
						|
{
 | 
						|
	if (len <= 191)
 | 
						|
	{
 | 
						|
		*h++ = len & 255;
 | 
						|
	}
 | 
						|
	else if (len > 191 && len <= 8383)
 | 
						|
	{
 | 
						|
		*h++ = ((len - 192) >> 8) + 192;
 | 
						|
		*h++ = (len - 192) & 255;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		*h++ = 255;
 | 
						|
		*h++ = (len >> 24) & 255;
 | 
						|
		*h++ = (len >> 16) & 255;
 | 
						|
		*h++ = (len >> 8) & 255;
 | 
						|
		*h++ = len & 255;
 | 
						|
	}
 | 
						|
	return h;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
write_tag_only(PushFilter *dst, int tag)
 | 
						|
{
 | 
						|
	uint8		hdr = 0xC0 | tag;
 | 
						|
 | 
						|
	return pushf_write(dst, &hdr, 1);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
write_normal_header(PushFilter *dst, int tag, int len)
 | 
						|
{
 | 
						|
	uint8		hdr[8];
 | 
						|
	uint8	   *h = hdr;
 | 
						|
 | 
						|
	*h++ = 0xC0 | tag;
 | 
						|
	h = render_newlen(h, len);
 | 
						|
	return pushf_write(dst, hdr, h - hdr);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * MAC writer
 | 
						|
 */
 | 
						|
 | 
						|
static int
 | 
						|
mdc_init(PushFilter *dst, void *init_arg, void **priv_p)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
	PX_MD	   *md;
 | 
						|
 | 
						|
	res = pgp_load_digest(PGP_DIGEST_SHA1, &md);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	*priv_p = md;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
mdc_write(PushFilter *dst, void *priv, const uint8 *data, int len)
 | 
						|
{
 | 
						|
	PX_MD	   *md = priv;
 | 
						|
 | 
						|
	px_md_update(md, data, len);
 | 
						|
	return pushf_write(dst, data, len);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
mdc_flush(PushFilter *dst, void *priv)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
	uint8		pkt[2 + MDC_DIGEST_LEN];
 | 
						|
	PX_MD	   *md = priv;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * create mdc pkt
 | 
						|
	 */
 | 
						|
	pkt[0] = 0xD3;
 | 
						|
	pkt[1] = 0x14;				/* MDC_DIGEST_LEN */
 | 
						|
	px_md_update(md, pkt, 2);
 | 
						|
	px_md_finish(md, pkt + 2);
 | 
						|
 | 
						|
	res = pushf_write(dst, pkt, 2 + MDC_DIGEST_LEN);
 | 
						|
	memset(pkt, 0, 2 + MDC_DIGEST_LEN);
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
mdc_free(void *priv)
 | 
						|
{
 | 
						|
	PX_MD	   *md = priv;
 | 
						|
 | 
						|
	px_md_free(md);
 | 
						|
}
 | 
						|
 | 
						|
static const PushFilterOps mdc_filter = {
 | 
						|
	mdc_init, mdc_write, mdc_flush, mdc_free
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Encrypted pkt writer
 | 
						|
 */
 | 
						|
#define ENCBUF 8192
 | 
						|
struct EncStat
 | 
						|
{
 | 
						|
	PGP_CFB    *ciph;
 | 
						|
	uint8		buf[ENCBUF];
 | 
						|
};
 | 
						|
 | 
						|
static int
 | 
						|
encrypt_init(PushFilter *next, void *init_arg, void **priv_p)
 | 
						|
{
 | 
						|
	struct EncStat *st;
 | 
						|
	PGP_Context *ctx = init_arg;
 | 
						|
	PGP_CFB    *ciph;
 | 
						|
	int			resync = 1;
 | 
						|
	int			res;
 | 
						|
 | 
						|
	/* should we use newer packet format? */
 | 
						|
	if (ctx->disable_mdc == 0)
 | 
						|
	{
 | 
						|
		uint8		ver = 1;
 | 
						|
 | 
						|
		resync = 0;
 | 
						|
		res = pushf_write(next, &ver, 1);
 | 
						|
		if (res < 0)
 | 
						|
			return res;
 | 
						|
	}
 | 
						|
	res = pgp_cfb_create(&ciph, ctx->cipher_algo,
 | 
						|
						 ctx->sess_key, ctx->sess_key_len, resync, NULL);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	st = px_alloc(sizeof(*st));
 | 
						|
	memset(st, 0, sizeof(*st));
 | 
						|
	st->ciph = ciph;
 | 
						|
 | 
						|
	*priv_p = st;
 | 
						|
	return ENCBUF;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
encrypt_process(PushFilter *next, void *priv, const uint8 *data, int len)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
	struct EncStat *st = priv;
 | 
						|
	int			avail = len;
 | 
						|
 | 
						|
	while (avail > 0)
 | 
						|
	{
 | 
						|
		int			tmplen = avail > ENCBUF ? ENCBUF : avail;
 | 
						|
 | 
						|
		res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf);
 | 
						|
		if (res < 0)
 | 
						|
			return res;
 | 
						|
 | 
						|
		res = pushf_write(next, st->buf, tmplen);
 | 
						|
		if (res < 0)
 | 
						|
			return res;
 | 
						|
 | 
						|
		data += tmplen;
 | 
						|
		avail -= tmplen;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
encrypt_free(void *priv)
 | 
						|
{
 | 
						|
	struct EncStat *st = priv;
 | 
						|
 | 
						|
	memset(st, 0, sizeof(*st));
 | 
						|
	px_free(st);
 | 
						|
}
 | 
						|
 | 
						|
static const PushFilterOps encrypt_filter = {
 | 
						|
	encrypt_init, encrypt_process, NULL, encrypt_free
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * Write Streamable pkts
 | 
						|
 */
 | 
						|
 | 
						|
struct PktStreamStat
 | 
						|
{
 | 
						|
	int			final_done;
 | 
						|
	int			pkt_block;
 | 
						|
};
 | 
						|
 | 
						|
static int
 | 
						|
pkt_stream_init(PushFilter *next, void *init_arg, void **priv_p)
 | 
						|
{
 | 
						|
	struct PktStreamStat *st;
 | 
						|
 | 
						|
	st = px_alloc(sizeof(*st));
 | 
						|
	st->final_done = 0;
 | 
						|
	st->pkt_block = 1 << STREAM_BLOCK_SHIFT;
 | 
						|
	*priv_p = st;
 | 
						|
 | 
						|
	return st->pkt_block;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
pkt_stream_process(PushFilter *next, void *priv, const uint8 *data, int len)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
	uint8		hdr[8];
 | 
						|
	uint8	   *h = hdr;
 | 
						|
	struct PktStreamStat *st = priv;
 | 
						|
 | 
						|
	if (st->final_done)
 | 
						|
		return PXE_BUG;
 | 
						|
 | 
						|
	if (len == st->pkt_block)
 | 
						|
		*h++ = STREAM_ID | STREAM_BLOCK_SHIFT;
 | 
						|
	else
 | 
						|
	{
 | 
						|
		h = render_newlen(h, len);
 | 
						|
		st->final_done = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	res = pushf_write(next, hdr, h - hdr);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	return pushf_write(next, data, len);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
pkt_stream_flush(PushFilter *next, void *priv)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
	uint8		hdr[8];
 | 
						|
	uint8	   *h = hdr;
 | 
						|
	struct PktStreamStat *st = priv;
 | 
						|
 | 
						|
	/* stream MUST end with normal packet. */
 | 
						|
	if (!st->final_done)
 | 
						|
	{
 | 
						|
		h = render_newlen(h, 0);
 | 
						|
		res = pushf_write(next, hdr, h - hdr);
 | 
						|
		if (res < 0)
 | 
						|
			return res;
 | 
						|
		st->final_done = 1;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
pkt_stream_free(void *priv)
 | 
						|
{
 | 
						|
	struct PktStreamStat *st = priv;
 | 
						|
 | 
						|
	memset(st, 0, sizeof(*st));
 | 
						|
	px_free(st);
 | 
						|
}
 | 
						|
 | 
						|
static const PushFilterOps pkt_stream_filter = {
 | 
						|
	pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free
 | 
						|
};
 | 
						|
 | 
						|
int
 | 
						|
pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
 | 
						|
	res = write_tag_only(dst, tag);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	return pushf_create(res_p, &pkt_stream_filter, NULL, dst);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Text conversion filter
 | 
						|
 */
 | 
						|
 | 
						|
static int
 | 
						|
crlf_process(PushFilter *dst, void *priv, const uint8 *data, int len)
 | 
						|
{
 | 
						|
	const uint8 *data_end = data + len;
 | 
						|
	const uint8 *p2,
 | 
						|
			   *p1 = data;
 | 
						|
	int			line_len;
 | 
						|
	static const uint8 crlf[] = {'\r', '\n'};
 | 
						|
	int			res = 0;
 | 
						|
 | 
						|
	while (p1 < data_end)
 | 
						|
	{
 | 
						|
		p2 = memchr(p1, '\n', data_end - p1);
 | 
						|
		if (p2 == NULL)
 | 
						|
			p2 = data_end;
 | 
						|
 | 
						|
		line_len = p2 - p1;
 | 
						|
 | 
						|
		/* write data */
 | 
						|
		res = 0;
 | 
						|
		if (line_len > 0)
 | 
						|
		{
 | 
						|
			res = pushf_write(dst, p1, line_len);
 | 
						|
			if (res < 0)
 | 
						|
				break;
 | 
						|
			p1 += line_len;
 | 
						|
		}
 | 
						|
 | 
						|
		/* write crlf */
 | 
						|
		while (p1 < data_end && *p1 == '\n')
 | 
						|
		{
 | 
						|
			res = pushf_write(dst, crlf, 2);
 | 
						|
			if (res < 0)
 | 
						|
				break;
 | 
						|
			p1++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
static const PushFilterOps crlf_filter = {
 | 
						|
	NULL, crlf_process, NULL, NULL
 | 
						|
};
 | 
						|
 | 
						|
/*
 | 
						|
 * Initialize literal data packet
 | 
						|
 */
 | 
						|
static int
 | 
						|
init_litdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
	int			hdrlen;
 | 
						|
	uint8		hdr[6];
 | 
						|
	uint32		t;
 | 
						|
	PushFilter *pkt;
 | 
						|
	int			type;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Create header
 | 
						|
	 */
 | 
						|
 | 
						|
	if (ctx->text_mode)
 | 
						|
		type = ctx->unicode_mode ? 'u' : 't';
 | 
						|
	else
 | 
						|
		type = 'b';
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Store the creation time into packet. The goal is to have as few known
 | 
						|
	 * bytes as possible.
 | 
						|
	 */
 | 
						|
	t = (uint32) time(NULL);
 | 
						|
 | 
						|
	hdr[0] = type;
 | 
						|
	hdr[1] = 0;
 | 
						|
	hdr[2] = (t >> 24) & 255;
 | 
						|
	hdr[3] = (t >> 16) & 255;
 | 
						|
	hdr[4] = (t >> 8) & 255;
 | 
						|
	hdr[5] = t & 255;
 | 
						|
	hdrlen = 6;
 | 
						|
 | 
						|
	res = write_tag_only(dst, PGP_PKT_LITERAL_DATA);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	res = pushf_write(pkt, hdr, hdrlen);
 | 
						|
	if (res < 0)
 | 
						|
	{
 | 
						|
		pushf_free(pkt);
 | 
						|
		return res;
 | 
						|
	}
 | 
						|
 | 
						|
	*pf_res = pkt;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Initialize compression filter
 | 
						|
 */
 | 
						|
static int
 | 
						|
init_compress(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
	uint8		type = ctx->compress_algo;
 | 
						|
	PushFilter *pkt;
 | 
						|
 | 
						|
	res = write_tag_only(dst, PGP_PKT_COMPRESSED_DATA);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	res = pushf_create(&pkt, &pkt_stream_filter, ctx, dst);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	res = pushf_write(pkt, &type, 1);
 | 
						|
	if (res >= 0)
 | 
						|
		res = pgp_compress_filter(pf_res, ctx, pkt);
 | 
						|
 | 
						|
	if (res < 0)
 | 
						|
		pushf_free(pkt);
 | 
						|
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Initialize encdata packet
 | 
						|
 */
 | 
						|
static int
 | 
						|
init_encdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
	int			tag;
 | 
						|
 | 
						|
	if (ctx->disable_mdc)
 | 
						|
		tag = PGP_PKT_SYMENCRYPTED_DATA;
 | 
						|
	else
 | 
						|
		tag = PGP_PKT_SYMENCRYPTED_DATA_MDC;
 | 
						|
 | 
						|
	res = write_tag_only(dst, tag);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	return pushf_create(pf_res, &pkt_stream_filter, ctx, dst);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * write prefix
 | 
						|
 */
 | 
						|
static int
 | 
						|
write_prefix(PGP_Context *ctx, PushFilter *dst)
 | 
						|
{
 | 
						|
	uint8		prefix[PGP_MAX_BLOCK + 2];
 | 
						|
	int			res,
 | 
						|
				bs;
 | 
						|
 | 
						|
	bs = pgp_get_cipher_block_size(ctx->cipher_algo);
 | 
						|
	res = px_get_random_bytes(prefix, bs);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	prefix[bs + 0] = prefix[bs - 2];
 | 
						|
	prefix[bs + 1] = prefix[bs - 1];
 | 
						|
 | 
						|
	res = pushf_write(dst, prefix, bs + 2);
 | 
						|
	memset(prefix, 0, bs + 2);
 | 
						|
	return res < 0 ? res : 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * write symmetrically encrypted session key packet
 | 
						|
 */
 | 
						|
 | 
						|
static int
 | 
						|
symencrypt_sesskey(PGP_Context *ctx, uint8 *dst)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
	PGP_CFB    *cfb;
 | 
						|
	uint8		algo = ctx->cipher_algo;
 | 
						|
 | 
						|
	res = pgp_cfb_create(&cfb, ctx->s2k_cipher_algo,
 | 
						|
						 ctx->s2k.key, ctx->s2k.key_len, 0, NULL);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	pgp_cfb_encrypt(cfb, &algo, 1, dst);
 | 
						|
	pgp_cfb_encrypt(cfb, ctx->sess_key, ctx->sess_key_len, dst + 1);
 | 
						|
 | 
						|
	pgp_cfb_free(cfb);
 | 
						|
	return ctx->sess_key_len + 1;
 | 
						|
}
 | 
						|
 | 
						|
/* 5.3: Symmetric-Key Encrypted Session-Key */
 | 
						|
static int
 | 
						|
write_symenc_sesskey(PGP_Context *ctx, PushFilter *dst)
 | 
						|
{
 | 
						|
	uint8		pkt[256];
 | 
						|
	int			pktlen;
 | 
						|
	int			res;
 | 
						|
	uint8	   *p = pkt;
 | 
						|
 | 
						|
	*p++ = 4;					/* 5.3 - version number  */
 | 
						|
	*p++ = ctx->s2k_cipher_algo;
 | 
						|
 | 
						|
	*p++ = ctx->s2k.mode;
 | 
						|
	*p++ = ctx->s2k.digest_algo;
 | 
						|
	if (ctx->s2k.mode > 0)
 | 
						|
	{
 | 
						|
		memcpy(p, ctx->s2k.salt, 8);
 | 
						|
		p += 8;
 | 
						|
	}
 | 
						|
	if (ctx->s2k.mode == 3)
 | 
						|
		*p++ = ctx->s2k.iter;
 | 
						|
 | 
						|
	if (ctx->use_sess_key)
 | 
						|
	{
 | 
						|
		res = symencrypt_sesskey(ctx, p);
 | 
						|
		if (res < 0)
 | 
						|
			return res;
 | 
						|
		p += res;
 | 
						|
	}
 | 
						|
 | 
						|
	pktlen = p - pkt;
 | 
						|
	res = write_normal_header(dst, PGP_PKT_SYMENCRYPTED_SESSKEY, pktlen);
 | 
						|
	if (res >= 0)
 | 
						|
		res = pushf_write(dst, pkt, pktlen);
 | 
						|
 | 
						|
	memset(pkt, 0, pktlen);
 | 
						|
	return res;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * key setup
 | 
						|
 */
 | 
						|
static int
 | 
						|
init_s2k_key(PGP_Context *ctx)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
 | 
						|
	if (ctx->s2k_cipher_algo < 0)
 | 
						|
		ctx->s2k_cipher_algo = ctx->cipher_algo;
 | 
						|
 | 
						|
	res = pgp_s2k_fill(&ctx->s2k, ctx->s2k_mode, ctx->s2k_digest_algo);
 | 
						|
	if (res < 0)
 | 
						|
		return res;
 | 
						|
 | 
						|
	return pgp_s2k_process(&ctx->s2k, ctx->s2k_cipher_algo,
 | 
						|
						   ctx->sym_key, ctx->sym_key_len);
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
init_sess_key(PGP_Context *ctx)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
 | 
						|
	if (ctx->use_sess_key || ctx->pub_key)
 | 
						|
	{
 | 
						|
		ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo);
 | 
						|
		res = px_get_random_bytes(ctx->sess_key, ctx->sess_key_len);
 | 
						|
		if (res < 0)
 | 
						|
			return res;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		ctx->sess_key_len = ctx->s2k.key_len;
 | 
						|
		memcpy(ctx->sess_key, ctx->s2k.key, ctx->s2k.key_len);
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * combine
 | 
						|
 */
 | 
						|
int
 | 
						|
pgp_encrypt(PGP_Context *ctx, MBuf *src, MBuf *dst)
 | 
						|
{
 | 
						|
	int			res;
 | 
						|
	int			len;
 | 
						|
	uint8	   *buf;
 | 
						|
	PushFilter *pf,
 | 
						|
			   *pf_tmp;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * do we have any key
 | 
						|
	 */
 | 
						|
	if (!ctx->sym_key && !ctx->pub_key)
 | 
						|
		return PXE_ARGUMENT_ERROR;
 | 
						|
 | 
						|
	/* MBuf writer */
 | 
						|
	res = pushf_create_mbuf_writer(&pf, dst);
 | 
						|
	if (res < 0)
 | 
						|
		goto out;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * initialize symkey
 | 
						|
	 */
 | 
						|
	if (ctx->sym_key)
 | 
						|
	{
 | 
						|
		res = init_s2k_key(ctx);
 | 
						|
		if (res < 0)
 | 
						|
			goto out;
 | 
						|
	}
 | 
						|
 | 
						|
	res = init_sess_key(ctx);
 | 
						|
	if (res < 0)
 | 
						|
		goto out;
 | 
						|
 | 
						|
	/*
 | 
						|
	 * write keypkt
 | 
						|
	 */
 | 
						|
	if (ctx->pub_key)
 | 
						|
		res = pgp_write_pubenc_sesskey(ctx, pf);
 | 
						|
	else
 | 
						|
		res = write_symenc_sesskey(ctx, pf);
 | 
						|
	if (res < 0)
 | 
						|
		goto out;
 | 
						|
 | 
						|
	/* encrypted data pkt */
 | 
						|
	res = init_encdata_packet(&pf_tmp, ctx, pf);
 | 
						|
	if (res < 0)
 | 
						|
		goto out;
 | 
						|
	pf = pf_tmp;
 | 
						|
 | 
						|
	/* encrypter */
 | 
						|
	res = pushf_create(&pf_tmp, &encrypt_filter, ctx, pf);
 | 
						|
	if (res < 0)
 | 
						|
		goto out;
 | 
						|
	pf = pf_tmp;
 | 
						|
 | 
						|
	/* hasher */
 | 
						|
	if (ctx->disable_mdc == 0)
 | 
						|
	{
 | 
						|
		res = pushf_create(&pf_tmp, &mdc_filter, ctx, pf);
 | 
						|
		if (res < 0)
 | 
						|
			goto out;
 | 
						|
		pf = pf_tmp;
 | 
						|
	}
 | 
						|
 | 
						|
	/* prefix */
 | 
						|
	res = write_prefix(ctx, pf);
 | 
						|
	if (res < 0)
 | 
						|
		goto out;
 | 
						|
 | 
						|
	/* compressor */
 | 
						|
	if (ctx->compress_algo > 0 && ctx->compress_level > 0)
 | 
						|
	{
 | 
						|
		res = init_compress(&pf_tmp, ctx, pf);
 | 
						|
		if (res < 0)
 | 
						|
			goto out;
 | 
						|
		pf = pf_tmp;
 | 
						|
	}
 | 
						|
 | 
						|
	/* data streamer */
 | 
						|
	res = init_litdata_packet(&pf_tmp, ctx, pf);
 | 
						|
	if (res < 0)
 | 
						|
		goto out;
 | 
						|
	pf = pf_tmp;
 | 
						|
 | 
						|
 | 
						|
	/* text conversion? */
 | 
						|
	if (ctx->text_mode && ctx->convert_crlf)
 | 
						|
	{
 | 
						|
		res = pushf_create(&pf_tmp, &crlf_filter, ctx, pf);
 | 
						|
		if (res < 0)
 | 
						|
			goto out;
 | 
						|
		pf = pf_tmp;
 | 
						|
	}
 | 
						|
 | 
						|
	/*
 | 
						|
	 * chain complete
 | 
						|
	 */
 | 
						|
 | 
						|
	len = mbuf_grab(src, mbuf_avail(src), &buf);
 | 
						|
	res = pushf_write(pf, buf, len);
 | 
						|
	if (res >= 0)
 | 
						|
		res = pushf_flush(pf);
 | 
						|
out:
 | 
						|
	pushf_free_all(pf);
 | 
						|
	return res;
 | 
						|
}
 |