2 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 Ben Kibbey <bjk@luxsci.net>
5 This file is part of pwmd.
7 Pwmd is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 2 of the License, or
10 (at your option) any later version.
12 Pwmd is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Pwmd. If not, see <http://www.gnu.org/licenses/>.
28 #include "pwmd-error.h"
34 #include "util-misc.h"
38 #define _(msgid) gettext(msgid)
58 static unsigned char crypto_magic
[5] = "\177PWMD";
60 static void gz_cleanup(void *arg
)
62 struct gz_s
**gz
= (struct gz_s
**)arg
;
67 if (!(*gz
)->done
&& (*gz
)->out
)
68 gcry_free((*gz
)->out
);
71 inflateEnd(&(*gz
)->z
);
77 static void *z_alloc(void *data
, unsigned items
, unsigned size
)
79 return gcry_calloc(items
, size
);
82 static void z_free(void *data
, void *p
)
87 #define ZLIB_BUFSIZE 65536
89 static gpg_error_t
decompress(void * in
, unsigned long insize
, void * *out
,
90 unsigned long *outsize
)
98 gz
= xcalloc(1, sizeof(struct gz_s
));
100 return GPG_ERR_ENOMEM
;
102 gz
->z
.zalloc
= z_alloc
;
103 gz
->z
.zfree
= z_free
;
105 gz
->z
.avail_in
= (uInt
)insize
;
106 gz
->z
.avail_out
= ZLIB_BUFSIZE
;
107 gz
->z
.next_out
= gz
->out
= gcry_malloc(ZLIB_BUFSIZE
);
110 return GPG_ERR_ENOMEM
;
113 zrc
= inflateInit2(&gz
->z
, 47);
116 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
119 memset(&h
, 0, sizeof(gz_header
));
120 h
.comment
= (unsigned char *)buf
;
121 h
.comm_max
= sizeof(buf
);
122 zrc
= inflateGetHeader(&gz
->z
, &h
);
125 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
128 zrc
= inflate(&gz
->z
, Z_BLOCK
);
131 return zrc
== Z_MEM_ERROR
? GPG_ERR_ENOMEM
: GPG_ERR_COMPR_ALGO
;
135 insize
= strtoul((char *)h
.comment
, NULL
, 10);
140 zrc
= inflate(&gz
->z
, Z_FINISH
);
145 if (!gz
->z
.avail_out
) {
146 p
= gcry_realloc(gz
->out
, gz
->z
.total_out
+ ZLIB_BUFSIZE
);
153 gz
->z
.next_out
= (unsigned char *)gz
->out
+ gz
->z
.total_out
;
154 gz
->z
.avail_out
= ZLIB_BUFSIZE
;
157 rc
= GPG_ERR_COMPR_ALGO
;
165 rc
= GPG_ERR_COMPR_ALGO
;
169 } while (zrc
!= Z_STREAM_END
);
172 *outsize
= gz
->z
.total_out
;
182 static gpg_error_t
decrypt(v2_file_header_t
*fh
, unsigned char *key
,
183 unsigned char **ciphertext
, size_t datalen
, void * *result
,
187 size_t blocksize
, keysize
, len
;
188 int algo
= cipher_to_gcrypt(fh
->flags
);
189 gcry_cipher_hd_t gh
= NULL
;
190 uint64_t iter
= 0ULL;
191 unsigned char *data
= *ciphertext
;
196 /* No encryption iterations. This is a plain (gzipped) file. */
201 return GPG_ERR_CIPHER_ALGO
;
203 rc
= gcry_cipher_algo_info(algo
, GCRYCTL_TEST_ALGO
, NULL
, NULL
);
207 rc
= gcry_cipher_algo_info(algo
, GCRYCTL_GET_KEYLEN
, NULL
, &keysize
);
211 rc
= gcry_cipher_algo_info(algo
, GCRYCTL_GET_BLKLEN
, NULL
, &blocksize
);
215 rc
= gcry_cipher_open(&gh
, algo
, GCRY_CIPHER_MODE_CBC
, 0);
219 if ((rc
= gcry_cipher_setiv(gh
, fh
->iv
, blocksize
)))
222 if ((rc
= gcry_cipher_setkey(gh
, key
, keysize
)))
225 rc
= gcry_cipher_decrypt(gh
, data
, datalen
, NULL
, 0);
230 if ((rc
= gcry_cipher_setkey(gh
, key
, keysize
)))
233 while (++iter
< fh
->iter
) {
234 if ((rc
= gcry_cipher_setiv(gh
, fh
->iv
, blocksize
)))
237 rc
= gcry_cipher_decrypt(gh
, data
, datalen
, NULL
, 0);
244 if (fh
->version
>= 0x218 && fh
->iter
> 0ULL) {
245 if (memcmp(data
, crypto_magic
, sizeof(crypto_magic
))) {
246 rc
= GPG_ERR_BAD_PASSPHRASE
;
250 len
= sizeof(crypto_magic
);
253 rc
= decompress(data
+len
, datalen
-len
, result
, (unsigned long *)result_len
);
255 if (fh
->version
< 0x218 && rc
== GPG_ERR_COMPR_ALGO
)
256 rc
= GPG_ERR_BAD_PASSPHRASE
;
260 if (strncasecmp((char *)*result
, "<?xml ", 6) != 0) {
264 rc
= GPG_ERR_BAD_PASSPHRASE
;
270 gcry_cipher_close(gh
);
275 gpg_error_t
read_v2_datafile(const char *filename
, const char *keyfile
,
276 void * *result
, size_t *result_len
, uint16_t *ver
, int *algo
)
281 size_t len
, passphraselen
, datalen
;
282 struct agent_s
*agent
= NULL
;
283 char *passphrase
= NULL
;
284 unsigned char *data
= NULL
;
286 unsigned char *key
= NULL
;
289 if (stat(filename
, &st
) == -1)
290 return gpg_error_from_syserror();
292 fd
= open(filename
, O_RDONLY
);
294 return gpg_error_from_syserror();
296 len
= read(fd
, &fh
, sizeof(fh
)-8);
297 if (len
!= sizeof(fh
)-8) {
298 rc
= GPG_ERR_INV_LENGTH
;
302 if (fh
.version
>= 0x221) {
303 len
= read(fd
, &fh
.salt
, 8);
305 rc
= GPG_ERR_INV_LENGTH
;
311 *algo
= cipher_to_gcrypt(fh
.flags
);
312 rc
= agent_init(&agent
);
316 if (!keyfile
&& fh
.iter
> 0) {
317 char *desc
= plus_escape(_(
318 "A passphrase is required to decrypt the file for converting. "
319 "Please enter the passphrase below."));
321 rc
= set_pinentry_options(agent
);
325 assuan_begin_confidential(agent
->ctx
);
326 rc
= send_to_agent(agent
, &passphrase
, &passphraselen
,
327 "GET_PASSPHRASE --data pwmd:convert + %s %s",
328 _("Passphrase:"), desc
);
329 assuan_end_confidential(agent
->ctx
);
334 passphraselen
--; // null byte
335 send_to_agent(agent
, NULL
, NULL
, "CLEAR_PASSPHRASE pwmd:convert");
336 cleanup_agent(agent
);
341 int pfd
= open(keyfile
, O_RDONLY
);
344 rc
= gpg_error_from_syserror();
348 if (stat(keyfile
, &pst
) == -1) {
349 rc
= gpg_error_from_syserror();
354 passphrase
= xmalloc(pst
.st_size
);
361 passphraselen
= read(pfd
, passphrase
, pst
.st_size
);
363 if (passphraselen
!= pst
.st_size
) {
364 rc
= GPG_ERR_INV_LENGTH
;
369 key
= gcry_malloc(KEYSIZE
);
375 fp
= fdopen(fd
, "r");
376 len
= st
.st_size
- ftell(fp
);
378 if (fh
.version
>= 0x221 && fh
.version
< 0x0300) {
379 rc
= gcry_kdf_derive(passphrase
, passphraselen
, GCRY_KDF_ITERSALTED_S2K
,
380 GCRY_MD_SHA1
, fh
.salt
, 8, 1000, KEYSIZE
, key
);
385 gcry_md_hash_buffer(GCRY_MD_SHA256
, key
, passphrase
, passphraselen
);
387 data
= gcry_malloc(len
);
393 datalen
= read(fd
, data
, len
);
394 if (datalen
!= len
) {
395 rc
= GPG_ERR_INV_LENGTH
;
399 fprintf(stderr
, _("Decrypting ...\n"));
400 rc
= decrypt(&fh
, key
, &data
, datalen
, result
, result_len
);
408 cleanup_agent(agent
);