00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
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
00122
00123
00124
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
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
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
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
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 }