1 /*
2  * pgp-pubenc.c
3  *	  Encrypt session key with public key.
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-pubenc.c
30  */
31 #include "postgres.h"
32 
33 #include "px.h"
34 #include "pgp.h"
35 
36 /*
37  * padded msg: 02 || non-zero pad bytes || 00 || msg
38  */
39 static int
pad_eme_pkcs1_v15(uint8 * data,int data_len,int res_len,uint8 ** res_p)40 pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
41 {
42 #ifdef HAVE_STRONG_RANDOM
43 	uint8	   *buf,
44 			   *p;
45 	int			pad_len = res_len - 2 - data_len;
46 
47 	if (pad_len < 8)
48 		return PXE_BUG;
49 
50 	buf = px_alloc(res_len);
51 	buf[0] = 0x02;
52 
53 	if (!pg_strong_random((char *) buf + 1, pad_len))
54 	{
55 		px_free(buf);
56 		return PXE_NO_RANDOM;
57 	}
58 
59 	/* pad must not contain zero bytes */
60 	p = buf + 1;
61 	while (p < buf + 1 + pad_len)
62 	{
63 		if (*p == 0)
64 		{
65 			if (!pg_strong_random((char *) p, 1))
66 			{
67 				px_memset(buf, 0, res_len);
68 				px_free(buf);
69 				return PXE_NO_RANDOM;
70 			}
71 		}
72 		if (*p != 0)
73 			p++;
74 	}
75 
76 	buf[pad_len + 1] = 0;
77 	memcpy(buf + pad_len + 2, data, data_len);
78 	*res_p = buf;
79 
80 	return 0;
81 
82 #else
83 	return PXE_NO_RANDOM;
84 #endif
85 }
86 
87 static int
create_secmsg(PGP_Context * ctx,PGP_MPI ** msg_p,int full_bytes)88 create_secmsg(PGP_Context *ctx, PGP_MPI **msg_p, int full_bytes)
89 {
90 	uint8	   *secmsg;
91 	int			res,
92 				i;
93 	unsigned	cksum = 0;
94 	int			klen = ctx->sess_key_len;
95 	uint8	   *padded = NULL;
96 	PGP_MPI    *m = NULL;
97 
98 	/* calc checksum */
99 	for (i = 0; i < klen; i++)
100 		cksum += ctx->sess_key[i];
101 
102 	/*
103 	 * create "secret message"
104 	 */
105 	secmsg = px_alloc(klen + 3);
106 	secmsg[0] = ctx->cipher_algo;
107 	memcpy(secmsg + 1, ctx->sess_key, klen);
108 	secmsg[klen + 1] = (cksum >> 8) & 0xFF;
109 	secmsg[klen + 2] = cksum & 0xFF;
110 
111 	/*
112 	 * now create a large integer of it
113 	 */
114 	res = pad_eme_pkcs1_v15(secmsg, klen + 3, full_bytes, &padded);
115 	if (res >= 0)
116 	{
117 		/* first byte will be 0x02 */
118 		int			full_bits = full_bytes * 8 - 6;
119 
120 		res = pgp_mpi_create(padded, full_bits, &m);
121 	}
122 
123 	if (padded)
124 	{
125 		px_memset(padded, 0, full_bytes);
126 		px_free(padded);
127 	}
128 	px_memset(secmsg, 0, klen + 3);
129 	px_free(secmsg);
130 
131 	if (res >= 0)
132 		*msg_p = m;
133 
134 	return res;
135 }
136 
137 static int
encrypt_and_write_elgamal(PGP_Context * ctx,PGP_PubKey * pk,PushFilter * pkt)138 encrypt_and_write_elgamal(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt)
139 {
140 	int			res;
141 	PGP_MPI    *m = NULL,
142 			   *c1 = NULL,
143 			   *c2 = NULL;
144 
145 	/* create padded msg */
146 	res = create_secmsg(ctx, &m, pk->pub.elg.p->bytes - 1);
147 	if (res < 0)
148 		goto err;
149 
150 	/* encrypt it */
151 	res = pgp_elgamal_encrypt(pk, m, &c1, &c2);
152 	if (res < 0)
153 		goto err;
154 
155 	/* write out */
156 	res = pgp_mpi_write(pkt, c1);
157 	if (res < 0)
158 		goto err;
159 	res = pgp_mpi_write(pkt, c2);
160 
161 err:
162 	pgp_mpi_free(m);
163 	pgp_mpi_free(c1);
164 	pgp_mpi_free(c2);
165 	return res;
166 }
167 
168 static int
encrypt_and_write_rsa(PGP_Context * ctx,PGP_PubKey * pk,PushFilter * pkt)169 encrypt_and_write_rsa(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt)
170 {
171 	int			res;
172 	PGP_MPI    *m = NULL,
173 			   *c = NULL;
174 
175 	/* create padded msg */
176 	res = create_secmsg(ctx, &m, pk->pub.rsa.n->bytes - 1);
177 	if (res < 0)
178 		goto err;
179 
180 	/* encrypt it */
181 	res = pgp_rsa_encrypt(pk, m, &c);
182 	if (res < 0)
183 		goto err;
184 
185 	/* write out */
186 	res = pgp_mpi_write(pkt, c);
187 
188 err:
189 	pgp_mpi_free(m);
190 	pgp_mpi_free(c);
191 	return res;
192 }
193 
194 int
pgp_write_pubenc_sesskey(PGP_Context * ctx,PushFilter * dst)195 pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
196 {
197 	int			res;
198 	PGP_PubKey *pk = ctx->pub_key;
199 	uint8		ver = 3;
200 	PushFilter *pkt = NULL;
201 	uint8		algo;
202 
203 	if (pk == NULL)
204 	{
205 		px_debug("no pubkey?\n");
206 		return PXE_BUG;
207 	}
208 
209 	algo = pk->algo;
210 
211 	/*
212 	 * now write packet
213 	 */
214 	res = pgp_create_pkt_writer(dst, PGP_PKT_PUBENCRYPTED_SESSKEY, &pkt);
215 	if (res < 0)
216 		goto err;
217 	res = pushf_write(pkt, &ver, 1);
218 	if (res < 0)
219 		goto err;
220 	res = pushf_write(pkt, pk->key_id, 8);
221 	if (res < 0)
222 		goto err;
223 	res = pushf_write(pkt, &algo, 1);
224 	if (res < 0)
225 		goto err;
226 
227 	switch (algo)
228 	{
229 		case PGP_PUB_ELG_ENCRYPT:
230 			res = encrypt_and_write_elgamal(ctx, pk, pkt);
231 			break;
232 		case PGP_PUB_RSA_ENCRYPT:
233 		case PGP_PUB_RSA_ENCRYPT_SIGN:
234 			res = encrypt_and_write_rsa(ctx, pk, pkt);
235 			break;
236 	}
237 	if (res < 0)
238 		goto err;
239 
240 	/*
241 	 * done, signal packet end
242 	 */
243 	res = pushf_flush(pkt);
244 err:
245 	if (pkt)
246 		pushf_free(pkt);
247 
248 	return res;
249 }
250