LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-mpi-openssl.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 83.2 % 161 134
Test Date: 2026-07-03 19:57:34 Functions: 100.0 % 7 7
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 50.0 % 146 73

             Branch data     Line data    Source code
       1                 :             : /*
       2                 :             :  * pgp-mpi-openssl.c
       3                 :             :  *    OpenPGP MPI functions using OpenSSL BIGNUM code.
       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-mpi-openssl.c
      30                 :             :  */
      31                 :             : #include "postgres.h"
      32                 :             : 
      33                 :             : #include <openssl/bn.h>
      34                 :             : 
      35                 :             : #include "pgp.h"
      36                 :             : #include "px.h"
      37                 :             : 
      38                 :             : static BIGNUM *
      39                 :          74 : mpi_to_bn(PGP_MPI *n)
      40                 :             : {
      41                 :          74 :     BIGNUM     *bn = BN_bin2bn(n->data, n->bytes, NULL);
      42                 :             : 
      43         [ -  + ]:          74 :     if (!bn)
      44                 :           0 :         return NULL;
      45         [ -  + ]:          74 :     if (BN_num_bits(bn) != n->bits)
      46                 :             :     {
      47                 :           0 :         px_debug("mpi_to_bn: bignum conversion failed: mpi=%d, bn=%d",
      48                 :             :                  n->bits, BN_num_bits(bn));
      49                 :           0 :         BN_clear_free(bn);
      50                 :           0 :         return NULL;
      51                 :             :     }
      52                 :          74 :     return bn;
      53                 :             : }
      54                 :             : 
      55                 :             : static PGP_MPI *
      56                 :          25 : bn_to_mpi(BIGNUM *bn)
      57                 :             : {
      58                 :             :     int         res;
      59                 :             :     PGP_MPI    *n;
      60                 :             : 
      61                 :          25 :     res = pgp_mpi_alloc(BN_num_bits(bn), &n);
      62         [ -  + ]:          25 :     if (res < 0)
      63                 :           0 :         return NULL;
      64                 :             : 
      65         [ -  + ]:          25 :     if (BN_num_bytes(bn) != n->bytes)
      66                 :             :     {
      67                 :           0 :         px_debug("bn_to_mpi: bignum conversion failed: bn=%d, mpi=%d",
      68                 :           0 :                  BN_num_bytes(bn), n->bytes);
      69                 :           0 :         pgp_mpi_free(n);
      70                 :           0 :         return NULL;
      71                 :             :     }
      72                 :          25 :     BN_bn2bin(bn, n->data);
      73                 :          25 :     return n;
      74                 :             : }
      75                 :             : 
      76                 :             : /*
      77                 :             :  * Decide the number of bits in the random component k
      78                 :             :  *
      79                 :             :  * It should be in the same range as p for signing (which
      80                 :             :  * is deprecated), but can be much smaller for encrypting.
      81                 :             :  *
      82                 :             :  * Until I research it further, I just mimic gpg behaviour.
      83                 :             :  * It has a special mapping table, for values <= 5120,
      84                 :             :  * above that it uses 'arbitrary high number'.  Following
      85                 :             :  * algorithm hovers 10-70 bits above gpg values.  And for
      86                 :             :  * larger p, it uses gpg's algorithm.
      87                 :             :  *
      88                 :             :  * The point is - if k gets large, encryption will be
      89                 :             :  * really slow.  It does not matter for decryption.
      90                 :             :  */
      91                 :             : static int
      92                 :           5 : decide_k_bits(int p_bits)
      93                 :             : {
      94         [ +  - ]:           5 :     if (p_bits <= 5120)
      95                 :           5 :         return p_bits / 10 + 160;
      96                 :             :     else
      97                 :           0 :         return (p_bits / 8 + 200) * 3 / 2;
      98                 :             : }
      99                 :             : 
     100                 :             : int
     101                 :           5 : pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
     102                 :             :                     PGP_MPI **c1_p, PGP_MPI **c2_p)
     103                 :             : {
     104                 :           5 :     int         res = PXE_PGP_MATH_FAILED;
     105                 :             :     int         k_bits;
     106                 :           5 :     BIGNUM     *m = mpi_to_bn(_m);
     107                 :           5 :     BIGNUM     *p = mpi_to_bn(pk->pub.elg.p);
     108                 :           5 :     BIGNUM     *g = mpi_to_bn(pk->pub.elg.g);
     109                 :           5 :     BIGNUM     *y = mpi_to_bn(pk->pub.elg.y);
     110                 :           5 :     BIGNUM     *k = BN_new();
     111                 :           5 :     BIGNUM     *yk = BN_new();
     112                 :           5 :     BIGNUM     *c1 = BN_new();
     113                 :           5 :     BIGNUM     *c2 = BN_new();
     114                 :           5 :     BN_CTX     *tmp = BN_CTX_new();
     115                 :             : 
     116   [ +  -  +  -  :           5 :     if (!m || !p || !g || !y || !k || !yk || !c1 || !c2 || !tmp)
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  -  + ]
     117                 :           0 :         goto err;
     118                 :             : 
     119                 :             :     /*
     120                 :             :      * generate k
     121                 :             :      */
     122                 :           5 :     k_bits = decide_k_bits(BN_num_bits(p));
     123         [ -  + ]:           5 :     if (!BN_rand(k, k_bits, 0, 0))
     124                 :           0 :         goto err;
     125                 :             : 
     126                 :             :     /*
     127                 :             :      * c1 = g^k c2 = m * y^k
     128                 :             :      */
     129         [ -  + ]:           5 :     if (!BN_mod_exp(c1, g, k, p, tmp))
     130                 :           0 :         goto err;
     131         [ -  + ]:           5 :     if (!BN_mod_exp(yk, y, k, p, tmp))
     132                 :           0 :         goto err;
     133         [ -  + ]:           5 :     if (!BN_mod_mul(c2, m, yk, p, tmp))
     134                 :           0 :         goto err;
     135                 :             : 
     136                 :             :     /* result */
     137                 :           5 :     *c1_p = bn_to_mpi(c1);
     138                 :           5 :     *c2_p = bn_to_mpi(c2);
     139   [ -  +  -  + ]:           5 :     if (*c1_p && *c2_p)
     140                 :           5 :         res = 0;
     141                 :           0 : err:
     142         [ +  - ]:           5 :     if (tmp)
     143                 :           5 :         BN_CTX_free(tmp);
     144         [ +  - ]:           5 :     if (c2)
     145                 :           5 :         BN_clear_free(c2);
     146         [ +  - ]:           5 :     if (c1)
     147                 :           5 :         BN_clear_free(c1);
     148         [ +  - ]:           5 :     if (yk)
     149                 :           5 :         BN_clear_free(yk);
     150         [ +  - ]:           5 :     if (k)
     151                 :           5 :         BN_clear_free(k);
     152         [ +  - ]:           5 :     if (y)
     153                 :           5 :         BN_clear_free(y);
     154         [ +  - ]:           5 :     if (g)
     155                 :           5 :         BN_clear_free(g);
     156         [ +  - ]:           5 :     if (p)
     157                 :           5 :         BN_clear_free(p);
     158         [ +  - ]:           5 :     if (m)
     159                 :           5 :         BN_clear_free(m);
     160                 :           5 :     return res;
     161                 :             : }
     162                 :             : 
     163                 :             : int
     164                 :           9 : pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2,
     165                 :             :                     PGP_MPI **msg_p)
     166                 :             : {
     167                 :           9 :     int         res = PXE_PGP_MATH_FAILED;
     168                 :           9 :     BIGNUM     *c1 = mpi_to_bn(_c1);
     169                 :           9 :     BIGNUM     *c2 = mpi_to_bn(_c2);
     170                 :           9 :     BIGNUM     *p = mpi_to_bn(pk->pub.elg.p);
     171                 :           9 :     BIGNUM     *x = mpi_to_bn(pk->sec.elg.x);
     172                 :           9 :     BIGNUM     *c1x = BN_new();
     173                 :           9 :     BIGNUM     *div = BN_new();
     174                 :           9 :     BIGNUM     *m = BN_new();
     175                 :           9 :     BN_CTX     *tmp = BN_CTX_new();
     176                 :             : 
     177   [ +  -  +  -  :           9 :     if (!c1 || !c2 || !p || !x || !c1x || !div || !m || !tmp)
          +  -  +  -  +  
          -  +  -  +  -  
                   -  + ]
     178                 :           0 :         goto err;
     179                 :             : 
     180                 :             :     /*
     181                 :             :      * m = c2 / (c1^x)
     182                 :             :      */
     183         [ -  + ]:           9 :     if (!BN_mod_exp(c1x, c1, x, p, tmp))
     184                 :           0 :         goto err;
     185         [ -  + ]:           9 :     if (!BN_mod_inverse(div, c1x, p, tmp))
     186                 :           0 :         goto err;
     187         [ -  + ]:           9 :     if (!BN_mod_mul(m, c2, div, p, tmp))
     188                 :           0 :         goto err;
     189                 :             : 
     190                 :             :     /* result */
     191                 :           9 :     *msg_p = bn_to_mpi(m);
     192         [ -  + ]:           9 :     if (*msg_p)
     193                 :           9 :         res = 0;
     194                 :           0 : err:
     195         [ +  - ]:           9 :     if (tmp)
     196                 :           9 :         BN_CTX_free(tmp);
     197         [ +  - ]:           9 :     if (m)
     198                 :           9 :         BN_clear_free(m);
     199         [ +  - ]:           9 :     if (div)
     200                 :           9 :         BN_clear_free(div);
     201         [ +  - ]:           9 :     if (c1x)
     202                 :           9 :         BN_clear_free(c1x);
     203         [ +  - ]:           9 :     if (x)
     204                 :           9 :         BN_clear_free(x);
     205         [ +  - ]:           9 :     if (p)
     206                 :           9 :         BN_clear_free(p);
     207         [ +  - ]:           9 :     if (c2)
     208                 :           9 :         BN_clear_free(c2);
     209         [ +  - ]:           9 :     if (c1)
     210                 :           9 :         BN_clear_free(c1);
     211                 :           9 :     return res;
     212                 :             : }
     213                 :             : 
     214                 :             : int
     215                 :           1 : pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *_m, PGP_MPI **c_p)
     216                 :             : {
     217                 :           1 :     int         res = PXE_PGP_MATH_FAILED;
     218                 :           1 :     BIGNUM     *m = mpi_to_bn(_m);
     219                 :           1 :     BIGNUM     *e = mpi_to_bn(pk->pub.rsa.e);
     220                 :           1 :     BIGNUM     *n = mpi_to_bn(pk->pub.rsa.n);
     221                 :           1 :     BIGNUM     *c = BN_new();
     222                 :           1 :     BN_CTX     *tmp = BN_CTX_new();
     223                 :             : 
     224   [ +  -  +  -  :           1 :     if (!m || !e || !n || !c || !tmp)
          +  -  +  -  -  
                      + ]
     225                 :           0 :         goto err;
     226                 :             : 
     227                 :             :     /*
     228                 :             :      * c = m ^ e
     229                 :             :      */
     230         [ -  + ]:           1 :     if (!BN_mod_exp(c, m, e, n, tmp))
     231                 :           0 :         goto err;
     232                 :             : 
     233                 :           1 :     *c_p = bn_to_mpi(c);
     234         [ -  + ]:           1 :     if (*c_p)
     235                 :           1 :         res = 0;
     236                 :           0 : err:
     237         [ +  - ]:           1 :     if (tmp)
     238                 :           1 :         BN_CTX_free(tmp);
     239         [ +  - ]:           1 :     if (c)
     240                 :           1 :         BN_clear_free(c);
     241         [ +  - ]:           1 :     if (n)
     242                 :           1 :         BN_clear_free(n);
     243         [ +  - ]:           1 :     if (e)
     244                 :           1 :         BN_clear_free(e);
     245         [ +  - ]:           1 :     if (m)
     246                 :           1 :         BN_clear_free(m);
     247                 :           1 :     return res;
     248                 :             : }
     249                 :             : 
     250                 :             : int
     251                 :           5 : pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *_c, PGP_MPI **m_p)
     252                 :             : {
     253                 :           5 :     int         res = PXE_PGP_MATH_FAILED;
     254                 :           5 :     BIGNUM     *c = mpi_to_bn(_c);
     255                 :           5 :     BIGNUM     *d = mpi_to_bn(pk->sec.rsa.d);
     256                 :           5 :     BIGNUM     *n = mpi_to_bn(pk->pub.rsa.n);
     257                 :           5 :     BIGNUM     *m = BN_new();
     258                 :           5 :     BN_CTX     *tmp = BN_CTX_new();
     259                 :             : 
     260   [ +  -  +  -  :           5 :     if (!m || !d || !n || !c || !tmp)
          +  -  +  -  -  
                      + ]
     261                 :           0 :         goto err;
     262                 :             : 
     263                 :             :     /*
     264                 :             :      * m = c ^ d
     265                 :             :      */
     266         [ -  + ]:           5 :     if (!BN_mod_exp(m, c, d, n, tmp))
     267                 :           0 :         goto err;
     268                 :             : 
     269                 :           5 :     *m_p = bn_to_mpi(m);
     270         [ -  + ]:           5 :     if (*m_p)
     271                 :           5 :         res = 0;
     272                 :           0 : err:
     273         [ +  - ]:           5 :     if (tmp)
     274                 :           5 :         BN_CTX_free(tmp);
     275         [ +  - ]:           5 :     if (m)
     276                 :           5 :         BN_clear_free(m);
     277         [ +  - ]:           5 :     if (n)
     278                 :           5 :         BN_clear_free(n);
     279         [ +  - ]:           5 :     if (d)
     280                 :           5 :         BN_clear_free(d);
     281         [ +  - ]:           5 :     if (c)
     282                 :           5 :         BN_clear_free(c);
     283                 :           5 :     return res;
     284                 :             : }
        

Generated by: LCOV version 2.0-1