/* * pgp-pubenc.c * Encrypt session key with public key. * * Copyright (c) 2005 Marko Kreen * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * contrib/pgcrypto/pgp-pubenc.c */ #include "postgres.h" #include "pgp.h" #include "px.h" /* * padded msg: 02 || non-zero pad bytes || 00 || msg */ static int pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p) { uint8 *buf, *p; int pad_len = res_len - 2 - data_len; if (pad_len < 8) return PXE_BUG; buf = palloc(res_len); buf[0] = 0x02; if (!pg_strong_random(buf + 1, pad_len)) { pfree(buf); return PXE_NO_RANDOM; } /* pad must not contain zero bytes */ p = buf + 1; while (p < buf + 1 + pad_len) { if (*p == 0) { if (!pg_strong_random(p, 1)) { px_memset(buf, 0, res_len); pfree(buf); return PXE_NO_RANDOM; } } if (*p != 0) p++; } buf[pad_len + 1] = 0; memcpy(buf + pad_len + 2, data, data_len); *res_p = buf; return 0; } static int create_secmsg(PGP_Context *ctx, PGP_MPI **msg_p, int full_bytes) { uint8 *secmsg; int res, i; unsigned cksum = 0; int klen = ctx->sess_key_len; uint8 *padded = NULL; PGP_MPI *m = NULL; /* calc checksum */ for (i = 0; i < klen; i++) cksum += ctx->sess_key[i]; /* * create "secret message" */ secmsg = palloc(klen + 3); secmsg[0] = ctx->cipher_algo; memcpy(secmsg + 1, ctx->sess_key, klen); secmsg[klen + 1] = (cksum >> 8) & 0xFF; secmsg[klen + 2] = cksum & 0xFF; /* * now create a large integer of it */ res = pad_eme_pkcs1_v15(secmsg, klen + 3, full_bytes, &padded); if (res >= 0) { /* first byte will be 0x02 */ int full_bits = full_bytes * 8 - 6; res = pgp_mpi_create(padded, full_bits, &m); } if (padded) { px_memset(padded, 0, full_bytes); pfree(padded); } px_memset(secmsg, 0, klen + 3); pfree(secmsg); if (res >= 0) *msg_p = m; return res; } static int encrypt_and_write_elgamal(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt) { int res; PGP_MPI *m = NULL, *c1 = NULL, *c2 = NULL; /* create padded msg */ res = create_secmsg(ctx, &m, pk->pub.elg.p->bytes - 1); if (res < 0) goto err; /* encrypt it */ res = pgp_elgamal_encrypt(pk, m, &c1, &c2); if (res < 0) goto err; /* write out */ res = pgp_mpi_write(pkt, c1); if (res < 0) goto err; res = pgp_mpi_write(pkt, c2); err: pgp_mpi_free(m); pgp_mpi_free(c1); pgp_mpi_free(c2); return res; } static int encrypt_and_write_rsa(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt) { int res; PGP_MPI *m = NULL, *c = NULL; /* create padded msg */ res = create_secmsg(ctx, &m, pk->pub.rsa.n->bytes - 1); if (res < 0) goto err; /* encrypt it */ res = pgp_rsa_encrypt(pk, m, &c); if (res < 0) goto err; /* write out */ res = pgp_mpi_write(pkt, c); err: pgp_mpi_free(m); pgp_mpi_free(c); return res; } int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst) { int res; PGP_PubKey *pk = ctx->pub_key; uint8 ver = 3; PushFilter *pkt = NULL; uint8 algo; if (pk == NULL) { px_debug("no pubkey?\n"); return PXE_BUG; } algo = pk->algo; /* * now write packet */ res = pgp_create_pkt_writer(dst, PGP_PKT_PUBENCRYPTED_SESSKEY, &pkt); if (res < 0) goto err; res = pushf_write(pkt, &ver, 1); if (res < 0) goto err; res = pushf_write(pkt, pk->key_id, 8); if (res < 0) goto err; res = pushf_write(pkt, &algo, 1); if (res < 0) goto err; switch (algo) { case PGP_PUB_ELG_ENCRYPT: res = encrypt_and_write_elgamal(ctx, pk, pkt); break; case PGP_PUB_RSA_ENCRYPT: case PGP_PUB_RSA_ENCRYPT_SIGN: res = encrypt_and_write_rsa(ctx, pk, pkt); break; } if (res < 0) goto err; /* * done, signal packet end */ res = pushf_flush(pkt); err: if (pkt) pushf_free(pkt); return res; }