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, int 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, int 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, unsigned char *buffer)
172 uint64_t start, length, end;
173 crypt_keyslot_info ki;
175 for (i = 0; i < crypt_keyslot_max(CRYPT_LUKS1) ; i++) {
176 fprintf(out, "- processing keyslot %d:", i);
177 ki = crypt_keyslot_status(cd, i);
178 if (ki == CRYPT_SLOT_INACTIVE) {
179 fprintf(out, " keyslot not in use\n");
183 if (ki == CRYPT_SLOT_INVALID) {
184 fprintf(out, "\nError: keyslot invalid.\n");
188 if (crypt_keyslot_area(cd, i, &start, &length) < 0) {
189 fprintf(stderr,"\nError: querying keyslot area failed for slot %d\n", i);
193 end = start + length;
195 fprintf(out, " start: ");
196 print_address(out, start);
197 fprintf(out, " end: ");
198 print_address(out, end);
201 /* check whether sector-size divides size */
202 if (length % sector_size != 0) {
203 fprintf(stderr,"\nError: Argument to -s does not divide keyslot size\n");
207 for (j = start; j < end; j += sector_size) {
209 lseek(f_luks, ofs, SEEK_SET);
210 read(f_luks, buffer, sector_size);
211 ent = ent_samp(buffer, sector_size);
212 // printf("slot: %d offset: %8x ent: %f\n", i, ofs, ent);
213 if (ent < threshold) {
214 fprintf(out, " low entropy at: ");
215 print_address(out, ofs);
216 fprintf(out, " entropy: %f\n", ent);
218 fprintf(out, " Binary dump:\n");
219 hexdump_sector(out, buffer, ofs, sector_size);
230 int main(int argc, char **argv)
232 /* for option processing */
235 unsigned char *buffer;
237 /* for use of libcryptsetup */
238 struct crypt_device *cd;
241 int f_luks; /* device file for the luks device */
244 /* temporary helper vars */
252 /* global initializations */
255 /* get commandline parameters */
256 while ((c = getopt (argc, argv, "t:s:vd")) != -1) {
260 tvalue = strtod(s, &end);
262 fprintf(stderr, "\nError: Parsing of argument to -t failed.\n");
266 if (tvalue < 0.0 || tvalue > 1.0) {
267 fprintf(stderr,"\nError: Argument to -t must be in 0.0 ... 1.0\n");
274 svalue = strtol(s, &end, 10);
276 fprintf(stderr, "\nError: Parsing of argument to -s failed.\n");
281 fprintf(stderr,"\nError: Argument to -s must be >= 1 \n");
284 sector_size = svalue;
293 if (optopt == 't' || optopt == 's')
294 fprintf (stderr,"\nError: Option -%c requires an argument.\n",
296 else if (isprint (optopt)) {
297 fprintf(stderr,"\nError: Unknown option `-%c'.\n", optopt);
298 fprintf(stderr,"\n\n%s", help);
300 fprintf (stderr, "\nError: Unknown option character `\\x%x'.\n",
302 fprintf(stderr,"\n\n%s", help);
310 /* parse non-option stuff. Should be exactly one, the device. */
311 if (optind+1 != argc) {
312 fprintf(stderr,"\nError: exactly one non-option argument expected!\n");
313 fprintf(stderr,"\n\n%s", help);
316 device = argv[optind];
318 buffer = calloc(sector_size, 1);
320 fprintf(stderr,"\nError: Cannot allocate buffer.\n");
324 /* test whether we can open and read device */
325 /* This is neded as we are reading the actual data
326 * in the keyslots dirtectly from the LUKS container.
328 f_luks = open(device, O_RDONLY);
330 fprintf(stderr,"\nError: Opening of device %s failed:\n", device);
335 /* now get the parameters we need via libcryptsetup */
336 /* Basically we need all active keyslots and their placement on disk */
338 /* first init. This does the following:
339 * - gets us a crypt_device struct with some values filled in
340 * Note: This does some init stuff we do not need, but that
341 * should not cause trouble.
344 res = crypt_init(&cd, device);
346 fprintf(stderr, "crypt_init() failed. Maybe not running as root?\n");
351 /* now load LUKS header into the crypt_device
352 * This should also make sure a valid LUKS1 header is on disk
353 * and hence we should be able to skip magic and version checks.
355 res = crypt_load(cd, CRYPT_LUKS1, NULL);
357 fprintf(stderr, "crypt_load() failed. LUKS header too broken/absent?\n");
363 fprintf(out, "\nparameters (commandline and LUKS header):\n");
364 fprintf(out, " sector size: %d\n", sector_size);
365 fprintf(out, " threshold: %0f\n\n", threshold);
367 r = check_keyslots(out, cd, f_luks, buffer);