1 : /* -*- mode: C -*-
2 : *
3 : * File: pdf-stm-f-aesv2.c
4 : * Date: Sun Dec 14 20:13:53 2008
5 : *
6 : * GNU PDF Library - AESV2 stream filter
7 : *
8 : */
9 :
10 : /* Copyright (C) 2008, 2009 Free Software Foundation, Inc. */
11 :
12 : /* This program is free software: you can redistribute it and/or modify
13 : * it under the terms of the GNU General Public License as published by
14 : * the Free Software Foundation, either version 3 of the License, or
15 : * (at your option) any later version.
16 : *
17 : * This program is distributed in the hope that it will be useful,
18 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : * GNU General Public License for more details.
21 : *
22 : * You should have received a copy of the GNU General Public License
23 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #include <config.h>
27 :
28 : #include <stdlib.h>
29 : #include <string.h>
30 :
31 : #include <pdf-stm-f-aesv2.h>
32 : #include <pdf-hash-helper.h>
33 :
34 : #define AESV2_CACHE_SIZE 16
35 :
36 :
37 : /* Internal state */
38 : struct pdf_stm_f_aesv2_s
39 : {
40 : pdf_crypt_cipher_t cipher;
41 : pdf_buffer_t in_cache;
42 : pdf_buffer_t out_cache;
43 : };
44 : typedef struct pdf_stm_f_aesv2_s * pdf_stm_f_aesv2_t;
45 :
46 :
47 : /* Encryption and decryption */
48 : enum pdf_stm_f_aesv2_mode_e
49 : {
50 : PDF_STM_F_AESV2_MODE_ENCODE,
51 : PDF_STM_F_AESV2_MODE_DECODE
52 : };
53 : typedef enum pdf_stm_f_aesv2_mode_e pdf_stm_f_aesv2_mode_t;
54 :
55 :
56 :
57 : static inline pdf_status_t
58 : pdf_stm_f_aesv2_init (pdf_hash_t params, void **state)
59 3 : {
60 : pdf_status_t ret;
61 : pdf_stm_f_aesv2_t filter_state;
62 :
63 3 : filter_state = pdf_alloc (sizeof (struct pdf_stm_f_aesv2_s));
64 :
65 3 : if (filter_state == NULL)
66 : {
67 0 : ret = PDF_ENOMEM;
68 : }
69 3 : else if (state == NULL)
70 : {
71 0 : pdf_dealloc (filter_state);
72 0 : ret = PDF_EBADDATA;
73 : }
74 : else
75 : {
76 : pdf_char_t *key;
77 : pdf_size_t keysize;
78 : pdf_crypt_cipher_t cipher;
79 :
80 : /* We demand all parameters are present */
81 3 : if ((( pdf_hash_key_p (params, "Key") == PDF_TRUE))
82 : && pdf_hash_key_p (params, "KeySize") == PDF_TRUE)
83 : {
84 3 : pdf_hash_get_string (params, "Key", &key);
85 3 : pdf_hash_get_size (params, "KeySize", &keysize);
86 :
87 3 : ret = pdf_crypt_cipher_new (PDF_CRYPT_CIPHER_ALGO_AESV2, &cipher);
88 3 : if (ret == PDF_OK)
89 : {
90 6 : ret = pdf_crypt_cipher_setkey (cipher, key, keysize);
91 3 : if (ret == PDF_OK)
92 : {
93 3 : filter_state->cipher = cipher;
94 :
95 : /* Initialize cache buffers */
96 3 : filter_state->in_cache = pdf_buffer_new (AESV2_CACHE_SIZE);
97 3 : filter_state->out_cache = pdf_buffer_new (AESV2_CACHE_SIZE);
98 :
99 3 : if (filter_state->in_cache == NULL || filter_state->out_cache == NULL)
100 : {
101 0 : ret = PDF_ERROR;
102 : }
103 : else
104 : {
105 3 : ret = PDF_OK;
106 3 : *state = filter_state;
107 : }
108 : }
109 : }
110 : }
111 : else
112 : {
113 0 : ret = PDF_EBADDATA;
114 : }
115 :
116 3 : if (ret != PDF_OK)
117 : {
118 0 : pdf_dealloc (filter_state);
119 : }
120 : }
121 :
122 3 : return ret;
123 : }
124 :
125 :
126 :
127 :
128 : static inline pdf_status_t
129 : pdf_stm_f_aesv2_apply (pdf_stm_f_aesv2_mode_t mode,
130 : pdf_hash_t params, void *state, pdf_buffer_t in,
131 : pdf_buffer_t out, pdf_bool_t finish_p)
132 9 : {
133 9 : pdf_stm_f_aesv2_t filter_state = state;
134 9 : pdf_crypt_cipher_t cipher = filter_state->cipher;
135 9 : pdf_buffer_t in_cache = filter_state->in_cache;
136 9 : pdf_buffer_t out_cache = filter_state->out_cache;
137 :
138 : while(1)
139 : {
140 : pdf_size_t in_size;
141 : pdf_size_t out_size;
142 : pdf_size_t in_cache_size;
143 : pdf_size_t out_cache_size;
144 : pdf_size_t bytes_to_read;
145 : pdf_size_t bytes_to_write;
146 :
147 : /* Read bytes from IN and fill IN_CACHE*/
148 18 : in_size = in->wp - in->rp;
149 18 : in_cache_size = in_cache->size - in_cache->wp;
150 18 : bytes_to_read = PDF_MIN (in_size, in_cache_size);
151 :
152 18 : memcpy (in_cache->data + in_cache->wp,
153 : in->data + in->rp,
154 : bytes_to_read);
155 :
156 18 : in_cache->wp += bytes_to_read;
157 18 : in->rp += bytes_to_read;
158 :
159 :
160 : /* If we cannot fill all IN_CACHE... */
161 18 : if (!pdf_buffer_full_p (in_cache))
162 : {
163 8 : if (finish_p && mode == PDF_STM_F_AESV2_MODE_DECODE
164 : && in_cache->wp > 0)
165 0 : return PDF_ERROR;
166 :
167 : /* ...pad the cache if we have reached EOD */
168 10 : if (finish_p
169 : && !pdf_buffer_full_p (in_cache)
170 : && mode == PDF_STM_F_AESV2_MODE_ENCODE)
171 : {
172 : pdf_size_t padding;
173 2 : padding = in_cache->size - in_cache->wp;
174 :
175 2 : memset (in_cache->data + in_cache->wp,
176 : padding,
177 : padding);
178 :
179 2 : in_cache->wp += padding;
180 : }
181 : else
182 : {
183 6 : if (pdf_buffer_eob_p (out_cache))
184 5 : return PDF_ENINPUT; /* ...ask more input */
185 : }
186 : }
187 :
188 :
189 : /* If OUT_CACHE is empty and IN_CACHE is full, then it is ready
190 : to be processed. */
191 13 : if (pdf_buffer_full_p (in_cache) && pdf_buffer_eob_p (out_cache))
192 : {
193 12 : switch (mode)
194 : {
195 : case PDF_STM_F_AESV2_MODE_ENCODE:
196 9 : pdf_crypt_cipher_encrypt (cipher,
197 : out_cache->data,
198 : out_cache->size,
199 : in_cache->data,
200 : in_cache->size,
201 : NULL);
202 : break;
203 :
204 : case PDF_STM_F_AESV2_MODE_DECODE:
205 3 : pdf_crypt_cipher_decrypt (cipher,
206 : out_cache->data,
207 : out_cache->size,
208 : in_cache->data,
209 : in_cache->size,
210 : NULL);
211 : break;
212 :
213 : default: /* not reached */
214 : break;
215 : }
216 :
217 : /* Both cache are full now */
218 12 : pdf_buffer_rewind (in_cache);
219 12 : out_cache->wp = out_cache->size;
220 : }
221 :
222 :
223 : /* When we are decrypting data, we need know what block is the
224 : last. If both IN and IN_CACHE are empty, then OUT_CACHE could
225 : hold it. So, we ask more input to we make sure.*/
226 13 : if (mode == PDF_STM_F_AESV2_MODE_DECODE
227 : && pdf_buffer_eob_p (in) && pdf_buffer_eob_p (in_cache))
228 : {
229 : /* When we know it is the last, remove the padding. */
230 2 : if (finish_p)
231 : {
232 : pdf_size_t padding;
233 1 : padding = out_cache->data[out_cache->size - 1];
234 :
235 1 : if (padding > AESV2_CACHE_SIZE)
236 0 : return PDF_ERROR;
237 :
238 1 : out_cache->wp = out_cache->size - padding;
239 : }
240 : else
241 1 : return PDF_ENINPUT;
242 : }
243 :
244 :
245 : /* Finally, we fill the OUT buffer */
246 12 : out_size = out->size - out->wp;
247 12 : out_cache_size = out_cache->wp - out_cache->rp;
248 12 : bytes_to_write = PDF_MIN (out_size, out_cache_size);
249 :
250 12 : memcpy (out->data + out->wp,
251 : out_cache->data + out_cache->rp,
252 : bytes_to_write);
253 :
254 12 : out_cache->rp += bytes_to_write;
255 12 : out->wp += bytes_to_write;
256 :
257 :
258 12 : if (finish_p)
259 : {
260 3 : return PDF_EEOF;
261 : }
262 9 : else if (pdf_buffer_full_p (out))
263 : {
264 0 : return PDF_ENOUTPUT;
265 : }
266 : else
267 : {
268 9 : pdf_buffer_rewind (out_cache);
269 : }
270 9 : }
271 : }
272 :
273 :
274 :
275 : static inline pdf_status_t
276 : pdf_stm_f_aesv2_dealloc_state (void *state)
277 3 : {
278 3 : pdf_stm_f_aesv2_t filter_state = state;
279 3 : pdf_crypt_cipher_destroy (filter_state->cipher);
280 3 : pdf_buffer_destroy (filter_state->in_cache);
281 3 : pdf_buffer_destroy (filter_state->out_cache);
282 3 : pdf_dealloc (state);
283 3 : return PDF_OK;
284 : }
285 :
286 :
287 :
288 :
289 : /* Encode filter */
290 :
291 : pdf_status_t
292 : pdf_stm_f_aesv2enc_init (pdf_hash_t params, void **state)
293 2 : {
294 2 : return pdf_stm_f_aesv2_init (params, state);
295 : }
296 :
297 : pdf_status_t
298 : pdf_stm_f_aesv2enc_apply (pdf_hash_t params, void *state, pdf_buffer_t in,
299 : pdf_buffer_t out, pdf_bool_t finish_p)
300 6 : {
301 6 : return pdf_stm_f_aesv2_apply (PDF_STM_F_AESV2_MODE_ENCODE,
302 : params, state, in, out, finish_p);
303 : }
304 :
305 : pdf_status_t
306 : pdf_stm_f_aesv2enc_dealloc_state (void *state)
307 2 : {
308 2 : return pdf_stm_f_aesv2_dealloc_state (state);
309 : }
310 :
311 :
312 :
313 : /* Decode filter */
314 :
315 : pdf_status_t
316 : pdf_stm_f_aesv2dec_init (pdf_hash_t params, void **state)
317 1 : {
318 1 : return pdf_stm_f_aesv2_init (params, state);
319 : }
320 :
321 :
322 : pdf_status_t
323 : pdf_stm_f_aesv2dec_apply (pdf_hash_t params, void *state, pdf_buffer_t in,
324 : pdf_buffer_t out, pdf_bool_t finish_p)
325 3 : {
326 3 : return pdf_stm_f_aesv2_apply (PDF_STM_F_AESV2_MODE_DECODE,
327 : params, state, in, out, finish_p);
328 : }
329 :
330 :
331 : pdf_status_t
332 : pdf_stm_f_aesv2dec_dealloc_state (void *state)
333 1 : {
334 1 : return pdf_stm_f_aesv2_dealloc_state (state);
335 : }
336 :
337 :
338 :
339 : /* End of pdf_stm_f_aesv2.c */
|