LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-cfb.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 95.1 % 103 98
Test Date: 2026-03-04 08:14:57 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * pgp-cfb.c
       3              :  *    Implements both normal and PGP-specific CFB mode.
       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-cfb.c
      30              :  */
      31              : 
      32              : #include "postgres.h"
      33              : 
      34              : #include "pgp.h"
      35              : #include "px.h"
      36              : 
      37              : typedef int (*mix_data_t) (PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
      38              : 
      39              : struct PGP_CFB
      40              : {
      41              :     PX_Cipher  *ciph;
      42              :     int         block_size;
      43              :     int         pos;
      44              :     int         block_no;
      45              :     int         resync;
      46              :     uint8       fr[PGP_MAX_BLOCK];
      47              :     uint8       fre[PGP_MAX_BLOCK];
      48              :     uint8       encbuf[PGP_MAX_BLOCK];
      49              : };
      50              : 
      51              : int
      52          121 : pgp_cfb_create(PGP_CFB **ctx_p, int algo, const uint8 *key, int key_len,
      53              :                int resync, uint8 *iv)
      54              : {
      55              :     int         res;
      56              :     PX_Cipher  *ciph;
      57              :     PGP_CFB    *ctx;
      58              : 
      59          121 :     res = pgp_load_cipher(algo, &ciph);
      60          121 :     if (res < 0)
      61            0 :         return res;
      62              : 
      63          121 :     res = px_cipher_init(ciph, key, key_len, NULL);
      64          121 :     if (res < 0)
      65              :     {
      66            0 :         px_cipher_free(ciph);
      67            0 :         return res;
      68              :     }
      69              : 
      70          121 :     ctx = palloc0_object(PGP_CFB);
      71          121 :     ctx->ciph = ciph;
      72          121 :     ctx->block_size = px_cipher_block_size(ciph);
      73          121 :     ctx->resync = resync;
      74              : 
      75          121 :     if (iv)
      76            4 :         memcpy(ctx->fr, iv, ctx->block_size);
      77              : 
      78          121 :     *ctx_p = ctx;
      79          121 :     return 0;
      80              : }
      81              : 
      82              : void
      83          121 : pgp_cfb_free(PGP_CFB *ctx)
      84              : {
      85          121 :     px_cipher_free(ctx->ciph);
      86          121 :     px_memset(ctx, 0, sizeof(*ctx));
      87          121 :     pfree(ctx);
      88          121 : }
      89              : 
      90              : /*
      91              :  * Data processing for normal CFB.  (PGP_PKT_SYMENCRYPTED_DATA_MDC)
      92              :  */
      93              : static int
      94         5278 : mix_encrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
      95              : {
      96              :     int         i;
      97              : 
      98        89241 :     for (i = ctx->pos; i < ctx->pos + len; i++)
      99        83963 :         *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
     100         5278 :     ctx->pos += len;
     101         5278 :     return len;
     102              : }
     103              : 
     104              : static int
     105         6183 : mix_decrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
     106              : {
     107              :     int         i;
     108              : 
     109        93840 :     for (i = ctx->pos; i < ctx->pos + len; i++)
     110              :     {
     111        87657 :         ctx->encbuf[i] = *data++;
     112        87657 :         *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
     113              :     }
     114         6183 :     ctx->pos += len;
     115         6183 :     return len;
     116              : }
     117              : 
     118              : /*
     119              :  * Data processing for old PGP CFB mode. (PGP_PKT_SYMENCRYPTED_DATA)
     120              :  *
     121              :  * The goal is to hide the horror from the rest of the code,
     122              :  * thus its all concentrated here.
     123              :  */
     124              : static int
     125            3 : mix_encrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
     126              : {
     127              :     int         i,
     128              :                 n;
     129              : 
     130              :     /* block #2 is 2 bytes long */
     131            3 :     if (ctx->block_no == 2)
     132              :     {
     133            1 :         n = 2 - ctx->pos;
     134            1 :         if (len < n)
     135            0 :             n = len;
     136            3 :         for (i = ctx->pos; i < ctx->pos + n; i++)
     137            2 :             *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
     138              : 
     139            1 :         ctx->pos += n;
     140            1 :         len -= n;
     141              : 
     142            1 :         if (ctx->pos == 2)
     143              :         {
     144            1 :             memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
     145            1 :             memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
     146            1 :             ctx->pos = 0;
     147            1 :             return n;
     148              :         }
     149              :     }
     150           33 :     for (i = ctx->pos; i < ctx->pos + len; i++)
     151           31 :         *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
     152            2 :     ctx->pos += len;
     153            2 :     return len;
     154              : }
     155              : 
     156              : static int
     157           18 : mix_decrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
     158              : {
     159              :     int         i,
     160              :                 n;
     161              : 
     162              :     /* block #2 is 2 bytes long */
     163           18 :     if (ctx->block_no == 2)
     164              :     {
     165            2 :         n = 2 - ctx->pos;
     166            2 :         if (len < n)
     167            0 :             n = len;
     168            6 :         for (i = ctx->pos; i < ctx->pos + n; i++)
     169              :         {
     170            4 :             ctx->encbuf[i] = *data++;
     171            4 :             *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
     172              :         }
     173            2 :         ctx->pos += n;
     174            2 :         len -= n;
     175              : 
     176            2 :         if (ctx->pos == 2)
     177              :         {
     178            2 :             memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
     179            2 :             memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
     180            2 :             ctx->pos = 0;
     181            2 :             return n;
     182              :         }
     183              :     }
     184           90 :     for (i = ctx->pos; i < ctx->pos + len; i++)
     185              :     {
     186           74 :         ctx->encbuf[i] = *data++;
     187           74 :         *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
     188              :     }
     189           16 :     ctx->pos += len;
     190           16 :     return len;
     191              : }
     192              : 
     193              : /*
     194              :  * common code for both encrypt and decrypt.
     195              :  */
     196              : static int
     197          802 : cfb_process(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst,
     198              :             mix_data_t mix_data)
     199              : {
     200              :     int         n;
     201              :     int         res;
     202              : 
     203         1467 :     while (len > 0 && ctx->pos > 0)
     204              :     {
     205          665 :         n = ctx->block_size - ctx->pos;
     206          665 :         if (len < n)
     207          492 :             n = len;
     208              : 
     209          665 :         n = mix_data(ctx, data, n, dst);
     210          665 :         data += n;
     211          665 :         dst += n;
     212          665 :         len -= n;
     213              : 
     214          665 :         if (ctx->pos == ctx->block_size)
     215              :         {
     216          173 :             memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
     217          173 :             ctx->pos = 0;
     218              :         }
     219              :     }
     220              : 
     221        11619 :     while (len > 0)
     222              :     {
     223              :         unsigned    rlen;
     224              : 
     225        10817 :         px_cipher_encrypt(ctx->ciph, 0, ctx->fr, ctx->block_size, ctx->fre, &rlen);
     226        10817 :         if (ctx->block_no < 5)
     227          502 :             ctx->block_no++;
     228              : 
     229        10817 :         n = ctx->block_size;
     230        10817 :         if (len < n)
     231          296 :             n = len;
     232              : 
     233        10817 :         res = mix_data(ctx, data, n, dst);
     234        10817 :         data += res;
     235        10817 :         dst += res;
     236        10817 :         len -= res;
     237              : 
     238        10817 :         if (ctx->pos == ctx->block_size)
     239              :         {
     240        10520 :             memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
     241        10520 :             ctx->pos = 0;
     242              :         }
     243              :     }
     244          802 :     return 0;
     245              : }
     246              : 
     247              : /*
     248              :  * public interface
     249              :  */
     250              : 
     251              : int
     252           54 : pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
     253              : {
     254           54 :     mix_data_t  mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal;
     255              : 
     256           54 :     return cfb_process(ctx, data, len, dst, mix);
     257              : }
     258              : 
     259              : int
     260          748 : pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
     261              : {
     262          748 :     mix_data_t  mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal;
     263              : 
     264          748 :     return cfb_process(ctx, data, len, dst, mix);
     265              : }
        

Generated by: LCOV version 2.0-1