Logo Search packages:      
Sourcecode: postgresql-8.4 version File versions  Download package

pgp-cfb.c

/*
 * pgp-cfb.c
 *      Implements both normal and PGP-specific CFB mode.
 *
 * Copyright (c) 2005 Marko Kreen
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.      IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-cfb.c,v 1.4 2009/06/11 14:48:52 momjian Exp $
 */

#include "postgres.h"

#include "mbuf.h"
#include "px.h"
#include "pgp.h"

typedef int (*mix_data_t) (PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);

00040 struct PGP_CFB
{
      PX_Cipher  *ciph;
      int               block_size;
      int               pos;
      int               block_no;
      int               resync;
      uint8       fr[PGP_MAX_BLOCK];
      uint8       fre[PGP_MAX_BLOCK];
      uint8       encbuf[PGP_MAX_BLOCK];
};

int
pgp_cfb_create(PGP_CFB **ctx_p, int algo, const uint8 *key, int key_len,
                     int resync, uint8 *iv)
{
      int               res;
      PX_Cipher  *ciph;
      PGP_CFB    *ctx;

      res = pgp_load_cipher(algo, &ciph);
      if (res < 0)
            return res;

      res = px_cipher_init(ciph, key, key_len, NULL);
      if (res < 0)
      {
            px_cipher_free(ciph);
            return res;
      }

      ctx = px_alloc(sizeof(*ctx));
      memset(ctx, 0, sizeof(*ctx));
      ctx->ciph = ciph;
      ctx->block_size = px_cipher_block_size(ciph);
      ctx->resync = resync;

      if (iv)
            memcpy(ctx->fr, iv, ctx->block_size);

      *ctx_p = ctx;
      return 0;
}

void
pgp_cfb_free(PGP_CFB *ctx)
{
      px_cipher_free(ctx->ciph);
      memset(ctx, 0, sizeof(*ctx));
      px_free(ctx);
}

/*
 * Data processing for normal CFB.  (PGP_PKT_SYMENCRYPTED_DATA_MDC)
 */
static int
mix_encrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
{
      int               i;

      for (i = ctx->pos; i < ctx->pos + len; i++)
            *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
      ctx->pos += len;
      return len;
}

static int
mix_decrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
{
      int               i;

      for (i = ctx->pos; i < ctx->pos + len; i++)
      {
            ctx->encbuf[i] = *data++;
            *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
      }
      ctx->pos += len;
      return len;
}

/*
 * Data processing for old PGP CFB mode. (PGP_PKT_SYMENCRYPTED_DATA)
 *
 * The goal is to hide the horror from the rest of the code,
 * thus its all concentrated here.
 */
static int
mix_encrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
{
      int               i,
                        n;

      /* block #2 is 2 bytes long */
      if (ctx->block_no == 2)
      {
            n = 2 - ctx->pos;
            if (len < n)
                  n = len;
            for (i = ctx->pos; i < ctx->pos + n; i++)
                  *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);

            ctx->pos += n;
            len -= n;

            if (ctx->pos == 2)
            {
                  memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
                  memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
                  ctx->pos = 0;
                  return n;
            }
      }
      for (i = ctx->pos; i < ctx->pos + len; i++)
            *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
      ctx->pos += len;
      return len;
}

static int
mix_decrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
{
      int               i,
                        n;

      /* block #2 is 2 bytes long */
      if (ctx->block_no == 2)
      {
            n = 2 - ctx->pos;
            if (len < n)
                  n = len;
            for (i = ctx->pos; i < ctx->pos + n; i++)
            {
                  ctx->encbuf[i] = *data++;
                  *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
            }
            ctx->pos += n;
            len -= n;

            if (ctx->pos == 2)
            {
                  memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
                  memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
                  ctx->pos = 0;
                  return n;
            }
      }
      for (i = ctx->pos; i < ctx->pos + len; i++)
      {
            ctx->encbuf[i] = *data++;
            *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
      }
      ctx->pos += len;
      return len;
}

/*
 * common code for both encrypt and decrypt.
 */
static int
cfb_process(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst,
                  mix_data_t mix_data)
{
      int               n;
      int               res;

      while (len > 0 && ctx->pos > 0)
      {
            n = ctx->block_size - ctx->pos;
            if (len < n)
                  n = len;

            n = mix_data(ctx, data, n, dst);
            data += n;
            dst += n;
            len -= n;

            if (ctx->pos == ctx->block_size)
            {
                  memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
                  ctx->pos = 0;
            }
      }

      while (len > 0)
      {
            px_cipher_encrypt(ctx->ciph, ctx->fr, ctx->block_size, ctx->fre);
            if (ctx->block_no < 5)
                  ctx->block_no++;

            n = ctx->block_size;
            if (len < n)
                  n = len;

            res = mix_data(ctx, data, n, dst);
            data += res;
            dst += res;
            len -= res;

            if (ctx->pos == ctx->block_size)
            {
                  memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
                  ctx->pos = 0;
            }
      }
      return 0;
}

/*
 * public interface
 */

int
pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
{
      mix_data_t  mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal;

      return cfb_process(ctx, data, len, dst, mix);
}

int
pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
{
      mix_data_t  mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal;

      return cfb_process(ctx, data, len, dst, mix);
}

Generated by  Doxygen 1.6.0   Back to index