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 : }
|