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