LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-cfb.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 98 103 95.1 %
Date: 2024-03-28 23:11:20 Functions: 9 9 100.0 %
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         240 : 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         240 :     res = pgp_load_cipher(algo, &ciph);
      60         240 :     if (res < 0)
      61           0 :         return res;
      62             : 
      63         240 :     res = px_cipher_init(ciph, key, key_len, NULL);
      64         240 :     if (res < 0)
      65             :     {
      66           0 :         px_cipher_free(ciph);
      67           0 :         return res;
      68             :     }
      69             : 
      70         240 :     ctx = palloc0(sizeof(*ctx));
      71         240 :     ctx->ciph = ciph;
      72         240 :     ctx->block_size = px_cipher_block_size(ciph);
      73         240 :     ctx->resync = resync;
      74             : 
      75         240 :     if (iv)
      76           8 :         memcpy(ctx->fr, iv, ctx->block_size);
      77             : 
      78         240 :     *ctx_p = ctx;
      79         240 :     return 0;
      80             : }
      81             : 
      82             : void
      83         240 : pgp_cfb_free(PGP_CFB *ctx)
      84             : {
      85         240 :     px_cipher_free(ctx->ciph);
      86         240 :     px_memset(ctx, 0, sizeof(*ctx));
      87         240 :     pfree(ctx);
      88         240 : }
      89             : 
      90             : /*
      91             :  * Data processing for normal CFB.  (PGP_PKT_SYMENCRYPTED_DATA_MDC)
      92             :  */
      93             : static int
      94       10556 : mix_encrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
      95             : {
      96             :     int         i;
      97             : 
      98      178482 :     for (i = ctx->pos; i < ctx->pos + len; i++)
      99      167926 :         *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
     100       10556 :     ctx->pos += len;
     101       10556 :     return len;
     102             : }
     103             : 
     104             : static int
     105       12396 : mix_decrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
     106             : {
     107             :     int         i;
     108             : 
     109      187782 :     for (i = ctx->pos; i < ctx->pos + len; i++)
     110             :     {
     111      175386 :         ctx->encbuf[i] = *data++;
     112      175386 :         *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
     113             :     }
     114       12396 :     ctx->pos += len;
     115       12396 :     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           6 : 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           6 :     if (ctx->block_no == 2)
     132             :     {
     133           2 :         n = 2 - ctx->pos;
     134           2 :         if (len < n)
     135           0 :             n = len;
     136           6 :         for (i = ctx->pos; i < ctx->pos + n; i++)
     137           4 :             *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
     138             : 
     139           2 :         ctx->pos += n;
     140           2 :         len -= n;
     141             : 
     142           2 :         if (ctx->pos == 2)
     143             :         {
     144           2 :             memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
     145           2 :             memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
     146           2 :             ctx->pos = 0;
     147           2 :             return n;
     148             :         }
     149             :     }
     150          66 :     for (i = ctx->pos; i < ctx->pos + len; i++)
     151          62 :         *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
     152           4 :     ctx->pos += len;
     153           4 :     return len;
     154             : }
     155             : 
     156             : static int
     157          36 : 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          36 :     if (ctx->block_no == 2)
     164             :     {
     165           4 :         n = 2 - ctx->pos;
     166           4 :         if (len < n)
     167           0 :             n = len;
     168          12 :         for (i = ctx->pos; i < ctx->pos + n; i++)
     169             :         {
     170           8 :             ctx->encbuf[i] = *data++;
     171           8 :             *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
     172             :         }
     173           4 :         ctx->pos += n;
     174           4 :         len -= n;
     175             : 
     176           4 :         if (ctx->pos == 2)
     177             :         {
     178           4 :             memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
     179           4 :             memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
     180           4 :             ctx->pos = 0;
     181           4 :             return n;
     182             :         }
     183             :     }
     184         180 :     for (i = ctx->pos; i < ctx->pos + len; i++)
     185             :     {
     186         148 :         ctx->encbuf[i] = *data++;
     187         148 :         *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
     188             :     }
     189          32 :     ctx->pos += len;
     190          32 :     return len;
     191             : }
     192             : 
     193             : /*
     194             :  * common code for both encrypt and decrypt.
     195             :  */
     196             : static int
     197        1618 : 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        2964 :     while (len > 0 && ctx->pos > 0)
     204             :     {
     205        1346 :         n = ctx->block_size - ctx->pos;
     206        1346 :         if (len < n)
     207         990 :             n = len;
     208             : 
     209        1346 :         n = mix_data(ctx, data, n, dst);
     210        1346 :         data += n;
     211        1346 :         dst += n;
     212        1346 :         len -= n;
     213             : 
     214        1346 :         if (ctx->pos == ctx->block_size)
     215             :         {
     216         356 :             memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
     217         356 :             ctx->pos = 0;
     218             :         }
     219             :     }
     220             : 
     221       23266 :     while (len > 0)
     222             :     {
     223             :         unsigned    rlen;
     224             : 
     225       21648 :         px_cipher_encrypt(ctx->ciph, 0, ctx->fr, ctx->block_size, ctx->fre, &rlen);
     226       21648 :         if (ctx->block_no < 5)
     227        1008 :             ctx->block_no++;
     228             : 
     229       21648 :         n = ctx->block_size;
     230       21648 :         if (len < n)
     231         600 :             n = len;
     232             : 
     233       21648 :         res = mix_data(ctx, data, n, dst);
     234       21648 :         data += res;
     235       21648 :         dst += res;
     236       21648 :         len -= res;
     237             : 
     238       21648 :         if (ctx->pos == ctx->block_size)
     239             :         {
     240       21046 :             memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
     241       21046 :             ctx->pos = 0;
     242             :         }
     243             :     }
     244        1618 :     return 0;
     245             : }
     246             : 
     247             : /*
     248             :  * public interface
     249             :  */
     250             : 
     251             : int
     252         108 : pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
     253             : {
     254         108 :     mix_data_t  mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal;
     255             : 
     256         108 :     return cfb_process(ctx, data, len, dst, mix);
     257             : }
     258             : 
     259             : int
     260        1510 : pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
     261             : {
     262        1510 :     mix_data_t  mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal;
     263             : 
     264        1510 :     return cfb_process(ctx, data, len, dst, mix);
     265             : }

Generated by: LCOV version 1.14