Header And Logo

PostgreSQL
| The world's most advanced open source database.

pgp-cfb.c

Go to the documentation of this file.
00001 /*
00002  * pgp-cfb.c
00003  *    Implements both normal and PGP-specific CFB mode.
00004  *
00005  * Copyright (c) 2005 Marko Kreen
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * contrib/pgcrypto/pgp-cfb.c
00030  */
00031 
00032 #include "postgres.h"
00033 
00034 #include "mbuf.h"
00035 #include "px.h"
00036 #include "pgp.h"
00037 
00038 typedef int (*mix_data_t) (PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst);
00039 
00040 struct PGP_CFB
00041 {
00042     PX_Cipher  *ciph;
00043     int         block_size;
00044     int         pos;
00045     int         block_no;
00046     int         resync;
00047     uint8       fr[PGP_MAX_BLOCK];
00048     uint8       fre[PGP_MAX_BLOCK];
00049     uint8       encbuf[PGP_MAX_BLOCK];
00050 };
00051 
00052 int
00053 pgp_cfb_create(PGP_CFB **ctx_p, int algo, const uint8 *key, int key_len,
00054                int resync, uint8 *iv)
00055 {
00056     int         res;
00057     PX_Cipher  *ciph;
00058     PGP_CFB    *ctx;
00059 
00060     res = pgp_load_cipher(algo, &ciph);
00061     if (res < 0)
00062         return res;
00063 
00064     res = px_cipher_init(ciph, key, key_len, NULL);
00065     if (res < 0)
00066     {
00067         px_cipher_free(ciph);
00068         return res;
00069     }
00070 
00071     ctx = px_alloc(sizeof(*ctx));
00072     memset(ctx, 0, sizeof(*ctx));
00073     ctx->ciph = ciph;
00074     ctx->block_size = px_cipher_block_size(ciph);
00075     ctx->resync = resync;
00076 
00077     if (iv)
00078         memcpy(ctx->fr, iv, ctx->block_size);
00079 
00080     *ctx_p = ctx;
00081     return 0;
00082 }
00083 
00084 void
00085 pgp_cfb_free(PGP_CFB *ctx)
00086 {
00087     px_cipher_free(ctx->ciph);
00088     memset(ctx, 0, sizeof(*ctx));
00089     px_free(ctx);
00090 }
00091 
00092 /*
00093  * Data processing for normal CFB.  (PGP_PKT_SYMENCRYPTED_DATA_MDC)
00094  */
00095 static int
00096 mix_encrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
00097 {
00098     int         i;
00099 
00100     for (i = ctx->pos; i < ctx->pos + len; i++)
00101         *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
00102     ctx->pos += len;
00103     return len;
00104 }
00105 
00106 static int
00107 mix_decrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
00108 {
00109     int         i;
00110 
00111     for (i = ctx->pos; i < ctx->pos + len; i++)
00112     {
00113         ctx->encbuf[i] = *data++;
00114         *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
00115     }
00116     ctx->pos += len;
00117     return len;
00118 }
00119 
00120 /*
00121  * Data processing for old PGP CFB mode. (PGP_PKT_SYMENCRYPTED_DATA)
00122  *
00123  * The goal is to hide the horror from the rest of the code,
00124  * thus its all concentrated here.
00125  */
00126 static int
00127 mix_encrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
00128 {
00129     int         i,
00130                 n;
00131 
00132     /* block #2 is 2 bytes long */
00133     if (ctx->block_no == 2)
00134     {
00135         n = 2 - ctx->pos;
00136         if (len < n)
00137             n = len;
00138         for (i = ctx->pos; i < ctx->pos + n; i++)
00139             *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
00140 
00141         ctx->pos += n;
00142         len -= n;
00143 
00144         if (ctx->pos == 2)
00145         {
00146             memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
00147             memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
00148             ctx->pos = 0;
00149             return n;
00150         }
00151     }
00152     for (i = ctx->pos; i < ctx->pos + len; i++)
00153         *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
00154     ctx->pos += len;
00155     return len;
00156 }
00157 
00158 static int
00159 mix_decrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
00160 {
00161     int         i,
00162                 n;
00163 
00164     /* block #2 is 2 bytes long */
00165     if (ctx->block_no == 2)
00166     {
00167         n = 2 - ctx->pos;
00168         if (len < n)
00169             n = len;
00170         for (i = ctx->pos; i < ctx->pos + n; i++)
00171         {
00172             ctx->encbuf[i] = *data++;
00173             *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
00174         }
00175         ctx->pos += n;
00176         len -= n;
00177 
00178         if (ctx->pos == 2)
00179         {
00180             memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
00181             memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
00182             ctx->pos = 0;
00183             return n;
00184         }
00185     }
00186     for (i = ctx->pos; i < ctx->pos + len; i++)
00187     {
00188         ctx->encbuf[i] = *data++;
00189         *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
00190     }
00191     ctx->pos += len;
00192     return len;
00193 }
00194 
00195 /*
00196  * common code for both encrypt and decrypt.
00197  */
00198 static int
00199 cfb_process(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst,
00200             mix_data_t mix_data)
00201 {
00202     int         n;
00203     int         res;
00204 
00205     while (len > 0 && ctx->pos > 0)
00206     {
00207         n = ctx->block_size - ctx->pos;
00208         if (len < n)
00209             n = len;
00210 
00211         n = mix_data(ctx, data, n, dst);
00212         data += n;
00213         dst += n;
00214         len -= n;
00215 
00216         if (ctx->pos == ctx->block_size)
00217         {
00218             memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
00219             ctx->pos = 0;
00220         }
00221     }
00222 
00223     while (len > 0)
00224     {
00225         px_cipher_encrypt(ctx->ciph, ctx->fr, ctx->block_size, ctx->fre);
00226         if (ctx->block_no < 5)
00227             ctx->block_no++;
00228 
00229         n = ctx->block_size;
00230         if (len < n)
00231             n = len;
00232 
00233         res = mix_data(ctx, data, n, dst);
00234         data += res;
00235         dst += res;
00236         len -= res;
00237 
00238         if (ctx->pos == ctx->block_size)
00239         {
00240             memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
00241             ctx->pos = 0;
00242         }
00243     }
00244     return 0;
00245 }
00246 
00247 /*
00248  * public interface
00249  */
00250 
00251 int
00252 pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
00253 {
00254     mix_data_t  mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal;
00255 
00256     return cfb_process(ctx, data, len, dst, mix);
00257 }
00258 
00259 int
00260 pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
00261 {
00262     mix_data_t  mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal;
00263 
00264     return cfb_process(ctx, data, len, dst, mix);
00265 }