3 * Encrypt session key with public key.
5 * Copyright (c) 2005 Marko Kreen
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
29 * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pubenc.c,v 1.1 2005/07/10 13:46:29 momjian Exp $
38 * padded msg: 02 || non-zero pad bytes || 00 || msg
41 pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
45 int pad_len = res_len - 2 - data_len;
50 buf = px_alloc(res_len);
52 res = px_get_random_bytes(buf + 1, pad_len);
59 /* pad must not contain zero bytes */
61 while (p < buf + 1 + pad_len)
65 res = px_get_random_bytes(p, 1);
75 memset(buf, 0, res_len);
81 memcpy(buf + pad_len + 2, data, data_len);
88 * Decide the padded message length in bytes.
89 * It should be as large as possible, but not larger
92 * To get max size (and assuming p may have weird sizes):
93 * ((p->bytes * 8 - 6) > p->bits) ? (p->bytes - 1) : p->bytes
95 * Following mirrors gnupg behaviour.
98 decide_msglen(PGP_MPI *p)
104 create_secmsg(PGP_Context *ctx, PGP_MPI **msg_p)
107 int res, i, full_bytes;
109 int klen = ctx->sess_key_len;
110 uint8 *padded = NULL;
112 PGP_PubKey *pk = ctx->pub_key;
115 * Refuse to operate with keys < 1024
117 if (pk->elg_p->bits < 1024)
118 return PXE_PGP_SHORT_ELGAMAL_KEY;
121 for (i = 0; i < klen; i++)
122 cksum += ctx->sess_key[i];
125 * create "secret message"
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;
134 * now create a large integer of it
136 full_bytes = decide_msglen(pk->elg_p);
137 res = pad_eme_pkcs1_v15(secmsg, klen + 3, full_bytes, &padded);
140 /* first byte will be 0x02 */
141 int full_bits = full_bytes * 8 - 6;
142 res = pgp_mpi_create(padded, full_bits, &m);
147 memset(padded, 0, full_bytes);
150 memset(secmsg, 0, klen + 3);
159 int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
162 PGP_PubKey *pk = ctx->pub_key;
163 PGP_MPI *m = NULL, *c1 = NULL, *c2 = NULL;
165 uint8 algo = PGP_PUB_ELG_ENCRYPT;
166 PushFilter *pkt = NULL;
169 px_debug("no pubkey?\n");
172 if (!pk->elg_p || !pk->elg_g || !pk->elg_y) {
173 px_debug("pubkey not loaded?\n");
180 res = create_secmsg(ctx, &m);
187 res = pgp_elgamal_encrypt(pk, m, &c1, &c2);
194 res = pgp_create_pkt_writer(dst, PGP_PKT_PUBENCRYPTED_SESSKEY, &pkt);
197 res = pushf_write(pkt, &ver, 1);
200 res = pushf_write(pkt, pk->key_id, 8);
203 res = pushf_write(pkt, &algo, 1);
206 res = pgp_mpi_write(pkt, c1);
209 res = pgp_mpi_write(pkt, c2);
214 * done, signal packet end
216 res = pushf_flush(pkt);