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