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