Header And Logo

PostgreSQL
| The world's most advanced open source database.

pgp-pubenc.c

Go to the documentation of this file.
00001 /*
00002  * pgp-pubenc.c
00003  *    Encrypt session key with public key.
00004  *
00005  * Copyright (c) 2005 Marko Kreen
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * contrib/pgcrypto/pgp-pubenc.c
00030  */
00031 #include "postgres.h"
00032 
00033 #include "px.h"
00034 #include "mbuf.h"
00035 #include "pgp.h"
00036 
00037 /*
00038  * padded msg: 02 || non-zero pad bytes || 00 || msg
00039  */
00040 static int
00041 pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
00042 {
00043     int         res;
00044     uint8      *buf,
00045                *p;
00046     int         pad_len = res_len - 2 - data_len;
00047 
00048     if (pad_len < 8)
00049         return PXE_BUG;
00050 
00051     buf = px_alloc(res_len);
00052     buf[0] = 0x02;
00053     res = px_get_random_bytes(buf + 1, pad_len);
00054     if (res < 0)
00055     {
00056         px_free(buf);
00057         return res;
00058     }
00059 
00060     /* pad must not contain zero bytes */
00061     p = buf + 1;
00062     while (p < buf + 1 + pad_len)
00063     {
00064         if (*p == 0)
00065         {
00066             res = px_get_random_bytes(p, 1);
00067             if (res < 0)
00068                 break;
00069         }
00070         if (*p != 0)
00071             p++;
00072     }
00073 
00074     if (res < 0)
00075     {
00076         memset(buf, 0, res_len);
00077         px_free(buf);
00078         return res;
00079     }
00080 
00081     buf[pad_len + 1] = 0;
00082     memcpy(buf + pad_len + 2, data, data_len);
00083     *res_p = buf;
00084 
00085     return 0;
00086 }
00087 
00088 static int
00089 create_secmsg(PGP_Context *ctx, PGP_MPI **msg_p, int full_bytes)
00090 {
00091     uint8      *secmsg;
00092     int         res,
00093                 i;
00094     unsigned    cksum = 0;
00095     int         klen = ctx->sess_key_len;
00096     uint8      *padded = NULL;
00097     PGP_MPI    *m = NULL;
00098 
00099     /* calc checksum */
00100     for (i = 0; i < klen; i++)
00101         cksum += ctx->sess_key[i];
00102 
00103     /*
00104      * create "secret message"
00105      */
00106     secmsg = px_alloc(klen + 3);
00107     secmsg[0] = ctx->cipher_algo;
00108     memcpy(secmsg + 1, ctx->sess_key, klen);
00109     secmsg[klen + 1] = (cksum >> 8) & 0xFF;
00110     secmsg[klen + 2] = cksum & 0xFF;
00111 
00112     /*
00113      * now create a large integer of it
00114      */
00115     res = pad_eme_pkcs1_v15(secmsg, klen + 3, full_bytes, &padded);
00116     if (res >= 0)
00117     {
00118         /* first byte will be 0x02 */
00119         int         full_bits = full_bytes * 8 - 6;
00120 
00121         res = pgp_mpi_create(padded, full_bits, &m);
00122     }
00123 
00124     if (padded)
00125     {
00126         memset(padded, 0, full_bytes);
00127         px_free(padded);
00128     }
00129     memset(secmsg, 0, klen + 3);
00130     px_free(secmsg);
00131 
00132     if (res >= 0)
00133         *msg_p = m;
00134 
00135     return res;
00136 }
00137 
00138 static int
00139 encrypt_and_write_elgamal(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt)
00140 {
00141     int         res;
00142     PGP_MPI    *m = NULL,
00143                *c1 = NULL,
00144                *c2 = NULL;
00145 
00146     /* create padded msg */
00147     res = create_secmsg(ctx, &m, pk->pub.elg.p->bytes - 1);
00148     if (res < 0)
00149         goto err;
00150 
00151     /* encrypt it */
00152     res = pgp_elgamal_encrypt(pk, m, &c1, &c2);
00153     if (res < 0)
00154         goto err;
00155 
00156     /* write out */
00157     res = pgp_mpi_write(pkt, c1);
00158     if (res < 0)
00159         goto err;
00160     res = pgp_mpi_write(pkt, c2);
00161 
00162 err:
00163     pgp_mpi_free(m);
00164     pgp_mpi_free(c1);
00165     pgp_mpi_free(c2);
00166     return res;
00167 }
00168 
00169 static int
00170 encrypt_and_write_rsa(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt)
00171 {
00172     int         res;
00173     PGP_MPI    *m = NULL,
00174                *c = NULL;
00175 
00176     /* create padded msg */
00177     res = create_secmsg(ctx, &m, pk->pub.rsa.n->bytes - 1);
00178     if (res < 0)
00179         goto err;
00180 
00181     /* encrypt it */
00182     res = pgp_rsa_encrypt(pk, m, &c);
00183     if (res < 0)
00184         goto err;
00185 
00186     /* write out */
00187     res = pgp_mpi_write(pkt, c);
00188 
00189 err:
00190     pgp_mpi_free(m);
00191     pgp_mpi_free(c);
00192     return res;
00193 }
00194 
00195 int
00196 pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
00197 {
00198     int         res;
00199     PGP_PubKey *pk = ctx->pub_key;
00200     uint8       ver = 3;
00201     PushFilter *pkt = NULL;
00202     uint8       algo;
00203 
00204     if (pk == NULL)
00205     {
00206         px_debug("no pubkey?\n");
00207         return PXE_BUG;
00208     }
00209 
00210     algo = pk->algo;
00211 
00212     /*
00213      * now write packet
00214      */
00215     res = pgp_create_pkt_writer(dst, PGP_PKT_PUBENCRYPTED_SESSKEY, &pkt);
00216     if (res < 0)
00217         goto err;
00218     res = pushf_write(pkt, &ver, 1);
00219     if (res < 0)
00220         goto err;
00221     res = pushf_write(pkt, pk->key_id, 8);
00222     if (res < 0)
00223         goto err;
00224     res = pushf_write(pkt, &algo, 1);
00225     if (res < 0)
00226         goto err;
00227 
00228     switch (algo)
00229     {
00230         case PGP_PUB_ELG_ENCRYPT:
00231             res = encrypt_and_write_elgamal(ctx, pk, pkt);
00232             break;
00233         case PGP_PUB_RSA_ENCRYPT:
00234         case PGP_PUB_RSA_ENCRYPT_SIGN:
00235             res = encrypt_and_write_rsa(ctx, pk, pkt);
00236             break;
00237     }
00238     if (res < 0)
00239         goto err;
00240 
00241     /*
00242      * done, signal packet end
00243      */
00244     res = pushf_flush(pkt);
00245 err:
00246     if (pkt)
00247         pushf_free(pkt);
00248 
00249     return res;
00250 }