Branch data 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 : : int ignore_decrypt_cipher_failure; /* for CVE-2026-14663 recovery */
47 : : uint8 fr[PGP_MAX_BLOCK];
48 : : uint8 fre[PGP_MAX_BLOCK];
49 : : uint8 encbuf[PGP_MAX_BLOCK];
50 : : };
51 : :
52 : : int
53 : 122 : pgp_cfb_create(PGP_CFB **ctx_p, int algo, const uint8 *key, int key_len,
54 : : int resync, uint8 *iv, int ignore_decrypt_cipher_failure)
55 : : {
56 : : int res;
57 : : PX_Cipher *ciph;
58 : : PGP_CFB *ctx;
59 : :
60 : 122 : res = pgp_load_cipher(algo, &ciph);
61 [ - + ]: 122 : if (res < 0)
62 : 0 : return res;
63 : :
64 : 122 : res = px_cipher_init(ciph, key, key_len, NULL);
65 [ - + ]: 122 : if (res < 0)
66 : : {
67 : 0 : px_cipher_free(ciph);
68 : 0 : return res;
69 : : }
70 : :
71 : 122 : ctx = palloc0_object(PGP_CFB);
72 : 122 : ctx->ciph = ciph;
73 : 122 : ctx->block_size = px_cipher_block_size(ciph);
74 : 122 : ctx->resync = resync;
75 : 122 : ctx->ignore_decrypt_cipher_failure = ignore_decrypt_cipher_failure;
76 : :
77 [ + + ]: 122 : if (iv)
78 : 4 : memcpy(ctx->fr, iv, ctx->block_size);
79 : :
80 : 122 : *ctx_p = ctx;
81 : 122 : return 0;
82 : : }
83 : :
84 : : void
85 : 116 : pgp_cfb_free(PGP_CFB *ctx)
86 : : {
87 : 116 : px_cipher_free(ctx->ciph);
88 : 116 : px_memset(ctx, 0, sizeof(*ctx));
89 : 116 : pfree(ctx);
90 : 116 : }
91 : :
92 : : /*
93 : : * Data processing for normal CFB. (PGP_PKT_SYMENCRYPTED_DATA_MDC)
94 : : */
95 : : static int
96 : 5262 : mix_encrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
97 : : {
98 : : int i;
99 : :
100 [ + + ]: 89114 : for (i = ctx->pos; i < ctx->pos + len; i++)
101 : 83852 : *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
102 : 5262 : ctx->pos += len;
103 : 5262 : return len;
104 : : }
105 : :
106 : : static int
107 : 6177 : mix_decrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
108 : : {
109 : : int i;
110 : :
111 [ + + ]: 93809 : for (i = ctx->pos; i < ctx->pos + len; i++)
112 : : {
113 : 87632 : ctx->encbuf[i] = *data++;
114 : 87632 : *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
115 : : }
116 : 6177 : ctx->pos += len;
117 : 6177 : return len;
118 : : }
119 : :
120 : : /*
121 : : * Data processing for old PGP CFB mode. (PGP_PKT_SYMENCRYPTED_DATA)
122 : : *
123 : : * The goal is to hide the horror from the rest of the code,
124 : : * thus its all concentrated here.
125 : : */
126 : : static int
127 : 3 : mix_encrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
128 : : {
129 : : int i,
130 : : n;
131 : :
132 : : /* block #2 is 2 bytes long */
133 [ + + ]: 3 : if (ctx->block_no == 2)
134 : : {
135 : 1 : n = 2 - ctx->pos;
136 [ - + ]: 1 : if (len < n)
137 : 0 : n = len;
138 [ + + ]: 3 : for (i = ctx->pos; i < ctx->pos + n; i++)
139 : 2 : *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
140 : :
141 : 1 : ctx->pos += n;
142 : 1 : len -= n;
143 : :
144 [ + - ]: 1 : if (ctx->pos == 2)
145 : : {
146 : 1 : memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
147 : 1 : memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
148 : 1 : ctx->pos = 0;
149 : 1 : return n;
150 : : }
151 : : }
152 [ + + ]: 33 : for (i = ctx->pos; i < ctx->pos + len; i++)
153 : 31 : *dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
154 : 2 : ctx->pos += len;
155 : 2 : return len;
156 : : }
157 : :
158 : : static int
159 : 18 : mix_decrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
160 : : {
161 : : int i,
162 : : n;
163 : :
164 : : /* block #2 is 2 bytes long */
165 [ + + ]: 18 : if (ctx->block_no == 2)
166 : : {
167 : 2 : n = 2 - ctx->pos;
168 [ - + ]: 2 : if (len < n)
169 : 0 : n = len;
170 [ + + ]: 6 : for (i = ctx->pos; i < ctx->pos + n; i++)
171 : : {
172 : 4 : ctx->encbuf[i] = *data++;
173 : 4 : *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
174 : : }
175 : 2 : ctx->pos += n;
176 : 2 : len -= n;
177 : :
178 [ + - ]: 2 : if (ctx->pos == 2)
179 : : {
180 : 2 : memcpy(ctx->fr, ctx->encbuf + 2, ctx->block_size - 2);
181 : 2 : memcpy(ctx->fr + ctx->block_size - 2, ctx->encbuf, 2);
182 : 2 : ctx->pos = 0;
183 : 2 : return n;
184 : : }
185 : : }
186 [ + + ]: 90 : for (i = ctx->pos; i < ctx->pos + len; i++)
187 : : {
188 : 74 : ctx->encbuf[i] = *data++;
189 : 74 : *dst++ = ctx->fre[i] ^ ctx->encbuf[i];
190 : : }
191 : 16 : ctx->pos += len;
192 : 16 : return len;
193 : : }
194 : :
195 : : /*
196 : : * common code for both encrypt and decrypt.
197 : : */
198 : : static int
199 : 800 : cfb_process(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst,
200 : : mix_data_t mix_data, int ignore_cipher_failure)
201 : : {
202 : : int n;
203 : : int res;
204 : :
205 [ + + + + ]: 1462 : while (len > 0 && ctx->pos > 0)
206 : : {
207 : 662 : n = ctx->block_size - ctx->pos;
208 [ + + ]: 662 : if (len < n)
209 : 491 : n = len;
210 : :
211 : 662 : n = mix_data(ctx, data, n, dst);
212 : 662 : data += n;
213 : 662 : dst += n;
214 : 662 : len -= n;
215 : :
216 [ + + ]: 662 : if (ctx->pos == ctx->block_size)
217 : : {
218 : 171 : memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
219 : 171 : ctx->pos = 0;
220 : : }
221 : : }
222 : :
223 [ + + ]: 11598 : while (len > 0)
224 : : {
225 : : unsigned rlen;
226 : : int err;
227 : :
228 : 10804 : err = px_cipher_encrypt(ctx->ciph, 0, ctx->fr, ctx->block_size, ctx->fre, &rlen);
229 : :
230 : : /*
231 : : * XXX Ignoring cipher failures is dangerous, but we allow it during
232 : : * decryption to return to the behavior prior to the fix for
233 : : * CVE-2026-14663. This lets users recover data from a badly-encrypted
234 : : * message.
235 : : */
236 [ + + + + ]: 10804 : if (err && !ignore_cipher_failure)
237 [ + - ]: 6 : ereport(ERROR,
238 : : (errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),
239 : : errmsg("encrypt error: %s", px_strerror(err))));
240 : :
241 [ + + ]: 10798 : if (ctx->block_no < 5)
242 : 484 : ctx->block_no++;
243 : :
244 : 10798 : n = ctx->block_size;
245 [ + + ]: 10798 : if (len < n)
246 : 289 : n = len;
247 : :
248 : 10798 : res = mix_data(ctx, data, n, dst);
249 : 10798 : data += res;
250 : 10798 : dst += res;
251 : 10798 : len -= res;
252 : :
253 [ + + ]: 10798 : if (ctx->pos == ctx->block_size)
254 : : {
255 : 10508 : memcpy(ctx->fr, ctx->encbuf, ctx->block_size);
256 : 10508 : ctx->pos = 0;
257 : : }
258 : : }
259 : 794 : return 0;
260 : : }
261 : :
262 : : /*
263 : : * public interface
264 : : */
265 : :
266 : : int
267 : 52 : pgp_cfb_encrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
268 : : {
269 [ + + ]: 52 : mix_data_t mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal;
270 : :
271 : 52 : return cfb_process(ctx, data, len, dst, mix,
272 : : 0 /* never ignore cipher failures for encrypt */ );
273 : : }
274 : :
275 : : int
276 : 748 : pgp_cfb_decrypt(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
277 : : {
278 [ + + ]: 748 : mix_data_t mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal;
279 : :
280 : 748 : return cfb_process(ctx, data, len, dst, mix,
281 : : ctx->ignore_decrypt_cipher_failure);
282 : : }
|