Branch data Line data Source code
1 : : /* -*- mode: C -*-
2 : : *
3 : : * File: pdf-crypt.c
4 : : * Date: Fri Feb 22 21:05:05 2008
5 : : *
6 : : * GNU PDF Library - AESV2 backend encryption module
7 : : *
8 : : */
9 : :
10 : : /* Copyright (C) 2008 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 : : #include <gcrypt.h>
31 : :
32 : : #include <pdf-alloc.h>
33 : : #include <pdf-types.h>
34 : : #include <pdf-error.h>
35 : : #include <pdf-crypt-c-aesv2.h>
36 : :
37 : : #define AESV2_BLKSIZE 16 /* Size of a block in AES128 */
38 : :
39 : : struct pdf_crypt_cipher_aesv2_s {
40 : : /* Implementation */
41 : : struct pdf_crypt_cipher_s parent;
42 : : /* Implementation-specific private data */
43 : : gcry_cipher_hd_t hd;
44 : : pdf_bool_t first_block;
45 : : };
46 : :
47 : : static pdf_bool_t
48 : 27 : aesv2_set_key (pdf_crypt_cipher_t *cipher,
49 : : const pdf_char_t *key,
50 : : pdf_size_t size,
51 : : pdf_error_t **error)
52 : : {
53 : 27 : struct pdf_crypt_cipher_aesv2_s *aesv2 = (struct pdf_crypt_cipher_aesv2_s *)cipher;
54 : : gcry_error_t gcry_error;
55 : :
56 : 27 : gcry_error = gcry_cipher_setkey (aesv2->hd, key, size);
57 [ + + ]: 27 : if (gcry_error != GPG_ERR_NO_ERROR)
58 : : {
59 : 1 : pdf_set_error (error,
60 : : PDF_EDOMAIN_BASE_ENCRYPTION,
61 : : PDF_EBADAESKEY,
62 : : "cannot set key in AESv2 cipher: '%s/%s'",
63 : : gcry_strsource (gcry_error),
64 : : gcry_strerror (gcry_error));
65 : 1 : return PDF_FALSE;
66 : : }
67 : 27 : return PDF_TRUE;
68 : : }
69 : :
70 : : static pdf_bool_t
71 : 36 : aesv2_encrypt (pdf_crypt_cipher_t *cipher,
72 : : pdf_char_t *out,
73 : : pdf_size_t out_size,
74 : : const pdf_char_t *in,
75 : : pdf_size_t in_size,
76 : : pdf_size_t *result_size,
77 : : pdf_error_t **error)
78 : : {
79 : 36 : struct pdf_crypt_cipher_aesv2_s *aesv2 = (struct pdf_crypt_cipher_aesv2_s *)cipher;
80 : : gcry_error_t gcry_error;
81 : : pdf_char_t *output;
82 : : pdf_size_t output_size;
83 : : const pdf_char_t *input;
84 : : pdf_size_t input_size;
85 : :
86 [ + - ][ - + ]: 36 : if (in_size < AESV2_BLKSIZE ||
87 : 36 : in_size % AESV2_BLKSIZE != 0)
88 : : {
89 : 0 : pdf_set_error (error,
90 : : PDF_EDOMAIN_BASE_ENCRYPTION,
91 : : PDF_EBADDATA,
92 : : "cannot encrypt in AESv2 cipher: "
93 : : "invalid input size (%lu), "
94 : : "must be multiple of block size (%lu)",
95 : : (unsigned long)in_size,
96 : : (unsigned long)AESV2_BLKSIZE);
97 : 0 : return PDF_FALSE;
98 : : }
99 : :
100 [ - + ]: 36 : if (out_size < in_size)
101 : : {
102 : 0 : pdf_set_error (error,
103 : : PDF_EDOMAIN_BASE_ENCRYPTION,
104 : : PDF_EBADDATA,
105 : : "cannot encrypt in AESv2 cipher: "
106 : : "output size (%lu) cannot be smaller than input size (%lu)",
107 : : (unsigned long)out_size,
108 : : (unsigned long)in_size);
109 : 0 : return PDF_FALSE;
110 : : }
111 : :
112 : : /* If we are at first block, then we have found the IV vector */
113 [ + + ]: 36 : if (aesv2->first_block)
114 : : {
115 : 12 : const pdf_char_t *iv = in;
116 : :
117 : 12 : gcry_cipher_setiv (aesv2->hd, iv, AESV2_BLKSIZE);
118 : 12 : input = in + AESV2_BLKSIZE;
119 : 12 : input_size = in_size - AESV2_BLKSIZE;
120 : :
121 : 12 : memcpy (out, iv, AESV2_BLKSIZE);
122 : :
123 : 12 : output = out + AESV2_BLKSIZE;
124 : 12 : output_size = out_size - AESV2_BLKSIZE;
125 : :
126 : 12 : aesv2->first_block = PDF_FALSE;
127 : : }
128 : : else
129 : : {
130 : 24 : output = out;
131 : 24 : output_size = out_size;
132 : 24 : input = in;
133 : 24 : input_size = in_size;
134 : : }
135 : :
136 : 36 : gcry_error = gcry_cipher_encrypt (aesv2->hd, output, output_size, input, input_size);
137 [ - + ]: 36 : if (gcry_error != GPG_ERR_NO_ERROR)
138 : : {
139 : 0 : pdf_set_error (error,
140 : : PDF_EDOMAIN_BASE_ENCRYPTION,
141 : : PDF_ENOMEM,
142 : : "cannot encrypt with AESv2 cipher: '%s/%s'",
143 : : gcry_strsource (gcry_error),
144 : : gcry_strerror (gcry_error));
145 : 0 : return PDF_FALSE;
146 : : }
147 : :
148 [ - + ]: 36 : if (result_size)
149 : 0 : *result_size = in_size;
150 : :
151 : 36 : return PDF_TRUE;
152 : : }
153 : :
154 : : static pdf_bool_t
155 : 37 : aesv2_decrypt (pdf_crypt_cipher_t *cipher,
156 : : pdf_char_t *out,
157 : : pdf_size_t out_size,
158 : : const pdf_char_t *in,
159 : : pdf_size_t in_size,
160 : : pdf_size_t *result_size,
161 : : pdf_error_t **error)
162 : : {
163 : 37 : struct pdf_crypt_cipher_aesv2_s *aesv2 = (struct pdf_crypt_cipher_aesv2_s *)cipher;
164 : : gcry_error_t gcry_error;
165 : : pdf_char_t *output;
166 : : pdf_size_t output_size;
167 : : const pdf_char_t *input;
168 : : pdf_size_t input_size;
169 : :
170 [ + - ][ - + ]: 37 : if (in_size < AESV2_BLKSIZE ||
171 : 37 : in_size % AESV2_BLKSIZE != 0)
172 : : {
173 : 0 : pdf_set_error (error,
174 : : PDF_EDOMAIN_BASE_ENCRYPTION,
175 : : PDF_EBADDATA,
176 : : "cannot decrypt in AESv2 cipher: "
177 : : "invalid input size (%lu), "
178 : : "must be multiple of block size (%lu)",
179 : : (unsigned long)in_size,
180 : : (unsigned long)AESV2_BLKSIZE);
181 : 0 : return PDF_FALSE;
182 : : }
183 : :
184 [ - + ]: 37 : if (out_size < in_size)
185 : : {
186 : 0 : pdf_set_error (error,
187 : : PDF_EDOMAIN_BASE_ENCRYPTION,
188 : : PDF_EBADDATA,
189 : : "cannot decrypt in AESv2 cipher: "
190 : : "output size (%lu) cannot be smaller than input size (%lu)",
191 : : (unsigned long)out_size,
192 : : (unsigned long)in_size);
193 : 0 : return PDF_FALSE;
194 : : }
195 : :
196 : : /* If we are at first block, then we have found the IV vector */
197 [ + + ]: 37 : if (aesv2->first_block)
198 : : {
199 : 13 : const pdf_char_t *iv = in;
200 : :
201 : 13 : gcry_cipher_setiv (aesv2->hd, iv, AESV2_BLKSIZE);
202 : 13 : input = in + AESV2_BLKSIZE;
203 : 13 : input_size = in_size - AESV2_BLKSIZE;
204 : :
205 : 13 : memcpy (out, iv, AESV2_BLKSIZE);
206 : :
207 : 13 : output = out + AESV2_BLKSIZE;
208 : 13 : output_size = out_size - AESV2_BLKSIZE;
209 : :
210 : 13 : aesv2->first_block = PDF_FALSE;
211 : : }
212 : : else
213 : : {
214 : 24 : output = out;
215 : 24 : output_size = out_size;
216 : 24 : input = in;
217 : 24 : input_size = in_size;
218 : : }
219 : :
220 : 37 : gcry_error = gcry_cipher_decrypt (aesv2->hd, output, output_size, input, input_size);
221 [ - + ]: 37 : if (gcry_error != GPG_ERR_NO_ERROR)
222 : : {
223 : 0 : pdf_set_error (error,
224 : : PDF_EDOMAIN_BASE_ENCRYPTION,
225 : : PDF_ENOMEM,
226 : : "cannot decrypt with AESv2 cipher: '%s/%s'",
227 : : gcry_strsource (gcry_error),
228 : : gcry_strerror (gcry_error));
229 : 0 : return PDF_FALSE;
230 : : }
231 : :
232 [ - + ]: 37 : if (result_size)
233 : 0 : *result_size = in_size;
234 : :
235 : 37 : return PDF_TRUE;
236 : : }
237 : :
238 : : static void
239 : 28 : aesv2_destroy (pdf_crypt_cipher_t *cipher)
240 : : {
241 : 28 : struct pdf_crypt_cipher_aesv2_s *aesv2 = (struct pdf_crypt_cipher_aesv2_s *)cipher;
242 : :
243 : 28 : gcry_cipher_close (aesv2->hd);
244 : 28 : pdf_dealloc (aesv2);
245 : 28 : }
246 : :
247 : : /* Implementation of the cipher module */
248 : : static const struct pdf_crypt_cipher_s implementation = {
249 : : .set_key = aesv2_set_key,
250 : : .encrypt = aesv2_encrypt,
251 : : .decrypt = aesv2_decrypt,
252 : : .destroy = aesv2_destroy
253 : : };
254 : :
255 : : pdf_crypt_cipher_t *
256 : 28 : pdf_crypt_cipher_aesv2_new (pdf_error_t **error)
257 : : {
258 : : gcry_error_t gcry_error;
259 : : struct pdf_crypt_cipher_aesv2_s *cipher;
260 : :
261 : 28 : cipher = pdf_alloc (sizeof (struct pdf_crypt_cipher_aesv2_s));
262 [ - + ]: 28 : if (!cipher)
263 : : {
264 : 0 : pdf_set_error (error,
265 : : PDF_EDOMAIN_BASE_ENCRYPTION,
266 : : PDF_ENOMEM,
267 : : "cannot create new AESv2 cipher object: "
268 : : "couldn't allocate %lu bytes",
269 : : (unsigned long)sizeof (struct pdf_crypt_cipher_aesv2_s));
270 : 0 : return NULL;
271 : : }
272 : :
273 : : /* Set implementation API */
274 : 28 : cipher->parent = implementation;
275 : :
276 : : /* Initialize cipher object */
277 : 28 : cipher->first_block = PDF_TRUE;
278 : 28 : gcry_error = gcry_cipher_open (&(cipher->hd),
279 : : GCRY_CIPHER_AES128,
280 : : GCRY_CIPHER_MODE_CBC,
281 : : 0);
282 [ - + ]: 28 : if (gcry_error != GPG_ERR_NO_ERROR)
283 : : {
284 : 0 : pdf_set_error (error,
285 : : PDF_EDOMAIN_BASE_ENCRYPTION,
286 : : PDF_ENOMEM,
287 : : "cannot initialize AESv2 cipher: '%s/%s'",
288 : : gcry_strsource (gcry_error),
289 : : gcry_strerror (gcry_error));
290 : 0 : pdf_dealloc (cipher);
291 : 0 : return NULL;
292 : : }
293 : :
294 : 28 : return (pdf_crypt_cipher_t *)cipher;
295 : : }
296 : :
297 : : /* End of pdf-crypt-c-aesv2.c */
|