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