LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-s2k.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 91.2 % 148 135
Test Date: 2026-03-04 09:14:58 Functions: 100.0 % 7 7
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * pgp-s2k.c
       3              :  *    OpenPGP string2key functions.
       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-s2k.c
      30              :  */
      31              : 
      32              : #include "postgres.h"
      33              : 
      34              : #include "pgp.h"
      35              : #include "px.h"
      36              : 
      37              : static int
      38            5 : calc_s2k_simple(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
      39              :                 unsigned key_len)
      40              : {
      41              :     unsigned    md_rlen;
      42              :     uint8       buf[PGP_MAX_DIGEST];
      43              :     unsigned    preload;
      44              :     unsigned    remain;
      45            5 :     uint8      *dst = s2k->key;
      46              : 
      47            5 :     md_rlen = px_md_result_size(md);
      48              : 
      49            5 :     remain = s2k->key_len;
      50            5 :     preload = 0;
      51           12 :     while (remain > 0)
      52              :     {
      53            7 :         px_md_reset(md);
      54              : 
      55            7 :         if (preload)
      56              :         {
      57            2 :             memset(buf, 0, preload);
      58            2 :             px_md_update(md, buf, preload);
      59              :         }
      60            7 :         preload++;
      61              : 
      62            7 :         px_md_update(md, key, key_len);
      63            7 :         px_md_finish(md, buf);
      64              : 
      65            7 :         if (remain > md_rlen)
      66              :         {
      67            2 :             memcpy(dst, buf, md_rlen);
      68            2 :             dst += md_rlen;
      69            2 :             remain -= md_rlen;
      70              :         }
      71              :         else
      72              :         {
      73            5 :             memcpy(dst, buf, remain);
      74            5 :             remain = 0;
      75              :         }
      76              :     }
      77            5 :     px_memset(buf, 0, sizeof(buf));
      78            5 :     return 0;
      79              : }
      80              : 
      81              : static int
      82            5 : calc_s2k_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key, unsigned key_len)
      83              : {
      84              :     unsigned    md_rlen;
      85              :     uint8       buf[PGP_MAX_DIGEST];
      86            5 :     unsigned    preload = 0;
      87              :     uint8      *dst;
      88              :     unsigned    remain;
      89              : 
      90            5 :     md_rlen = px_md_result_size(md);
      91              : 
      92            5 :     dst = s2k->key;
      93            5 :     remain = s2k->key_len;
      94           12 :     while (remain > 0)
      95              :     {
      96            7 :         px_md_reset(md);
      97              : 
      98            7 :         if (preload > 0)
      99              :         {
     100            2 :             memset(buf, 0, preload);
     101            2 :             px_md_update(md, buf, preload);
     102              :         }
     103            7 :         preload++;
     104              : 
     105            7 :         px_md_update(md, s2k->salt, PGP_S2K_SALT);
     106            7 :         px_md_update(md, key, key_len);
     107            7 :         px_md_finish(md, buf);
     108              : 
     109            7 :         if (remain > md_rlen)
     110              :         {
     111            2 :             memcpy(dst, buf, md_rlen);
     112            2 :             remain -= md_rlen;
     113            2 :             dst += md_rlen;
     114              :         }
     115              :         else
     116              :         {
     117            5 :             memcpy(dst, buf, remain);
     118            5 :             remain = 0;
     119              :         }
     120              :     }
     121            5 :     px_memset(buf, 0, sizeof(buf));
     122            5 :     return 0;
     123              : }
     124              : 
     125              : static int
     126           84 : calc_s2k_iter_salted(PGP_S2K *s2k, PX_MD *md, const uint8 *key,
     127              :                      unsigned key_len)
     128              : {
     129              :     unsigned    md_rlen;
     130              :     uint8       buf[PGP_MAX_DIGEST];
     131              :     uint8      *dst;
     132           84 :     unsigned    preload = 0;
     133              :     unsigned    remain,
     134              :                 c,
     135              :                 curcnt,
     136              :                 count;
     137              : 
     138           84 :     count = s2k_decode_count(s2k->iter);
     139              : 
     140           84 :     md_rlen = px_md_result_size(md);
     141              : 
     142           84 :     remain = s2k->key_len;
     143           84 :     dst = s2k->key;
     144          181 :     while (remain > 0)
     145              :     {
     146           97 :         px_md_reset(md);
     147              : 
     148           97 :         if (preload)
     149              :         {
     150           13 :             memset(buf, 0, preload);
     151           13 :             px_md_update(md, buf, preload);
     152              :         }
     153           97 :         preload++;
     154              : 
     155           97 :         px_md_update(md, s2k->salt, PGP_S2K_SALT);
     156           97 :         px_md_update(md, key, key_len);
     157           97 :         curcnt = PGP_S2K_SALT + key_len;
     158              : 
     159     12768042 :         while (curcnt < count)
     160              :         {
     161     12768014 :             if (curcnt + PGP_S2K_SALT < count)
     162     12767945 :                 c = PGP_S2K_SALT;
     163              :             else
     164           69 :                 c = count - curcnt;
     165     12768014 :             px_md_update(md, s2k->salt, c);
     166     12768014 :             curcnt += c;
     167              : 
     168     12768014 :             if (curcnt + key_len < count)
     169     12767917 :                 c = key_len;
     170           97 :             else if (curcnt < count)
     171           28 :                 c = count - curcnt;
     172              :             else
     173           69 :                 break;
     174     12767945 :             px_md_update(md, key, c);
     175     12767945 :             curcnt += c;
     176              :         }
     177           97 :         px_md_finish(md, buf);
     178              : 
     179           97 :         if (remain > md_rlen)
     180              :         {
     181           13 :             memcpy(dst, buf, md_rlen);
     182           13 :             remain -= md_rlen;
     183           13 :             dst += md_rlen;
     184              :         }
     185              :         else
     186              :         {
     187           84 :             memcpy(dst, buf, remain);
     188           84 :             remain = 0;
     189              :         }
     190              :     }
     191           84 :     px_memset(buf, 0, sizeof(buf));
     192           84 :     return 0;
     193              : }
     194              : 
     195              : /*
     196              :  * Decide PGP_S2K_ISALTED iteration count (in OpenPGP one-byte representation)
     197              :  *
     198              :  * Too small: weak
     199              :  * Too big: slow
     200              :  * gpg defaults to 96 => 65536 iters
     201              :  *
     202              :  * For our default (count=-1) we let it float a bit: 96 + 32 => between 65536
     203              :  * and 262144 iterations.
     204              :  *
     205              :  * Otherwise, find the smallest number which provides at least the specified
     206              :  * iteration count.
     207              :  */
     208              : static uint8
     209           28 : decide_s2k_iter(unsigned rand_byte, int count)
     210              : {
     211              :     int         iter;
     212              : 
     213           28 :     if (count == -1)
     214           26 :         return 96 + (rand_byte & 0x1F);
     215              :     /* this is a bit brute-force, but should be quick enough */
     216          257 :     for (iter = 0; iter <= 255; iter++)
     217          257 :         if (s2k_decode_count(iter) >= count)
     218            2 :             return iter;
     219            0 :     return 255;
     220              : }
     221              : 
     222              : int
     223           30 : pgp_s2k_fill(PGP_S2K *s2k, int mode, int digest_algo, int count)
     224              : {
     225           30 :     int         res = 0;
     226              :     uint8       tmp;
     227              : 
     228           30 :     s2k->mode = mode;
     229           30 :     s2k->digest_algo = digest_algo;
     230              : 
     231           30 :     switch (s2k->mode)
     232              :     {
     233            1 :         case PGP_S2K_SIMPLE:
     234            1 :             break;
     235            1 :         case PGP_S2K_SALTED:
     236            1 :             if (!pg_strong_random(s2k->salt, PGP_S2K_SALT))
     237            0 :                 return PXE_NO_RANDOM;
     238            1 :             break;
     239           28 :         case PGP_S2K_ISALTED:
     240           28 :             if (!pg_strong_random(s2k->salt, PGP_S2K_SALT))
     241            0 :                 return PXE_NO_RANDOM;
     242           28 :             if (!pg_strong_random(&tmp, 1))
     243            0 :                 return PXE_NO_RANDOM;
     244           28 :             s2k->iter = decide_s2k_iter(tmp, count);
     245           28 :             break;
     246            0 :         default:
     247            0 :             res = PXE_PGP_BAD_S2K_MODE;
     248              :     }
     249           30 :     return res;
     250              : }
     251              : 
     252              : int
     253           64 : pgp_s2k_read(PullFilter *src, PGP_S2K *s2k)
     254              : {
     255           64 :     int         res = 0;
     256              : 
     257           64 :     GETBYTE(src, s2k->mode);
     258           64 :     GETBYTE(src, s2k->digest_algo);
     259           64 :     switch (s2k->mode)
     260              :     {
     261            4 :         case 0:
     262            4 :             break;
     263            4 :         case 1:
     264            4 :             res = pullf_read_fixed(src, 8, s2k->salt);
     265            4 :             break;
     266           56 :         case 3:
     267           56 :             res = pullf_read_fixed(src, 8, s2k->salt);
     268           56 :             if (res < 0)
     269            0 :                 break;
     270           56 :             GETBYTE(src, s2k->iter);
     271           56 :             break;
     272            0 :         default:
     273            0 :             res = PXE_PGP_BAD_S2K_MODE;
     274              :     }
     275           64 :     return res;
     276              : }
     277              : 
     278              : int
     279           94 : pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int key_len)
     280              : {
     281              :     int         res;
     282              :     PX_MD      *md;
     283              : 
     284           94 :     s2k->key_len = pgp_get_cipher_key_size(cipher);
     285           94 :     if (s2k->key_len <= 0)
     286            0 :         return PXE_PGP_UNSUPPORTED_CIPHER;
     287              : 
     288           94 :     res = pgp_load_digest(s2k->digest_algo, &md);
     289           94 :     if (res < 0)
     290            0 :         return res;
     291              : 
     292           94 :     switch (s2k->mode)
     293              :     {
     294            5 :         case 0:
     295            5 :             res = calc_s2k_simple(s2k, md, key, key_len);
     296            5 :             break;
     297            5 :         case 1:
     298            5 :             res = calc_s2k_salted(s2k, md, key, key_len);
     299            5 :             break;
     300           84 :         case 3:
     301           84 :             res = calc_s2k_iter_salted(s2k, md, key, key_len);
     302           84 :             break;
     303            0 :         default:
     304            0 :             res = PXE_PGP_BAD_S2K_MODE;
     305              :     }
     306           94 :     px_md_free(md);
     307           94 :     return res;
     308              : }
        

Generated by: LCOV version 2.0-1