| /* |
| * Example of LUKS/TrueCrypt password dictionary search |
| * |
| * Copyright (C) 2012 Milan Broz <gmazyland@gmail.com> |
| * |
| * Run this (for LUKS as root), |
| * e.g. ./crypt_dict test.img /usr/share/john/password.lst 4 |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * as published by the Free Software Foundation; either version 2 |
| * of the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <sys/types.h> |
| #include <sys/wait.h> |
| #include <sys/prctl.h> |
| #include <sys/time.h> |
| #include <sys/resource.h> |
| #include <libcryptsetup.h> |
| |
| #define MAX_LEN 512 |
| |
| static enum { LUKS, TCRYPT } device_type; |
| |
| static void check(struct crypt_device *cd, const char *pwd_file, unsigned my_id, unsigned max_id) |
| { |
| FILE *f; |
| int len, r = -1; |
| unsigned long line = 0; |
| char pwd[MAX_LEN]; |
| |
| if (fork()) |
| return; |
| |
| /* open password file, now in separate process */ |
| f = fopen(pwd_file, "r"); |
| if (!f) { |
| printf("Cannot open %s.\n", pwd_file); |
| exit(EXIT_FAILURE); |
| } |
| |
| while (fgets(pwd, MAX_LEN, f)) { |
| |
| /* every process tries N-th line, skip others */ |
| if (line++ % max_id != my_id) |
| continue; |
| |
| len = strlen(pwd); |
| |
| /* strip EOL - this is like a input from tty */ |
| if (len && pwd[len - 1] == '\n') { |
| pwd[len - 1] = '\0'; |
| len--; |
| } |
| |
| /* lines starting "#!comment" are comments */ |
| if (len >= 9 && !strncmp(pwd, "#!comment", 9)) { |
| /* printf("skipping %s\n", pwd); */ |
| continue; |
| } |
| |
| /* printf("%d: checking %s\n", my_id, pwd); */ |
| if (device_type == LUKS) |
| r = crypt_activate_by_passphrase(cd, NULL, CRYPT_ANY_SLOT, pwd, len, 0); |
| else if (device_type == TCRYPT) { |
| struct crypt_params_tcrypt params = { |
| .flags = CRYPT_TCRYPT_LEGACY_MODES, |
| .passphrase = pwd, |
| .passphrase_size = len, |
| }; |
| r = crypt_load(cd, CRYPT_TCRYPT, ¶ms); |
| } |
| if (r >= 0) { |
| printf("Found passphrase for slot %d: \"%s\"\n", r, pwd); |
| break; |
| } |
| } |
| |
| fclose(f); |
| crypt_free(cd); |
| exit(r >= 0 ? 2 : EXIT_SUCCESS); |
| } |
| |
| int main(int argc, char *argv[]) |
| { |
| int i, status, procs = 4; |
| struct crypt_device *cd; |
| |
| if (argc < 4 || argc > 5) { |
| printf("Use: %s luks|tcrypt <device|file> <password file> [#processes] %d\n", argv[0], argc); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (argc == 5 && (sscanf(argv[4], "%i", &procs) != 1 || procs < 1)) { |
| printf("Wrong number of processes.\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (!strcmp(argv[1], "luks")) |
| device_type = LUKS; |
| else if (!strcmp(argv[1], "tcrypt")) |
| device_type = TCRYPT; |
| else { |
| printf("Wrong device type %s.\n", argv[1]); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* crypt_set_debug_level(CRYPT_DEBUG_ALL); */ |
| |
| /* |
| * Need to create temporary keyslot device-mapper devices and allocate loop if needed, |
| * so root is requried here. |
| */ |
| if (getuid() != 0) { |
| printf("You must be root to run this program.\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* signal all children if anything happens */ |
| prctl(PR_SET_PDEATHSIG, SIGHUP); |
| setpriority(PRIO_PROCESS, 0, -5); |
| |
| /* we are not going to modify anything, so common init is ok */ |
| if (crypt_init(&cd, argv[2]) || |
| (device_type == LUKS && crypt_load(cd, CRYPT_LUKS1, NULL))) { |
| printf("Cannot open %s.\n", argv[2]); |
| exit(EXIT_FAILURE); |
| } |
| |
| /* run scan in separate processes, it is up to scheduler to assign CPUs inteligently */ |
| for (i = 0; i < procs; i++) |
| check(cd, argv[3], i, procs); |
| |
| /* wait until at least one finishes with error or status 2 (key found) */ |
| while (wait(&status) != -1 && WIFEXITED(status)) { |
| if (WEXITSTATUS(status) == EXIT_SUCCESS) |
| continue; |
| /* kill rest of processes */ |
| kill(0, SIGHUP); |
| /* not reached */ |
| break; |
| } |
| exit(0); |
| } |