LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-pubenc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 95 113 84.1 %
Date: 2024-04-26 00:11:43 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             :  * contrib/pgcrypto/pgp-pubenc.c
      30             :  */
      31             : #include "postgres.h"
      32             : 
      33             : #include "pgp.h"
      34             : #include "px.h"
      35             : 
      36             : /*
      37             :  * padded msg: 02 || non-zero pad bytes || 00 || msg
      38             :  */
      39             : static int
      40          12 : pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
      41             : {
      42             :     uint8      *buf,
      43             :                *p;
      44          12 :     int         pad_len = res_len - 2 - data_len;
      45             : 
      46          12 :     if (pad_len < 8)
      47           0 :         return PXE_BUG;
      48             : 
      49          12 :     buf = palloc(res_len);
      50          12 :     buf[0] = 0x02;
      51             : 
      52          12 :     if (!pg_strong_random(buf + 1, pad_len))
      53             :     {
      54           0 :         pfree(buf);
      55           0 :         return PXE_NO_RANDOM;
      56             :     }
      57             : 
      58             :     /* pad must not contain zero bytes */
      59          12 :     p = buf + 1;
      60        2564 :     while (p < buf + 1 + pad_len)
      61             :     {
      62        2552 :         if (*p == 0)
      63             :         {
      64          14 :             if (!pg_strong_random(p, 1))
      65             :             {
      66           0 :                 px_memset(buf, 0, res_len);
      67           0 :                 pfree(buf);
      68           0 :                 return PXE_NO_RANDOM;
      69             :             }
      70             :         }
      71        2552 :         if (*p != 0)
      72        2552 :             p++;
      73             :     }
      74             : 
      75          12 :     buf[pad_len + 1] = 0;
      76          12 :     memcpy(buf + pad_len + 2, data, data_len);
      77          12 :     *res_p = buf;
      78             : 
      79          12 :     return 0;
      80             : }
      81             : 
      82             : static int
      83          12 : create_secmsg(PGP_Context *ctx, PGP_MPI **msg_p, int full_bytes)
      84             : {
      85             :     uint8      *secmsg;
      86             :     int         res,
      87             :                 i;
      88          12 :     unsigned    cksum = 0;
      89          12 :     int         klen = ctx->sess_key_len;
      90          12 :     uint8      *padded = NULL;
      91          12 :     PGP_MPI    *m = NULL;
      92             : 
      93             :     /* calc checksum */
      94         204 :     for (i = 0; i < klen; i++)
      95         192 :         cksum += ctx->sess_key[i];
      96             : 
      97             :     /*
      98             :      * create "secret message"
      99             :      */
     100          12 :     secmsg = palloc(klen + 3);
     101          12 :     secmsg[0] = ctx->cipher_algo;
     102          12 :     memcpy(secmsg + 1, ctx->sess_key, klen);
     103          12 :     secmsg[klen + 1] = (cksum >> 8) & 0xFF;
     104          12 :     secmsg[klen + 2] = cksum & 0xFF;
     105             : 
     106             :     /*
     107             :      * now create a large integer of it
     108             :      */
     109          12 :     res = pad_eme_pkcs1_v15(secmsg, klen + 3, full_bytes, &padded);
     110          12 :     if (res >= 0)
     111             :     {
     112             :         /* first byte will be 0x02 */
     113          12 :         int         full_bits = full_bytes * 8 - 6;
     114             : 
     115          12 :         res = pgp_mpi_create(padded, full_bits, &m);
     116             :     }
     117             : 
     118          12 :     if (padded)
     119             :     {
     120          12 :         px_memset(padded, 0, full_bytes);
     121          12 :         pfree(padded);
     122             :     }
     123          12 :     px_memset(secmsg, 0, klen + 3);
     124          12 :     pfree(secmsg);
     125             : 
     126          12 :     if (res >= 0)
     127          12 :         *msg_p = m;
     128             : 
     129          12 :     return res;
     130             : }
     131             : 
     132             : static int
     133          10 : encrypt_and_write_elgamal(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt)
     134             : {
     135             :     int         res;
     136          10 :     PGP_MPI    *m = NULL,
     137          10 :                *c1 = NULL,
     138          10 :                *c2 = NULL;
     139             : 
     140             :     /* create padded msg */
     141          10 :     res = create_secmsg(ctx, &m, pk->pub.elg.p->bytes - 1);
     142          10 :     if (res < 0)
     143           0 :         goto err;
     144             : 
     145             :     /* encrypt it */
     146          10 :     res = pgp_elgamal_encrypt(pk, m, &c1, &c2);
     147          10 :     if (res < 0)
     148           0 :         goto err;
     149             : 
     150             :     /* write out */
     151          10 :     res = pgp_mpi_write(pkt, c1);
     152          10 :     if (res < 0)
     153           0 :         goto err;
     154          10 :     res = pgp_mpi_write(pkt, c2);
     155             : 
     156          10 : err:
     157          10 :     pgp_mpi_free(m);
     158          10 :     pgp_mpi_free(c1);
     159          10 :     pgp_mpi_free(c2);
     160          10 :     return res;
     161             : }
     162             : 
     163             : static int
     164           2 : encrypt_and_write_rsa(PGP_Context *ctx, PGP_PubKey *pk, PushFilter *pkt)
     165             : {
     166             :     int         res;
     167           2 :     PGP_MPI    *m = NULL,
     168           2 :                *c = NULL;
     169             : 
     170             :     /* create padded msg */
     171           2 :     res = create_secmsg(ctx, &m, pk->pub.rsa.n->bytes - 1);
     172           2 :     if (res < 0)
     173           0 :         goto err;
     174             : 
     175             :     /* encrypt it */
     176           2 :     res = pgp_rsa_encrypt(pk, m, &c);
     177           2 :     if (res < 0)
     178           0 :         goto err;
     179             : 
     180             :     /* write out */
     181           2 :     res = pgp_mpi_write(pkt, c);
     182             : 
     183           2 : err:
     184           2 :     pgp_mpi_free(m);
     185           2 :     pgp_mpi_free(c);
     186           2 :     return res;
     187             : }
     188             : 
     189             : int
     190          12 : pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
     191             : {
     192             :     int         res;
     193          12 :     PGP_PubKey *pk = ctx->pub_key;
     194          12 :     uint8       ver = 3;
     195          12 :     PushFilter *pkt = NULL;
     196             :     uint8       algo;
     197             : 
     198          12 :     if (pk == NULL)
     199             :     {
     200           0 :         px_debug("no pubkey?\n");
     201           0 :         return PXE_BUG;
     202             :     }
     203             : 
     204          12 :     algo = pk->algo;
     205             : 
     206             :     /*
     207             :      * now write packet
     208             :      */
     209          12 :     res = pgp_create_pkt_writer(dst, PGP_PKT_PUBENCRYPTED_SESSKEY, &pkt);
     210          12 :     if (res < 0)
     211           0 :         goto err;
     212          12 :     res = pushf_write(pkt, &ver, 1);
     213          12 :     if (res < 0)
     214           0 :         goto err;
     215          12 :     res = pushf_write(pkt, pk->key_id, 8);
     216          12 :     if (res < 0)
     217           0 :         goto err;
     218          12 :     res = pushf_write(pkt, &algo, 1);
     219          12 :     if (res < 0)
     220           0 :         goto err;
     221             : 
     222          12 :     switch (algo)
     223             :     {
     224          10 :         case PGP_PUB_ELG_ENCRYPT:
     225          10 :             res = encrypt_and_write_elgamal(ctx, pk, pkt);
     226          10 :             break;
     227           2 :         case PGP_PUB_RSA_ENCRYPT:
     228             :         case PGP_PUB_RSA_ENCRYPT_SIGN:
     229           2 :             res = encrypt_and_write_rsa(ctx, pk, pkt);
     230           2 :             break;
     231             :     }
     232          12 :     if (res < 0)
     233           0 :         goto err;
     234             : 
     235             :     /*
     236             :      * done, signal packet end
     237             :      */
     238          12 :     res = pushf_flush(pkt);
     239          12 : err:
     240          12 :     if (pkt)
     241          12 :         pushf_free(pkt);
     242             : 
     243          12 :     return res;
     244             : }

Generated by: LCOV version 1.14