Allow IPv6 address entry in tools>ping - Loosens valid character check
[tomato/davidwu.git] / release / src / router / ntfs-3g / ntfsprogs / ntfsdecrypt.c
blob6be2b030ae07284dffedf76437dcaa03ccd70448
1 /**
2 * ntfsdecrypt - Decrypt ntfs encrypted files. Part of the Linux-NTFS project.
4 * Copyright (c) 2005 Yuval Fledel
5 * Copyright (c) 2005-2007 Anton Altaparmakov
6 * Copyright (c) 2007 Yura Pakhuchiy
8 * This utility will decrypt files and print the decrypted data on the standard
9 * output.
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (in the main directory of the Linux-NTFS
23 * distribution in the file COPYING); if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "config.h"
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32 #ifdef HAVE_SYS_STAT_H
33 #include <sys/stat.h>
34 #endif
35 #ifdef HAVE_FCNTL_H
36 #include <fcntl.h>
37 #endif
38 #ifdef HAVE_STDIO_H
39 #include <stdio.h>
40 #endif
41 #ifdef HAVE_GETOPT_H
42 #include <getopt.h>
43 #endif
44 #ifdef HAVE_STDLIB_H
45 #include <stdlib.h>
46 #endif
47 #ifdef HAVE_STRING_H
48 #include <string.h>
49 #endif
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53 #ifdef HAVE_ERRNO_H
54 #include <errno.h>
55 #endif
56 #include <gcrypt.h>
57 #include <gnutls/pkcs12.h>
59 #include "types.h"
60 #include "attrib.h"
61 #include "utils.h"
62 #include "volume.h"
63 #include "debug.h"
64 #include "dir.h"
65 #include "layout.h"
66 /* #include "version.h" */
68 typedef gcry_sexp_t ntfs_rsa_private_key;
70 #define NTFS_SHA1_THUMBPRINT_SIZE 0x14
72 #define NTFS_CRED_TYPE_CERT_THUMBPRINT const_cpu_to_le32(3)
74 #define NTFS_EFS_CERT_PURPOSE_OID_DDF "1.3.6.1.4.1.311.10.3.4"
75 #define NTFS_EFS_CERT_PURPOSE_OID_DRF "1.3.6.1.4.1.311.10.3.4.1"
77 typedef enum {
78 DF_TYPE_UNKNOWN,
79 DF_TYPE_DDF,
80 DF_TYPE_DRF,
81 } NTFS_DF_TYPES;
83 /**
84 * enum NTFS_CRYPTO_ALGORITHMS - List of crypto algorithms used by EFS (32 bit)
86 * To choose which one is used in Windows, create or set the REG_DWORD registry
87 * key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EFS\
88 * AlgorithmID to the value of your chosen crypto algorithm, e.g. to use DesX,
89 * set AlgorithmID to 0x6604.
91 * Note that the Windows versions I have tried so far (all are high crypto
92 * enabled) ignore the AlgorithmID value if it is not one of CALG_3DES,
93 * CALG_DESX, or CALG_AES_256, i.e. you cannot select CALG_DES at all using
94 * this registry key. It would be interesting to check out encryption on one
95 * of the "crippled" crypto Windows versions...
97 typedef enum {
98 CALG_DES = const_cpu_to_le32(0x6601),
99 /* If not one of the below three, fall back to standard Des. */
100 CALG_3DES = const_cpu_to_le32(0x6603),
101 CALG_DESX = const_cpu_to_le32(0x6604),
102 CALG_AES_256 = const_cpu_to_le32(0x6610),
103 } NTFS_CRYPTO_ALGORITHMS;
106 * struct ntfs_fek - Decrypted, in-memory file encryption key.
108 typedef struct {
109 gcry_cipher_hd_t gcry_cipher_hd;
110 le32 alg_id;
111 u8 *key_data;
112 gcry_cipher_hd_t *des_gcry_cipher_hd_ptr;
113 } ntfs_fek;
115 /* DESX-MS128 implementation for libgcrypt. */
116 static gcry_module_t ntfs_desx_module;
117 static int ntfs_desx_algorithm_id = -1;
119 typedef struct {
120 u64 in_whitening, out_whitening;
121 gcry_cipher_hd_t gcry_cipher_hd;
122 } ntfs_desx_ctx;
124 struct options {
125 char *keyfile; /* .pfx file containing the user's private key. */
126 char *device; /* Device/File to work with */
127 char *file; /* File to display */
128 s64 inode; /* Inode to work with */
129 ATTR_TYPES attr; /* Attribute type to display */
130 int force; /* Override common sense */
131 int quiet; /* Less output */
132 int verbose; /* Extra output */
135 static const char *EXEC_NAME = "ntfsdecrypt";
136 static struct options opts;
138 static ntfschar EFS[5] = {
139 const_cpu_to_le16('$'), const_cpu_to_le16('E'), const_cpu_to_le16('F'),
140 const_cpu_to_le16('S'), const_cpu_to_le16('\0')
144 * version - Print version information about the program
146 * Print a copyright statement and a brief description of the program.
148 * Return: none
150 static void version(void)
152 ntfs_log_info("\n%s v%s (libntfs-3g) - Decrypt files and print on the "
153 "standard output.\n\n", EXEC_NAME, VERSION);
154 ntfs_log_info("Copyright (c) 2005 Yuval Fledel\n");
155 ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n");
156 ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
160 * usage - Print a list of the parameters to the program
162 * Print a list of the parameters and options for the program.
164 * Return: none
166 static void usage(void)
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);
181 * parse_options - Read and validate the programs command line
183 * Read the command line, verify the syntax and parse the options.
184 * This function is very long, but quite simple.
186 * Return: 1 Success
187 * 0 Error, one or more problems
189 static int parse_options(int argc, char **argv)
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}
203 int c = -1;
204 int err = 0;
205 int ver = 0;
206 int help = 0;
208 opterr = 0; /* We'll handle the errors, thank you. */
210 opts.inode = -1;
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++;
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++;
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;
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++;
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++;
296 if (ver)
297 version();
298 if (help || err)
299 usage();
301 return (!err && !help && !ver);
305 * ntfs_pkcs12_load_pfxfile
307 static int ntfs_pkcs12_load_pfxfile(const char *keyfile, u8 **pfx,
308 unsigned *pfx_size)
310 int f, to_read, total, attempts, br;
311 struct stat key_stat;
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;
319 f = open(keyfile, O_RDONLY);
320 if (f == -1) {
321 ntfs_log_perror("Failed to open key file");
322 return -1;
324 if (fstat(f, &key_stat) == -1) {
325 ntfs_log_perror("Failed to stat key file");
326 goto file_out;
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;
333 if (!key_stat.st_size) {
334 ntfs_log_error("Key file has zero size.\n");
335 goto file_out;
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;
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;
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;
361 free_out:
362 free(*pfx);
363 file_out:
364 close(f);
365 return -1;
369 * ntfs_crypto_init
371 static int ntfs_crypto_init(void)
373 int err;
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;
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;
387 return 0;
391 * ntfs_crypto_deinit
393 static void ntfs_crypto_deinit(void)
395 gnutls_global_deinit();
396 if (ntfs_desx_module) {
397 gcry_cipher_unregister(ntfs_desx_module);
398 ntfs_desx_module = NULL;
399 ntfs_desx_algorithm_id = -1;
404 * ntfs_rsa_private_key_import_from_gnutls
406 static ntfs_rsa_private_key ntfs_rsa_private_key_import_from_gnutls(
407 gnutls_x509_privkey_t priv_key)
409 int i, j;
410 size_t tmp_size;
411 gnutls_datum_t rd[6];
412 gcry_mpi_t rm[6];
413 gcry_sexp_t rsa_key;
415 /* Extract the RSA parameters from the GNU TLS private key. */
416 if (gnutls_x509_privkey_export_rsa_raw(priv_key, &rd[0], &rd[1],
417 &rd[2], &rd[3], &rd[4], &rd[5])) {
418 ntfs_log_error("Failed to export rsa parameters. (Is the "
419 "key an RSA private key?)\n");
420 return NULL;
422 /* Convert each RSA parameter to mpi format. */
423 for (i = 0; i < 6; i++) {
424 if (gcry_mpi_scan(&rm[i], GCRYMPI_FMT_USG, rd[i].data,
425 rd[i].size, &tmp_size) != GPG_ERR_NO_ERROR) {
426 ntfs_log_error("Failed to convert RSA parameter %i "
427 "to mpi format (size %d)\n", i,
428 rd[i].size);
429 rsa_key = NULL;
430 break;
433 /* Release the no longer needed datum values. */
434 for (j = 0; j < 6; j++) {
435 if (rd[j].data && rd[j].size)
436 gnutls_free(rd[j].data);
439 * Build the gcrypt private key, note libgcrypt uses p and q inversed
440 * to what gnutls uses.
442 if (i == 6 && gcry_sexp_build(&rsa_key, NULL,
443 "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
444 rm[0], rm[1], rm[2], rm[4], rm[3], rm[5]) !=
445 GPG_ERR_NO_ERROR) {
446 ntfs_log_error("Failed to build RSA private key s-exp.\n");
447 rsa_key = NULL;
449 /* Release the no longer needed mpi values. */
450 for (j = 0; j < i; j++)
451 gcry_mpi_release(rm[j]);
452 return (ntfs_rsa_private_key)rsa_key;
456 * ntfs_rsa_private_key_release
458 static void ntfs_rsa_private_key_release(ntfs_rsa_private_key rsa_key)
460 gcry_sexp_release((gcry_sexp_t)rsa_key);
464 * ntfs_pkcs12_extract_rsa_key
466 static ntfs_rsa_private_key ntfs_pkcs12_extract_rsa_key(u8 *pfx, int pfx_size,
467 char *password, char *thumbprint, int thumbprint_size,
468 NTFS_DF_TYPES *df_type)
470 int err, bag_index, flags;
471 gnutls_datum_t dpfx, dkey;
472 gnutls_pkcs12_t pkcs12 = NULL;
473 gnutls_pkcs12_bag_t bag = NULL;
474 gnutls_x509_privkey_t pkey = NULL;
475 gnutls_x509_crt_t crt = NULL;
476 ntfs_rsa_private_key rsa_key = NULL;
477 char purpose_oid[100];
478 size_t purpose_oid_size = sizeof(purpose_oid);
479 size_t tp_size = thumbprint_size;
480 BOOL have_thumbprint = FALSE;
482 *df_type = DF_TYPE_UNKNOWN;
483 /* Create a pkcs12 structure. */
484 err = gnutls_pkcs12_init(&pkcs12);
485 if (err) {
486 ntfs_log_error("Failed to initialize PKCS#12 structure: %s\n",
487 gnutls_strerror(err));
488 return NULL;
490 /* Convert the PFX file (DER format) to native pkcs12 format. */
491 dpfx.data = pfx;
492 dpfx.size = pfx_size;
493 err = gnutls_pkcs12_import(pkcs12, &dpfx, GNUTLS_X509_FMT_DER, 0);
494 if (err) {
495 ntfs_log_error("Failed to convert the PFX file from DER to "
496 "native PKCS#12 format: %s\n",
497 gnutls_strerror(err));
498 goto err;
501 * Verify that the password is correct and that the key file has not
502 * been tampered with. Note if the password has zero length and the
503 * verification fails, retry with password set to NULL. This is needed
504 * to get passwordless .pfx files generated with Windows XP SP1 (and
505 * probably earlier versions of Windows) to work.
507 retry_verify:
508 err = gnutls_pkcs12_verify_mac(pkcs12, password);
509 if (err) {
510 if (err == GNUTLS_E_MAC_VERIFY_FAILED &&
511 password && !strlen(password)) {
512 password = NULL;
513 goto retry_verify;
515 ntfs_log_error("Failed to verify the MAC: %s Is the "
516 "password correct?\n", gnutls_strerror(err));
517 goto err;
519 for (bag_index = 0; ; bag_index++) {
520 err = gnutls_pkcs12_bag_init(&bag);
521 if (err) {
522 ntfs_log_error("Failed to initialize PKCS#12 Bag "
523 "structure: %s\n",
524 gnutls_strerror(err));
525 goto err;
527 err = gnutls_pkcs12_get_bag(pkcs12, bag_index, bag);
528 if (err) {
529 if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
530 err = 0;
531 break;
533 ntfs_log_error("Failed to obtain Bag from PKCS#12 "
534 "structure: %s\n",
535 gnutls_strerror(err));
536 goto err;
538 check_again:
539 err = gnutls_pkcs12_bag_get_count(bag);
540 if (err < 0) {
541 ntfs_log_error("Failed to obtain Bag count: %s\n",
542 gnutls_strerror(err));
543 goto err;
545 err = gnutls_pkcs12_bag_get_type(bag, 0);
546 if (err < 0) {
547 ntfs_log_error("Failed to determine Bag type: %s\n",
548 gnutls_strerror(err));
549 goto err;
551 flags = 0;
552 switch (err) {
553 case GNUTLS_BAG_PKCS8_KEY:
554 flags = GNUTLS_PKCS_PLAIN;
555 case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY:
556 err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey);
557 if (err < 0) {
558 ntfs_log_error("Failed to obtain Bag data: "
559 "%s\n", gnutls_strerror(err));
560 goto err;
562 err = gnutls_x509_privkey_init(&pkey);
563 if (err) {
564 ntfs_log_error("Failed to initialized "
565 "private key structure: %s\n",
566 gnutls_strerror(err));
567 goto err;
569 /* Decrypt the private key into GNU TLS format. */
570 err = gnutls_x509_privkey_import_pkcs8(pkey, &dkey,
571 GNUTLS_X509_FMT_DER, password, flags);
572 if (err) {
573 ntfs_log_error("Failed to convert private "
574 "key from DER to GNU TLS "
575 "format: %s\n",
576 gnutls_strerror(err));
577 goto err;
579 #if 0
581 * Export the key again, but unencrypted, and output it
582 * to stderr. Note the output has an RSA header so to
583 * compare to openssl pkcs12 -nodes -in myfile.pfx
584 * output need to ignore the part of the key between
585 * the first "MII..." up to the second "MII...". The
586 * actual RSA private key begins at the second "MII..."
587 * and in my testing at least was identical to openssl
588 * output and was also identical both on big and little
589 * endian so gnutls should be endianness safe.
591 char *buf = malloc(8192);
592 size_t bufsize = 8192;
593 err = gnutls_x509_privkey_export_pkcs8(pkey,
594 GNUTLS_X509_FMT_PEM, "", GNUTLS_PKCS_PLAIN, buf,
595 &bufsize);
596 if (err) {
597 ntfs_log_error("eek1\n");
598 exit(1);
600 ntfs_log_error("%s\n", buf);
601 free(buf);
602 #endif
603 /* Convert the private key to our internal format. */
604 rsa_key = ntfs_rsa_private_key_import_from_gnutls(pkey);
605 if (!rsa_key)
606 goto err;
607 break;
608 case GNUTLS_BAG_ENCRYPTED:
609 err = gnutls_pkcs12_bag_decrypt(bag, password);
610 if (err) {
611 ntfs_log_error("Failed to decrypt Bag: %s\n",
612 gnutls_strerror(err));
613 goto err;
615 goto check_again;
616 case GNUTLS_BAG_CERTIFICATE:
617 err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey);
618 if (err < 0) {
619 ntfs_log_error("Failed to obtain Bag data: "
620 "%s\n", gnutls_strerror(err));
621 goto err;
623 err = gnutls_x509_crt_init(&crt);
624 if (err) {
625 ntfs_log_error("Failed to initialize "
626 "certificate structure: %s\n",
627 gnutls_strerror(err));
628 goto err;
630 err = gnutls_x509_crt_import(crt, &dkey,
631 GNUTLS_X509_FMT_DER);
632 if (err) {
633 ntfs_log_error("Failed to convert certificate "
634 "from DER to GNU TLS format: "
635 "%s\n", gnutls_strerror(err));
636 goto err;
638 err = gnutls_x509_crt_get_key_purpose_oid(crt, 0,
639 purpose_oid, &purpose_oid_size, NULL);
640 if (err) {
641 ntfs_log_error("Failed to get key purpose "
642 "OID: %s\n",
643 gnutls_strerror(err));
644 goto err;
646 purpose_oid[purpose_oid_size - 1] = '\0';
647 if (!strcmp(purpose_oid,
648 NTFS_EFS_CERT_PURPOSE_OID_DRF))
649 *df_type = DF_TYPE_DRF;
650 else if (!strcmp(purpose_oid,
651 NTFS_EFS_CERT_PURPOSE_OID_DDF))
652 *df_type = DF_TYPE_DDF;
653 else {
654 ntfs_log_error("Certificate has unknown "
655 "purpose OID %s.\n",
656 purpose_oid);
657 err = EINVAL;
658 goto err;
660 /* Return the thumbprint to the caller. */
661 err = gnutls_x509_crt_get_fingerprint(crt,
662 GNUTLS_DIG_SHA1, thumbprint, &tp_size);
663 if (err) {
664 ntfs_log_error("Failed to get thumbprint: "
665 "%s\n", gnutls_strerror(err));
666 goto err;
668 if (tp_size != NTFS_SHA1_THUMBPRINT_SIZE) {
669 ntfs_log_error("Invalid thumbprint size %zd. "
670 "Should be %d.\n", tp_size,
671 thumbprint_size);
672 err = EINVAL;
673 goto err;
675 have_thumbprint = TRUE;
676 gnutls_x509_crt_deinit(crt);
677 crt = NULL;
678 break;
679 default:
680 /* We do not care about other types. */
681 break;
683 gnutls_pkcs12_bag_deinit(bag);
685 err:
686 if (rsa_key && (err || *df_type == DF_TYPE_UNKNOWN ||
687 !have_thumbprint)) {
688 if (!err)
689 ntfs_log_error("Key type or thumbprint not found, "
690 "aborting.\n");
691 ntfs_rsa_private_key_release(rsa_key);
692 rsa_key = NULL;
694 if (crt)
695 gnutls_x509_crt_deinit(crt);
696 if (pkey)
697 gnutls_x509_privkey_deinit(pkey);
698 if (bag)
699 gnutls_pkcs12_bag_deinit(bag);
700 if (pkcs12)
701 gnutls_pkcs12_deinit(pkcs12);
702 return rsa_key;
706 * ntfs_buffer_reverse -
708 * This is a utility function for reversing the order of a buffer in place.
709 * Users of this function should be very careful not to sweep byte order
710 * problems under the rug.
712 static inline void ntfs_buffer_reverse(u8 *buf, unsigned buf_size)
714 unsigned i;
715 u8 t;
717 for (i = 0; i < buf_size / 2; i++) {
718 t = buf[i];
719 buf[i] = buf[buf_size - i - 1];
720 buf[buf_size - i - 1] = t;
724 #ifndef HAVE_STRNLEN
726 * strnlen - strnlen is a gnu extension so emulate it if not present
728 static size_t strnlen(const char *s, size_t maxlen)
730 const char *p, *end;
732 /* Look for a '\0' character. */
733 for (p = s, end = s + maxlen; p < end && *p; p++)
735 return p - s;
737 #endif /* ! HAVE_STRNLEN */
740 * ntfs_raw_fek_decrypt -
742 * Note: decrypting into the input buffer.
744 static unsigned ntfs_raw_fek_decrypt(u8 *fek, u32 fek_size,
745 ntfs_rsa_private_key rsa_key)
747 gcry_mpi_t fek_mpi;
748 gcry_sexp_t fek_sexp, fek_sexp2;
749 gcry_error_t err;
750 size_t size, padding;
752 /* Reverse the raw FEK. */
753 ntfs_buffer_reverse(fek, fek_size);
754 /* Convert the FEK to internal MPI format. */
755 err = gcry_mpi_scan(&fek_mpi, GCRYMPI_FMT_USG, fek, fek_size, NULL);
756 if (err != GPG_ERR_NO_ERROR) {
757 ntfs_log_error("Failed to convert file encryption key to "
758 "internal MPI format: %s\n",
759 gcry_strerror(err));
760 return 0;
762 /* Create an internal S-expression from the FEK. */
763 err = gcry_sexp_build(&fek_sexp, NULL,
764 "(enc-val (flags) (rsa (a %m)))", fek_mpi);
765 gcry_mpi_release(fek_mpi);
766 if (err != GPG_ERR_NO_ERROR) {
767 ntfs_log_error("Failed to create internal S-expression of "
768 "the file encryption key: %s\n",
769 gcry_strerror(err));
770 return 0;
772 /* Decrypt the FEK. */
773 err = gcry_pk_decrypt(&fek_sexp2, fek_sexp, (gcry_sexp_t)rsa_key);
774 gcry_sexp_release(fek_sexp);
775 if (err != GPG_ERR_NO_ERROR) {
776 ntfs_log_error("Failed to decrypt the file encryption key: "
777 "%s\n", gcry_strerror(err));
778 return 0;
780 /* Extract the actual FEK from the decrypted raw S-expression. */
781 fek_sexp = gcry_sexp_find_token(fek_sexp2, "value", 0);
782 gcry_sexp_release(fek_sexp2);
783 if (!fek_sexp) {
784 ntfs_log_error("Failed to find the decrypted file encryption "
785 "key in the internal S-expression.\n");
786 return 0;
788 /* Convert the decrypted FEK S-expression into MPI format. */
789 fek_mpi = gcry_sexp_nth_mpi(fek_sexp, 1, GCRYMPI_FMT_USG);
790 gcry_sexp_release(fek_sexp);
791 if (!fek_mpi) {
792 ntfs_log_error("Failed to convert the decrypted file "
793 "encryption key S-expression to internal MPI "
794 "format.\n");
795 return 0;
797 /* Convert the decrypted FEK from MPI format to binary data. */
798 err = gcry_mpi_print(GCRYMPI_FMT_USG, fek, fek_size, &size, fek_mpi);
799 gcry_mpi_release(fek_mpi);
800 if (err != GPG_ERR_NO_ERROR || !size) {
801 ntfs_log_error("Failed to convert decrypted file encryption "
802 "key from internal MPI format to binary data: "
803 "%s\n", gcry_strerror(err));
804 return 0;
807 * Finally, remove the PKCS#1 padding and return the size of the
808 * decrypted FEK.
810 padding = strnlen((char *)fek, size) + 1;
811 if (padding > size) {
812 ntfs_log_error("Failed to remove PKCS#1 padding from "
813 "decrypted file encryption key.\n");
814 return 0;
816 size -= padding;
817 memmove(fek, fek + padding, size);
818 return size;
822 * ntfs_desx_key_expand - expand a 128-bit desx key to the needed 192-bit key
823 * @src: source buffer containing 128-bit key
825 * Expands the on-disk 128-bit desx key to the needed des key, the in-, and the
826 * out-whitening keys required to perform desx {de,en}cryption.
828 static gcry_error_t ntfs_desx_key_expand(const u8 *src, u32 *des_key,
829 u64 *out_whitening, u64 *in_whitening)
831 static const u8 *salt1 = (const u8*)"Dan Simon ";
832 static const u8 *salt2 = (const u8*)"Scott Field";
833 static const int salt_len = 12;
834 gcry_md_hd_t hd1, hd2;
835 u32 *md;
836 gcry_error_t err;
838 err = gcry_md_open(&hd1, GCRY_MD_MD5, 0);
839 if (err != GPG_ERR_NO_ERROR) {
840 ntfs_log_error("Failed to open MD5 digest.\n");
841 return err;
843 /* Hash the on-disk key. */
844 gcry_md_write(hd1, src, 128 / 8);
845 /* Copy the current hash for efficiency. */
846 err = gcry_md_copy(&hd2, hd1);
847 if (err != GPG_ERR_NO_ERROR) {
848 ntfs_log_error("Failed to copy MD5 digest object.\n");
849 goto out;
851 /* Hash with the first salt and store the result. */
852 gcry_md_write(hd1, salt1, salt_len);
853 md = (u32*)gcry_md_read(hd1, 0);
854 des_key[0] = md[0] ^ md[1];
855 des_key[1] = md[2] ^ md[3];
856 /* Hash with the second salt and store the result. */
857 gcry_md_write(hd2, salt2, salt_len);
858 md = (u32*)gcry_md_read(hd2, 0);
859 *out_whitening = *(u64*)md;
860 *in_whitening = *(u64*)(md + 2);
861 gcry_md_close(hd2);
862 out:
863 gcry_md_close(hd1);
864 return err;
868 * ntfs_desx_setkey - libgcrypt set_key implementation for DES-X-MS128
869 * @context: pointer to a variable of type ntfs_desx_ctx
870 * @key: the 128 bit DES-X-MS128 key, concated with the DES handle
871 * @keylen: must always be 16
873 * This is the libgcrypt set_key implementation for DES-X-MS128.
875 static gcry_err_code_t ntfs_desx_setkey(void *context, const u8 *key,
876 unsigned keylen)
878 ntfs_desx_ctx *ctx = context;
879 gcry_error_t err;
880 u8 des_key[8];
882 if (keylen != 16) {
883 ntfs_log_error("Key length for desx must be 16.\n");
884 return GPG_ERR_INV_KEYLEN;
886 err = gcry_cipher_open(&ctx->gcry_cipher_hd, GCRY_CIPHER_DES,
887 GCRY_CIPHER_MODE_ECB, 0);
888 if (err != GPG_ERR_NO_ERROR) {
889 ntfs_log_error("Failed to open des cipher (error 0x%x).\n",
890 err);
891 return err;
893 err = ntfs_desx_key_expand(key, (u32*)des_key, &ctx->out_whitening,
894 &ctx->in_whitening);
895 if (err != GPG_ERR_NO_ERROR) {
896 ntfs_log_error("Failed to expand desx key (error 0x%x).\n",
897 err);
898 gcry_cipher_close(ctx->gcry_cipher_hd);
899 return err;
901 err = gcry_cipher_setkey(ctx->gcry_cipher_hd, des_key, sizeof(des_key));
902 if (err != GPG_ERR_NO_ERROR) {
903 ntfs_log_error("Failed to set des key (error 0x%x).\n", err);
904 gcry_cipher_close(ctx->gcry_cipher_hd);
905 return err;
908 * Take a note of the ctx->gcry_cipher_hd since we need to close it at
909 * ntfs_decrypt_data_key_close() time.
911 **(gcry_cipher_hd_t***)(key + ((keylen + 7) & ~7)) =
912 &ctx->gcry_cipher_hd;
913 return GPG_ERR_NO_ERROR;
917 * ntfs_desx_decrypt
919 static void ntfs_desx_decrypt(void *context, u8 *outbuf, const u8 *inbuf)
921 ntfs_desx_ctx *ctx = context;
922 gcry_error_t err;
924 err = gcry_cipher_reset(ctx->gcry_cipher_hd);
925 if (err != GPG_ERR_NO_ERROR)
926 ntfs_log_error("Failed to reset des cipher (error 0x%x).\n",
927 err);
928 *(u64*)outbuf = *(const u64*)inbuf ^ ctx->out_whitening;
929 err = gcry_cipher_encrypt(ctx->gcry_cipher_hd, outbuf, 8, NULL, 0);
930 if (err != GPG_ERR_NO_ERROR)
931 ntfs_log_error("Des decryption failed (error 0x%x).\n", err);
932 *(u64*)outbuf ^= ctx->in_whitening;
935 static gcry_cipher_spec_t ntfs_desx_cipher = {
936 .name = "DES-X-MS128",
937 .blocksize = 8,
938 .keylen = 128,
939 .contextsize = sizeof(ntfs_desx_ctx),
940 .setkey = ntfs_desx_setkey,
941 .decrypt = ntfs_desx_decrypt,
944 //#define DO_CRYPTO_TESTS 1
946 #ifdef DO_CRYPTO_TESTS
948 /* Do not remove this test code from this file! AIA */
950 * ntfs_desx_key_expand_test
952 static BOOL ntfs_desx_key_expand_test(void)
954 const u8 known_desx_on_disk_key[16] = {
955 0xa1, 0xf9, 0xe0, 0xb2, 0x53, 0x23, 0x9e, 0x8f,
956 0x0f, 0x91, 0x45, 0xd9, 0x8e, 0x20, 0xec, 0x30
958 const u8 known_des_key[8] = {
959 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f,
961 const u8 known_out_whitening[8] = {
962 0xed, 0xda, 0x4c, 0x47, 0x60, 0x49, 0xdb, 0x8d,
964 const u8 known_in_whitening[8] = {
965 0x75, 0xf6, 0xa0, 0x1a, 0xc0, 0xca, 0x28, 0x1e
967 u64 test_out_whitening, test_in_whitening;
968 union {
969 u64 u64;
970 u32 u32[2];
971 } test_des_key;
972 gcry_error_t err;
973 BOOL res;
975 err = ntfs_desx_key_expand(known_desx_on_disk_key, test_des_key.u32,
976 &test_out_whitening, &test_in_whitening);
977 if (err != GPG_ERR_NO_ERROR)
978 res = FALSE;
979 else
980 res = test_des_key.u64 == *(u64*)known_des_key &&
981 test_out_whitening ==
982 *(u64*)known_out_whitening &&
983 test_in_whitening ==
984 *(u64*)known_in_whitening;
985 ntfs_log_error("Testing whether ntfs_desx_key_expand() works: %s\n",
986 res ? "SUCCESS" : "FAILED");
987 return res;
991 * ntfs_des_test
993 static BOOL ntfs_des_test(void)
995 const u8 known_des_key[8] = {
996 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f
998 const u8 known_des_encrypted_data[8] = {
999 0xdc, 0xf7, 0x68, 0x2a, 0xaf, 0x48, 0x53, 0x0f
1001 const u8 known_decrypted_data[8] = {
1002 0xd8, 0xd9, 0x15, 0x23, 0x5b, 0x88, 0x0e, 0x09
1004 u8 test_decrypted_data[8];
1005 int res;
1006 gcry_error_t err;
1007 gcry_cipher_hd_t gcry_cipher_hd;
1009 err = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_DES,
1010 GCRY_CIPHER_MODE_ECB, 0);
1011 if (err != GPG_ERR_NO_ERROR) {
1012 ntfs_log_error("Failed to open des cipher (error 0x%x).\n",
1013 err);
1014 return FALSE;
1016 err = gcry_cipher_setkey(gcry_cipher_hd, known_des_key,
1017 sizeof(known_des_key));
1018 if (err != GPG_ERR_NO_ERROR) {
1019 ntfs_log_error("Failed to set des key (error 0x%x.\n", err);
1020 gcry_cipher_close(gcry_cipher_hd);
1021 return FALSE;
1024 * Apply DES decryption (ntfs actually uses encryption when decrypting).
1026 err = gcry_cipher_encrypt(gcry_cipher_hd, test_decrypted_data,
1027 sizeof(test_decrypted_data), known_des_encrypted_data,
1028 sizeof(known_des_encrypted_data));
1029 gcry_cipher_close(gcry_cipher_hd);
1030 if (err) {
1031 ntfs_log_error("Failed to des decrypt test data (error "
1032 "0x%x).\n", err);
1033 return FALSE;
1035 res = !memcmp(test_decrypted_data, known_decrypted_data,
1036 sizeof(known_decrypted_data));
1037 ntfs_log_error("Testing whether des decryption works: %s\n",
1038 res ? "SUCCESS" : "FAILED");
1039 return res;
1042 #else /* !defined(DO_CRYPTO_TESTS) */
1045 * ntfs_desx_key_expand_test
1047 static inline BOOL ntfs_desx_key_expand_test(void)
1049 return TRUE;
1053 * ntfs_des_test
1055 static inline BOOL ntfs_des_test(void)
1057 return TRUE;
1060 #endif /* !defined(DO_CRYPTO_TESTS) */
1063 * ntfs_fek_import_from_raw
1065 static ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf, unsigned fek_size)
1067 ntfs_fek *fek;
1068 u32 key_size, wanted_key_size, gcry_algo;
1069 gcry_error_t err;
1071 key_size = le32_to_cpup(fek_buf);
1072 ntfs_log_debug("key_size 0x%x\n", key_size);
1073 if (key_size + 16 > fek_size) {
1074 ntfs_log_debug("Invalid FEK. It was probably decrypted with "
1075 "the incorrect RSA key.");
1076 errno = EINVAL;
1077 return NULL;
1079 fek = malloc(((((sizeof(*fek) + 7) & ~7) + key_size + 7) & ~7) +
1080 sizeof(gcry_cipher_hd_t));
1081 if (!fek) {
1082 errno = ENOMEM;
1083 return NULL;
1085 fek->alg_id = *(le32*)(fek_buf + 8);
1086 //ntfs_log_debug("alg_id 0x%x\n", le32_to_cpu(fek->alg_id));
1087 fek->key_data = (u8*)fek + ((sizeof(*fek) + 7) & ~7);
1088 memcpy(fek->key_data, fek_buf + 16, key_size);
1089 fek->des_gcry_cipher_hd_ptr = NULL;
1090 *(gcry_cipher_hd_t***)(fek->key_data + ((key_size + 7) & ~7)) =
1091 &fek->des_gcry_cipher_hd_ptr;
1092 switch (fek->alg_id) {
1093 case CALG_DESX:
1094 if (!ntfs_desx_module) {
1095 if (!ntfs_desx_key_expand_test() || !ntfs_des_test()) {
1096 err = EINVAL;
1097 goto out;
1099 err = gcry_cipher_register(&ntfs_desx_cipher,
1100 &ntfs_desx_algorithm_id,
1101 &ntfs_desx_module);
1102 if (err != GPG_ERR_NO_ERROR) {
1103 ntfs_log_error("Failed to register desx "
1104 "cipher: %s\n",
1105 gcry_strerror(err));
1106 err = EINVAL;
1107 goto out;
1110 wanted_key_size = 16;
1111 gcry_algo = ntfs_desx_algorithm_id;
1112 break;
1113 case CALG_3DES:
1114 wanted_key_size = 24;
1115 gcry_algo = GCRY_CIPHER_3DES;
1116 break;
1117 case CALG_AES_256:
1118 wanted_key_size = 32;
1119 gcry_algo = GCRY_CIPHER_AES256;
1120 break;
1121 default:
1122 wanted_key_size = 8;
1123 gcry_algo = GCRY_CIPHER_DES;
1124 if (fek->alg_id == CALG_DES)
1125 ntfs_log_error("DES is not supported at present\n");
1126 else
1127 ntfs_log_error("Unknown crypto algorithm 0x%x\n",
1128 le32_to_cpu(fek->alg_id));
1129 ntfs_log_error(". Please email %s and say that you saw this "
1130 "message. We will then try to implement "
1131 "support for this algorithm.\n", NTFS_DEV_LIST);
1132 err = EOPNOTSUPP;
1133 goto out;
1135 if (key_size != wanted_key_size) {
1136 ntfs_log_error("%s key of %u bytes but needed size is %u "
1137 "bytes, assuming corrupt or incorrect key. "
1138 "Aborting.\n",
1139 gcry_cipher_algo_name(gcry_algo),
1140 (unsigned)key_size, (unsigned)wanted_key_size);
1141 err = EIO;
1142 goto out;
1144 err = gcry_cipher_open(&fek->gcry_cipher_hd, gcry_algo,
1145 GCRY_CIPHER_MODE_CBC, 0);
1146 if (err != GPG_ERR_NO_ERROR) {
1147 ntfs_log_error("gcry_cipher_open() failed: %s\n",
1148 gcry_strerror(err));
1149 err = EINVAL;
1150 goto out;
1152 err = gcry_cipher_setkey(fek->gcry_cipher_hd, fek->key_data, key_size);
1153 if (err != GPG_ERR_NO_ERROR) {
1154 ntfs_log_error("gcry_cipher_setkey() failed: %s\n",
1155 gcry_strerror(err));
1156 gcry_cipher_close(fek->gcry_cipher_hd);
1157 err = EINVAL;
1158 goto out;
1160 return fek;
1161 out:
1162 free(fek);
1163 errno = err;
1164 return NULL;
1168 * ntfs_fek_release
1170 static void ntfs_fek_release(ntfs_fek *fek)
1172 if (fek->des_gcry_cipher_hd_ptr)
1173 gcry_cipher_close(*fek->des_gcry_cipher_hd_ptr);
1174 gcry_cipher_close(fek->gcry_cipher_hd);
1175 free(fek);
1179 * ntfs_df_array_fek_get
1181 static ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array,
1182 ntfs_rsa_private_key rsa_key, char *thumbprint,
1183 int thumbprint_size)
1185 EFS_DF_HEADER *df_header;
1186 EFS_DF_CREDENTIAL_HEADER *df_cred;
1187 EFS_DF_CERT_THUMBPRINT_HEADER *df_cert;
1188 u8 *fek_buf;
1189 ntfs_fek *fek;
1190 u32 df_count, fek_size;
1191 unsigned i;
1193 df_count = le32_to_cpu(df_array->df_count);
1194 if (!df_count)
1195 ntfs_log_error("There are no elements in the DF array.\n");
1196 df_header = (EFS_DF_HEADER*)(df_array + 1);
1197 for (i = 0; i < df_count; i++, df_header = (EFS_DF_HEADER*)(
1198 (u8*)df_header + le32_to_cpu(df_header->df_length))) {
1199 df_cred = (EFS_DF_CREDENTIAL_HEADER*)((u8*)df_header +
1200 le32_to_cpu(df_header->cred_header_offset));
1201 if (df_cred->type != NTFS_CRED_TYPE_CERT_THUMBPRINT) {
1202 ntfs_log_debug("Credential type is not certificate "
1203 "thumbprint, skipping DF entry.\n");
1204 continue;
1206 df_cert = (EFS_DF_CERT_THUMBPRINT_HEADER*)((u8*)df_cred +
1207 le32_to_cpu(
1208 df_cred->cert_thumbprint_header_offset));
1209 if (le32_to_cpu(df_cert->thumbprint_size) != thumbprint_size) {
1210 ntfs_log_error("Thumbprint size %d is not valid "
1211 "(should be %d), skipping this DF "
1212 "entry.\n",
1213 le32_to_cpu(df_cert->thumbprint_size),
1214 thumbprint_size);
1215 continue;
1217 if (memcmp((u8*)df_cert +
1218 le32_to_cpu(df_cert->thumbprint_offset),
1219 thumbprint, thumbprint_size)) {
1220 ntfs_log_debug("Thumbprints do not match, skipping "
1221 "this DF entry.\n");
1222 continue;
1225 * The thumbprints match so this is probably the DF entry
1226 * matching the RSA key. Try to decrypt the FEK with it.
1228 fek_size = le32_to_cpu(df_header->fek_size);
1229 fek_buf = (u8*)df_header + le32_to_cpu(df_header->fek_offset);
1230 /* Decrypt the FEK. Note: This is done in place. */
1231 fek_size = ntfs_raw_fek_decrypt(fek_buf, fek_size, rsa_key);
1232 if (fek_size) {
1233 /* Convert the FEK to our internal format. */
1234 fek = ntfs_fek_import_from_raw(fek_buf, fek_size);
1235 if (fek)
1236 return fek;
1237 ntfs_log_error("Failed to convert the decrypted file "
1238 "encryption key to internal format.\n");
1239 } else
1240 ntfs_log_error("Failed to decrypt the file "
1241 "encryption key.\n");
1243 return NULL;
1247 * ntfs_inode_fek_get -
1249 static ntfs_fek *ntfs_inode_fek_get(ntfs_inode *inode,
1250 ntfs_rsa_private_key rsa_key, char *thumbprint,
1251 int thumbprint_size, NTFS_DF_TYPES df_type)
1253 EFS_ATTR_HEADER *efs;
1254 EFS_DF_ARRAY_HEADER *df_array = NULL;
1255 ntfs_fek *fek = NULL;
1257 /* Obtain the $EFS contents. */
1258 efs = ntfs_attr_readall(inode, AT_LOGGED_UTILITY_STREAM, EFS, 4, NULL);
1259 if (!efs) {
1260 ntfs_log_perror("Failed to read $EFS attribute");
1261 return NULL;
1264 * Depending on whether the key is a normal key or a data recovery key,
1265 * iterate through the DDF or DRF array, respectively.
1267 if (df_type == DF_TYPE_DDF) {
1268 if (efs->offset_to_ddf_array)
1269 df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs +
1270 le32_to_cpu(efs->offset_to_ddf_array));
1271 else
1272 ntfs_log_error("There are no entries in the DDF "
1273 "array.\n");
1274 } else if (df_type == DF_TYPE_DRF) {
1275 if (efs->offset_to_drf_array)
1276 df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs +
1277 le32_to_cpu(efs->offset_to_drf_array));
1278 else
1279 ntfs_log_error("There are no entries in the DRF "
1280 "array.\n");
1281 } else
1282 ntfs_log_error("Invalid DF type.\n");
1283 if (df_array)
1284 fek = ntfs_df_array_fek_get(df_array, rsa_key, thumbprint,
1285 thumbprint_size);
1286 free(efs);
1287 return fek;
1291 * ntfs_fek_decrypt_sector
1293 static int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset)
1295 gcry_error_t err;
1297 err = gcry_cipher_reset(fek->gcry_cipher_hd);
1298 if (err != GPG_ERR_NO_ERROR) {
1299 ntfs_log_error("Failed to reset cipher: %s\n",
1300 gcry_strerror(err));
1301 return -1;
1304 * Note: You may wonder why we are not calling gcry_cipher_setiv() here
1305 * instead of doing it by hand after the decryption. The answer is
1306 * that gcry_cipher_setiv() wants an iv of length 8 bytes but we give
1307 * it a length of 16 for AES256 so it does not like it.
1309 err = gcry_cipher_decrypt(fek->gcry_cipher_hd, data, 512, NULL, 0);
1310 if (err != GPG_ERR_NO_ERROR) {
1311 ntfs_log_error("Decryption failed: %s\n", gcry_strerror(err));
1312 return -1;
1314 /* Apply the IV. */
1315 if (fek->alg_id == CALG_AES_256) {
1316 ((le64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset);
1317 ((le64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset);
1318 } else {
1319 /* All other algos (Des, 3Des, DesX) use the same IV. */
1320 ((le64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset);
1322 return 512;
1326 * ntfs_cat_decrypt - Decrypt the contents of an encrypted file to stdout.
1327 * @inode: An encrypted file's inode structure, as obtained by
1328 * ntfs_inode_open().
1329 * @fek: A file encryption key. As obtained by ntfs_inode_fek_get().
1331 static int ntfs_cat_decrypt(ntfs_inode *inode, ntfs_fek *fek)
1333 int bufsize = 512;
1334 unsigned char *buffer;
1335 ntfs_attr *attr;
1336 s64 bytes_read, written, offset, total;
1337 s64 old_data_size, old_initialized_size;
1338 int i;
1340 buffer = malloc(bufsize);
1341 if (!buffer)
1342 return 1;
1343 attr = ntfs_attr_open(inode, AT_DATA, NULL, 0);
1344 if (!attr) {
1345 ntfs_log_error("Cannot cat a directory.\n");
1346 free(buffer);
1347 return 1;
1349 total = attr->data_size;
1351 // hack: make sure attr will not be commited to disk if you use this.
1352 // clear the encrypted bit, otherwise the library won't allow reading.
1353 NAttrClearEncrypted(attr);
1354 // extend the size, we may need to read past the end of the stream.
1355 old_data_size = attr->data_size;
1356 old_initialized_size = attr->initialized_size;
1357 attr->data_size = attr->initialized_size = attr->allocated_size;
1359 offset = 0;
1360 while (total > 0) {
1361 bytes_read = ntfs_attr_pread(attr, offset, 512, buffer);
1362 if (bytes_read == -1) {
1363 ntfs_log_perror("ERROR: Couldn't read file");
1364 break;
1366 if (!bytes_read)
1367 break;
1368 if ((i = ntfs_fek_decrypt_sector(fek, buffer, offset)) <
1369 bytes_read) {
1370 ntfs_log_perror("ERROR: Couldn't decrypt all data!");
1371 ntfs_log_error("%u/%lld/%lld/%lld\n", i,
1372 (long long)bytes_read, (long long)offset,
1373 (long long)total);
1374 break;
1376 if (bytes_read > total)
1377 bytes_read = total;
1378 written = fwrite(buffer, 1, bytes_read, stdout);
1379 if (written != bytes_read) {
1380 ntfs_log_perror("ERROR: Couldn't output all data!");
1381 break;
1383 offset += bytes_read;
1384 total -= bytes_read;
1386 attr->data_size = old_data_size;
1387 attr->initialized_size = old_initialized_size;
1388 NAttrSetEncrypted(attr);
1389 ntfs_attr_close(attr);
1390 free(buffer);
1391 return 0;
1395 * main - Begin here
1397 * Start from here.
1399 * Return: 0 Success, the program worked
1400 * 1 Error, something went wrong
1402 int main(int argc, char *argv[])
1404 u8 *pfx_buf;
1405 char *password;
1406 ntfs_rsa_private_key rsa_key;
1407 ntfs_volume *vol;
1408 ntfs_inode *inode;
1409 ntfs_fek *fek;
1410 unsigned pfx_size;
1411 int res;
1412 NTFS_DF_TYPES df_type;
1413 char thumbprint[NTFS_SHA1_THUMBPRINT_SIZE];
1415 ntfs_log_set_handler(ntfs_log_handler_stderr);
1417 if (!parse_options(argc, argv))
1418 return 1;
1419 utils_set_locale();
1421 /* Initialize crypto in ntfs. */
1422 if (ntfs_crypto_init()) {
1423 ntfs_log_error("Failed to initialize crypto. Aborting.\n");
1424 return 1;
1426 /* Load the PKCS#12 (.pfx) file containing the user's private key. */
1427 if (ntfs_pkcs12_load_pfxfile(opts.keyfile, &pfx_buf, &pfx_size)) {
1428 ntfs_log_error("Failed to load key file. Aborting.\n");
1429 ntfs_crypto_deinit();
1430 return 1;
1432 /* Ask the user for their password. */
1433 password = getpass("Enter the password with which the private key was "
1434 "encrypted: ");
1435 if (!password) {
1436 ntfs_log_perror("Failed to obtain user password");
1437 free(pfx_buf);
1438 ntfs_crypto_deinit();
1439 return 1;
1441 /* Obtain the user's private RSA key from the key file. */
1442 rsa_key = ntfs_pkcs12_extract_rsa_key(pfx_buf, pfx_size, password,
1443 thumbprint, sizeof(thumbprint), &df_type);
1444 /* Destroy the password. */
1445 memset(password, 0, strlen(password));
1446 /* No longer need the pfx file contents. */
1447 free(pfx_buf);
1448 if (!rsa_key) {
1449 ntfs_log_error("Failed to extract the private RSA key.\n");
1450 ntfs_crypto_deinit();
1451 return 1;
1453 /* Mount the ntfs volume. */
1454 vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY |
1455 (opts.force ? NTFS_MNT_RECOVER : 0));
1456 if (!vol) {
1457 ntfs_log_error("Failed to mount ntfs volume. Aborting.\n");
1458 ntfs_rsa_private_key_release(rsa_key);
1459 ntfs_crypto_deinit();
1460 return 1;
1462 /* Open the encrypted ntfs file. */
1463 if (opts.inode != -1)
1464 inode = ntfs_inode_open(vol, opts.inode);
1465 else
1466 inode = ntfs_pathname_to_inode(vol, NULL, opts.file);
1467 if (!inode) {
1468 ntfs_log_error("Failed to open encrypted file. Aborting.\n");
1469 ntfs_umount(vol, FALSE);
1470 ntfs_rsa_private_key_release(rsa_key);
1471 ntfs_crypto_deinit();
1472 return 1;
1474 /* Obtain the file encryption key of the encrypted file. */
1475 fek = ntfs_inode_fek_get(inode, rsa_key, thumbprint,
1476 sizeof(thumbprint), df_type);
1477 ntfs_rsa_private_key_release(rsa_key);
1478 if (fek) {
1479 res = ntfs_cat_decrypt(inode, fek);
1480 ntfs_fek_release(fek);
1481 } else {
1482 ntfs_log_error("Failed to obtain file encryption key. "
1483 "Aborting.\n");
1484 res = 1;
1486 ntfs_inode_close(inode);
1487 ntfs_umount(vol, FALSE);
1488 ntfs_crypto_deinit();
1489 return res;