OSDN Git Service

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