2 * LUKS keyslot entropy tester. Works only for header version 1.
4 * Functionality: Determines sample entropy (symbols: bytes) for
5 * each (by default) 512B sector in each used keyslot. If it
6 * is lower than a threshold, the sector address is printed
7 * as it is suspected of having non-"random" data in it, indicating
8 * damage by overwriting. This can obviously not find overwriting
9 * with random or random-like data (encrypted, compressed).
12 * v0.1: 09.09.2012 Initial release
13 * v0.2: 08.10.2012 Converted to use libcryptsetup
15 * Copyright (C) 2012, Arno Wagner <arno@wagner.name>
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * version 2 as published by the Free Software Foundation.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 #include <libcryptsetup.h>
41 "Version 0.2 [8.10.2012]\n"
43 " chk_luks_keyslots [options] luks-device \n"
45 "This tool checks all keyslots of a LUKS device for \n"
46 "low entropy sections. If any are found, they are reported. \n"
47 "This allows to find areas damaged by things like filesystem \n"
48 "creation or RAID superblocks. \n"
51 " -t <num> Entropy threshold. Possible values 0.0 ... 1.0 \n"
52 " Default: 0.90, which works well for 512B sectors.\n"
53 " For 512B sectors, you will get frequent misdetections\n"
54 " at thresholds around 0.94\n"
55 " Higher value: more sensitive but more false detections.\n"
56 " -s <num> Sector size. Must divide keyslot-size.\n"
57 " Default: 512 Bytes.\n"
58 " Values smaller than 128 are generally not very useful.\n"
59 " For values smaller than the default, you need to adjust\n"
60 " the threshold down to reduce misdetection. For values\n"
61 " larger than the default you need to adjust the threshold\n"
62 " up to retain sensitivity.\n"
63 " -v Print found suspicuous sectors verbosely. \n"
64 " -d Print decimal addresses instead of hex ones.\n"
70 static int sector_size = 512;
71 static double threshold = 0.90;
72 static int print_decimal = 0;
73 static int verbose = 0;
77 /* Calculates and returns sample entropy on byte level for
80 static double ent_samp(unsigned char * buf, int len)
82 int freq[256]; /* stores symbol frequencies */
86 /* 0. Plausibility checks */
90 /* 1. count all frequencies */
91 for (i = 0; i < 256; i++) {
95 for (i = 0; i < len; i ++)
98 /* 2. calculate sample entropy */
100 for (i = 0; i < 256; i++) {
115 static void print_address(FILE *out, uint64_t value)
118 fprintf(out,"%08" PRIu64 " ", value);
120 fprintf(out,"%#08" PRIx64 " ", value);
124 /* uses default "hd" style, i.e. 16 bytes followed by ASCII */
125 static void hexdump_line(FILE *out, uint64_t address, unsigned char *buf) {
127 static char tbl[16] = "0123456789ABCDEF";
130 print_address(out, address);
134 for (i = 0; i < 16; i++) {
136 tbl[(unsigned char)buf[i]>> 4],
137 tbl[(unsigned char)buf[i] & 0x0f]);
146 for (i = 0; i < 16; i++) {
147 if (isprint(buf[i])) {
148 fprintf(out, "%c", buf[i]);
156 static void hexdump_sector(FILE *out, unsigned char *buf, uint64_t address, int len)
161 while (len - done >= 16) {
162 hexdump_line(out, address + done, buf + done);
167 static int check_keyslots(FILE *out, struct crypt_device *cd, int f_luks)
172 uint64_t start, length, end;
173 crypt_keyslot_info ki;
174 unsigned char buffer[sector_size];
176 for (i = 0; i < crypt_keyslot_max(CRYPT_LUKS1) ; i++) {
177 fprintf(out, "- processing keyslot %d:", i);
178 ki = crypt_keyslot_status(cd, i);
179 if (ki == CRYPT_SLOT_INACTIVE) {
180 fprintf(out, " keyslot not in use\n");
184 if (ki == CRYPT_SLOT_INVALID) {
185 fprintf(out, "\nError: keyslot invalid.\n");
189 if (crypt_keyslot_area(cd, i, &start, &length) < 0) {
190 fprintf(stderr,"\nError: querying keyslot area failed for slot %d\n", i);
194 end = start + length;
196 fprintf(out, " start: ");
197 print_address(out, start);
198 fprintf(out, " end: ");
199 print_address(out, end);
202 /* check whether sector-size divides size */
203 if (length % sector_size != 0) {
204 fprintf(stderr,"\nError: Argument to -s does not divide keyslot size\n");
208 for (ofs = start; (uint64_t)ofs < end; ofs += sector_size) {
209 if (lseek(f_luks, ofs, SEEK_SET) != ofs) {
210 fprintf(stderr,"\nCannot seek to keyslot area.\n");
213 if (read(f_luks, buffer, sector_size) != sector_size) {
214 fprintf(stderr,"\nCannot read keyslot area.\n");
217 ent = ent_samp(buffer, sector_size);
218 if (ent < threshold) {
219 fprintf(out, " low entropy at: ");
220 print_address(out, ofs);
221 fprintf(out, " entropy: %f\n", ent);
223 fprintf(out, " Binary dump:\n");
224 hexdump_sector(out, buffer, (uint64_t)ofs, sector_size);
235 int main(int argc, char **argv)
237 /* for option processing */
241 /* for use of libcryptsetup */
242 struct crypt_device *cd;
245 int f_luks; /* device file for the luks device */
248 /* temporary helper vars */
256 /* global initializations */
259 /* get commandline parameters */
260 while ((c = getopt (argc, argv, "t:s:vd")) != -1) {
264 tvalue = strtod(s, &end);
266 fprintf(stderr, "\nError: Parsing of argument to -t failed.\n");
270 if (tvalue < 0.0 || tvalue > 1.0) {
271 fprintf(stderr,"\nError: Argument to -t must be in 0.0 ... 1.0\n");
278 svalue = strtol(s, &end, 10);
280 fprintf(stderr, "\nError: Parsing of argument to -s failed.\n");
285 fprintf(stderr,"\nError: Argument to -s must be >= 1 \n");
288 sector_size = svalue;
297 if (optopt == 't' || optopt == 's')
298 fprintf (stderr,"\nError: Option -%c requires an argument.\n",
300 else if (isprint (optopt)) {
301 fprintf(stderr,"\nError: Unknown option `-%c'.\n", optopt);
302 fprintf(stderr,"\n\n%s", help);
304 fprintf (stderr, "\nError: Unknown option character `\\x%x'.\n",
306 fprintf(stderr,"\n\n%s", help);
314 /* parse non-option stuff. Should be exactly one, the device. */
315 if (optind+1 != argc) {
316 fprintf(stderr,"\nError: exactly one non-option argument expected!\n");
317 fprintf(stderr,"\n\n%s", help);
320 device = argv[optind];
322 /* test whether we can open and read device */
323 /* This is neded as we are reading the actual data
324 * in the keyslots dirtectly from the LUKS container.
326 f_luks = open(device, O_RDONLY);
328 fprintf(stderr,"\nError: Opening of device %s failed:\n", device);
333 /* now get the parameters we need via libcryptsetup */
334 /* Basically we need all active keyslots and their placement on disk */
336 /* first init. This does the following:
337 * - gets us a crypt_device struct with some values filled in
338 * Note: This does some init stuff we do not need, but that
339 * should not cause trouble.
342 res = crypt_init(&cd, device);
344 fprintf(stderr, "crypt_init() failed. Maybe not running as root?\n");
349 /* now load LUKS header into the crypt_device
350 * This should also make sure a valid LUKS1 header is on disk
351 * and hence we should be able to skip magic and version checks.
353 res = crypt_load(cd, CRYPT_LUKS1, NULL);
355 fprintf(stderr, "crypt_load() failed. LUKS header too broken/absent?\n");
361 fprintf(out, "\nparameters (commandline and LUKS header):\n");
362 fprintf(out, " sector size: %d\n", sector_size);
363 fprintf(out, " threshold: %0f\n\n", threshold);
365 r = check_keyslots(out, cd, f_luks);