1987da915Sopenharmony_ci/** 2987da915Sopenharmony_ci * ntfsdecrypt - Decrypt ntfs encrypted files. Part of the Linux-NTFS project. 3987da915Sopenharmony_ci * 4987da915Sopenharmony_ci * Copyright (c) 2005 Yuval Fledel 5987da915Sopenharmony_ci * Copyright (c) 2005-2007 Anton Altaparmakov 6987da915Sopenharmony_ci * Copyright (c) 2007 Yura Pakhuchiy 7987da915Sopenharmony_ci * Copyright (c) 2014-2015 Jean-Pierre Andre 8987da915Sopenharmony_ci * 9987da915Sopenharmony_ci * This utility will decrypt files and print the decrypted data on the standard 10987da915Sopenharmony_ci * output. 11987da915Sopenharmony_ci * 12987da915Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 13987da915Sopenharmony_ci * it under the terms of the GNU General Public License as published by 14987da915Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 15987da915Sopenharmony_ci * (at your option) any later version. 16987da915Sopenharmony_ci * 17987da915Sopenharmony_ci * This program is distributed in the hope that it will be useful, 18987da915Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 19987da915Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20987da915Sopenharmony_ci * GNU General Public License for more details. 21987da915Sopenharmony_ci * 22987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License 23987da915Sopenharmony_ci * along with this program (in the main directory of the Linux-NTFS 24987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software 25987da915Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 26987da915Sopenharmony_ci */ 27987da915Sopenharmony_ci 28987da915Sopenharmony_ci#include "config.h" 29987da915Sopenharmony_ci 30987da915Sopenharmony_ci#ifdef HAVE_SYS_TYPES_H 31987da915Sopenharmony_ci#include <sys/types.h> 32987da915Sopenharmony_ci#endif 33987da915Sopenharmony_ci#ifdef HAVE_SYS_STAT_H 34987da915Sopenharmony_ci#include <sys/stat.h> 35987da915Sopenharmony_ci#endif 36987da915Sopenharmony_ci#ifdef HAVE_FCNTL_H 37987da915Sopenharmony_ci#include <fcntl.h> 38987da915Sopenharmony_ci#endif 39987da915Sopenharmony_ci#ifdef HAVE_STDIO_H 40987da915Sopenharmony_ci#include <stdio.h> 41987da915Sopenharmony_ci#endif 42987da915Sopenharmony_ci#ifdef HAVE_GETOPT_H 43987da915Sopenharmony_ci#include <getopt.h> 44987da915Sopenharmony_ci#endif 45987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H 46987da915Sopenharmony_ci#include <stdlib.h> 47987da915Sopenharmony_ci#endif 48987da915Sopenharmony_ci#ifdef HAVE_STRING_H 49987da915Sopenharmony_ci#include <string.h> 50987da915Sopenharmony_ci#endif 51987da915Sopenharmony_ci#ifdef HAVE_UNISTD_H 52987da915Sopenharmony_ci#include <unistd.h> 53987da915Sopenharmony_ci#endif 54987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H 55987da915Sopenharmony_ci#include <errno.h> 56987da915Sopenharmony_ci#endif 57987da915Sopenharmony_ci#include <gcrypt.h> 58987da915Sopenharmony_ci#include <gnutls/pkcs12.h> 59987da915Sopenharmony_ci 60987da915Sopenharmony_ci#include "types.h" 61987da915Sopenharmony_ci#include "attrib.h" 62987da915Sopenharmony_ci#include "utils.h" 63987da915Sopenharmony_ci#include "volume.h" 64987da915Sopenharmony_ci#include "debug.h" 65987da915Sopenharmony_ci#include "dir.h" 66987da915Sopenharmony_ci#include "layout.h" 67987da915Sopenharmony_ci/* #include "version.h" */ 68987da915Sopenharmony_ci#include "misc.h" 69987da915Sopenharmony_ci 70987da915Sopenharmony_citypedef gcry_sexp_t ntfs_rsa_private_key; 71987da915Sopenharmony_ci 72987da915Sopenharmony_ci#define NTFS_SHA1_THUMBPRINT_SIZE 0x14 73987da915Sopenharmony_ci 74987da915Sopenharmony_ci#define NTFS_CRED_TYPE_CERT_THUMBPRINT const_cpu_to_le32(3) 75987da915Sopenharmony_ci 76987da915Sopenharmony_ci#define NTFS_EFS_CERT_PURPOSE_OID_DDF "1.3.6.1.4.1.311.10.3.4" /* decryption */ 77987da915Sopenharmony_ci#define NTFS_EFS_CERT_PURPOSE_OID_DRF "1.3.6.1.4.1.311.10.3.4.1" /* recovery */ 78987da915Sopenharmony_ci 79987da915Sopenharmony_citypedef enum { 80987da915Sopenharmony_ci DF_TYPE_UNKNOWN, 81987da915Sopenharmony_ci DF_TYPE_DDF, /* decryption */ 82987da915Sopenharmony_ci DF_TYPE_DRF, /* recovery */ 83987da915Sopenharmony_ci} NTFS_DF_TYPES; 84987da915Sopenharmony_ci 85987da915Sopenharmony_ci/** 86987da915Sopenharmony_ci * enum NTFS_CRYPTO_ALGORITHMS - List of crypto algorithms used by EFS (32 bit) 87987da915Sopenharmony_ci * 88987da915Sopenharmony_ci * To choose which one is used in Windows, create or set the REG_DWORD registry 89987da915Sopenharmony_ci * key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EFS\ 90987da915Sopenharmony_ci * AlgorithmID to the value of your chosen crypto algorithm, e.g. to use DesX, 91987da915Sopenharmony_ci * set AlgorithmID to 0x6604. 92987da915Sopenharmony_ci * 93987da915Sopenharmony_ci * Note that the Windows versions I have tried so far (all are high crypto 94987da915Sopenharmony_ci * enabled) ignore the AlgorithmID value if it is not one of CALG_3DES, 95987da915Sopenharmony_ci * CALG_DESX, or CALG_AES_256, i.e. you cannot select CALG_DES at all using 96987da915Sopenharmony_ci * this registry key. It would be interesting to check out encryption on one 97987da915Sopenharmony_ci * of the "crippled" crypto Windows versions... 98987da915Sopenharmony_ci */ 99987da915Sopenharmony_citypedef enum { 100987da915Sopenharmony_ci CALG_DES = const_cpu_to_le32(0x6601), 101987da915Sopenharmony_ci /* If not one of the below three, fall back to standard Des. */ 102987da915Sopenharmony_ci CALG_3DES = const_cpu_to_le32(0x6603), 103987da915Sopenharmony_ci CALG_DESX = const_cpu_to_le32(0x6604), 104987da915Sopenharmony_ci CALG_AES_256 = const_cpu_to_le32(0x6610), 105987da915Sopenharmony_ci} NTFS_CRYPTO_ALGORITHMS; 106987da915Sopenharmony_ci 107987da915Sopenharmony_citypedef struct { 108987da915Sopenharmony_ci u64 in_whitening, out_whitening; 109987da915Sopenharmony_ci u8 des_key[8]; 110987da915Sopenharmony_ci u64 prev_blk; 111987da915Sopenharmony_ci} ntfs_desx_ctx; 112987da915Sopenharmony_ci 113987da915Sopenharmony_ci/** 114987da915Sopenharmony_ci * struct ntfs_fek - Decrypted, in-memory file encryption key. 115987da915Sopenharmony_ci */ 116987da915Sopenharmony_ci 117987da915Sopenharmony_citypedef struct { 118987da915Sopenharmony_ci gcry_cipher_hd_t gcry_cipher_hd; 119987da915Sopenharmony_ci le32 alg_id; 120987da915Sopenharmony_ci u8 *key_data; 121987da915Sopenharmony_ci gcry_cipher_hd_t *des_gcry_cipher_hd_ptr; 122987da915Sopenharmony_ci ntfs_desx_ctx desx_ctx; 123987da915Sopenharmony_ci} ntfs_fek; 124987da915Sopenharmony_ci 125987da915Sopenharmony_cistruct options { 126987da915Sopenharmony_ci char *keyfile; /* .pfx file containing the user's private key. */ 127987da915Sopenharmony_ci char *device; /* Device/File to work with */ 128987da915Sopenharmony_ci char *file; /* File to display */ 129987da915Sopenharmony_ci s64 inode; /* Inode to work with */ 130987da915Sopenharmony_ci ATTR_TYPES attr; /* Attribute type to display */ 131987da915Sopenharmony_ci int force; /* Override common sense */ 132987da915Sopenharmony_ci int quiet; /* Less output */ 133987da915Sopenharmony_ci int verbose; /* Extra output */ 134987da915Sopenharmony_ci int encrypt; /* Encrypt */ 135987da915Sopenharmony_ci}; 136987da915Sopenharmony_ci 137987da915Sopenharmony_cistatic const char *EXEC_NAME = "ntfsdecrypt"; 138987da915Sopenharmony_cistatic struct options opts; 139987da915Sopenharmony_ci 140987da915Sopenharmony_cistatic ntfschar EFS[5] = { 141987da915Sopenharmony_ci const_cpu_to_le16('$'), const_cpu_to_le16('E'), const_cpu_to_le16('F'), 142987da915Sopenharmony_ci const_cpu_to_le16('S'), const_cpu_to_le16('\0') 143987da915Sopenharmony_ci}; 144987da915Sopenharmony_ci 145987da915Sopenharmony_ci/** 146987da915Sopenharmony_ci * version - Print version information about the program 147987da915Sopenharmony_ci * 148987da915Sopenharmony_ci * Print a copyright statement and a brief description of the program. 149987da915Sopenharmony_ci * 150987da915Sopenharmony_ci * Return: none 151987da915Sopenharmony_ci */ 152987da915Sopenharmony_cistatic void version(void) 153987da915Sopenharmony_ci{ 154987da915Sopenharmony_ci ntfs_log_info("\n%s v%s (libntfs-3g) - Decrypt files and print on the " 155987da915Sopenharmony_ci "standard output.\n\n", EXEC_NAME, VERSION); 156987da915Sopenharmony_ci ntfs_log_info("Copyright (c) 2005 Yuval Fledel\n"); 157987da915Sopenharmony_ci ntfs_log_info("Copyright (c) 2005 Anton Altaparmakov\n"); 158987da915Sopenharmony_ci ntfs_log_info("Copyright (c) 2014-2015 Jean-Pierre Andre\n"); 159987da915Sopenharmony_ci ntfs_log_info("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); 160987da915Sopenharmony_ci} 161987da915Sopenharmony_ci 162987da915Sopenharmony_ci/** 163987da915Sopenharmony_ci * usage - Print a list of the parameters to the program 164987da915Sopenharmony_ci * 165987da915Sopenharmony_ci * Print a list of the parameters and options for the program. 166987da915Sopenharmony_ci * 167987da915Sopenharmony_ci * Return: none 168987da915Sopenharmony_ci */ 169987da915Sopenharmony_cistatic void usage(void) 170987da915Sopenharmony_ci{ 171987da915Sopenharmony_ci ntfs_log_info("\nUsage: %s [options] -k name.pfx device [file]\n\n" 172987da915Sopenharmony_ci " -i, --inode num Display this inode\n\n" 173987da915Sopenharmony_ci " -k --keyfile name.pfx Use file name as the user's private key file.\n" 174987da915Sopenharmony_ci " -e --encrypt Update an encrypted file\n" 175987da915Sopenharmony_ci " -f --force Use less caution\n" 176987da915Sopenharmony_ci " -h --help Print this help\n" 177987da915Sopenharmony_ci " -q --quiet Less output\n" 178987da915Sopenharmony_ci " -V --version Version information\n" 179987da915Sopenharmony_ci " -v --verbose More output\n\n", 180987da915Sopenharmony_ci EXEC_NAME); 181987da915Sopenharmony_ci ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home); 182987da915Sopenharmony_ci} 183987da915Sopenharmony_ci 184987da915Sopenharmony_ci/** 185987da915Sopenharmony_ci * parse_options - Read and validate the programs command line 186987da915Sopenharmony_ci * 187987da915Sopenharmony_ci * Read the command line, verify the syntax and parse the options. 188987da915Sopenharmony_ci * This function is very long, but quite simple. 189987da915Sopenharmony_ci * 190987da915Sopenharmony_ci * Return: 1 Success 191987da915Sopenharmony_ci * 0 Error, one or more problems 192987da915Sopenharmony_ci */ 193987da915Sopenharmony_cistatic int parse_options(int argc, char **argv) 194987da915Sopenharmony_ci{ 195987da915Sopenharmony_ci static const char *sopt = "-fh?ei:k:qVv"; 196987da915Sopenharmony_ci static const struct option lopt[] = { 197987da915Sopenharmony_ci {"encrypt", no_argument, NULL, 'e'}, 198987da915Sopenharmony_ci {"force", no_argument, NULL, 'f'}, 199987da915Sopenharmony_ci {"help", no_argument, NULL, 'h'}, 200987da915Sopenharmony_ci {"inode", required_argument, NULL, 'i'}, 201987da915Sopenharmony_ci {"keyfile", required_argument, NULL, 'k'}, 202987da915Sopenharmony_ci {"quiet", no_argument, NULL, 'q'}, 203987da915Sopenharmony_ci {"version", no_argument, NULL, 'V'}, 204987da915Sopenharmony_ci {"verbose", no_argument, NULL, 'v'}, 205987da915Sopenharmony_ci {NULL, 0, NULL, 0} 206987da915Sopenharmony_ci }; 207987da915Sopenharmony_ci 208987da915Sopenharmony_ci int c = -1; 209987da915Sopenharmony_ci int err = 0; 210987da915Sopenharmony_ci int ver = 0; 211987da915Sopenharmony_ci int help = 0; 212987da915Sopenharmony_ci 213987da915Sopenharmony_ci opterr = 0; /* We'll handle the errors, thank you. */ 214987da915Sopenharmony_ci 215987da915Sopenharmony_ci opts.inode = -1; 216987da915Sopenharmony_ci 217987da915Sopenharmony_ci while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { 218987da915Sopenharmony_ci switch (c) { 219987da915Sopenharmony_ci case 1: /* A non-option argument */ 220987da915Sopenharmony_ci if (!opts.device) 221987da915Sopenharmony_ci opts.device = argv[optind - 1]; 222987da915Sopenharmony_ci else if (!opts.file) 223987da915Sopenharmony_ci opts.file = argv[optind - 1]; 224987da915Sopenharmony_ci else { 225987da915Sopenharmony_ci ntfs_log_error("You must specify exactly one " 226987da915Sopenharmony_ci "file.\n"); 227987da915Sopenharmony_ci err++; 228987da915Sopenharmony_ci } 229987da915Sopenharmony_ci break; 230987da915Sopenharmony_ci case 'e': 231987da915Sopenharmony_ci opts.encrypt++; 232987da915Sopenharmony_ci break; 233987da915Sopenharmony_ci case 'f': 234987da915Sopenharmony_ci opts.force++; 235987da915Sopenharmony_ci break; 236987da915Sopenharmony_ci case 'h': 237987da915Sopenharmony_ci help++; 238987da915Sopenharmony_ci break; 239987da915Sopenharmony_ci case 'k': 240987da915Sopenharmony_ci if (!opts.keyfile) 241987da915Sopenharmony_ci opts.keyfile = argv[optind - 1]; 242987da915Sopenharmony_ci else { 243987da915Sopenharmony_ci ntfs_log_error("You must specify exactly one " 244987da915Sopenharmony_ci "key file.\n"); 245987da915Sopenharmony_ci err++; 246987da915Sopenharmony_ci } 247987da915Sopenharmony_ci break; 248987da915Sopenharmony_ci case 'i': 249987da915Sopenharmony_ci if (opts.inode != -1) 250987da915Sopenharmony_ci ntfs_log_error("You must specify exactly one " 251987da915Sopenharmony_ci "inode.\n"); 252987da915Sopenharmony_ci else if (utils_parse_size(optarg, &opts.inode, FALSE)) 253987da915Sopenharmony_ci break; 254987da915Sopenharmony_ci else 255987da915Sopenharmony_ci ntfs_log_error("Couldn't parse inode number.\n"); 256987da915Sopenharmony_ci err++; 257987da915Sopenharmony_ci break; 258987da915Sopenharmony_ci case 'q': 259987da915Sopenharmony_ci opts.quiet++; 260987da915Sopenharmony_ci ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); 261987da915Sopenharmony_ci break; 262987da915Sopenharmony_ci case 'V': 263987da915Sopenharmony_ci ver++; 264987da915Sopenharmony_ci break; 265987da915Sopenharmony_ci case 'v': 266987da915Sopenharmony_ci opts.verbose++; 267987da915Sopenharmony_ci ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); 268987da915Sopenharmony_ci break; 269987da915Sopenharmony_ci case '?': 270987da915Sopenharmony_ci default: 271987da915Sopenharmony_ci ntfs_log_error("Unknown option '%s'.\n", 272987da915Sopenharmony_ci argv[optind - 1]); 273987da915Sopenharmony_ci err++; 274987da915Sopenharmony_ci break; 275987da915Sopenharmony_ci } 276987da915Sopenharmony_ci } 277987da915Sopenharmony_ci 278987da915Sopenharmony_ci if (help || ver) { 279987da915Sopenharmony_ci opts.quiet = 0; 280987da915Sopenharmony_ci ntfs_log_set_levels(NTFS_LOG_LEVEL_QUIET); 281987da915Sopenharmony_ci } else { 282987da915Sopenharmony_ci if (!opts.keyfile) { 283987da915Sopenharmony_ci ntfs_log_error("You must specify a key file.\n"); 284987da915Sopenharmony_ci err++; 285987da915Sopenharmony_ci } else if (opts.device == NULL) { 286987da915Sopenharmony_ci ntfs_log_error("You must specify a device.\n"); 287987da915Sopenharmony_ci err++; 288987da915Sopenharmony_ci } else if (opts.file == NULL && opts.inode == -1) { 289987da915Sopenharmony_ci ntfs_log_error("You must specify a file or inode with " 290987da915Sopenharmony_ci "the -i option.\n"); 291987da915Sopenharmony_ci err++; 292987da915Sopenharmony_ci } else if (opts.file != NULL && opts.inode != -1) { 293987da915Sopenharmony_ci ntfs_log_error("You can't specify both a file and " 294987da915Sopenharmony_ci "inode.\n"); 295987da915Sopenharmony_ci err++; 296987da915Sopenharmony_ci } 297987da915Sopenharmony_ci if (opts.quiet && opts.verbose) { 298987da915Sopenharmony_ci ntfs_log_error("You may not use --quiet and --verbose " 299987da915Sopenharmony_ci "at the same time.\n"); 300987da915Sopenharmony_ci err++; 301987da915Sopenharmony_ci } 302987da915Sopenharmony_ci } 303987da915Sopenharmony_ci 304987da915Sopenharmony_ci if (ver) 305987da915Sopenharmony_ci version(); 306987da915Sopenharmony_ci if (help || err) 307987da915Sopenharmony_ci usage(); 308987da915Sopenharmony_ci 309987da915Sopenharmony_ci /* tri-state 0 : done, 1 : error, -1 : proceed */ 310987da915Sopenharmony_ci return (err ? 1 : (help || ver ? 0 : -1)); 311987da915Sopenharmony_ci} 312987da915Sopenharmony_ci 313987da915Sopenharmony_ci/** 314987da915Sopenharmony_ci * ntfs_pkcs12_load_pfxfile 315987da915Sopenharmony_ci */ 316987da915Sopenharmony_cistatic int ntfs_pkcs12_load_pfxfile(const char *keyfile, u8 **pfx, 317987da915Sopenharmony_ci unsigned *pfx_size) 318987da915Sopenharmony_ci{ 319987da915Sopenharmony_ci int f, to_read, total, attempts, br; 320987da915Sopenharmony_ci struct stat key_stat; 321987da915Sopenharmony_ci 322987da915Sopenharmony_ci if (!keyfile || !pfx || !pfx_size) { 323987da915Sopenharmony_ci ntfs_log_error("You have to specify the key file, a pointer " 324987da915Sopenharmony_ci "to hold the key file contents, and a pointer " 325987da915Sopenharmony_ci "to hold the size of the key file contents.\n"); 326987da915Sopenharmony_ci return -1; 327987da915Sopenharmony_ci } 328987da915Sopenharmony_ci f = open(keyfile, O_RDONLY); 329987da915Sopenharmony_ci if (f == -1) { 330987da915Sopenharmony_ci ntfs_log_perror("Failed to open key file"); 331987da915Sopenharmony_ci return -1; 332987da915Sopenharmony_ci } 333987da915Sopenharmony_ci if (fstat(f, &key_stat) == -1) { 334987da915Sopenharmony_ci ntfs_log_perror("Failed to stat key file"); 335987da915Sopenharmony_ci goto file_out; 336987da915Sopenharmony_ci } 337987da915Sopenharmony_ci if (!S_ISREG(key_stat.st_mode)) { 338987da915Sopenharmony_ci ntfs_log_error("Key file is not a regular file, cannot read " 339987da915Sopenharmony_ci "it.\n"); 340987da915Sopenharmony_ci goto file_out; 341987da915Sopenharmony_ci } 342987da915Sopenharmony_ci if (!key_stat.st_size) { 343987da915Sopenharmony_ci ntfs_log_error("Key file has zero size.\n"); 344987da915Sopenharmony_ci goto file_out; 345987da915Sopenharmony_ci } 346987da915Sopenharmony_ci *pfx = malloc(key_stat.st_size + 1); 347987da915Sopenharmony_ci if (!*pfx) { 348987da915Sopenharmony_ci ntfs_log_perror("Failed to allocate buffer for key file " 349987da915Sopenharmony_ci "contents"); 350987da915Sopenharmony_ci goto file_out; 351987da915Sopenharmony_ci } 352987da915Sopenharmony_ci to_read = key_stat.st_size; 353987da915Sopenharmony_ci total = attempts = 0; 354987da915Sopenharmony_ci do { 355987da915Sopenharmony_ci br = read(f, *pfx + total, to_read); 356987da915Sopenharmony_ci if (br == -1) { 357987da915Sopenharmony_ci ntfs_log_perror("Failed to read from key file"); 358987da915Sopenharmony_ci goto free_out; 359987da915Sopenharmony_ci } 360987da915Sopenharmony_ci if (!br) 361987da915Sopenharmony_ci attempts++; 362987da915Sopenharmony_ci to_read -= br; 363987da915Sopenharmony_ci total += br; 364987da915Sopenharmony_ci } while (to_read > 0 && attempts < 3); 365987da915Sopenharmony_ci close(f); 366987da915Sopenharmony_ci /* Make sure it is zero terminated. */ 367987da915Sopenharmony_ci (*pfx)[key_stat.st_size] = 0; 368987da915Sopenharmony_ci *pfx_size = key_stat.st_size; 369987da915Sopenharmony_ci return 0; 370987da915Sopenharmony_cifree_out: 371987da915Sopenharmony_ci free(*pfx); 372987da915Sopenharmony_cifile_out: 373987da915Sopenharmony_ci close(f); 374987da915Sopenharmony_ci return -1; 375987da915Sopenharmony_ci} 376987da915Sopenharmony_ci 377987da915Sopenharmony_ci/** 378987da915Sopenharmony_ci * ntfs_crypto_init 379987da915Sopenharmony_ci */ 380987da915Sopenharmony_cistatic int ntfs_crypto_init(void) 381987da915Sopenharmony_ci{ 382987da915Sopenharmony_ci int err; 383987da915Sopenharmony_ci 384987da915Sopenharmony_ci /* Initialize gcrypt library. Note: Must come before GNU TLS init. */ 385987da915Sopenharmony_ci if (gcry_control(GCRYCTL_DISABLE_SECMEM, 0) != GPG_ERR_NO_ERROR) { 386987da915Sopenharmony_ci ntfs_log_error("Failed to initialize the gcrypt library.\n"); 387987da915Sopenharmony_ci return -1; 388987da915Sopenharmony_ci } 389987da915Sopenharmony_ci /* Initialize GNU TLS library. Note: Must come after libgcrypt init. */ 390987da915Sopenharmony_ci err = gnutls_global_init(); 391987da915Sopenharmony_ci if (err < 0) { 392987da915Sopenharmony_ci ntfs_log_error("Failed to initialize GNU TLS library: %s\n", 393987da915Sopenharmony_ci gnutls_strerror(err)); 394987da915Sopenharmony_ci return -1; 395987da915Sopenharmony_ci } 396987da915Sopenharmony_ci return 0; 397987da915Sopenharmony_ci} 398987da915Sopenharmony_ci 399987da915Sopenharmony_ci/** 400987da915Sopenharmony_ci * ntfs_crypto_deinit 401987da915Sopenharmony_ci */ 402987da915Sopenharmony_cistatic void ntfs_crypto_deinit(void) 403987da915Sopenharmony_ci{ 404987da915Sopenharmony_ci gnutls_global_deinit(); 405987da915Sopenharmony_ci} 406987da915Sopenharmony_ci 407987da915Sopenharmony_ci/** 408987da915Sopenharmony_ci * ntfs_rsa_private_key_import_from_gnutls 409987da915Sopenharmony_ci */ 410987da915Sopenharmony_cistatic ntfs_rsa_private_key ntfs_rsa_private_key_import_from_gnutls( 411987da915Sopenharmony_ci gnutls_x509_privkey_t priv_key) 412987da915Sopenharmony_ci{ 413987da915Sopenharmony_ci int i, j; 414987da915Sopenharmony_ci size_t tmp_size; 415987da915Sopenharmony_ci gnutls_datum_t rd[6]; 416987da915Sopenharmony_ci gcry_mpi_t rm[6]; 417987da915Sopenharmony_ci gcry_sexp_t rsa_key; 418987da915Sopenharmony_ci 419987da915Sopenharmony_ci /* Extract the RSA parameters from the GNU TLS private key. */ 420987da915Sopenharmony_ci if (gnutls_x509_privkey_export_rsa_raw(priv_key, &rd[0], &rd[1], 421987da915Sopenharmony_ci &rd[2], &rd[3], &rd[4], &rd[5])) { 422987da915Sopenharmony_ci ntfs_log_error("Failed to export rsa parameters. (Is the " 423987da915Sopenharmony_ci "key an RSA private key?)\n"); 424987da915Sopenharmony_ci return NULL; 425987da915Sopenharmony_ci } 426987da915Sopenharmony_ci /* Convert each RSA parameter to mpi format. */ 427987da915Sopenharmony_ci for (i = 0; i < 6; i++) { 428987da915Sopenharmony_ci if (gcry_mpi_scan(&rm[i], GCRYMPI_FMT_USG, rd[i].data, 429987da915Sopenharmony_ci rd[i].size, &tmp_size) != GPG_ERR_NO_ERROR) { 430987da915Sopenharmony_ci ntfs_log_error("Failed to convert RSA parameter %i " 431987da915Sopenharmony_ci "to mpi format (size %d)\n", i, 432987da915Sopenharmony_ci rd[i].size); 433987da915Sopenharmony_ci rsa_key = NULL; 434987da915Sopenharmony_ci break; 435987da915Sopenharmony_ci } 436987da915Sopenharmony_ci } 437987da915Sopenharmony_ci /* Release the no longer needed datum values. */ 438987da915Sopenharmony_ci for (j = 0; j < 6; j++) { 439987da915Sopenharmony_ci if (rd[j].data && rd[j].size) 440987da915Sopenharmony_ci gnutls_free(rd[j].data); 441987da915Sopenharmony_ci } 442987da915Sopenharmony_ci /* 443987da915Sopenharmony_ci * Build the gcrypt private key, note libgcrypt uses p and q inversed 444987da915Sopenharmony_ci * to what gnutls uses. 445987da915Sopenharmony_ci */ 446987da915Sopenharmony_ci if (i == 6 && gcry_sexp_build(&rsa_key, NULL, 447987da915Sopenharmony_ci "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))", 448987da915Sopenharmony_ci rm[0], rm[1], rm[2], rm[4], rm[3], rm[5]) != 449987da915Sopenharmony_ci GPG_ERR_NO_ERROR) { 450987da915Sopenharmony_ci ntfs_log_error("Failed to build RSA private key s-exp.\n"); 451987da915Sopenharmony_ci rsa_key = NULL; 452987da915Sopenharmony_ci } 453987da915Sopenharmony_ci /* Release the no longer needed mpi values. */ 454987da915Sopenharmony_ci for (j = 0; j < i; j++) 455987da915Sopenharmony_ci gcry_mpi_release(rm[j]); 456987da915Sopenharmony_ci return (ntfs_rsa_private_key)rsa_key; 457987da915Sopenharmony_ci} 458987da915Sopenharmony_ci 459987da915Sopenharmony_ci/** 460987da915Sopenharmony_ci * ntfs_rsa_private_key_release 461987da915Sopenharmony_ci */ 462987da915Sopenharmony_cistatic void ntfs_rsa_private_key_release(ntfs_rsa_private_key rsa_key) 463987da915Sopenharmony_ci{ 464987da915Sopenharmony_ci gcry_sexp_release((gcry_sexp_t)rsa_key); 465987da915Sopenharmony_ci} 466987da915Sopenharmony_ci 467987da915Sopenharmony_ci/** 468987da915Sopenharmony_ci * ntfs_pkcs12_extract_rsa_key 469987da915Sopenharmony_ci */ 470987da915Sopenharmony_cistatic ntfs_rsa_private_key ntfs_pkcs12_extract_rsa_key(u8 *pfx, int pfx_size, 471987da915Sopenharmony_ci char *password, char *thumbprint, int thumbprint_size, 472987da915Sopenharmony_ci NTFS_DF_TYPES *df_type) 473987da915Sopenharmony_ci{ 474987da915Sopenharmony_ci int err, bag_index, flags; 475987da915Sopenharmony_ci gnutls_datum_t dpfx, dkey; 476987da915Sopenharmony_ci gnutls_pkcs12_t pkcs12 = NULL; 477987da915Sopenharmony_ci gnutls_pkcs12_bag_t bag = NULL; 478987da915Sopenharmony_ci gnutls_x509_privkey_t pkey = NULL; 479987da915Sopenharmony_ci gnutls_x509_crt_t crt = NULL; 480987da915Sopenharmony_ci ntfs_rsa_private_key rsa_key = NULL; 481987da915Sopenharmony_ci char purpose_oid[100]; 482987da915Sopenharmony_ci size_t purpose_oid_size = sizeof(purpose_oid); 483987da915Sopenharmony_ci int oid_index; 484987da915Sopenharmony_ci size_t tp_size = thumbprint_size; 485987da915Sopenharmony_ci BOOL have_thumbprint = FALSE; 486987da915Sopenharmony_ci 487987da915Sopenharmony_ci *df_type = DF_TYPE_UNKNOWN; 488987da915Sopenharmony_ci /* Create a pkcs12 structure. */ 489987da915Sopenharmony_ci err = gnutls_pkcs12_init(&pkcs12); 490987da915Sopenharmony_ci if (err) { 491987da915Sopenharmony_ci ntfs_log_error("Failed to initialize PKCS#12 structure: %s\n", 492987da915Sopenharmony_ci gnutls_strerror(err)); 493987da915Sopenharmony_ci return NULL; 494987da915Sopenharmony_ci } 495987da915Sopenharmony_ci /* Convert the PFX file (DER format) to native pkcs12 format. */ 496987da915Sopenharmony_ci dpfx.data = pfx; 497987da915Sopenharmony_ci dpfx.size = pfx_size; 498987da915Sopenharmony_ci err = gnutls_pkcs12_import(pkcs12, &dpfx, GNUTLS_X509_FMT_DER, 0); 499987da915Sopenharmony_ci if (err) { 500987da915Sopenharmony_ci ntfs_log_error("Failed to convert the PFX file from DER to " 501987da915Sopenharmony_ci "native PKCS#12 format: %s\n", 502987da915Sopenharmony_ci gnutls_strerror(err)); 503987da915Sopenharmony_ci goto err; 504987da915Sopenharmony_ci } 505987da915Sopenharmony_ci /* 506987da915Sopenharmony_ci * Verify that the password is correct and that the key file has not 507987da915Sopenharmony_ci * been tampered with. Note if the password has zero length and the 508987da915Sopenharmony_ci * verification fails, retry with password set to NULL. This is needed 509987da915Sopenharmony_ci * to get passwordless .pfx files generated with Windows XP SP1 (and 510987da915Sopenharmony_ci * probably earlier versions of Windows) to work. 511987da915Sopenharmony_ci */ 512987da915Sopenharmony_ciretry_verify: 513987da915Sopenharmony_ci err = gnutls_pkcs12_verify_mac(pkcs12, password); 514987da915Sopenharmony_ci if (err) { 515987da915Sopenharmony_ci if (err == GNUTLS_E_MAC_VERIFY_FAILED && 516987da915Sopenharmony_ci password && !strlen(password)) { 517987da915Sopenharmony_ci password = NULL; 518987da915Sopenharmony_ci goto retry_verify; 519987da915Sopenharmony_ci } 520987da915Sopenharmony_ci ntfs_log_error("Failed to verify the MAC: %s Is the " 521987da915Sopenharmony_ci "password correct?\n", gnutls_strerror(err)); 522987da915Sopenharmony_ci goto err; 523987da915Sopenharmony_ci } 524987da915Sopenharmony_ci for (bag_index = 0; ; bag_index++) { 525987da915Sopenharmony_ci err = gnutls_pkcs12_bag_init(&bag); 526987da915Sopenharmony_ci if (err) { 527987da915Sopenharmony_ci ntfs_log_error("Failed to initialize PKCS#12 Bag " 528987da915Sopenharmony_ci "structure: %s\n", 529987da915Sopenharmony_ci gnutls_strerror(err)); 530987da915Sopenharmony_ci goto err; 531987da915Sopenharmony_ci } 532987da915Sopenharmony_ci err = gnutls_pkcs12_get_bag(pkcs12, bag_index, bag); 533987da915Sopenharmony_ci if (err) { 534987da915Sopenharmony_ci if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { 535987da915Sopenharmony_ci err = 0; 536987da915Sopenharmony_ci break; 537987da915Sopenharmony_ci } 538987da915Sopenharmony_ci ntfs_log_error("Failed to obtain Bag from PKCS#12 " 539987da915Sopenharmony_ci "structure: %s\n", 540987da915Sopenharmony_ci gnutls_strerror(err)); 541987da915Sopenharmony_ci goto err; 542987da915Sopenharmony_ci } 543987da915Sopenharmony_cicheck_again: 544987da915Sopenharmony_ci err = gnutls_pkcs12_bag_get_count(bag); 545987da915Sopenharmony_ci if (err < 0) { 546987da915Sopenharmony_ci ntfs_log_error("Failed to obtain Bag count: %s\n", 547987da915Sopenharmony_ci gnutls_strerror(err)); 548987da915Sopenharmony_ci goto err; 549987da915Sopenharmony_ci } 550987da915Sopenharmony_ci err = gnutls_pkcs12_bag_get_type(bag, 0); 551987da915Sopenharmony_ci if (err < 0) { 552987da915Sopenharmony_ci ntfs_log_error("Failed to determine Bag type: %s\n", 553987da915Sopenharmony_ci gnutls_strerror(err)); 554987da915Sopenharmony_ci goto err; 555987da915Sopenharmony_ci } 556987da915Sopenharmony_ci flags = 0; 557987da915Sopenharmony_ci switch (err) { 558987da915Sopenharmony_ci case GNUTLS_BAG_PKCS8_KEY: 559987da915Sopenharmony_ci flags = GNUTLS_PKCS_PLAIN; 560987da915Sopenharmony_ci /* FALLTHRU */ 561987da915Sopenharmony_ci case GNUTLS_BAG_PKCS8_ENCRYPTED_KEY: 562987da915Sopenharmony_ci err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey); 563987da915Sopenharmony_ci if (err < 0) { 564987da915Sopenharmony_ci ntfs_log_error("Failed to obtain Bag data: " 565987da915Sopenharmony_ci "%s\n", gnutls_strerror(err)); 566987da915Sopenharmony_ci goto err; 567987da915Sopenharmony_ci } 568987da915Sopenharmony_ci err = gnutls_x509_privkey_init(&pkey); 569987da915Sopenharmony_ci if (err) { 570987da915Sopenharmony_ci ntfs_log_error("Failed to initialized " 571987da915Sopenharmony_ci "private key structure: %s\n", 572987da915Sopenharmony_ci gnutls_strerror(err)); 573987da915Sopenharmony_ci goto err; 574987da915Sopenharmony_ci } 575987da915Sopenharmony_ci /* Decrypt the private key into GNU TLS format. */ 576987da915Sopenharmony_ci err = gnutls_x509_privkey_import_pkcs8(pkey, &dkey, 577987da915Sopenharmony_ci GNUTLS_X509_FMT_DER, password, flags); 578987da915Sopenharmony_ci if (err) { 579987da915Sopenharmony_ci ntfs_log_error("Failed to convert private " 580987da915Sopenharmony_ci "key from DER to GNU TLS " 581987da915Sopenharmony_ci "format: %s\n", 582987da915Sopenharmony_ci gnutls_strerror(err)); 583987da915Sopenharmony_ci goto err; 584987da915Sopenharmony_ci } 585987da915Sopenharmony_ci#if 0 586987da915Sopenharmony_ci /* 587987da915Sopenharmony_ci * Export the key again, but unencrypted, and output it 588987da915Sopenharmony_ci * to stderr. Note the output has an RSA header so to 589987da915Sopenharmony_ci * compare to openssl pkcs12 -nodes -in myfile.pfx 590987da915Sopenharmony_ci * output need to ignore the part of the key between 591987da915Sopenharmony_ci * the first "MII..." up to the second "MII...". The 592987da915Sopenharmony_ci * actual RSA private key begins at the second "MII..." 593987da915Sopenharmony_ci * and in my testing at least was identical to openssl 594987da915Sopenharmony_ci * output and was also identical both on big and little 595987da915Sopenharmony_ci * endian so gnutls should be endianness safe. 596987da915Sopenharmony_ci */ 597987da915Sopenharmony_ci char *buf = malloc(8192); 598987da915Sopenharmony_ci size_t bufsize = 8192; 599987da915Sopenharmony_ci err = gnutls_x509_privkey_export_pkcs8(pkey, 600987da915Sopenharmony_ci GNUTLS_X509_FMT_PEM, "", GNUTLS_PKCS_PLAIN, buf, 601987da915Sopenharmony_ci &bufsize); 602987da915Sopenharmony_ci if (err) { 603987da915Sopenharmony_ci ntfs_log_error("eek1\n"); 604987da915Sopenharmony_ci exit(1); 605987da915Sopenharmony_ci } 606987da915Sopenharmony_ci ntfs_log_error("%s\n", buf); 607987da915Sopenharmony_ci free(buf); 608987da915Sopenharmony_ci#endif 609987da915Sopenharmony_ci /* Convert the private key to our internal format. */ 610987da915Sopenharmony_ci rsa_key = ntfs_rsa_private_key_import_from_gnutls(pkey); 611987da915Sopenharmony_ci if (!rsa_key) 612987da915Sopenharmony_ci goto err; 613987da915Sopenharmony_ci break; 614987da915Sopenharmony_ci case GNUTLS_BAG_ENCRYPTED: 615987da915Sopenharmony_ci err = gnutls_pkcs12_bag_decrypt(bag, password); 616987da915Sopenharmony_ci if (err) { 617987da915Sopenharmony_ci ntfs_log_error("Failed to decrypt Bag: %s\n", 618987da915Sopenharmony_ci gnutls_strerror(err)); 619987da915Sopenharmony_ci goto err; 620987da915Sopenharmony_ci } 621987da915Sopenharmony_ci goto check_again; 622987da915Sopenharmony_ci case GNUTLS_BAG_CERTIFICATE: 623987da915Sopenharmony_ci err = gnutls_pkcs12_bag_get_data(bag, 0, &dkey); 624987da915Sopenharmony_ci if (err < 0) { 625987da915Sopenharmony_ci ntfs_log_error("Failed to obtain Bag data: " 626987da915Sopenharmony_ci "%s\n", gnutls_strerror(err)); 627987da915Sopenharmony_ci goto err; 628987da915Sopenharmony_ci } 629987da915Sopenharmony_ci err = gnutls_x509_crt_init(&crt); 630987da915Sopenharmony_ci if (err) { 631987da915Sopenharmony_ci ntfs_log_error("Failed to initialize " 632987da915Sopenharmony_ci "certificate structure: %s\n", 633987da915Sopenharmony_ci gnutls_strerror(err)); 634987da915Sopenharmony_ci goto err; 635987da915Sopenharmony_ci } 636987da915Sopenharmony_ci err = gnutls_x509_crt_import(crt, &dkey, 637987da915Sopenharmony_ci GNUTLS_X509_FMT_DER); 638987da915Sopenharmony_ci if (err) { 639987da915Sopenharmony_ci ntfs_log_error("Failed to convert certificate " 640987da915Sopenharmony_ci "from DER to GNU TLS format: " 641987da915Sopenharmony_ci "%s\n", gnutls_strerror(err)); 642987da915Sopenharmony_ci goto err; 643987da915Sopenharmony_ci } 644987da915Sopenharmony_ci oid_index = 0; 645987da915Sopenharmony_ci /* 646987da915Sopenharmony_ci * Search in the key purposes for an EFS 647987da915Sopenharmony_ci * encryption purpose or an EFS recovery 648987da915Sopenharmony_ci * purpose, and use the first one found. 649987da915Sopenharmony_ci */ 650987da915Sopenharmony_ci do { 651987da915Sopenharmony_ci purpose_oid_size = sizeof(purpose_oid); 652987da915Sopenharmony_ci err = gnutls_x509_crt_get_key_purpose_oid(crt, 653987da915Sopenharmony_ci oid_index, 654987da915Sopenharmony_ci purpose_oid, &purpose_oid_size, NULL); 655987da915Sopenharmony_ci if (!err) { 656987da915Sopenharmony_ci purpose_oid[purpose_oid_size - 1] 657987da915Sopenharmony_ci = '\0'; 658987da915Sopenharmony_ci if (!strcmp(purpose_oid, 659987da915Sopenharmony_ci NTFS_EFS_CERT_PURPOSE_OID_DRF)) 660987da915Sopenharmony_ci *df_type = DF_TYPE_DRF; 661987da915Sopenharmony_ci else if (!strcmp(purpose_oid, 662987da915Sopenharmony_ci NTFS_EFS_CERT_PURPOSE_OID_DDF)) 663987da915Sopenharmony_ci *df_type = DF_TYPE_DDF; 664987da915Sopenharmony_ci else 665987da915Sopenharmony_ci oid_index++; 666987da915Sopenharmony_ci } 667987da915Sopenharmony_ci } while (!err && (*df_type == DF_TYPE_UNKNOWN)); 668987da915Sopenharmony_ci if (*df_type == DF_TYPE_UNKNOWN) { 669987da915Sopenharmony_ci /* End of list reached ? */ 670987da915Sopenharmony_ci if (err 671987da915Sopenharmony_ci == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) 672987da915Sopenharmony_ci ntfs_log_error("Key does not have an " 673987da915Sopenharmony_ci "EFS purpose OID\n"); 674987da915Sopenharmony_ci else 675987da915Sopenharmony_ci ntfs_log_error("Failed to get a key " 676987da915Sopenharmony_ci "purpose OID : %s ", 677987da915Sopenharmony_ci gnutls_strerror(err)); 678987da915Sopenharmony_ci goto err; 679987da915Sopenharmony_ci } 680987da915Sopenharmony_ci /* Return the thumbprint to the caller. */ 681987da915Sopenharmony_ci err = gnutls_x509_crt_get_fingerprint(crt, 682987da915Sopenharmony_ci GNUTLS_DIG_SHA1, thumbprint, &tp_size); 683987da915Sopenharmony_ci if (err) { 684987da915Sopenharmony_ci ntfs_log_error("Failed to get thumbprint: " 685987da915Sopenharmony_ci "%s\n", gnutls_strerror(err)); 686987da915Sopenharmony_ci goto err; 687987da915Sopenharmony_ci } 688987da915Sopenharmony_ci if (tp_size != NTFS_SHA1_THUMBPRINT_SIZE) { 689987da915Sopenharmony_ci ntfs_log_error("Invalid thumbprint size %zd. " 690987da915Sopenharmony_ci "Should be %d.\n", tp_size, 691987da915Sopenharmony_ci thumbprint_size); 692987da915Sopenharmony_ci err = EINVAL; 693987da915Sopenharmony_ci goto err; 694987da915Sopenharmony_ci } 695987da915Sopenharmony_ci have_thumbprint = TRUE; 696987da915Sopenharmony_ci gnutls_x509_crt_deinit(crt); 697987da915Sopenharmony_ci crt = NULL; 698987da915Sopenharmony_ci break; 699987da915Sopenharmony_ci default: 700987da915Sopenharmony_ci /* We do not care about other types. */ 701987da915Sopenharmony_ci break; 702987da915Sopenharmony_ci } 703987da915Sopenharmony_ci gnutls_pkcs12_bag_deinit(bag); 704987da915Sopenharmony_ci } 705987da915Sopenharmony_cierr: 706987da915Sopenharmony_ci if (rsa_key && (err || *df_type == DF_TYPE_UNKNOWN || 707987da915Sopenharmony_ci !have_thumbprint)) { 708987da915Sopenharmony_ci if (!err) 709987da915Sopenharmony_ci ntfs_log_error("Key type or thumbprint not found, " 710987da915Sopenharmony_ci "aborting.\n"); 711987da915Sopenharmony_ci ntfs_rsa_private_key_release(rsa_key); 712987da915Sopenharmony_ci rsa_key = NULL; 713987da915Sopenharmony_ci } 714987da915Sopenharmony_ci if (crt) 715987da915Sopenharmony_ci gnutls_x509_crt_deinit(crt); 716987da915Sopenharmony_ci if (pkey) 717987da915Sopenharmony_ci gnutls_x509_privkey_deinit(pkey); 718987da915Sopenharmony_ci if (bag) 719987da915Sopenharmony_ci gnutls_pkcs12_bag_deinit(bag); 720987da915Sopenharmony_ci if (pkcs12) 721987da915Sopenharmony_ci gnutls_pkcs12_deinit(pkcs12); 722987da915Sopenharmony_ci return rsa_key; 723987da915Sopenharmony_ci} 724987da915Sopenharmony_ci 725987da915Sopenharmony_ci/** 726987da915Sopenharmony_ci * ntfs_buffer_reverse - 727987da915Sopenharmony_ci * 728987da915Sopenharmony_ci * This is a utility function for reversing the order of a buffer in place. 729987da915Sopenharmony_ci * Users of this function should be very careful not to sweep byte order 730987da915Sopenharmony_ci * problems under the rug. 731987da915Sopenharmony_ci */ 732987da915Sopenharmony_cistatic inline void ntfs_buffer_reverse(u8 *buf, unsigned buf_size) 733987da915Sopenharmony_ci{ 734987da915Sopenharmony_ci unsigned i; 735987da915Sopenharmony_ci u8 t; 736987da915Sopenharmony_ci 737987da915Sopenharmony_ci for (i = 0; i < buf_size / 2; i++) { 738987da915Sopenharmony_ci t = buf[i]; 739987da915Sopenharmony_ci buf[i] = buf[buf_size - i - 1]; 740987da915Sopenharmony_ci buf[buf_size - i - 1] = t; 741987da915Sopenharmony_ci } 742987da915Sopenharmony_ci} 743987da915Sopenharmony_ci 744987da915Sopenharmony_ci#ifndef HAVE_STRNLEN 745987da915Sopenharmony_ci/** 746987da915Sopenharmony_ci * strnlen - strnlen is a gnu extension so emulate it if not present 747987da915Sopenharmony_ci */ 748987da915Sopenharmony_cistatic size_t strnlen(const char *s, size_t maxlen) 749987da915Sopenharmony_ci{ 750987da915Sopenharmony_ci const char *p, *end; 751987da915Sopenharmony_ci 752987da915Sopenharmony_ci /* Look for a '\0' character. */ 753987da915Sopenharmony_ci for (p = s, end = s + maxlen; p < end && *p; p++) 754987da915Sopenharmony_ci ; 755987da915Sopenharmony_ci return p - s; 756987da915Sopenharmony_ci} 757987da915Sopenharmony_ci#endif /* ! HAVE_STRNLEN */ 758987da915Sopenharmony_ci 759987da915Sopenharmony_ci/** 760987da915Sopenharmony_ci * ntfs_raw_fek_decrypt - 761987da915Sopenharmony_ci * 762987da915Sopenharmony_ci * Note: decrypting into the input buffer. 763987da915Sopenharmony_ci */ 764987da915Sopenharmony_cistatic unsigned ntfs_raw_fek_decrypt(u8 *fek, u32 fek_size, 765987da915Sopenharmony_ci ntfs_rsa_private_key rsa_key) 766987da915Sopenharmony_ci{ 767987da915Sopenharmony_ci gcry_mpi_t fek_mpi; 768987da915Sopenharmony_ci gcry_sexp_t fek_sexp, fek_sexp2; 769987da915Sopenharmony_ci gcry_error_t err; 770987da915Sopenharmony_ci size_t size, padding; 771987da915Sopenharmony_ci 772987da915Sopenharmony_ci /* Reverse the raw FEK. */ 773987da915Sopenharmony_ci ntfs_buffer_reverse(fek, fek_size); 774987da915Sopenharmony_ci /* Convert the FEK to internal MPI format. */ 775987da915Sopenharmony_ci err = gcry_mpi_scan(&fek_mpi, GCRYMPI_FMT_USG, fek, fek_size, NULL); 776987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 777987da915Sopenharmony_ci ntfs_log_error("Failed to convert file encryption key to " 778987da915Sopenharmony_ci "internal MPI format: %s\n", 779987da915Sopenharmony_ci gcry_strerror(err)); 780987da915Sopenharmony_ci return 0; 781987da915Sopenharmony_ci } 782987da915Sopenharmony_ci /* Create an internal S-expression from the FEK. */ 783987da915Sopenharmony_ci err = gcry_sexp_build(&fek_sexp, NULL, 784987da915Sopenharmony_ci "(enc-val (flags) (rsa (a %m)))", fek_mpi); 785987da915Sopenharmony_ci gcry_mpi_release(fek_mpi); 786987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 787987da915Sopenharmony_ci ntfs_log_error("Failed to create internal S-expression of " 788987da915Sopenharmony_ci "the file encryption key: %s\n", 789987da915Sopenharmony_ci gcry_strerror(err)); 790987da915Sopenharmony_ci return 0; 791987da915Sopenharmony_ci } 792987da915Sopenharmony_ci /* Decrypt the FEK. */ 793987da915Sopenharmony_ci err = gcry_pk_decrypt(&fek_sexp2, fek_sexp, (gcry_sexp_t)rsa_key); 794987da915Sopenharmony_ci gcry_sexp_release(fek_sexp); 795987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 796987da915Sopenharmony_ci ntfs_log_error("Failed to decrypt the file encryption key: " 797987da915Sopenharmony_ci "%s\n", gcry_strerror(err)); 798987da915Sopenharmony_ci return 0; 799987da915Sopenharmony_ci } 800987da915Sopenharmony_ci /* Extract the actual FEK from the decrypted raw S-expression. */ 801987da915Sopenharmony_ci fek_sexp = gcry_sexp_find_token(fek_sexp2, "value", 0); 802987da915Sopenharmony_ci gcry_sexp_release(fek_sexp2); 803987da915Sopenharmony_ci if (!fek_sexp) { 804987da915Sopenharmony_ci ntfs_log_error("Failed to find the decrypted file encryption " 805987da915Sopenharmony_ci "key in the internal S-expression.\n"); 806987da915Sopenharmony_ci return 0; 807987da915Sopenharmony_ci } 808987da915Sopenharmony_ci /* Convert the decrypted FEK S-expression into MPI format. */ 809987da915Sopenharmony_ci fek_mpi = gcry_sexp_nth_mpi(fek_sexp, 1, GCRYMPI_FMT_USG); 810987da915Sopenharmony_ci gcry_sexp_release(fek_sexp); 811987da915Sopenharmony_ci if (!fek_mpi) { 812987da915Sopenharmony_ci ntfs_log_error("Failed to convert the decrypted file " 813987da915Sopenharmony_ci "encryption key S-expression to internal MPI " 814987da915Sopenharmony_ci "format.\n"); 815987da915Sopenharmony_ci return 0; 816987da915Sopenharmony_ci } 817987da915Sopenharmony_ci /* Convert the decrypted FEK from MPI format to binary data. */ 818987da915Sopenharmony_ci err = gcry_mpi_print(GCRYMPI_FMT_USG, fek, fek_size, &size, fek_mpi); 819987da915Sopenharmony_ci gcry_mpi_release(fek_mpi); 820987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR || !size) { 821987da915Sopenharmony_ci ntfs_log_error("Failed to convert decrypted file encryption " 822987da915Sopenharmony_ci "key from internal MPI format to binary data: " 823987da915Sopenharmony_ci "%s\n", gcry_strerror(err)); 824987da915Sopenharmony_ci return 0; 825987da915Sopenharmony_ci } 826987da915Sopenharmony_ci /* 827987da915Sopenharmony_ci * Finally, remove the PKCS#1 padding and return the size of the 828987da915Sopenharmony_ci * decrypted FEK. 829987da915Sopenharmony_ci */ 830987da915Sopenharmony_ci padding = strnlen((char *)fek, size) + 1; 831987da915Sopenharmony_ci if (padding > size) { 832987da915Sopenharmony_ci ntfs_log_error("Failed to remove PKCS#1 padding from " 833987da915Sopenharmony_ci "decrypted file encryption key.\n"); 834987da915Sopenharmony_ci return 0; 835987da915Sopenharmony_ci } 836987da915Sopenharmony_ci size -= padding; 837987da915Sopenharmony_ci memmove(fek, fek + padding, size); 838987da915Sopenharmony_ci return size; 839987da915Sopenharmony_ci} 840987da915Sopenharmony_ci 841987da915Sopenharmony_ci/** 842987da915Sopenharmony_ci * ntfs_desx_key_expand - expand a 128-bit desx key to the needed 192-bit key 843987da915Sopenharmony_ci * @src: source buffer containing 128-bit key 844987da915Sopenharmony_ci * 845987da915Sopenharmony_ci * Expands the on-disk 128-bit desx key to the needed des key, the in-, and the 846987da915Sopenharmony_ci * out-whitening keys required to perform desx {de,en}cryption. 847987da915Sopenharmony_ci */ 848987da915Sopenharmony_cistatic gcry_error_t ntfs_desx_key_expand(const u8 *src, u32 *des_key, 849987da915Sopenharmony_ci u64 *out_whitening, u64 *in_whitening) 850987da915Sopenharmony_ci{ 851987da915Sopenharmony_ci static const u8 *salt1 = (const u8*)"Dan Simon "; 852987da915Sopenharmony_ci static const u8 *salt2 = (const u8*)"Scott Field"; 853987da915Sopenharmony_ci static const int salt_len = 12; 854987da915Sopenharmony_ci gcry_md_hd_t hd1, hd2; 855987da915Sopenharmony_ci u32 *md; 856987da915Sopenharmony_ci gcry_error_t err; 857987da915Sopenharmony_ci 858987da915Sopenharmony_ci err = gcry_md_open(&hd1, GCRY_MD_MD5, 0); 859987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 860987da915Sopenharmony_ci ntfs_log_error("Failed to open MD5 digest.\n"); 861987da915Sopenharmony_ci return err; 862987da915Sopenharmony_ci } 863987da915Sopenharmony_ci /* Hash the on-disk key. */ 864987da915Sopenharmony_ci gcry_md_write(hd1, src, 128 / 8); 865987da915Sopenharmony_ci /* Copy the current hash for efficiency. */ 866987da915Sopenharmony_ci err = gcry_md_copy(&hd2, hd1); 867987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 868987da915Sopenharmony_ci ntfs_log_error("Failed to copy MD5 digest object.\n"); 869987da915Sopenharmony_ci goto out; 870987da915Sopenharmony_ci } 871987da915Sopenharmony_ci /* Hash with the first salt and store the result. */ 872987da915Sopenharmony_ci gcry_md_write(hd1, salt1, salt_len); 873987da915Sopenharmony_ci md = (u32*)gcry_md_read(hd1, 0); 874987da915Sopenharmony_ci des_key[0] = md[0] ^ md[1]; 875987da915Sopenharmony_ci des_key[1] = md[2] ^ md[3]; 876987da915Sopenharmony_ci /* Hash with the second salt and store the result. */ 877987da915Sopenharmony_ci gcry_md_write(hd2, salt2, salt_len); 878987da915Sopenharmony_ci md = (u32*)gcry_md_read(hd2, 0); 879987da915Sopenharmony_ci *out_whitening = *(u64*)md; 880987da915Sopenharmony_ci *in_whitening = *(u64*)(md + 2); 881987da915Sopenharmony_ci gcry_md_close(hd2); 882987da915Sopenharmony_ciout: 883987da915Sopenharmony_ci gcry_md_close(hd1); 884987da915Sopenharmony_ci return err; 885987da915Sopenharmony_ci} 886987da915Sopenharmony_ci 887987da915Sopenharmony_ci/** 888987da915Sopenharmony_ci * ntfs_desx_decrypt 889987da915Sopenharmony_ci */ 890987da915Sopenharmony_cistatic gcry_error_t ntfs_desx_decrypt(ntfs_fek *fek, u8 *outbuf, 891987da915Sopenharmony_ci const u8 *inbuf) 892987da915Sopenharmony_ci{ 893987da915Sopenharmony_ci gcry_error_t err; 894987da915Sopenharmony_ci u64 curr_blk; 895987da915Sopenharmony_ci ntfs_desx_ctx *ctx = &fek->desx_ctx; 896987da915Sopenharmony_ci 897987da915Sopenharmony_ci curr_blk = *(const u64*)inbuf; 898987da915Sopenharmony_ci *(u64*)outbuf = curr_blk ^ ctx->out_whitening; 899987da915Sopenharmony_ci err = gcry_cipher_encrypt(fek->gcry_cipher_hd, outbuf, 8, NULL, 0); 900987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) 901987da915Sopenharmony_ci ntfs_log_error("Des decryption failed (error 0x%x).\n", err); 902987da915Sopenharmony_ci *(u64*)outbuf ^= ctx->in_whitening ^ ctx->prev_blk; 903987da915Sopenharmony_ci ctx->prev_blk = curr_blk; 904987da915Sopenharmony_ci return (err); 905987da915Sopenharmony_ci} 906987da915Sopenharmony_ci 907987da915Sopenharmony_ci/** 908987da915Sopenharmony_ci * ntfs_desx_encrypt 909987da915Sopenharmony_ci */ 910987da915Sopenharmony_cistatic gcry_error_t ntfs_desx_encrypt(ntfs_fek *fek, u8 *outbuf, 911987da915Sopenharmony_ci const u8 *inbuf) 912987da915Sopenharmony_ci{ 913987da915Sopenharmony_ci gcry_error_t err; 914987da915Sopenharmony_ci ntfs_desx_ctx *ctx = &fek->desx_ctx; 915987da915Sopenharmony_ci 916987da915Sopenharmony_ci *(u64*)outbuf = *(const u64*)inbuf ^ ctx->in_whitening ^ ctx->prev_blk; 917987da915Sopenharmony_ci err = gcry_cipher_decrypt(fek->gcry_cipher_hd, outbuf, 8, NULL, 0); 918987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) 919987da915Sopenharmony_ci ntfs_log_error("Des decryption failed (error 0x%x).\n", err); 920987da915Sopenharmony_ci *(u64*)outbuf ^= ctx->out_whitening; 921987da915Sopenharmony_ci ctx->prev_blk = *(u64*)outbuf; 922987da915Sopenharmony_ci return (err); 923987da915Sopenharmony_ci} 924987da915Sopenharmony_ci 925987da915Sopenharmony_ci//#define DO_CRYPTO_TESTS 1 926987da915Sopenharmony_ci 927987da915Sopenharmony_ci#ifdef DO_CRYPTO_TESTS 928987da915Sopenharmony_ci 929987da915Sopenharmony_ci/* Do not remove this test code from this file! AIA */ 930987da915Sopenharmony_ci/** 931987da915Sopenharmony_ci * ntfs_desx_key_expand_test 932987da915Sopenharmony_ci */ 933987da915Sopenharmony_cistatic BOOL ntfs_desx_key_expand_test(void) 934987da915Sopenharmony_ci{ 935987da915Sopenharmony_ci const u8 known_desx_on_disk_key[16] = { 936987da915Sopenharmony_ci 0xa1, 0xf9, 0xe0, 0xb2, 0x53, 0x23, 0x9e, 0x8f, 937987da915Sopenharmony_ci 0x0f, 0x91, 0x45, 0xd9, 0x8e, 0x20, 0xec, 0x30 938987da915Sopenharmony_ci }; 939987da915Sopenharmony_ci const u8 known_des_key[8] = { 940987da915Sopenharmony_ci 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f, 941987da915Sopenharmony_ci }; 942987da915Sopenharmony_ci const u8 known_out_whitening[8] = { 943987da915Sopenharmony_ci 0xed, 0xda, 0x4c, 0x47, 0x60, 0x49, 0xdb, 0x8d, 944987da915Sopenharmony_ci }; 945987da915Sopenharmony_ci const u8 known_in_whitening[8] = { 946987da915Sopenharmony_ci 0x75, 0xf6, 0xa0, 0x1a, 0xc0, 0xca, 0x28, 0x1e 947987da915Sopenharmony_ci }; 948987da915Sopenharmony_ci u64 test_out_whitening, test_in_whitening; 949987da915Sopenharmony_ci union { 950987da915Sopenharmony_ci u64 u64; 951987da915Sopenharmony_ci u32 u32[2]; 952987da915Sopenharmony_ci } test_des_key; 953987da915Sopenharmony_ci gcry_error_t err; 954987da915Sopenharmony_ci BOOL res; 955987da915Sopenharmony_ci 956987da915Sopenharmony_ci err = ntfs_desx_key_expand(known_desx_on_disk_key, test_des_key.u32, 957987da915Sopenharmony_ci &test_out_whitening, &test_in_whitening); 958987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) 959987da915Sopenharmony_ci res = FALSE; 960987da915Sopenharmony_ci else 961987da915Sopenharmony_ci res = test_des_key.u64 == *(u64*)known_des_key && 962987da915Sopenharmony_ci test_out_whitening == 963987da915Sopenharmony_ci *(u64*)known_out_whitening && 964987da915Sopenharmony_ci test_in_whitening == 965987da915Sopenharmony_ci *(u64*)known_in_whitening; 966987da915Sopenharmony_ci ntfs_log_error("Testing whether ntfs_desx_key_expand() works: %s\n", 967987da915Sopenharmony_ci res ? "SUCCESS" : "FAILED"); 968987da915Sopenharmony_ci return res; 969987da915Sopenharmony_ci} 970987da915Sopenharmony_ci 971987da915Sopenharmony_ci/** 972987da915Sopenharmony_ci * ntfs_des_test 973987da915Sopenharmony_ci */ 974987da915Sopenharmony_cistatic BOOL ntfs_des_test(void) 975987da915Sopenharmony_ci{ 976987da915Sopenharmony_ci const u8 known_des_key[8] = { 977987da915Sopenharmony_ci 0x27, 0xd1, 0x93, 0x09, 0xcb, 0x78, 0x93, 0x1f 978987da915Sopenharmony_ci }; 979987da915Sopenharmony_ci const u8 known_des_encrypted_data[8] = { 980987da915Sopenharmony_ci 0xdc, 0xf7, 0x68, 0x2a, 0xaf, 0x48, 0x53, 0x0f 981987da915Sopenharmony_ci }; 982987da915Sopenharmony_ci const u8 known_decrypted_data[8] = { 983987da915Sopenharmony_ci 0xd8, 0xd9, 0x15, 0x23, 0x5b, 0x88, 0x0e, 0x09 984987da915Sopenharmony_ci }; 985987da915Sopenharmony_ci u8 test_decrypted_data[8]; 986987da915Sopenharmony_ci int res; 987987da915Sopenharmony_ci gcry_error_t err; 988987da915Sopenharmony_ci gcry_cipher_hd_t gcry_cipher_hd; 989987da915Sopenharmony_ci 990987da915Sopenharmony_ci err = gcry_cipher_open(&gcry_cipher_hd, GCRY_CIPHER_DES, 991987da915Sopenharmony_ci GCRY_CIPHER_MODE_ECB, 0); 992987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 993987da915Sopenharmony_ci ntfs_log_error("Failed to open des cipher (error 0x%x).\n", 994987da915Sopenharmony_ci err); 995987da915Sopenharmony_ci return FALSE; 996987da915Sopenharmony_ci } 997987da915Sopenharmony_ci err = gcry_cipher_setkey(gcry_cipher_hd, known_des_key, 998987da915Sopenharmony_ci sizeof(known_des_key)); 999987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 1000987da915Sopenharmony_ci ntfs_log_error("Failed to set des key (error 0x%x.\n", err); 1001987da915Sopenharmony_ci gcry_cipher_close(gcry_cipher_hd); 1002987da915Sopenharmony_ci return FALSE; 1003987da915Sopenharmony_ci } 1004987da915Sopenharmony_ci /* 1005987da915Sopenharmony_ci * Apply DES decryption (ntfs actually uses encryption when decrypting). 1006987da915Sopenharmony_ci */ 1007987da915Sopenharmony_ci err = gcry_cipher_encrypt(gcry_cipher_hd, test_decrypted_data, 1008987da915Sopenharmony_ci sizeof(test_decrypted_data), known_des_encrypted_data, 1009987da915Sopenharmony_ci sizeof(known_des_encrypted_data)); 1010987da915Sopenharmony_ci gcry_cipher_close(gcry_cipher_hd); 1011987da915Sopenharmony_ci if (err) { 1012987da915Sopenharmony_ci ntfs_log_error("Failed to des decrypt test data (error " 1013987da915Sopenharmony_ci "0x%x).\n", err); 1014987da915Sopenharmony_ci return FALSE; 1015987da915Sopenharmony_ci } 1016987da915Sopenharmony_ci res = !memcmp(test_decrypted_data, known_decrypted_data, 1017987da915Sopenharmony_ci sizeof(known_decrypted_data)); 1018987da915Sopenharmony_ci ntfs_log_error("Testing whether des decryption works: %s\n", 1019987da915Sopenharmony_ci res ? "SUCCESS" : "FAILED"); 1020987da915Sopenharmony_ci return res; 1021987da915Sopenharmony_ci} 1022987da915Sopenharmony_ci 1023987da915Sopenharmony_ci#else /* !defined(DO_CRYPTO_TESTS) */ 1024987da915Sopenharmony_ci 1025987da915Sopenharmony_ci/** 1026987da915Sopenharmony_ci * ntfs_desx_key_expand_test 1027987da915Sopenharmony_ci */ 1028987da915Sopenharmony_cistatic inline BOOL ntfs_desx_key_expand_test(void) 1029987da915Sopenharmony_ci{ 1030987da915Sopenharmony_ci return TRUE; 1031987da915Sopenharmony_ci} 1032987da915Sopenharmony_ci 1033987da915Sopenharmony_ci/** 1034987da915Sopenharmony_ci * ntfs_des_test 1035987da915Sopenharmony_ci */ 1036987da915Sopenharmony_cistatic inline BOOL ntfs_des_test(void) 1037987da915Sopenharmony_ci{ 1038987da915Sopenharmony_ci return TRUE; 1039987da915Sopenharmony_ci} 1040987da915Sopenharmony_ci 1041987da915Sopenharmony_ci#endif /* !defined(DO_CRYPTO_TESTS) */ 1042987da915Sopenharmony_ci 1043987da915Sopenharmony_ci/** 1044987da915Sopenharmony_ci * ntfs_fek_import_from_raw 1045987da915Sopenharmony_ci */ 1046987da915Sopenharmony_cistatic ntfs_fek *ntfs_fek_import_from_raw(u8 *fek_buf, unsigned fek_size) 1047987da915Sopenharmony_ci{ 1048987da915Sopenharmony_ci ntfs_fek *fek; 1049987da915Sopenharmony_ci u32 key_size, wanted_key_size, gcry_algo; 1050987da915Sopenharmony_ci int gcry_mode; 1051987da915Sopenharmony_ci gcry_error_t err; 1052987da915Sopenharmony_ci ntfs_desx_ctx *ctx; 1053987da915Sopenharmony_ci 1054987da915Sopenharmony_ci key_size = le32_to_cpup((le32*) fek_buf); 1055987da915Sopenharmony_ci ntfs_log_debug("key_size 0x%x\n", key_size); 1056987da915Sopenharmony_ci if (key_size + 16 > fek_size) { 1057987da915Sopenharmony_ci ntfs_log_debug("Invalid FEK. It was probably decrypted with " 1058987da915Sopenharmony_ci "the incorrect RSA key."); 1059987da915Sopenharmony_ci errno = EINVAL; 1060987da915Sopenharmony_ci return NULL; 1061987da915Sopenharmony_ci } 1062987da915Sopenharmony_ci fek = malloc(((((sizeof(*fek) + 7) & ~7) + key_size + 7) & ~7) + 1063987da915Sopenharmony_ci sizeof(gcry_cipher_hd_t)); 1064987da915Sopenharmony_ci if (!fek) { 1065987da915Sopenharmony_ci errno = ENOMEM; 1066987da915Sopenharmony_ci return NULL; 1067987da915Sopenharmony_ci } 1068987da915Sopenharmony_ci ctx = &fek->desx_ctx; 1069987da915Sopenharmony_ci fek->alg_id = *(le32*)(fek_buf + 8); 1070987da915Sopenharmony_ci //ntfs_log_debug("alg_id 0x%x\n", le32_to_cpu(fek->alg_id)); 1071987da915Sopenharmony_ci fek->key_data = (u8*)fek + ((sizeof(*fek) + 7) & ~7); 1072987da915Sopenharmony_ci memcpy(fek->key_data, fek_buf + 16, key_size); 1073987da915Sopenharmony_ci fek->des_gcry_cipher_hd_ptr = NULL; 1074987da915Sopenharmony_ci *(gcry_cipher_hd_t***)(fek->key_data + ((key_size + 7) & ~7)) = 1075987da915Sopenharmony_ci &fek->des_gcry_cipher_hd_ptr; 1076987da915Sopenharmony_ci switch (fek->alg_id) { 1077987da915Sopenharmony_ci case CALG_DESX: 1078987da915Sopenharmony_ci wanted_key_size = 16; 1079987da915Sopenharmony_ci gcry_algo = GCRY_CIPHER_DES; 1080987da915Sopenharmony_ci gcry_mode = GCRY_CIPHER_MODE_ECB; 1081987da915Sopenharmony_ci break; 1082987da915Sopenharmony_ci case CALG_3DES: 1083987da915Sopenharmony_ci wanted_key_size = 24; 1084987da915Sopenharmony_ci gcry_algo = GCRY_CIPHER_3DES; 1085987da915Sopenharmony_ci gcry_mode = GCRY_CIPHER_MODE_CBC; 1086987da915Sopenharmony_ci break; 1087987da915Sopenharmony_ci case CALG_AES_256: 1088987da915Sopenharmony_ci wanted_key_size = 32; 1089987da915Sopenharmony_ci gcry_algo = GCRY_CIPHER_AES256; 1090987da915Sopenharmony_ci gcry_mode = GCRY_CIPHER_MODE_CBC; 1091987da915Sopenharmony_ci break; 1092987da915Sopenharmony_ci default: 1093987da915Sopenharmony_ci wanted_key_size = 8; 1094987da915Sopenharmony_ci gcry_algo = GCRY_CIPHER_DES; 1095987da915Sopenharmony_ci gcry_mode = GCRY_CIPHER_MODE_CBC; 1096987da915Sopenharmony_ci if (fek->alg_id == CALG_DES) 1097987da915Sopenharmony_ci ntfs_log_error("DES is not supported at present\n"); 1098987da915Sopenharmony_ci else 1099987da915Sopenharmony_ci ntfs_log_error("Unknown crypto algorithm 0x%x\n", 1100987da915Sopenharmony_ci le32_to_cpu(fek->alg_id)); 1101987da915Sopenharmony_ci ntfs_log_error(". Please email %s and say that you saw this " 1102987da915Sopenharmony_ci "message. We will then try to implement " 1103987da915Sopenharmony_ci "support for this algorithm.\n", NTFS_DEV_LIST); 1104987da915Sopenharmony_ci err = EOPNOTSUPP; 1105987da915Sopenharmony_ci goto out; 1106987da915Sopenharmony_ci } 1107987da915Sopenharmony_ci if (key_size != wanted_key_size) { 1108987da915Sopenharmony_ci ntfs_log_error("%s key of %u bytes but needed size is %u " 1109987da915Sopenharmony_ci "bytes, assuming corrupt or incorrect key. " 1110987da915Sopenharmony_ci "Aborting.\n", 1111987da915Sopenharmony_ci gcry_cipher_algo_name(gcry_algo), 1112987da915Sopenharmony_ci (unsigned)key_size, (unsigned)wanted_key_size); 1113987da915Sopenharmony_ci err = EIO; 1114987da915Sopenharmony_ci goto out; 1115987da915Sopenharmony_ci } 1116987da915Sopenharmony_ci err = gcry_cipher_open(&fek->gcry_cipher_hd, gcry_algo, 1117987da915Sopenharmony_ci gcry_mode, 0); 1118987da915Sopenharmony_ci 1119987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 1120987da915Sopenharmony_ci ntfs_log_error("gcry_cipher_open() failed: %s\n", 1121987da915Sopenharmony_ci gcry_strerror(err)); 1122987da915Sopenharmony_ci err = EINVAL; 1123987da915Sopenharmony_ci goto out; 1124987da915Sopenharmony_ci } 1125987da915Sopenharmony_ci if (fek->alg_id == CALG_DESX) { 1126987da915Sopenharmony_ci err = ntfs_desx_key_expand(fek->key_data, (u32*)ctx->des_key, 1127987da915Sopenharmony_ci &ctx->out_whitening, &ctx->in_whitening); 1128987da915Sopenharmony_ci if (err == GPG_ERR_NO_ERROR) 1129987da915Sopenharmony_ci err = gcry_cipher_setkey(fek->gcry_cipher_hd, 1130987da915Sopenharmony_ci ctx->des_key, 8); 1131987da915Sopenharmony_ci } else { 1132987da915Sopenharmony_ci err = gcry_cipher_setkey(fek->gcry_cipher_hd, fek->key_data, 1133987da915Sopenharmony_ci key_size); 1134987da915Sopenharmony_ci } 1135987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 1136987da915Sopenharmony_ci ntfs_log_error("gcry_cipher_setkey() failed: %s\n", 1137987da915Sopenharmony_ci gcry_strerror(err)); 1138987da915Sopenharmony_ci gcry_cipher_close(fek->gcry_cipher_hd); 1139987da915Sopenharmony_ci err = EINVAL; 1140987da915Sopenharmony_ci goto out; 1141987da915Sopenharmony_ci } 1142987da915Sopenharmony_ci return fek; 1143987da915Sopenharmony_ciout: 1144987da915Sopenharmony_ci free(fek); 1145987da915Sopenharmony_ci errno = err; 1146987da915Sopenharmony_ci return NULL; 1147987da915Sopenharmony_ci} 1148987da915Sopenharmony_ci 1149987da915Sopenharmony_ci/** 1150987da915Sopenharmony_ci * ntfs_fek_release 1151987da915Sopenharmony_ci */ 1152987da915Sopenharmony_cistatic void ntfs_fek_release(ntfs_fek *fek) 1153987da915Sopenharmony_ci{ 1154987da915Sopenharmony_ci if (fek->des_gcry_cipher_hd_ptr) 1155987da915Sopenharmony_ci gcry_cipher_close(*fek->des_gcry_cipher_hd_ptr); 1156987da915Sopenharmony_ci gcry_cipher_close(fek->gcry_cipher_hd); 1157987da915Sopenharmony_ci free(fek); 1158987da915Sopenharmony_ci} 1159987da915Sopenharmony_ci 1160987da915Sopenharmony_ci/** 1161987da915Sopenharmony_ci * ntfs_df_array_fek_get 1162987da915Sopenharmony_ci */ 1163987da915Sopenharmony_cistatic ntfs_fek *ntfs_df_array_fek_get(EFS_DF_ARRAY_HEADER *df_array, 1164987da915Sopenharmony_ci ntfs_rsa_private_key rsa_key, char *thumbprint, 1165987da915Sopenharmony_ci int thumbprint_size) 1166987da915Sopenharmony_ci{ 1167987da915Sopenharmony_ci EFS_DF_HEADER *df_header; 1168987da915Sopenharmony_ci EFS_DF_CREDENTIAL_HEADER *df_cred; 1169987da915Sopenharmony_ci EFS_DF_CERT_THUMBPRINT_HEADER *df_cert; 1170987da915Sopenharmony_ci u8 *fek_buf; 1171987da915Sopenharmony_ci ntfs_fek *fek; 1172987da915Sopenharmony_ci u32 df_count, fek_size; 1173987da915Sopenharmony_ci unsigned i; 1174987da915Sopenharmony_ci 1175987da915Sopenharmony_ci df_count = le32_to_cpu(df_array->df_count); 1176987da915Sopenharmony_ci if (!df_count) 1177987da915Sopenharmony_ci ntfs_log_error("There are no elements in the DF array.\n"); 1178987da915Sopenharmony_ci df_header = (EFS_DF_HEADER*)(df_array + 1); 1179987da915Sopenharmony_ci for (i = 0; i < df_count; i++, df_header = (EFS_DF_HEADER*)( 1180987da915Sopenharmony_ci (u8*)df_header + le32_to_cpu(df_header->df_length))) { 1181987da915Sopenharmony_ci df_cred = (EFS_DF_CREDENTIAL_HEADER*)((u8*)df_header + 1182987da915Sopenharmony_ci le32_to_cpu(df_header->cred_header_offset)); 1183987da915Sopenharmony_ci if (df_cred->type != NTFS_CRED_TYPE_CERT_THUMBPRINT) { 1184987da915Sopenharmony_ci ntfs_log_debug("Credential type is not certificate " 1185987da915Sopenharmony_ci "thumbprint, skipping DF entry.\n"); 1186987da915Sopenharmony_ci continue; 1187987da915Sopenharmony_ci } 1188987da915Sopenharmony_ci df_cert = (EFS_DF_CERT_THUMBPRINT_HEADER*)((u8*)df_cred + 1189987da915Sopenharmony_ci le32_to_cpu( 1190987da915Sopenharmony_ci df_cred->cert_thumbprint_header_offset)); 1191987da915Sopenharmony_ci if ((int)le32_to_cpu(df_cert->thumbprint_size) 1192987da915Sopenharmony_ci != thumbprint_size) { 1193987da915Sopenharmony_ci ntfs_log_error("Thumbprint size %d is not valid " 1194987da915Sopenharmony_ci "(should be %d), skipping this DF " 1195987da915Sopenharmony_ci "entry.\n", 1196987da915Sopenharmony_ci le32_to_cpu(df_cert->thumbprint_size), 1197987da915Sopenharmony_ci thumbprint_size); 1198987da915Sopenharmony_ci continue; 1199987da915Sopenharmony_ci } 1200987da915Sopenharmony_ci if (memcmp((u8*)df_cert + 1201987da915Sopenharmony_ci le32_to_cpu(df_cert->thumbprint_offset), 1202987da915Sopenharmony_ci thumbprint, thumbprint_size)) { 1203987da915Sopenharmony_ci ntfs_log_debug("Thumbprints do not match, skipping " 1204987da915Sopenharmony_ci "this DF entry.\n"); 1205987da915Sopenharmony_ci continue; 1206987da915Sopenharmony_ci } 1207987da915Sopenharmony_ci /* 1208987da915Sopenharmony_ci * The thumbprints match so this is probably the DF entry 1209987da915Sopenharmony_ci * matching the RSA key. Try to decrypt the FEK with it. 1210987da915Sopenharmony_ci */ 1211987da915Sopenharmony_ci fek_size = le32_to_cpu(df_header->fek_size); 1212987da915Sopenharmony_ci fek_buf = (u8*)df_header + le32_to_cpu(df_header->fek_offset); 1213987da915Sopenharmony_ci /* Decrypt the FEK. Note: This is done in place. */ 1214987da915Sopenharmony_ci fek_size = ntfs_raw_fek_decrypt(fek_buf, fek_size, rsa_key); 1215987da915Sopenharmony_ci if (fek_size) { 1216987da915Sopenharmony_ci /* Convert the FEK to our internal format. */ 1217987da915Sopenharmony_ci fek = ntfs_fek_import_from_raw(fek_buf, fek_size); 1218987da915Sopenharmony_ci if (fek) 1219987da915Sopenharmony_ci return fek; 1220987da915Sopenharmony_ci ntfs_log_error("Failed to convert the decrypted file " 1221987da915Sopenharmony_ci "encryption key to internal format.\n"); 1222987da915Sopenharmony_ci } else 1223987da915Sopenharmony_ci ntfs_log_error("Failed to decrypt the file " 1224987da915Sopenharmony_ci "encryption key.\n"); 1225987da915Sopenharmony_ci } 1226987da915Sopenharmony_ci return NULL; 1227987da915Sopenharmony_ci} 1228987da915Sopenharmony_ci 1229987da915Sopenharmony_ci/** 1230987da915Sopenharmony_ci * ntfs_inode_fek_get - 1231987da915Sopenharmony_ci */ 1232987da915Sopenharmony_cistatic ntfs_fek *ntfs_inode_fek_get(ntfs_inode *inode, 1233987da915Sopenharmony_ci ntfs_rsa_private_key rsa_key, char *thumbprint, 1234987da915Sopenharmony_ci int thumbprint_size, NTFS_DF_TYPES df_type) 1235987da915Sopenharmony_ci{ 1236987da915Sopenharmony_ci EFS_ATTR_HEADER *efs; 1237987da915Sopenharmony_ci EFS_DF_ARRAY_HEADER *df_array = NULL; 1238987da915Sopenharmony_ci ntfs_fek *fek = NULL; 1239987da915Sopenharmony_ci 1240987da915Sopenharmony_ci /* Obtain the $EFS contents. */ 1241987da915Sopenharmony_ci efs = ntfs_attr_readall(inode, AT_LOGGED_UTILITY_STREAM, EFS, 4, NULL); 1242987da915Sopenharmony_ci if (!efs) { 1243987da915Sopenharmony_ci ntfs_log_perror("Failed to read $EFS attribute"); 1244987da915Sopenharmony_ci return NULL; 1245987da915Sopenharmony_ci } 1246987da915Sopenharmony_ci /* 1247987da915Sopenharmony_ci * Depending on whether the key is a normal key or a data recovery key, 1248987da915Sopenharmony_ci * iterate through the DDF or DRF array, respectively. 1249987da915Sopenharmony_ci */ 1250987da915Sopenharmony_ci if (df_type == DF_TYPE_DDF) { 1251987da915Sopenharmony_ci if (efs->offset_to_ddf_array) 1252987da915Sopenharmony_ci df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs + 1253987da915Sopenharmony_ci le32_to_cpu(efs->offset_to_ddf_array)); 1254987da915Sopenharmony_ci else 1255987da915Sopenharmony_ci ntfs_log_error("There are no entries in the DDF " 1256987da915Sopenharmony_ci "array.\n"); 1257987da915Sopenharmony_ci } else if (df_type == DF_TYPE_DRF) { 1258987da915Sopenharmony_ci if (efs->offset_to_drf_array) 1259987da915Sopenharmony_ci df_array = (EFS_DF_ARRAY_HEADER*)((u8*)efs + 1260987da915Sopenharmony_ci le32_to_cpu(efs->offset_to_drf_array)); 1261987da915Sopenharmony_ci else 1262987da915Sopenharmony_ci ntfs_log_error("There are no entries in the DRF " 1263987da915Sopenharmony_ci "array.\n"); 1264987da915Sopenharmony_ci } else 1265987da915Sopenharmony_ci ntfs_log_error("Invalid DF type.\n"); 1266987da915Sopenharmony_ci if (df_array) 1267987da915Sopenharmony_ci fek = ntfs_df_array_fek_get(df_array, rsa_key, thumbprint, 1268987da915Sopenharmony_ci thumbprint_size); 1269987da915Sopenharmony_ci free(efs); 1270987da915Sopenharmony_ci return fek; 1271987da915Sopenharmony_ci} 1272987da915Sopenharmony_ci 1273987da915Sopenharmony_ci/** 1274987da915Sopenharmony_ci * ntfs_fek_decrypt_sector 1275987da915Sopenharmony_ci */ 1276987da915Sopenharmony_cistatic int ntfs_fek_decrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset) 1277987da915Sopenharmony_ci{ 1278987da915Sopenharmony_ci gcry_error_t err; 1279987da915Sopenharmony_ci 1280987da915Sopenharmony_ci err = gcry_cipher_reset(fek->gcry_cipher_hd); 1281987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 1282987da915Sopenharmony_ci ntfs_log_error("Failed to reset cipher: %s\n", 1283987da915Sopenharmony_ci gcry_strerror(err)); 1284987da915Sopenharmony_ci return -1; 1285987da915Sopenharmony_ci } 1286987da915Sopenharmony_ci /* 1287987da915Sopenharmony_ci * Note: You may wonder why we are not calling gcry_cipher_setiv() here 1288987da915Sopenharmony_ci * instead of doing it by hand after the decryption. The answer is 1289987da915Sopenharmony_ci * that gcry_cipher_setiv() wants an iv of length 8 bytes but we give 1290987da915Sopenharmony_ci * it a length of 16 for AES256 so it does not like it. 1291987da915Sopenharmony_ci */ 1292987da915Sopenharmony_ci if (fek->alg_id == CALG_DESX) { 1293987da915Sopenharmony_ci int k; 1294987da915Sopenharmony_ci 1295987da915Sopenharmony_ci fek->desx_ctx.prev_blk = 0; 1296987da915Sopenharmony_ci for (k=0; (k < 512) && (err == GPG_ERR_NO_ERROR); k+=8) { 1297987da915Sopenharmony_ci err = ntfs_desx_decrypt(fek, &data[k], &data[k]); 1298987da915Sopenharmony_ci } 1299987da915Sopenharmony_ci } else 1300987da915Sopenharmony_ci err = gcry_cipher_decrypt(fek->gcry_cipher_hd, data, 512, NULL, 0); 1301987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 1302987da915Sopenharmony_ci ntfs_log_error("Decryption failed: %s\n", gcry_strerror(err)); 1303987da915Sopenharmony_ci return -1; 1304987da915Sopenharmony_ci } 1305987da915Sopenharmony_ci /* Apply the IV. */ 1306987da915Sopenharmony_ci if (fek->alg_id == CALG_AES_256) { 1307987da915Sopenharmony_ci ((le64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset); 1308987da915Sopenharmony_ci ((le64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset); 1309987da915Sopenharmony_ci } else { 1310987da915Sopenharmony_ci /* All other algos (Des, 3Des, DesX) use the same IV. */ 1311987da915Sopenharmony_ci ((le64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset); 1312987da915Sopenharmony_ci } 1313987da915Sopenharmony_ci return 512; 1314987da915Sopenharmony_ci} 1315987da915Sopenharmony_ci 1316987da915Sopenharmony_ci/** 1317987da915Sopenharmony_ci * ntfs_fek_encrypt_sector 1318987da915Sopenharmony_ci */ 1319987da915Sopenharmony_cistatic int ntfs_fek_encrypt_sector(ntfs_fek *fek, u8 *data, const u64 offset) 1320987da915Sopenharmony_ci{ 1321987da915Sopenharmony_ci gcry_error_t err; 1322987da915Sopenharmony_ci 1323987da915Sopenharmony_ci err = gcry_cipher_reset(fek->gcry_cipher_hd); 1324987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 1325987da915Sopenharmony_ci ntfs_log_error("Failed to reset cipher: %s\n", 1326987da915Sopenharmony_ci gcry_strerror(err)); 1327987da915Sopenharmony_ci return -1; 1328987da915Sopenharmony_ci } 1329987da915Sopenharmony_ci /* 1330987da915Sopenharmony_ci * Note: You may wonder why we are not calling gcry_cipher_setiv() here 1331987da915Sopenharmony_ci * instead of doing it by hand after the decryption. The answer is 1332987da915Sopenharmony_ci * that gcry_cipher_setiv() wants an iv of length 8 bytes but we give 1333987da915Sopenharmony_ci * it a length of 16 for AES256 so it does not like it. 1334987da915Sopenharmony_ci */ 1335987da915Sopenharmony_ci /* Apply the IV. */ 1336987da915Sopenharmony_ci if (fek->alg_id == CALG_AES_256) { 1337987da915Sopenharmony_ci ((le64*)data)[0] ^= cpu_to_le64(0x5816657be9161312ULL + offset); 1338987da915Sopenharmony_ci ((le64*)data)[1] ^= cpu_to_le64(0x1989adbe44918961ULL + offset); 1339987da915Sopenharmony_ci } else { 1340987da915Sopenharmony_ci /* All other algos (Des, 3Des, DesX) use the same IV. */ 1341987da915Sopenharmony_ci ((le64*)data)[0] ^= cpu_to_le64(0x169119629891ad13ULL + offset); 1342987da915Sopenharmony_ci } 1343987da915Sopenharmony_ci if (fek->alg_id == CALG_DESX) { 1344987da915Sopenharmony_ci int k; 1345987da915Sopenharmony_ci 1346987da915Sopenharmony_ci fek->desx_ctx.prev_blk = 0; 1347987da915Sopenharmony_ci for (k=0; (k < 512) && (err == GPG_ERR_NO_ERROR); k+=8) { 1348987da915Sopenharmony_ci err = ntfs_desx_encrypt(fek, &data[k], &data[k]); 1349987da915Sopenharmony_ci } 1350987da915Sopenharmony_ci } else 1351987da915Sopenharmony_ci err = gcry_cipher_encrypt(fek->gcry_cipher_hd, data, 512, NULL, 0); 1352987da915Sopenharmony_ci if (err != GPG_ERR_NO_ERROR) { 1353987da915Sopenharmony_ci ntfs_log_error("Encryption failed: %s\n", gcry_strerror(err)); 1354987da915Sopenharmony_ci return -1; 1355987da915Sopenharmony_ci } 1356987da915Sopenharmony_ci return 512; 1357987da915Sopenharmony_ci} 1358987da915Sopenharmony_ci 1359987da915Sopenharmony_ci/** 1360987da915Sopenharmony_ci * ntfs_cat_decrypt - Decrypt the contents of an encrypted file to stdout. 1361987da915Sopenharmony_ci * @inode: An encrypted file's inode structure, as obtained by 1362987da915Sopenharmony_ci * ntfs_inode_open(). 1363987da915Sopenharmony_ci * @fek: A file encryption key. As obtained by ntfs_inode_fek_get(). 1364987da915Sopenharmony_ci */ 1365987da915Sopenharmony_cistatic int ntfs_cat_decrypt(ntfs_inode *inode, ntfs_fek *fek) 1366987da915Sopenharmony_ci{ 1367987da915Sopenharmony_ci int bufsize = 512; 1368987da915Sopenharmony_ci unsigned char *buffer; 1369987da915Sopenharmony_ci ntfs_attr *attr; 1370987da915Sopenharmony_ci s64 bytes_read, written, offset, total; 1371987da915Sopenharmony_ci s64 old_data_size, old_initialized_size; 1372987da915Sopenharmony_ci int i; 1373987da915Sopenharmony_ci 1374987da915Sopenharmony_ci buffer = malloc(bufsize); 1375987da915Sopenharmony_ci if (!buffer) 1376987da915Sopenharmony_ci return 1; 1377987da915Sopenharmony_ci attr = ntfs_attr_open(inode, AT_DATA, NULL, 0); 1378987da915Sopenharmony_ci if (!attr) { 1379987da915Sopenharmony_ci ntfs_log_error("Cannot cat a directory.\n"); 1380987da915Sopenharmony_ci free(buffer); 1381987da915Sopenharmony_ci return 1; 1382987da915Sopenharmony_ci } 1383987da915Sopenharmony_ci total = attr->data_size; 1384987da915Sopenharmony_ci 1385987da915Sopenharmony_ci // hack: make sure attr will not be commited to disk if you use this. 1386987da915Sopenharmony_ci // clear the encrypted bit, otherwise the library won't allow reading. 1387987da915Sopenharmony_ci NAttrClearEncrypted(attr); 1388987da915Sopenharmony_ci // extend the size, we may need to read past the end of the stream. 1389987da915Sopenharmony_ci old_data_size = attr->data_size; 1390987da915Sopenharmony_ci old_initialized_size = attr->initialized_size; 1391987da915Sopenharmony_ci attr->data_size = attr->initialized_size = attr->allocated_size; 1392987da915Sopenharmony_ci 1393987da915Sopenharmony_ci offset = 0; 1394987da915Sopenharmony_ci while (total > 0) { 1395987da915Sopenharmony_ci bytes_read = ntfs_attr_pread(attr, offset, 512, buffer); 1396987da915Sopenharmony_ci if (bytes_read == -1) { 1397987da915Sopenharmony_ci ntfs_log_perror("ERROR: Couldn't read file"); 1398987da915Sopenharmony_ci break; 1399987da915Sopenharmony_ci } 1400987da915Sopenharmony_ci if (!bytes_read) 1401987da915Sopenharmony_ci break; 1402987da915Sopenharmony_ci if ((i = ntfs_fek_decrypt_sector(fek, buffer, offset)) < 1403987da915Sopenharmony_ci bytes_read) { 1404987da915Sopenharmony_ci ntfs_log_perror("ERROR: Couldn't decrypt all data!"); 1405987da915Sopenharmony_ci ntfs_log_error("%u/%lld/%lld/%lld\n", i, 1406987da915Sopenharmony_ci (long long)bytes_read, (long long)offset, 1407987da915Sopenharmony_ci (long long)total); 1408987da915Sopenharmony_ci break; 1409987da915Sopenharmony_ci } 1410987da915Sopenharmony_ci if (bytes_read > total) 1411987da915Sopenharmony_ci bytes_read = total; 1412987da915Sopenharmony_ci written = fwrite(buffer, 1, bytes_read, stdout); 1413987da915Sopenharmony_ci if (written != bytes_read) { 1414987da915Sopenharmony_ci ntfs_log_perror("ERROR: Couldn't output all data!"); 1415987da915Sopenharmony_ci break; 1416987da915Sopenharmony_ci } 1417987da915Sopenharmony_ci offset += bytes_read; 1418987da915Sopenharmony_ci total -= bytes_read; 1419987da915Sopenharmony_ci } 1420987da915Sopenharmony_ci attr->data_size = old_data_size; 1421987da915Sopenharmony_ci attr->initialized_size = old_initialized_size; 1422987da915Sopenharmony_ci NAttrSetEncrypted(attr); 1423987da915Sopenharmony_ci ntfs_attr_close(attr); 1424987da915Sopenharmony_ci free(buffer); 1425987da915Sopenharmony_ci return 0; 1426987da915Sopenharmony_ci} 1427987da915Sopenharmony_ci 1428987da915Sopenharmony_ci/** 1429987da915Sopenharmony_ci * ntfs_feed_encrypt - Encrypt the contents of stdin to an encrypted file 1430987da915Sopenharmony_ci * @inode: An encrypted file's inode structure, as obtained by 1431987da915Sopenharmony_ci * ntfs_inode_open(). 1432987da915Sopenharmony_ci * @fek: A file encryption key. As obtained by ntfs_inode_fek_get(). 1433987da915Sopenharmony_ci */ 1434987da915Sopenharmony_cistatic int ntfs_feed_encrypt(ntfs_inode *inode, ntfs_fek *fek) 1435987da915Sopenharmony_ci{ 1436987da915Sopenharmony_ci const int bufsize = 512; 1437987da915Sopenharmony_ci unsigned char *buffer; 1438987da915Sopenharmony_ci ntfs_attr *attr; 1439987da915Sopenharmony_ci s64 bytes_read, written, offset, total; 1440987da915Sopenharmony_ci unsigned char *b; 1441987da915Sopenharmony_ci long val; 1442987da915Sopenharmony_ci int count; 1443987da915Sopenharmony_ci int i; 1444987da915Sopenharmony_ci 1445987da915Sopenharmony_ci buffer = (unsigned char*)malloc(bufsize); 1446987da915Sopenharmony_ci if (!buffer) 1447987da915Sopenharmony_ci return 1; 1448987da915Sopenharmony_ci attr = ntfs_attr_open(inode, AT_DATA, NULL, 0); 1449987da915Sopenharmony_ci if (!attr) { 1450987da915Sopenharmony_ci ntfs_log_error("Cannot feed into a directory.\n"); 1451987da915Sopenharmony_ci goto rejected; 1452987da915Sopenharmony_ci } 1453987da915Sopenharmony_ci total = 0; 1454987da915Sopenharmony_ci 1455987da915Sopenharmony_ci if (!(attr->data_flags & ATTR_IS_ENCRYPTED)) { 1456987da915Sopenharmony_ci ntfs_log_error("The data stream was not encrypted\n"); 1457987da915Sopenharmony_ci goto rejected; 1458987da915Sopenharmony_ci } 1459987da915Sopenharmony_ci inode->vol->efs_raw = TRUE; 1460987da915Sopenharmony_ci 1461987da915Sopenharmony_ci if (ntfs_attr_truncate(attr, 0)) { 1462987da915Sopenharmony_ci ntfs_log_error("Failed to truncate the data stream\n"); 1463987da915Sopenharmony_ci goto rejected; 1464987da915Sopenharmony_ci } 1465987da915Sopenharmony_ci offset = 0; 1466987da915Sopenharmony_ci do { 1467987da915Sopenharmony_ci bytes_read = fread(buffer, 1, bufsize, stdin); 1468987da915Sopenharmony_ci if (bytes_read <= 0) { 1469987da915Sopenharmony_ci if (bytes_read < 0) 1470987da915Sopenharmony_ci ntfs_log_perror("ERROR: Couldn't read data"); 1471987da915Sopenharmony_ci } else { 1472987da915Sopenharmony_ci if (bytes_read < bufsize) { 1473987da915Sopenharmony_ci /* Fill with random data */ 1474987da915Sopenharmony_ci srandom((unsigned int)(sle64_to_cpu( 1475987da915Sopenharmony_ci inode->last_data_change_time) 1476987da915Sopenharmony_ci /100000000)); 1477987da915Sopenharmony_ci count = bufsize - bytes_read; 1478987da915Sopenharmony_ci b = &buffer[bytes_read]; 1479987da915Sopenharmony_ci do { 1480987da915Sopenharmony_ci val = random(); 1481987da915Sopenharmony_ci switch (count) { 1482987da915Sopenharmony_ci default : 1483987da915Sopenharmony_ci *b++ = val; 1484987da915Sopenharmony_ci val >>= 8; 1485987da915Sopenharmony_ci /* FALLTHRU */ 1486987da915Sopenharmony_ci case 3 : 1487987da915Sopenharmony_ci *b++ = val; 1488987da915Sopenharmony_ci val >>= 8; 1489987da915Sopenharmony_ci /* FALLTHRU */ 1490987da915Sopenharmony_ci case 2 : 1491987da915Sopenharmony_ci *b++ = val; 1492987da915Sopenharmony_ci val >>= 8; 1493987da915Sopenharmony_ci /* FALLTHRU */ 1494987da915Sopenharmony_ci case 1 : 1495987da915Sopenharmony_ci *b++ = val; 1496987da915Sopenharmony_ci val >>= 8; 1497987da915Sopenharmony_ci } 1498987da915Sopenharmony_ci count -= 4; 1499987da915Sopenharmony_ci } while (count > 0); 1500987da915Sopenharmony_ci } 1501987da915Sopenharmony_ci if ((i = ntfs_fek_encrypt_sector(fek, buffer, offset)) 1502987da915Sopenharmony_ci < bufsize) { 1503987da915Sopenharmony_ci ntfs_log_perror("ERROR: Couldn't encrypt all data!"); 1504987da915Sopenharmony_ci ntfs_log_error("%u/%lld/%lld/%lld\n", i, 1505987da915Sopenharmony_ci (long long)bytes_read, (long long)offset, 1506987da915Sopenharmony_ci (long long)total); 1507987da915Sopenharmony_ci break; 1508987da915Sopenharmony_ci } 1509987da915Sopenharmony_ci written = ntfs_attr_pwrite(attr, offset, bufsize, buffer); 1510987da915Sopenharmony_ci if (written != bufsize) { 1511987da915Sopenharmony_ci ntfs_log_perror("ERROR: Couldn't output all data!"); 1512987da915Sopenharmony_ci break; 1513987da915Sopenharmony_ci } 1514987da915Sopenharmony_ci offset += bufsize; 1515987da915Sopenharmony_ci total += bytes_read; 1516987da915Sopenharmony_ci } 1517987da915Sopenharmony_ci } while (bytes_read == bufsize); 1518987da915Sopenharmony_ci ntfs_attr_truncate(attr, total); 1519987da915Sopenharmony_ci inode->last_data_change_time = ntfs_current_time(); 1520987da915Sopenharmony_ci NAttrSetEncrypted(attr); 1521987da915Sopenharmony_ci ntfs_attr_close(attr); 1522987da915Sopenharmony_ci free(buffer); 1523987da915Sopenharmony_ci return 0; 1524987da915Sopenharmony_cirejected : 1525987da915Sopenharmony_ci free(buffer); 1526987da915Sopenharmony_ci return (-1); 1527987da915Sopenharmony_ci} 1528987da915Sopenharmony_ci 1529987da915Sopenharmony_ci/** 1530987da915Sopenharmony_ci * main - Begin here 1531987da915Sopenharmony_ci * 1532987da915Sopenharmony_ci * Start from here. 1533987da915Sopenharmony_ci * 1534987da915Sopenharmony_ci * Return: 0 Success, the program worked 1535987da915Sopenharmony_ci * 1 Error, something went wrong 1536987da915Sopenharmony_ci */ 1537987da915Sopenharmony_ciint main(int argc, char *argv[]) 1538987da915Sopenharmony_ci{ 1539987da915Sopenharmony_ci u8 *pfx_buf; 1540987da915Sopenharmony_ci char *password; 1541987da915Sopenharmony_ci ntfs_rsa_private_key rsa_key; 1542987da915Sopenharmony_ci ntfs_volume *vol; 1543987da915Sopenharmony_ci ntfs_inode *inode; 1544987da915Sopenharmony_ci ntfs_fek *fek; 1545987da915Sopenharmony_ci unsigned pfx_size; 1546987da915Sopenharmony_ci int res; 1547987da915Sopenharmony_ci NTFS_DF_TYPES df_type; 1548987da915Sopenharmony_ci char thumbprint[NTFS_SHA1_THUMBPRINT_SIZE]; 1549987da915Sopenharmony_ci 1550987da915Sopenharmony_ci ntfs_log_set_handler(ntfs_log_handler_stderr); 1551987da915Sopenharmony_ci 1552987da915Sopenharmony_ci res = parse_options(argc, argv); 1553987da915Sopenharmony_ci if (res >= 0) 1554987da915Sopenharmony_ci return (res); 1555987da915Sopenharmony_ci utils_set_locale(); 1556987da915Sopenharmony_ci 1557987da915Sopenharmony_ci /* Initialize crypto in ntfs. */ 1558987da915Sopenharmony_ci if (ntfs_crypto_init()) { 1559987da915Sopenharmony_ci ntfs_log_error("Failed to initialize crypto. Aborting.\n"); 1560987da915Sopenharmony_ci return 1; 1561987da915Sopenharmony_ci } 1562987da915Sopenharmony_ci /* Load the PKCS#12 (.pfx) file containing the user's private key. */ 1563987da915Sopenharmony_ci if (ntfs_pkcs12_load_pfxfile(opts.keyfile, &pfx_buf, &pfx_size)) { 1564987da915Sopenharmony_ci ntfs_log_error("Failed to load key file. Aborting.\n"); 1565987da915Sopenharmony_ci ntfs_crypto_deinit(); 1566987da915Sopenharmony_ci return 1; 1567987da915Sopenharmony_ci } 1568987da915Sopenharmony_ci /* Ask the user for their password. */ 1569987da915Sopenharmony_ci password = getpass("Enter the password with which the private key was " 1570987da915Sopenharmony_ci "encrypted: "); 1571987da915Sopenharmony_ci if (!password) { 1572987da915Sopenharmony_ci ntfs_log_perror("Failed to obtain user password"); 1573987da915Sopenharmony_ci free(pfx_buf); 1574987da915Sopenharmony_ci ntfs_crypto_deinit(); 1575987da915Sopenharmony_ci return 1; 1576987da915Sopenharmony_ci } 1577987da915Sopenharmony_ci /* Obtain the user's private RSA key from the key file. */ 1578987da915Sopenharmony_ci rsa_key = ntfs_pkcs12_extract_rsa_key(pfx_buf, pfx_size, password, 1579987da915Sopenharmony_ci thumbprint, sizeof(thumbprint), &df_type); 1580987da915Sopenharmony_ci /* Destroy the password. */ 1581987da915Sopenharmony_ci memset(password, 0, strlen(password)); 1582987da915Sopenharmony_ci /* No longer need the pfx file contents. */ 1583987da915Sopenharmony_ci free(pfx_buf); 1584987da915Sopenharmony_ci if (!rsa_key) { 1585987da915Sopenharmony_ci ntfs_log_error("Failed to extract the private RSA key.\n"); 1586987da915Sopenharmony_ci ntfs_crypto_deinit(); 1587987da915Sopenharmony_ci return 1; 1588987da915Sopenharmony_ci } 1589987da915Sopenharmony_ci /* Mount the ntfs volume. */ 1590987da915Sopenharmony_ci vol = utils_mount_volume(opts.device, 1591987da915Sopenharmony_ci (opts.encrypt ? 0 : NTFS_MNT_RDONLY) | 1592987da915Sopenharmony_ci (opts.force ? NTFS_MNT_RECOVER : 0)); 1593987da915Sopenharmony_ci if (!vol) { 1594987da915Sopenharmony_ci ntfs_log_error("Failed to mount ntfs volume. Aborting.\n"); 1595987da915Sopenharmony_ci ntfs_rsa_private_key_release(rsa_key); 1596987da915Sopenharmony_ci ntfs_crypto_deinit(); 1597987da915Sopenharmony_ci return 1; 1598987da915Sopenharmony_ci } 1599987da915Sopenharmony_ci /* Open the encrypted ntfs file. */ 1600987da915Sopenharmony_ci if (opts.inode != -1) 1601987da915Sopenharmony_ci inode = ntfs_inode_open(vol, opts.inode); 1602987da915Sopenharmony_ci else 1603987da915Sopenharmony_ci inode = ntfs_pathname_to_inode(vol, NULL, opts.file); 1604987da915Sopenharmony_ci if (!inode) { 1605987da915Sopenharmony_ci ntfs_log_error("Failed to open encrypted file. Aborting.\n"); 1606987da915Sopenharmony_ci ntfs_umount(vol, FALSE); 1607987da915Sopenharmony_ci ntfs_rsa_private_key_release(rsa_key); 1608987da915Sopenharmony_ci ntfs_crypto_deinit(); 1609987da915Sopenharmony_ci return 1; 1610987da915Sopenharmony_ci } 1611987da915Sopenharmony_ci /* Obtain the file encryption key of the encrypted file. */ 1612987da915Sopenharmony_ci fek = ntfs_inode_fek_get(inode, rsa_key, thumbprint, 1613987da915Sopenharmony_ci sizeof(thumbprint), df_type); 1614987da915Sopenharmony_ci ntfs_rsa_private_key_release(rsa_key); 1615987da915Sopenharmony_ci if (fek) { 1616987da915Sopenharmony_ci if (opts.encrypt) 1617987da915Sopenharmony_ci res = ntfs_feed_encrypt(inode, fek); 1618987da915Sopenharmony_ci else 1619987da915Sopenharmony_ci res = ntfs_cat_decrypt(inode, fek); 1620987da915Sopenharmony_ci ntfs_fek_release(fek); 1621987da915Sopenharmony_ci } else { 1622987da915Sopenharmony_ci ntfs_log_error("Failed to obtain file encryption key. " 1623987da915Sopenharmony_ci "Aborting.\n"); 1624987da915Sopenharmony_ci res = 1; 1625987da915Sopenharmony_ci } 1626987da915Sopenharmony_ci ntfs_inode_close(inode); 1627987da915Sopenharmony_ci ntfs_umount(vol, FALSE); 1628987da915Sopenharmony_ci ntfs_crypto_deinit(); 1629987da915Sopenharmony_ci return res; 1630987da915Sopenharmony_ci} 1631