1 /* main.c: dmsetup-tc main program
3 * Copyright (C) 2008 Jan Krueger <jk@jk.gs>
5 * This file is part of dmsetup-tc.
7 * dmsetup-tc is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * dmsetup-tc is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with dmsetup-tc. If not, see <http://www.gnu.org/licenses/>.
28 #include <sys/types.h>
33 void trace(const char *msg
, ...)
35 va_list ap
; va_start(ap
, msg
);
36 vfprintf(stderr
, msg
, ap
);
40 void trace(const char *msg
, ...) {}
44 #include "dmtc_version.h"
50 /* Disk interface {{{ ***************************************************** */
52 sdata
*read_header(const char *file
)
59 if (stat(file
, &sb
) == -1)
62 FILE *f
= fopen(file
, "r");
65 switch (sb
.st_mode
& S_IFMT
) {
67 /* Probably a disk device; seek to TC header */
68 if (-1 == fseek(f
, 62*512, SEEK_SET
)) goto err_nofree
;
71 /* Probably a header file, so don't seek */
79 if (!buf
) goto err_nofree
;
81 if (1 != fread(buf
, 512, 1, f
)) goto err
;
84 vh
= malloc(sizeof (sdata
));
98 static size_t get_part_info(const char *part
, const char *type
)
106 if (1 != sscanf(part
, "/dev/%15s", part_name
)) return 0;
107 snprintf(buf
, 512, "/sys/class/block/%s/%s", part_name
, type
);
112 if (1 != fscanf(f
, "%zu", &val
)) {
123 size_t get_part_start_sector(const char *part
)
125 return get_part_info(part
, "start");
128 size_t get_part_num_sectors(const char *part
)
130 return get_part_info(part
, "size");
133 /* }}} ******************************************************************** */
135 /* Data extraction interface {{{ ****************************************** */
137 sdata
*get_header_salt(sdata
*header
)
139 sdata
*salt
= malloc(sizeof (sdata
));
140 salt
->data
= header
->data
;
145 unsigned int boswap(int x
)
147 unsigned char *c
= (unsigned char *) &x
;
148 return (c
[0] << 24) + (c
[1] << 16) + (c
[2] << 8) + c
[3];
151 int validate_header(sdata
*header
)
153 unsigned char *data
= header
->data
;
154 int i
= header
->size
- 256;
156 trace(" * Validating header signature\n");
157 if (data
[0] != 'T' || data
[1] != 'R' || data
[2] != 'U' ||
158 data
[3] != 'E') return INVALID_SIGNATURE
;
160 trace(" * Validating header checksum\n");
161 if (boswap(((uint32_t *) data
)[47]) !=
163 return HEADER_CHECKSUM_MISMATCH
;
165 trace(" * Validating checksum of master keys\n");
166 if (boswap(((uint32_t *) data
)[2]) !=
167 crc32(&data
[i
], 256))
168 return KEY_CHECKSUM_MISMATCH
;
170 trace(" * Making sure we're dealing with system encryption\n");
171 if (!(data
[63] & 1)) return NOT_SYSTEM_ENCRYPTION
;
173 trace(" * Making sure we're not dealing with partial encryption\n");
174 if (memcmp(&data
[36], &data
[52], 8)) return PARTIALLY_ENCRYPTED
;
179 sdata
*get_header_keys(sdata
*header
)
181 sdata
*res
= malloc(sizeof (sdata
));
183 res
->data
= header
->data
+ 192;
189 /* }}} ******************************************************************** */
191 /* Crypt interface {{{ **************************************************** */
195 gcry_check_version(NULL
);
196 gcry_control(GCRYCTL_INIT_SECMEM
, 1048576);
199 sdata
*crypt_derive_key(sdata
*pass
, sdata
*salt
)
205 res
= malloc(sizeof (sdata
));
207 if (0 != gcry_pbkdf2(GCRY_MD_RMD160
,
208 (const char *) (pass
->data
), pass
->size
,
209 (const char *) (salt
->data
), salt
->size
,
223 sdata
*crypt_decrypt_header(sdata
*header
, sdata
*key
)
226 unsigned char *data
= header
->data
+ 64;
228 if (0 != aes_xts_decrypt(key
->data
, NULL
, 28, 0, data
)) return NULL
;
230 res
= malloc(sizeof (sdata
));
232 res
->size
= header
->size
- 64;
236 /* }}} ******************************************************************** */
238 /* Auxiliary CLI functions {{{ ******************************************** */
243 "dmsetup-tc version " DMTC_VERSION
"\n"
244 "Copyright (c) <year range here, who cares> Jan Krueger <jk@jk.gs>\n"
246 " This program is free software: you can redistribute it and/or modify\n"
247 " it under the terms of the GNU General Public License as published by\n"
248 " the Free Software Foundation, either version 3 of the License, or\n"
249 " (at your option) any later version.\n"
251 " This program is distributed in the hope that it will be useful,\n"
252 " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
253 " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
254 " GNU General Public License for more details.\n"
256 " You should have received a copy of the GNU General Public License\n"
257 " along with this program. If not, see <http://www.gnu.org/licenses/>.\n",
262 void die_error(char *err
)
265 perror("dmsetup-tc: fatal error");
267 fprintf(stderr
, "dmsetup-tc: fatal error: %s\n", err
);
274 puts("Fatal: dmsetup-tc needs to run as root");
281 "Syntax: dmsetup-tc [--stdin] <disk|header file> <partition>\n"
282 " --stdin Read passphrase from stdin rather than tty (do not prompt)\n"
284 "Example: dmsetup-tc /dev/sda /dev/sda3 | dmsetup create myvolume\n"
285 " dmsetup-tc headerfile /dev/sda3 | ...\n"
290 /* }}} ******************************************************************** */
292 int main(int argc
, char *argv
[])
296 char *header_file
, *part_dev
;
307 if (argc
> 1 && !strcmp(argv
[1], "--version"))
309 if (argc
== 1 || !strcmp(argv
[1], "--help"))
317 if (!strcmp(argv
[ofs
], "--stdin")) {
324 if ((argc
- ofs
) < 2) die_syntax();
326 header_file
= argv
[ofs
];
327 part_dev
= argv
[ofs
+1];
329 pass
.data
= getpass(from_stdin
? "" :
330 "Enter passphrase for encrypted volume: ");
331 pass
.size
= strlen(pass
.data
);
332 if (0 != mlock(pass
.data
, pass
.size
)) die_error(NULL
);
334 trace("Loading header from %s...\n", header_file
);
335 vh
= read_header(header_file
);
336 if (!vh
) die_error(NULL
);
340 trace("Deriving header key...\n");
341 vkey
= crypt_derive_key(&pass
, get_header_salt(vh
));
342 if (!vkey
) die_error(NULL
);
344 trace("Decrypting header...\n");
345 dh
= crypt_decrypt_header(vh
, vkey
);
348 snprintf(buf
, 1024, "%s/%s", aes_xts_err
, aes_xts_errsrc
);
352 trace("Validating header...\n");
353 val
= validate_header(dh
);
355 case INVALID_SIGNATURE
:
357 "Could not decrypt the volume. You probably entered a wrong password.\n",
360 case KEY_CHECKSUM_MISMATCH
:
362 "The master key in your volume header seems to be corrupted. I can't\n"
363 "really see this happening on its own, except maybe if your RAM is broken.\n"
364 "Have it checked and try restoring the header from your rescue CD.\n",
367 case HEADER_CHECKSUM_MISMATCH
:
369 "Your volume header is corrupted. I suspect faulty RAM. Have it checked\n"
370 "(and possibly fixed) and restore the header from your rescue CD.\n",
373 case NOT_SYSTEM_ENCRYPTION
:
375 "This volume is not using system drive/partition encryption. This program\n"
376 "only supports volumes within the scope of system encryption. Please use\n"
377 "the official TrueCrypt(R) program for accessing this volume.\n",
380 case PARTIALLY_ENCRYPTED
:
382 "System encryption is still in progress. We can't really support partially\n"
383 "encrypted volumes under Linux without a lot of effort, so please have the\n"
384 "official TrueCrypt(R) program for Windows finish encrypting the volume\n"
385 "before you use this program.\n",
389 if (val
!= VALID_HEADER
) exit(1);
391 hkey
= get_header_keys(dh
);
392 size
= get_part_num_sectors(part_dev
);
393 start
= get_part_start_sector(part_dev
);
395 for (i
= 0; i
< 16; i
++) {
396 sprintf(&hkey_hex
[i
*8], "%08x", boswap(((unsigned int *) hkey
->data
)[i
]));
399 printf("0 %zu crypt aes-xts-plain %s %zu %s 0", size
, hkey_hex
,