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