summaryrefslogtreecommitdiff
path: root/ntfsprogs/ntfsdecrypt.c (plain)
blob: e69daed61c9f20036ae95ff0ac0aae7bf853f6fd
1/**
2 * ntfsdecrypt - Decrypt ntfs encrypted files. Part of the Linux-NTFS project.
3 *
4 * Copyright (c) 2005 Yuval Fledel
5 * Copyright (c) 2005-2007 Anton Altaparmakov
6 * Copyright (c) 2007 Yura Pakhuchiy
7 * Copyright (c) 2014 Jean-Pierre Andre
8 *
9 * This utility will decrypt files and print the decrypted data on the standard
10 * output.
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 2 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 (in the main directory of the Linux-NTFS
24 * distribution in the file COPYING); if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28#include "config.h"
29
30#ifdef HAVE_SYS_TYPES_H
31#include <sys/types.h>
32#endif
33#ifdef HAVE_SYS_STAT_H
34#include <sys/stat.h>
35#endif
36#ifdef HAVE_FCNTL_H
37#include <fcntl.h>
38#endif
39#ifdef HAVE_STDIO_H
40#include <stdio.h>
41#endif
42#ifdef HAVE_GETOPT_H
43#include <getopt.h>
44#endif
45#ifdef HAVE_STDLIB_H
46#include <stdlib.h>
47#endif
48#ifdef HAVE_STRING_H
49#include <string.h>
50#endif
51#ifdef HAVE_UNISTD_H
52#include <unistd.h>
53#endif
54#ifdef HAVE_ERRNO_H
55#include <errno.h>
56#endif
57#include <gcrypt.h>
58#include <gnutls/pkcs12.h>
59
60#include "types.h"
61#include "attrib.h"
62#include "utils.h"
63#include "volume.h"
64#include "debug.h"
65#include "dir.h"
66#include "layout.h"
67/* #include "version.h" */
68
69typedef gcry_sexp_t ntfs_rsa_private_key;
70
71#define NTFS_SHA1_THUMBPRINT_SIZE 0x14
72
73#define NTFS_CRED_TYPE_CERT_THUMBPRINT const_cpu_to_le32(3)
74
75#define NTFS_EFS_CERT_PURPOSE_OID_DDF "1.3.6.1.4.1.311.10.3.4"
76#define NTFS_EFS_CERT_PURPOSE_OID_DRF "1.3.6.1.4.1.311.10.3.4.1"
77
78typedef enum {
79 DF_TYPE_UNKNOWN,
80 DF_TYPE_DDF,
81 DF_TYPE_DRF,
82} NTFS_DF_TYPES;
83
84/**
85 * enum NTFS_CRYPTO_ALGORITHMS - List of crypto algorithms used by EFS (32 bit)
86 *
87 * To choose which one is used in Windows, create or set the REG_DWORD registry
88 * key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EFS\
89 * AlgorithmID to the value of your chosen crypto algorithm, e.g. to use DesX,
90 * set AlgorithmID to 0x6604.
91 *
92 * Note that the Windows versions I have tried so far (all are high crypto
93 * enabled) ignore the AlgorithmID value if it is not one of CALG_3DES,
94 * CALG_DESX, or CALG_AES_256, i.e. you cannot select CALG_DES at all using
95 * this registry key. It would be interesting to check out encryption on one
96 * of the "crippled" crypto Windows versions...
97 */
98typedef enum {
99 CALG_DES = const_cpu_to_le32(0x6601),
100 /* If not one of the below three, fall back to standard Des. */
101 CALG_3DES = const_cpu_to_le32(0x6603),
102 CALG_DESX = const_cpu_to_le32(0x6604),
103 CALG_AES_256 = const_cpu_to_le32(0x6610),
104} NTFS_CRYPTO_ALGORITHMS;
105
106typedef struct {
107 u64 in_whitening, out_whitening;
108 u8 des_key[8];
109} ntfs_desx_ctx;
110
111/**
112 * struct ntfs_fek - Decrypted, in-memory file encryption key.
113 */
114
115typedef struct {
116 gcry_cipher_hd_t gcry_cipher_hd;
117 le32 alg_id;
118 u8 *key_data;
119 gcry_cipher_hd_t *des_gcry_cipher_hd_ptr;
120 ntfs_desx_ctx desx_ctx;
121} ntfs_fek;
122
123struct options {
124 char *keyfile; /* .pfx file containing the user's private key. */
125 char *device; /* Device/File to work with */
126 char *file; /* File to display */
127 s64 inode; /* Inode to work with */
128 ATTR_TYPES attr; /* Attribute type to display */
129 int force; /* Override common sense */
130 int quiet; /* Less output */
131 int verbose; /* Extra output */
132};
133
134static const char *EXEC_NAME = "ntfsdecrypt";
135static struct options opts;
136
137static ntfschar EFS[5] = {
138 const_cpu_to_le16('$'), const_cpu_to_le16('E'), const_cpu_to_le16('F'),
139 const_cpu_to_le16('S'), const_cpu_to_le16('\0')
140};
141
142/**
143 * version - Print version information about the program
144 *
145 * Print a copyright statement and a brief description of the program.
146 *
147 * Return: none
148 */
149static void version(void)
150{
151 ntfs_log_info("\n%s v%s (libntfs-3g) - Decrypt files and print on the "
152 "standard output.\n\n", EXEC_NAME, VERSION);
153 ntfs_log_info("Copyright (c) 2005 Yuval Fledel\n");
154 ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n");
155 ntfs_log_info("Copyright (c) 2014 Jean-Pierre Andre\n");
156 ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
157}
158
159/**
160 * usage - Print a list of the parameters to the program
161 *
162 * Print a list of the parameters and options for the program.
163 *
164 * Return: none
165 */
166static void usage(void)
167{
168 ntfs_log_info("\nUsage: %s [options] -k name.pfx device [file]\n\n"
169 " -i, --inode num Display this inode\n\n"
170 " -k --keyfile name.pfx Use file name as the user's private key file.\n"
171 " -f --force Use less caution\n"
172 " -h --help Print this help\n"
173 " -q --quiet Less output\n"
174 " -V --version Version information\n"
175 " -v --verbose More output\n\n",
176 EXEC_NAME);
177 ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
178}
179
180/**
181 * parse_options - Read and validate the programs command line
182 *
183 * Read the command line, verify the syntax and parse the options.
184 * This function is very long, but quite simple.
185 *
186 * Return: 1 Success
187 * 0 Error, one or more problems
188 */
189static int parse_options(int argc, char **argv)
190{
191 static const char *sopt = "-fh?i:k:qVv";
192 static const struct option lopt[] = {
193 {"force", no_argument, NULL, 'f'},
194 {"help", no_argument, NULL, 'h'},
195 {"inode", required_argument, NULL, 'i'},
196 {"keyfile", required_argument, NULL, 'k'},
197 {"quiet", no_argument, NULL, 'q'},
198 {"version", no_argument, NULL, 'V'},
199 {"verbose", no_argument, NULL, 'v'},
200 {NULL, 0, NULL, 0}
201 };
202
203 int c = -1;
204 int err = 0;
205 int ver = 0;
206 int help = 0;
207
208 opterr = 0; /* We'll handle the errors, thank you. */
209
210 opts.inode = -1;
211
212 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
213 switch (c) {
214 case 1: /* A non-option argument */
215 if (!opts.device)
216 opts.device = argv[optind - 1];
217 else if (!opts.file)
218 opts.file = argv[optind - 1];
219 else {
220 ntfs_log_error("You must specify exactly one "
221 "file.\n");
222 err++;
223 }
224 break;
225 case 'f':
226 opts.force++;
227 break;
228 case 'h':
229 case '?':
230 help++;
231 break;
232 case 'k':
233 if (!opts.keyfile)
234 opts.keyfile = argv[optind - 1];
235 else {
236 ntfs_log_error("You must specify exactly one "
237 "key file.\n");
238 err++;
239 }
240 break;
241 case 'i':
242 if (opts.inode != -1)
243 ntfs_log_error("You must specify exactly one "
244 "inode.\n");
245 else if (utils_parse_size(optarg, &opts.inode, FALSE))
246 break;
247 else
248 ntfs_log_error("Couldn't parse inode number.\n");
249 err++;
250 break;
251 case 'q':
252 opts.quiet++;
253 ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET);
254 break;
255 case 'V':
256 ver++;
257 break;
258 case 'v':
259 opts.verbose++;
260 ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE);
261 break;
262 default:
263 ntfs_log_error("Unknown option '%s'.\n",
264 argv[optind - 1]);
265 err++;
266 break;
267 }
268 }
269
270 if (help || ver) {
271 opts.quiet = 0;
272 ntfs_log_set_levels(NTFS_LOG_LEVEL_QUIET);
273 } else {
274 if (!opts.keyfile) {
275 ntfs_log_error("You must specify a key file.\n");
276 err++;
277 } else if (opts.device == NULL) {
278 ntfs_log_error("You must specify a device.\n");
279 err++;
280 } else if (opts.file == NULL && opts.inode == -1) {
281 ntfs_log_error("You must specify a file or inode with "
282 "the -i option.\n");
283 err++;
284 } else if (opts.file != NULL && opts.inode != -1) {
285 ntfs_log_error("You can't specify both a file and "
286 "inode.\n");
287 err++;
288 }
289 if (opts.quiet && opts.verbose) {
290 ntfs_log_error("You may not use --quiet and --verbose "
291 "at the same time.\n");
292 err++;
293 }
294 }
295
296 if (ver)
297 version();
298 if (help || err)
299 usage();
300
301 return (!err && !help && !ver);
302}
303
304/**
305 * ntfs_pkcs12_load_pfxfile
306 */
307static int ntfs_pkcs12_load_pfxfile(const char *keyfile, u8 **pfx,
308 unsigned *pfx_size)
309{
310 int f, to_read, total, attempts, br;
311 struct stat key_stat;
312
313 if (!keyfile || !pfx || !pfx_size) {
314 ntfs_log_error("You have to specify the key file, a pointer "
315 "to hold the key file contents, and a pointer "
316 "to hold the size of the key file contents.\n");
317 return -1;
318 }
319 f = open(keyfile, O_RDONLY);
320 if (f == -1) {
321 ntfs_log_perror("Failed to open key file");
322 return -1;
323 }
324 if (fstat(f, &key_stat) == -1) {
325 ntfs_log_perror("Failed to stat key file");
326 goto file_out;
327 }
328 if (!S_ISREG(key_stat.st_mode)) {
329 ntfs_log_error("Key file is not a regular file, cannot read "
330 "it.\n");
331 goto file_out;
332 }
333 if (!key_stat.st_size) {
334 ntfs_log_error("Key file has zero size.\n");
335 goto file_out;
336 }
337 *pfx = malloc(key_stat.st_size + 1);
338 if (!*pfx) {
339 ntfs_log_perror("Failed to allocate buffer for key file "
340 "contents");
341 goto file_out;
342 }
343 to_read = key_stat.st_size;
344 total = attempts = 0;
345 do {
346 br = read(f, *pfx + total, to_read);
347 if (br == -1) {
348 ntfs_log_perror("Failed to read from key file");
349 goto free_out;
350 }
351 if (!br)
352 attempts++;
353 to_read -= br;
354 total += br;
355 } while (to_read > 0 && attempts < 3);
356 close(f);
357 /* Make sure it is zero terminated. */
358 (*pfx)[key_stat.st_size] = 0;
359 *pfx_size = key_stat.st_size;
360 return 0;
361free_out:
362 free(*pfx);
363file_out:
364 close(f);
365 return -1;
366}
367
368/**
369 * ntfs_crypto_init
370 */
371static int ntfs_crypto_init(void)
372{
373 int err;
374
375 /* Initialize gcrypt library. Note: Must come before GNU TLS init. */
376 if (gcry_control(GCRYCTL_DISABLE_SECMEM, 0) != GPG_ERR_NO_ERROR) {
377 ntfs_log_error("Failed to initialize the gcrypt library.\n");
378 return -1;
379 }
380 /* Initialize GNU TLS library. Note: Must come after libgcrypt init. */
381 err = gnutls_global_init();
382 if (err < 0) {
383 ntfs_log_error("Failed to initialize GNU TLS library: %s\n",
384 gnutls_strerror(err));
385 return -1;
386 }
387 return 0;
388}
389
390/**
391 * ntfs_crypto_deinit
392 */
393static void ntfs_crypto_deinit(void)
394{
395 gnutls_global_deinit();
396}
397
398/**
399 * ntfs_rsa_private_key_import_from_gnutls
400 */
401static ntfs_rsa_private_key ntfs_rsa_private_key_import_from_gnutls(
402 gnutls_x509_privkey_t priv_key)
403{
404 int i, j;
405 size_t tmp_size;
406 gnutls_datum_t rd[6];
407 gcry_mpi_t rm[6];
408 gcry_sexp_t rsa_key;
409
410 /* Extract the RSA parameters from the GNU TLS private key. */
411 if (gnutls_x509_privkey_export_rsa_raw(priv_key, &rd[0], &rd[1],
412 &rd[2], &rd[3], &rd[4], &rd[5])) {
413 ntfs_log_error("Failed to export rsa parameters. (Is the "
414 "key an RSA private key?)\n");
415 return NULL;
416 }
417 /* Convert each RSA parameter to mpi format. */
418 for (i = 0; i < 6; i++) {
419 if (gcry_mpi_scan(&rm[i], GCRYMPI_FMT_USG, rd[i].data,
420 rd[i].size, &tmp_size) != GPG_ERR_NO_ERROR) {
421 ntfs_log_error("Failed to convert RSA parameter %i "
422 "to mpi format (size %d)\n", i,
423 rd[i].size);
424 rsa_key = NULL;
425 break;
426 }
427 }
428 /* Release the no longer needed datum values. */
429 for (j = 0; j < 6; j++) {
430 if (rd[j].data && rd[j].size)
431 gnutls_free(rd[j].data);
432 }
433 /*
434 * Build the gcrypt private key, note libgcrypt uses p and q inversed
435 * to what gnutls uses.
436 */
437 if (i == 6 && gcry_sexp_build(&rsa_key, NULL,
438 "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
439 rm[0], rm[1], rm[2], rm[4], rm[3], rm[5]) !=
440 GPG_ERR_NO_ERROR) {
441 ntfs_log_error("Failed to build RSA private key s-exp.\n");
442 rsa_key = NULL;
443 }
444 /* Release the no longer needed mpi values. */
445 for (j = 0; j < i; j++)
446 gcry_mpi_release(rm[j]);
447 return (ntfs_rsa_private_key)rsa_key;
448}
449
450/**
451 * ntfs_rsa_private_key_release
452 */
453static void ntfs_rsa_private_key_release(ntfs_rsa_private_key rsa_key)
454{
455 gcry_sexp_release((gcry_sexp_t)rsa_key);
456}
457
458/**
459 * ntfs_pkcs12_extract_rsa_key
460 */
461static ntfs_rsa_private_key ntfs_pkcs12_extract_rsa_key(u8 *pfx, int pfx_size,
462 char *password, char *thumbprint, int thumbprint_size,
463 NTFS_DF_TYPES *df_type)
464{
465 int err, bag_index, flags;
466 gnutls_datum_t dpfx, dkey;
467 gnutls_pkcs12_t pkcs12 = NULL;
468 gnutls_pkcs12_bag_t bag = NULL;
469 gnutls_x509_privkey_t pkey = NULL;
470 gnutls_x509_crt_t crt = NULL;
471 ntfs_rsa_private_key rsa_key = NULL;
472 char purpose_oid[100];
473 size_t purpose_oid_size = sizeof(purpose_oid);
474 size_t tp_size = thumbprint_size;
475 BOOL have_thumbprint = FALSE;
476
477 *df_type = DF_TYPE_UNKNOWN;
478 /* Create a pkcs12 structure. */
479 err = gnutls_pkcs12_init(&pkcs12);
480 if (err) {
481 ntfs_log_error("Failed to initialize PKCS#12 structure: %s\n",
482 gnutls_strerror(err));
483 return NULL;
484 }
485 /* Convert the PFX file (DER format) to native pkcs12 format. */
486 dpfx.data = pfx;
487 dpfx.size = pfx_size;
488 err = gnutls_pkcs12_import(pkcs12, &dpfx, GNUTLS_X509_FMT_DER, 0);
489 if (err) {
490 ntfs_log_error("Failed to convert the PFX file from DER to "
491 "native PKCS#12 format: %s\n",
492 gnutls_strerror(err));
493 goto err;
494 }
495 /*
496 * Verify that the password is correct and that the key file has not
497 * been tampered with. Note if the password has zero length and the
498 * verification fails, retry with password set to NULL. This is needed
499 * to get passwordless .pfx files generated with Windows XP SP1 (and
500 * probably earlier versions of Windows) to work.
501 */
502retry_verify:
503 err = gnutls_pkcs12_verify_mac(pkcs12, password);
504 if (err) {
505 if (err == GNUTLS_E_MAC_VERIFY_FAILED &&
506 password && !strlen(password)) {
507 password = NULL;
508 goto retry_verify;
509 }
510 ntfs_log_error("Failed to verify the MAC: %s Is the "
511 "password correct?\n", gnutls_strerror(err));
512 goto err;
513 }
514 for (bag_index = 0; ; bag_index++) {
515 err = gnutls_pkcs12_bag_init(&bag);
516 if (err) {
517 ntfs_log_error("Failed to initialize PKCS#12 Bag "
518 "structure: %s\n",
519 gnutls_strerror(err));
520 goto err;
521 }
522 err = gnutls_pkcs12_get_bag(pkcs12, bag_index, bag);
523 if (err) {
524 if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
525 err = 0;
526 break;
527 }
528 ntfs_log_error("Failed to obtain Bag from PKCS#12 "
529 "structure: %s\n",
530 gnutls_strerror(err));
531 goto err;
532 }
533check_again:
534 err = gnutls_pkcs12_bag_get_count(bag);
535 if (err < 0) {
536 ntfs_log_error("Failed to obtain Bag count: %s\n",
537 gnutls_strerror(err));
538 goto err;
539 }
540 err = gnutls_pkcs12_bag_get_type(bag, 0);
541 if (err < 0) {
542 ntfs_log_error("Failed to determine Bag type: %s\n",
543 gnutls_strerror(err));
544 goto err;
545 }
546 flags = 0;
547 switch (err) {
548 case GNUTLS_BAG_PKCS8_KEY:
549 flags = GNUTLS_PKCS_PLAIN;
550 case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
551 err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey);
552 if (err < 0) {
553 ntfs_log_error("Failed to obtain Bag data: "
554 "%s\n", gnutls_strerror(err));
555 goto err;
556 }
557 err = gnutls_x509_privkey_init(&pkey);
558 if (err) {
559 ntfs_log_error("Failed to initialized "
560 "private key structure: %s\n",
561 gnutls_strerror(err));
562 goto err;
563 }
564 /* Decrypt the private key into GNU TLS format. */
565 err = gnutls_x509_privkey_import_pkcs8(pkey, &dkey,
566 GNUTLS_X509_FMT_DER, password, flags);
567 if (err) {
568 ntfs_log_error("Failed to convert private "
569 "key from DER to GNU TLS "
570 "format: %s\n",
571 gnutls_strerror(err));
572 goto err;
573 }
574#if 0
575 /*
576 * Export the key again, but unencrypted, and output it
577 * to stderr. Note the output has an RSA header so to
578 * compare to openssl pkcs12 -nodes -in myfile.pfx
579 * output need to ignore the part of the key between
580 * the first "MII..." up to the second "MII...". The
581 * actual RSA private key begins at the second "MII..."
582 * and in my testing at least was identical to openssl
583 * output and was also identical both on big and little
584 * endian so gnutls should be endianness safe.
585 */
586 char *buf = malloc(8192);
587 size_t bufsize = 8192;
588 err = gnutls_x509_privkey_export_pkcs8(pkey,
589 GNUTLS_X509_FMT_PEM, "", GNUTLS_PKCS_PLAIN, buf,
590 &bufsize);
591 if (err) {
592 ntfs_log_error("eek1\n");
593 exit(1);
594 }
595 ntfs_log_error("%s\n", buf);
596 free(buf);
597#endif
598 /* Convert the private key to our internal format. */
599 rsa_key = ntfs_rsa_private_key_import_from_gnutls(pkey);
600 if (!rsa_key)
601 goto err;
602 break;
603 case GNUTLS_BAG_ENCRYPTED:
604 err = gnutls_pkcs12_bag_decrypt(bag, password);
605 if (err) {
606 ntfs_log_error("Failed to decrypt Bag: %s\n",
607 gnutls_strerror(err));
608 goto err;
609 }
610 goto check_again;
611 case GNUTLS_BAG_CERTIFICATE:
612 err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey);
613 if (err < 0) {
614 ntfs_log_error("Failed to obtain Bag data: "
615 "%s\n", gnutls_strerror(err));
616 goto err;
617 }
618 err = gnutls_x509_crt_init(&crt);
619 if (err) {
620 ntfs_log_error("Failed to initialize "
621 "certificate structure: %s\n",
622 gnutls_strerror(err));
623 goto err;
624 }
625 err = gnutls_x509_crt_import(crt, &dkey,
626 GNUTLS_X509_FMT_DER);
627 if (err) {
628 ntfs_log_error("Failed to convert certificate "
629 "from DER to GNU TLS format: "
630 "%s\n", gnutls_strerror(err));
631 goto err;
632 }
633 err = gnutls_x509_crt_get_key_purpose_oid(crt, 0,
634 purpose_oid, &purpose_oid_size, NULL);
635 if (err) {
636 ntfs_log_error("Failed to get key purpose "
637 "OID: %s\n",
638 gnutls_strerror(err));
639 goto err;
640 }
641 purpose_oid[purpose_oid_size - 1] = '\0';
642 if (!strcmp(purpose_oid,
643 NTFS_EFS_CERT_PURPOSE_OID_DRF))
644 *df_type = DF_TYPE_DRF;
645 else if (!strcmp(purpose_oid,
646 NTFS_EFS_CERT_PURPOSE_OID_DDF))
647 *df_type = DF_TYPE_DDF;
648 else {
649 ntfs_log_error("Certificate has unknown "
650 "purpose OID %s.\n",
651 purpose_oid);
652 err = EINVAL;
653 goto err;
654 }
655 /* Return the thumbprint to the caller. */
656 err = gnutls_x509_crt_get_fingerprint(crt,
657 GNUTLS_DIG_SHA1, thumbprint, &tp_size);
658 if (err) {
659 ntfs_log_error("Failed to get thumbprint: "
660 "%s\n", gnutls_strerror(err));
661 goto err;
662 }
663 if (tp_size != NTFS_SHA1_THUMBPRINT_SIZE) {
664 ntfs_log_error("Invalid thumbprint size %zd. "
665 "Should be %d.\n", tp_size,
666 thumbprint_size);
667 err = EINVAL;
668 goto err;
669 }
670 have_thumbprint = TRUE;
671 gnutls_x509_crt_deinit(crt);
672 crt = NULL;
673 break;
674 default:
675 /* We do not care about other types. */
676 break;
677 }
678 gnutls_pkcs12_bag_deinit(bag);
679 }
680err:
681 if (rsa_key && (err || *df_type == DF_TYPE_UNKNOWN ||
682 !have_thumbprint)) {
683 if (!err)
684 ntfs_log_error("Key type or thumbprint not found, "
685 "aborting.\n");
686 ntfs_rsa_private_key_release(rsa_key);
687 rsa_key = NULL;
688 }
689 if (crt)
690 gnutls_x509_crt_deinit(crt);
691 if (pkey)
692 gnutls_x509_privkey_deinit(pkey);
693 if (bag)
694 gnutls_pkcs12_bag_deinit(bag);
695 if (pkcs12)
696 gnutls_pkcs12_deinit(pkcs12);
697 return rsa_key;
698}
699
700/**
701 * ntfs_buffer_reverse -
702 *
703 * This is a utility function for reversing the order of a buffer in place.
704 * Users of this function should be very careful not to sweep byte order
705 * problems under the rug.
706 */
707static inline void ntfs_buffer_reverse(u8 *buf, unsigned buf_size)
708{
709 unsigned i;
710 u8 t;
711
712 for (i = 0; i < buf_size / 2; i++) {
713 t = buf[i];
714 buf[i] = buf[buf_size - i - 1];
715 buf[buf_size - i - 1] = t;
716 }
717}
718
719#ifndef HAVE_STRNLEN
720/**
721 * strnlen - strnlen is a gnu extension so emulate it if not present
722 */
723static size_t strnlen(const char *s, size_t maxlen)
724{
725 const char *p, *end;
726
727 /* Look for a '\0' character. */
728 for (p = s, end = s + maxlen; p < end && *p; p++)
729 ;
730 return p - s;
731}
732#endif /* ! HAVE_STRNLEN */
733
734/**
735 * ntfs_raw_fek_decrypt -
736 *
737 * Note: decrypting into the input buffer.
738 */
739static unsigned ntfs_raw_fek_decrypt(u8 *fek, u32 fek_size,
740 ntfs_rsa_private_key rsa_key)
741{
742 gcry_mpi_t fek_mpi;
743 gcry_sexp_t fek_sexp, fek_sexp2;
744 gcry_error_t err;
745 size_t size, padding;
746
747 /* Reverse the raw FEK. */
748 ntfs_buffer_reverse(fek, fek_size);
749 /* Convert the FEK to internal MPI format. */
750 err = gcry_mpi_scan(&fek_mpi, GCRYMPI_FMT_USG, fek, fek_size, NULL);
751 if (err != GPG_ERR_NO_ERROR) {
752 ntfs_log_error("Failed to convert file encryption key to "
753 "internal MPI format: %s\n",
754 gcry_strerror(err));
755 return 0;
756 }
757 /* Create an internal S-expression from the FEK. */
758 err = gcry_sexp_build(&fek_sexp, NULL,
759 "(enc-val (flags) (rsa (a %m)))", fek_mpi);
760 gcry_mpi_release(fek_mpi);
761 if (err != GPG_ERR_NO_ERROR) {
762 ntfs_log_error("Failed to create internal S-expression of "
763 "the file encryption key: %s\n",
764 gcry_strerror(err));
765 return 0;
766 }
767 /* Decrypt the FEK. */
768 err = gcry_pk_decrypt(&fek_sexp2, fek_sexp, (gcry_sexp_t)rsa_key);
769 gcry_sexp_release(fek_sexp);
770 if (err != GPG_ERR_NO_ERROR) {
771 ntfs_log_error("Failed to decrypt the file encryption key: "
772 "%s\n", gcry_strerror(err));
773 return 0;
774 }
775 /* Extract the actual FEK from the decrypted raw S-expression. */
776 fek_sexp = gcry_sexp_find_token(fek_sexp2, "value", 0);
777 gcry_sexp_release(fek_sexp2);
778 if (!fek_sexp) {
779 ntfs_log_error("Failed to find the decrypted file encryption "
780 "key in the internal S-expression.\n");
781 return 0;
782 }
783 /* Convert the decrypted FEK S-expression into MPI format. */
784 fek_mpi = gcry_sexp_nth_mpi(fek_sexp, 1, GCRYMPI_FMT_USG);
785 gcry_sexp_release(fek_sexp);
786 if (!fek_mpi) {
787 ntfs_log_error("Failed to convert the decrypted file "
788 "encryption key S-expression to internal MPI "
789 "format.\n");
790 return 0;
791 }
792 /* Convert the decrypted FEK from MPI format to binary data. */
793 err = gcry_mpi_print(GCRYMPI_FMT_USG, fek, fek_size, &size, fek_mpi);
794 gcry_mpi_release(fek_mpi);
795 if (err != GPG_ERR_NO_ERROR || !size) {
796 ntfs_log_error("Failed to convert decrypted file encryption "
797 "key from internal MPI format to binary data: "
798 "%s\n", gcry_strerror(err));
799 return 0;
800 }
801 /*
802 * Finally, remove the PKCS#1 padding and return the size of the
803 * decrypted FEK.
804 */
805 padding = strnlen((char *)fek, size) + 1;
806 if (padding > size) {
807 ntfs_log_error("Failed to remove PKCS#1 padding from "
808 "decrypted file encryption key.\n");
809 return 0;
810 }
811 size -= padding;
812 memmove(fek, fek + padding, size);
813 return size;
814}
815
816/**
817 * ntfs_desx_key_expand - expand a 128-bit desx key to the needed 192-bit key
818 * @src: source buffer containing 128-bit key
819 *
820 * Expands the on-disk 128-bit desx key to the needed des key, the in-, and the
821 * out-whitening keys required to perform desx {de,en}cryption.
822 */
823static gcry_error_t ntfs_desx_key_expand(const u8 *src, u32 *des_key,
824 u64 *out_whitening, u64 *in_whitening)
825{
826 static const u8 *salt1 = (const u8*)"Dan Simon ";
827 static const u8 *salt2 = (const u8*)"Scott Field";
828 static const int salt_len = 12;
829 gcry_md_hd_t hd1, hd2;
830 u32 *md;
831 gcry_error_t err;
832
833 err = gcry_md_open(&hd1, GCRY_MD_MD5, 0);
834 if (err != GPG_ERR_NO_ERROR) {
835 ntfs_log_error("Failed to open MD5 digest.\n");
836 return err;
837 }
838 /* Hash the on-disk key. */
839 gcry_md_write(hd1, src, 128 / 8);
840 /* Copy the current hash for efficiency. */
841 err = gcry_md_copy(&hd2, hd1);
842 if (err != GPG_ERR_NO_ERROR) {
843 ntfs_log_error("Failed to copy MD5 digest object.\n");
844 goto out;
845 }
846 /* Hash with the first salt and store the result. */
847 gcry_md_write(hd1, salt1, salt_len);
848 md = (u32*)gcry_md_read(hd1, 0);
849 des_key[0] = md[0] ^ md[1];
850 des_key[1] = md[2] ^ md[3];
851 /* Hash with the second salt and store the result. */
852 gcry_md_write(hd2, salt2, salt_len);
853 md = (u32*)gcry_md_read(hd2, 0);
854 *out_whitening = *(u64*)md;
855 *in_whitening = *(u64*)(md + 2);
856 gcry_md_close(hd2);
857out:
858 gcry_md_close(hd1);
859 return err;
860}
861
862/**
863 * ntfs_desx_decrypt
864 */
865static void ntfs_desx_decrypt(ntfs_fek *fek, u8 *outbuf, const u8 *inbuf)
866{
867 gcry_error_t err;
868 ntfs_desx_ctx *ctx = &fek->desx_ctx;
869
870 err = gcry_cipher_reset(fek->gcry_cipher_hd);
871 if (err != GPG_ERR_NO_ERROR)
872 ntfs_log_error("Failed to reset des cipher (error 0x%x).\n",
873 err);
874 *(u64*)outbuf = *(const u64*)inbuf ^ ctx->out_whitening;
875 err = gcry_cipher_encrypt(fek->gcry_cipher_hd, outbuf, 8, NULL, 0);
876 if (err != GPG_ERR_NO_ERROR)
877 ntfs_log_error("Des decryption failed (error 0x%x).\n", err);
878 *(u64*)outbuf ^= ctx->in_whitening;
879}
880
881//#define DO_CRYPTO_TESTS 1
882
883#ifdef DO_CRYPTO_TESTS
884
885/* Do not remove this test code from this file! AIA */
886/**
887 * ntfs_desx_key_expand_test
888 */
889static BOOL ntfs_desx_key_expand_test(void)
890{
891 const u8 known_desx_on_disk_key[16] = {
892 0xa1, 0xf9, 0xe0, 0xb2, 0x53, 0x23, 0x9e, 0x8f,
893 0x0f, 0x91, 0x45, 0xd9, 0x8e, 0x20, 0xec, 0x30
894 };
895 const u8 known_des_key[8] = {
896 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f,
897 };
898 const u8 known_out_whitening[8] = {
899 0xed, 0xda, 0x4c, 0x47, 0x60, 0x49, 0xdb, 0x8d,
900 };
901 const u8 known_in_whitening[8] = {
902 0x75, 0xf6, 0xa0, 0x1a, 0xc0, 0xca, 0x28, 0x1e
903 };
904 u64 test_out_whitening, test_in_whitening;
905 union {
906 u64 u64;
907 u32 u32[2];
908 } test_des_key;
909 gcry_error_t err;
910 BOOL res;
911
912 err = ntfs_desx_key_expand(known_desx_on_disk_key, test_des_key.u32,
913 &test_out_whitening, &test_in_whitening);
914 if (err != GPG_ERR_NO_ERROR)
915 res = FALSE;
916 else
917 res = test_des_key.u64 == *(u64*)known_des_key &&
918 test_out_whitening ==
919 *(u64*)known_out_whitening &&
920 test_in_whitening ==
921 *(u64*)known_in_whitening;
922 ntfs_log_error("Testing whether ntfs_desx_key_expand() works: %s\n",
923 res ? "SUCCESS" : "FAILED");
924 return res;
925}
926
927/**
928 * ntfs_des_test
929 */
930static BOOL ntfs_des_test(void)
931{
932 const u8 known_des_key[8] = {
933 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f
934 };
935 const u8 known_des_encrypted_data[8] = {
936 0xdc, 0xf7, 0x68, 0x2a, 0xaf, 0x48, 0x53, 0x0f
937 };
938 const u8 known_decrypted_data[8] = {
939 0xd8, 0xd9, 0x15, 0x23, 0x5b, 0x88, 0x0e, 0x09
940 };
941 u8 test_decrypted_data[8];
942 int res;
943 gcry_error_t err;
944 gcry_cipher_hd_t gcry_cipher_hd;
945
946 err = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_DES,
947 GCRY_CIPHER_MODE_ECB, 0);
948 if (err != GPG_ERR_NO_ERROR) {
949 ntfs_log_error("Failed to open des cipher (error 0x%x).\n",
950 err);
951 return FALSE;
952 }
953 err = gcry_cipher_setkey(gcry_cipher_hd, known_des_key,
954 sizeof(known_des_key));
955 if (err != GPG_ERR_NO_ERROR) {
956 ntfs_log_error("Failed to set des key (error 0x%x.\n", err);
957 gcry_cipher_close(gcry_cipher_hd);
958 return FALSE;
959 }
960 /*
961 * Apply DES decryption (ntfs actually uses encryption when decrypting).
962 */
963 err = gcry_cipher_encrypt(gcry_cipher_hd, test_decrypted_data,
964 sizeof(test_decrypted_data), known_des_encrypted_data,
965 sizeof(known_des_encrypted_data));
966 gcry_cipher_close(gcry_cipher_hd);
967 if (err) {
968 ntfs_log_error("Failed to des decrypt test data (error "
969 "0x%x).\n", err);
970 return FALSE;
971 }
972 res = !memcmp(test_decrypted_data, known_decrypted_data,
973 sizeof(known_decrypted_data));
974 ntfs_log_error("Testing whether des decryption works: %s\n",
975 res ? "SUCCESS" : "FAILED");
976 return res;
977}
978
979#else /* !defined(DO_CRYPTO_TESTS) */
980
981/**
982 * ntfs_desx_key_expand_test
983 */
984static inline BOOL ntfs_desx_key_expand_test(void)
985{
986 return TRUE;
987}
988
989/**
990 * ntfs_des_test
991 */
992static inline BOOL ntfs_des_test(void)
993{
994 return TRUE;
995}
996
997#endif /* !defined(DO_CRYPTO_TESTS) */
998
999/**
1000 * ntfs_fek_import_from_raw
1001 */
1002static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf, unsigned fek_size)
1003{
1004 ntfs_fek *fek;
1005 u32 key_size, wanted_key_size, gcry_algo;
1006 int gcry_mode;
1007 gcry_error_t err;
1008 ntfs_desx_ctx *ctx;
1009
1010 key_size = le32_to_cpup(fek_buf);
1011 ntfs_log_debug("key_size 0x%x\n", key_size);
1012 if (key_size + 16 > fek_size) {
1013 ntfs_log_debug("Invalid FEK. It was probably decrypted with "
1014 "the incorrect RSA key.");
1015 errno = EINVAL;
1016 return NULL;
1017 }
1018 fek = malloc(((((sizeof(*fek) + 7) & ~7) + key_size + 7) & ~7) +
1019 sizeof(gcry_cipher_hd_t));
1020 if (!fek) {
1021 errno = ENOMEM;
1022 return NULL;
1023 }
1024 ctx = &fek->desx_ctx;
1025 fek->alg_id = *(le32*)(fek_buf + 8);
1026 //ntfs_log_debug("alg_id 0x%x\n", le32_to_cpu(fek->alg_id));
1027 fek->key_data = (u8*)fek + ((sizeof(*fek) + 7) & ~7);
1028 memcpy(fek->key_data, fek_buf + 16, key_size);
1029 fek->des_gcry_cipher_hd_ptr = NULL;
1030 *(gcry_cipher_hd_t***)(fek->key_data + ((key_size + 7) & ~7)) =
1031 &fek->des_gcry_cipher_hd_ptr;
1032 switch (fek->alg_id) {
1033 case CALG_DESX:
1034 wanted_key_size = 16;
1035 gcry_algo = GCRY_CIPHER_DES;
1036 gcry_mode = GCRY_CIPHER_MODE_ECB;
1037 break;
1038 case CALG_3DES:
1039 wanted_key_size = 24;
1040 gcry_algo = GCRY_CIPHER_3DES;
1041 gcry_mode = GCRY_CIPHER_MODE_CBC;
1042 break;
1043 case CALG_AES_256:
1044 wanted_key_size = 32;
1045 gcry_algo = GCRY_CIPHER_AES256;
1046 gcry_mode = GCRY_CIPHER_MODE_CBC;
1047 break;
1048 default:
1049 wanted_key_size = 8;
1050 gcry_algo = GCRY_CIPHER_DES;
1051 gcry_mode = GCRY_CIPHER_MODE_CBC;
1052 if (fek->alg_id == CALG_DES)
1053 ntfs_log_error("DES is not supported at present\n");
1054 else
1055 ntfs_log_error("Unknown crypto algorithm 0x%x\n",
1056 le32_to_cpu(fek->alg_id));
1057 ntfs_log_error(". Please email %s and say that you saw this "
1058 "message. We will then try to implement "
1059 "support for this algorithm.\n", NTFS_DEV_LIST);
1060 err = EOPNOTSUPP;
1061 goto out;
1062 }
1063 if (key_size != wanted_key_size) {
1064 ntfs_log_error("%s key of %u bytes but needed size is %u "
1065 "bytes, assuming corrupt or incorrect key. "
1066 "Aborting.\n",
1067 gcry_cipher_algo_name(gcry_algo),
1068 (unsigned)key_size, (unsigned)wanted_key_size);
1069 err = EIO;
1070 goto out;
1071 }
1072 err = gcry_cipher_open(&fek->gcry_cipher_hd, gcry_algo,
1073 gcry_mode, 0);
1074
1075 if (err != GPG_ERR_NO_ERROR) {
1076 ntfs_log_error("gcry_cipher_open() failed: %s\n",
1077 gcry_strerror(err));
1078 err = EINVAL;
1079 goto out;
1080 }
1081 if (fek->alg_id == CALG_DESX) {
1082 err = ntfs_desx_key_expand(fek->key_data, (u32*)ctx->des_key,
1083 &ctx->out_whitening, &ctx->in_whitening);
1084 if (err == GPG_ERR_NO_ERROR)
1085 err = gcry_cipher_setkey(fek->gcry_cipher_hd,
1086 ctx->des_key, 8);
1087 } else {
1088 err = gcry_cipher_setkey(fek->gcry_cipher_hd, fek->key_data,
1089 key_size);
1090 }
1091 if (err != GPG_ERR_NO_ERROR) {
1092 ntfs_log_error("gcry_cipher_setkey() failed: %s\n",
1093 gcry_strerror(err));
1094 gcry_cipher_close(fek->gcry_cipher_hd);
1095 err = EINVAL;
1096 goto out;
1097 }
1098 return fek;
1099out:
1100 free(fek);
1101 errno = err;
1102 return NULL;
1103}
1104
1105/**
1106 * ntfs_fek_release
1107 */
1108static void ntfs_fek_release(ntfs_fek *fek)
1109{
1110 if (fek->des_gcry_cipher_hd_ptr)
1111 gcry_cipher_close(*fek->des_gcry_cipher_hd_ptr);
1112 gcry_cipher_close(fek->gcry_cipher_hd);
1113 free(fek);
1114}
1115
1116/**
1117 * ntfs_df_array_fek_get
1118 */
1119static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array,
1120 ntfs_rsa_private_key rsa_key, char *thumbprint,
1121 int thumbprint_size)
1122{
1123 EFS_DF_HEADER *df_header;
1124 EFS_DF_CREDENTIAL_HEADER *df_cred;
1125 EFS_DF_CERT_THUMBPRINT_HEADER *df_cert;
1126 u8 *fek_buf;
1127 ntfs_fek *fek;
1128 u32 df_count, fek_size;
1129 unsigned i;
1130
1131 df_count = le32_to_cpu(df_array->df_count);
1132 if (!df_count)
1133 ntfs_log_error("There are no elements in the DF array.\n");
1134 df_header = (EFS_DF_HEADER*)(df_array + 1);
1135 for (i = 0; i < df_count; i++, df_header = (EFS_DF_HEADER*)(
1136 (u8*)df_header + le32_to_cpu(df_header->df_length))) {
1137 df_cred = (EFS_DF_CREDENTIAL_HEADER*)((u8*)df_header +
1138 le32_to_cpu(df_header->cred_header_offset));
1139 if (df_cred->type != NTFS_CRED_TYPE_CERT_THUMBPRINT) {
1140 ntfs_log_debug("Credential type is not certificate "
1141 "thumbprint, skipping DF entry.\n");
1142 continue;
1143 }
1144 df_cert = (EFS_DF_CERT_THUMBPRINT_HEADER*)((u8*)df_cred +
1145 le32_to_cpu(
1146 df_cred->cert_thumbprint_header_offset));
1147 if ((int)le32_to_cpu(df_cert->thumbprint_size)
1148 != thumbprint_size) {
1149 ntfs_log_error("Thumbprint size %d is not valid "
1150 "(should be %d), skipping this DF "
1151 "entry.\n",
1152 le32_to_cpu(df_cert->thumbprint_size),
1153 thumbprint_size);
1154 continue;
1155 }
1156 if (memcmp((u8*)df_cert +
1157 le32_to_cpu(df_cert->thumbprint_offset),
1158 thumbprint, thumbprint_size)) {
1159 ntfs_log_debug("Thumbprints do not match, skipping "
1160 "this DF entry.\n");
1161 continue;
1162 }
1163 /*
1164 * The thumbprints match so this is probably the DF entry
1165 * matching the RSA key. Try to decrypt the FEK with it.
1166 */
1167 fek_size = le32_to_cpu(df_header->fek_size);
1168 fek_buf = (u8*)df_header + le32_to_cpu(df_header->fek_offset);
1169 /* Decrypt the FEK. Note: This is done in place. */
1170 fek_size = ntfs_raw_fek_decrypt(fek_buf, fek_size, rsa_key);
1171 if (fek_size) {
1172 /* Convert the FEK to our internal format. */
1173 fek = ntfs_fek_import_from_raw(fek_buf, fek_size);
1174 if (fek)
1175 return fek;
1176 ntfs_log_error("Failed to convert the decrypted file "
1177 "encryption key to internal format.\n");
1178 } else
1179 ntfs_log_error("Failed to decrypt the file "
1180 "encryption key.\n");
1181 }
1182 return NULL;
1183}
1184
1185/**
1186 * ntfs_inode_fek_get -
1187 */
1188static ntfs_fek *ntfs_inode_fek_get(ntfs_inode *inode,
1189 ntfs_rsa_private_key rsa_key, char *thumbprint,
1190 int thumbprint_size, NTFS_DF_TYPES df_type)
1191{
1192 EFS_ATTR_HEADER *efs;
1193 EFS_DF_ARRAY_HEADER *df_array = NULL;
1194 ntfs_fek *fek = NULL;
1195
1196 /* Obtain the $EFS contents. */
1197 efs = ntfs_attr_readall(inode, AT_LOGGED_UTILITY_STREAM, EFS, 4, NULL);
1198 if (!efs) {
1199 ntfs_log_perror("Failed to read $EFS attribute");
1200 return NULL;
1201 }
1202 /*
1203 * Depending on whether the key is a normal key or a data recovery key,
1204 * iterate through the DDF or DRF array, respectively.
1205 */
1206 if (df_type == DF_TYPE_DDF) {
1207 if (efs->offset_to_ddf_array)
1208 df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs +
1209 le32_to_cpu(efs->offset_to_ddf_array));
1210 else
1211 ntfs_log_error("There are no entries in the DDF "
1212 "array.\n");
1213 } else if (df_type == DF_TYPE_DRF) {
1214 if (efs->offset_to_drf_array)
1215 df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs +
1216 le32_to_cpu(efs->offset_to_drf_array));
1217 else
1218 ntfs_log_error("There are no entries in the DRF "
1219 "array.\n");
1220 } else
1221 ntfs_log_error("Invalid DF type.\n");
1222 if (df_array)
1223 fek = ntfs_df_array_fek_get(df_array, rsa_key, thumbprint,
1224 thumbprint_size);
1225 free(efs);
1226 return fek;
1227}
1228
1229/**
1230 * ntfs_fek_decrypt_sector
1231 */
1232static int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset)
1233{
1234 gcry_error_t err;
1235
1236 err = gcry_cipher_reset(fek->gcry_cipher_hd);
1237 if (err != GPG_ERR_NO_ERROR) {
1238 ntfs_log_error("Failed to reset cipher: %s\n",
1239 gcry_strerror(err));
1240 return -1;
1241 }
1242 /*
1243 * Note: You may wonder why we are not calling gcry_cipher_setiv() here
1244 * instead of doing it by hand after the decryption. The answer is
1245 * that gcry_cipher_setiv() wants an iv of length 8 bytes but we give
1246 * it a length of 16 for AES256 so it does not like it.
1247 */
1248 if (fek->alg_id == CALG_DESX) {
1249 int k;
1250
1251 for (k=0; k<512; k+=8) {
1252 ntfs_desx_decrypt(fek, &data[k], &data[k]);
1253 }
1254 } else
1255 err = gcry_cipher_decrypt(fek->gcry_cipher_hd, data, 512, NULL, 0);
1256 if (err != GPG_ERR_NO_ERROR) {
1257 ntfs_log_error("Decryption failed: %s\n", gcry_strerror(err));
1258 return -1;
1259 }
1260 /* Apply the IV. */
1261 if (fek->alg_id == CALG_AES_256) {
1262 ((le64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset);
1263 ((le64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset);
1264 } else {
1265 /* All other algos (Des, 3Des, DesX) use the same IV. */
1266 ((le64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset);
1267 }
1268 return 512;
1269}
1270
1271/**
1272 * ntfs_cat_decrypt - Decrypt the contents of an encrypted file to stdout.
1273 * @inode: An encrypted file's inode structure, as obtained by
1274 * ntfs_inode_open().
1275 * @fek: A file encryption key. As obtained by ntfs_inode_fek_get().
1276 */
1277static int ntfs_cat_decrypt(ntfs_inode *inode, ntfs_fek *fek)
1278{
1279 int bufsize = 512;
1280 unsigned char *buffer;
1281 ntfs_attr *attr;
1282 s64 bytes_read, written, offset, total;
1283 s64 old_data_size, old_initialized_size;
1284 int i;
1285
1286 buffer = malloc(bufsize);
1287 if (!buffer)
1288 return 1;
1289 attr = ntfs_attr_open(inode, AT_DATA, NULL, 0);
1290 if (!attr) {
1291 ntfs_log_error("Cannot cat a directory.\n");
1292 free(buffer);
1293 return 1;
1294 }
1295 total = attr->data_size;
1296
1297 // hack: make sure attr will not be commited to disk if you use this.
1298 // clear the encrypted bit, otherwise the library won't allow reading.
1299 NAttrClearEncrypted(attr);
1300 // extend the size, we may need to read past the end of the stream.
1301 old_data_size = attr->data_size;
1302 old_initialized_size = attr->initialized_size;
1303 attr->data_size = attr->initialized_size = attr->allocated_size;
1304
1305 offset = 0;
1306 while (total > 0) {
1307 bytes_read = ntfs_attr_pread(attr, offset, 512, buffer);
1308 if (bytes_read == -1) {
1309 ntfs_log_perror("ERROR: Couldn't read file");
1310 break;
1311 }
1312 if (!bytes_read)
1313 break;
1314 if ((i = ntfs_fek_decrypt_sector(fek, buffer, offset)) <
1315 bytes_read) {
1316 ntfs_log_perror("ERROR: Couldn't decrypt all data!");
1317 ntfs_log_error("%u/%lld/%lld/%lld\n", i,
1318 (long long)bytes_read, (long long)offset,
1319 (long long)total);
1320 break;
1321 }
1322 if (bytes_read > total)
1323 bytes_read = total;
1324 written = fwrite(buffer, 1, bytes_read, stdout);
1325 if (written != bytes_read) {
1326 ntfs_log_perror("ERROR: Couldn't output all data!");
1327 break;
1328 }
1329 offset += bytes_read;
1330 total -= bytes_read;
1331 }
1332 attr->data_size = old_data_size;
1333 attr->initialized_size = old_initialized_size;
1334 NAttrSetEncrypted(attr);
1335 ntfs_attr_close(attr);
1336 free(buffer);
1337 return 0;
1338}
1339
1340/**
1341 * main - Begin here
1342 *
1343 * Start from here.
1344 *
1345 * Return: 0 Success, the program worked
1346 * 1 Error, something went wrong
1347 */
1348int main(int argc, char *argv[])
1349{
1350 u8 *pfx_buf;
1351 char *password;
1352 ntfs_rsa_private_key rsa_key;
1353 ntfs_volume *vol;
1354 ntfs_inode *inode;
1355 ntfs_fek *fek;
1356 unsigned pfx_size;
1357 int res;
1358 NTFS_DF_TYPES df_type;
1359 char thumbprint[NTFS_SHA1_THUMBPRINT_SIZE];
1360
1361 ntfs_log_set_handler(ntfs_log_handler_stderr);
1362
1363 if (!parse_options(argc, argv))
1364 return 1;
1365 utils_set_locale();
1366
1367 /* Initialize crypto in ntfs. */
1368 if (ntfs_crypto_init()) {
1369 ntfs_log_error("Failed to initialize crypto. Aborting.\n");
1370 return 1;
1371 }
1372 /* Load the PKCS#12 (.pfx) file containing the user's private key. */
1373 if (ntfs_pkcs12_load_pfxfile(opts.keyfile, &pfx_buf, &pfx_size)) {
1374 ntfs_log_error("Failed to load key file. Aborting.\n");
1375 ntfs_crypto_deinit();
1376 return 1;
1377 }
1378 /* Ask the user for their password. */
1379 password = getpass("Enter the password with which the private key was "
1380 "encrypted: ");
1381 if (!password) {
1382 ntfs_log_perror("Failed to obtain user password");
1383 free(pfx_buf);
1384 ntfs_crypto_deinit();
1385 return 1;
1386 }
1387 /* Obtain the user's private RSA key from the key file. */
1388 rsa_key = ntfs_pkcs12_extract_rsa_key(pfx_buf, pfx_size, password,
1389 thumbprint, sizeof(thumbprint), &df_type);
1390 /* Destroy the password. */
1391 memset(password, 0, strlen(password));
1392 /* No longer need the pfx file contents. */
1393 free(pfx_buf);
1394 if (!rsa_key) {
1395 ntfs_log_error("Failed to extract the private RSA key.\n");
1396 ntfs_crypto_deinit();
1397 return 1;
1398 }
1399 /* Mount the ntfs volume. */
1400 vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY |
1401 (opts.force ? NTFS_MNT_RECOVER : 0));
1402 if (!vol) {
1403 ntfs_log_error("Failed to mount ntfs volume. Aborting.\n");
1404 ntfs_rsa_private_key_release(rsa_key);
1405 ntfs_crypto_deinit();
1406 return 1;
1407 }
1408 /* Open the encrypted ntfs file. */
1409 if (opts.inode != -1)
1410 inode = ntfs_inode_open(vol, opts.inode);
1411 else
1412 inode = ntfs_pathname_to_inode(vol, NULL, opts.file);
1413 if (!inode) {
1414 ntfs_log_error("Failed to open encrypted file. Aborting.\n");
1415 ntfs_umount(vol, FALSE);
1416 ntfs_rsa_private_key_release(rsa_key);
1417 ntfs_crypto_deinit();
1418 return 1;
1419 }
1420 /* Obtain the file encryption key of the encrypted file. */
1421 fek = ntfs_inode_fek_get(inode, rsa_key, thumbprint,
1422 sizeof(thumbprint), df_type);
1423 ntfs_rsa_private_key_release(rsa_key);
1424 if (fek) {
1425 res = ntfs_cat_decrypt(inode, fek);
1426 ntfs_fek_release(fek);
1427 } else {
1428 ntfs_log_error("Failed to obtain file encryption key. "
1429 "Aborting.\n");
1430 res = 1;
1431 }
1432 ntfs_inode_close(inode);
1433 ntfs_umount(vol, FALSE);
1434 ntfs_crypto_deinit();
1435 return res;
1436}
1437