245 lines
5.0 KiB
C
245 lines
5.0 KiB
C
/*
|
|
* 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;
|
|
}
|