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