]> granicus.if.org Git - postgresql/blob - contrib/pgcrypto/pgp-pubenc.c
Add missing pgcrypto files from previous commit.
[postgresql] / 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.1 2005/07/10 13:46:29 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, *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         res = px_get_random_bytes(buf + 1, pad_len);
53         if (res < 0)
54         {
55                 px_free(buf);
56                 return res;
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                         res = px_get_random_bytes(p, 1);
66                         if (res < 0)
67                                 break;
68                 }
69                 if (*p != 0)
70                         p++;
71         }
72
73         if (res < 0)
74         {
75                 memset(buf, 0, res_len);
76                 px_free(buf);
77                 return res;
78         }
79                         
80         buf[pad_len + 1] = 0;
81         memcpy(buf + pad_len + 2, data, data_len);
82         *res_p = buf;
83
84         return 0;
85 }
86
87 /*
88  * Decide the padded message length in bytes.
89  * It should be as large as possible, but not larger
90  * than p.
91  *
92  * To get max size (and assuming p may have weird sizes):
93  * ((p->bytes * 8 - 6) > p->bits) ? (p->bytes - 1) : p->bytes
94  *
95  * Following mirrors gnupg behaviour.
96  */
97 static int
98 decide_msglen(PGP_MPI *p)
99 {
100         return p->bytes - 1;
101 }
102
103 static int
104 create_secmsg(PGP_Context *ctx, PGP_MPI **msg_p)
105 {
106         uint8 *secmsg;
107         int res, i, full_bytes;
108         unsigned cksum = 0;
109         int klen = ctx->sess_key_len;
110         uint8 *padded = NULL;
111         PGP_MPI *m = NULL;
112         PGP_PubKey *pk = ctx->pub_key;
113
114         /*
115          * Refuse to operate with keys < 1024
116          */
117         if (pk->elg_p->bits < 1024)
118                 return PXE_PGP_SHORT_ELGAMAL_KEY;
119         
120         /* calc checksum */
121         for (i = 0; i < klen; i++)
122                 cksum += ctx->sess_key[i];
123         
124         /*
125          * create "secret message"
126          */
127         secmsg = px_alloc(klen + 3);
128         secmsg[0] = ctx->cipher_algo;
129         memcpy(secmsg + 1, ctx->sess_key, klen);
130         secmsg[klen + 1] = (cksum >> 8) & 0xFF;
131         secmsg[klen + 2] = cksum & 0xFF;
132
133         /*
134          * now create a large integer of it
135          */
136         full_bytes = decide_msglen(pk->elg_p);
137         res = pad_eme_pkcs1_v15(secmsg, klen + 3, full_bytes, &padded);
138         if (res >= 0)
139         {
140                 /* first byte will be 0x02 */
141                 int full_bits = full_bytes * 8 - 6;
142                 res = pgp_mpi_create(padded, full_bits, &m);
143         }
144
145         if (padded)
146         {
147                 memset(padded, 0, full_bytes);
148                 px_free(padded);
149         }
150         memset(secmsg, 0, klen + 3);
151         px_free(secmsg);
152
153         if (res >= 0)
154                 *msg_p = m;
155
156         return res;
157 }
158
159 int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
160 {
161         int res;
162         PGP_PubKey *pk = ctx->pub_key;
163         PGP_MPI *m = NULL, *c1 = NULL, *c2 = NULL;
164         uint8 ver = 3;
165         uint8 algo = PGP_PUB_ELG_ENCRYPT;
166         PushFilter *pkt = NULL;
167
168         if (pk == NULL) {
169                 px_debug("no pubkey?\n");
170                 return PXE_BUG;
171         }
172         if (!pk->elg_p || !pk->elg_g || !pk->elg_y) {
173                 px_debug("pubkey not loaded?\n");
174                 return PXE_BUG;
175         }
176
177         /*
178          * sesskey packet
179          */
180         res = create_secmsg(ctx, &m);
181         if (res < 0)
182                 goto err;
183
184         /*
185          * encrypt it
186          */
187         res = pgp_elgamal_encrypt(pk, m, &c1, &c2);
188         if (res < 0)
189                 goto err;
190
191         /*
192          * now write packet
193          */
194         res = pgp_create_pkt_writer(dst, PGP_PKT_PUBENCRYPTED_SESSKEY, &pkt);
195         if (res < 0)
196                 goto err;
197         res = pushf_write(pkt, &ver, 1);
198         if (res < 0)
199                 goto err;
200         res = pushf_write(pkt, pk->key_id, 8);
201         if (res < 0)
202                 goto err;
203         res = pushf_write(pkt, &algo, 1);
204         if (res < 0)
205                 goto err;
206         res = pgp_mpi_write(pkt, c1);
207         if (res < 0)
208                 goto err;
209         res = pgp_mpi_write(pkt, c2);
210         if (res < 0)
211                 goto err;
212
213         /*
214          * done, signal packet end
215          */
216         res = pushf_flush(pkt);
217 err:
218         if (pkt)
219                 pushf_free(pkt);
220         if (m)
221                 pgp_mpi_free(m);
222         if (c1)
223                 pgp_mpi_free(c1);
224         if (c2)
225                 pgp_mpi_free(c2);
226
227         return res;
228 }
229
230