2010-08-05 Milan Broz <mbroz@redhat.com>
* Wipe iteration and salt after KillSlot in LUKS header.
+ * Rewrite file differ test to C (and fix it to really work).
2010-07-28 Arno Wagner <arno@wagner.name>
* Add FAQ (Frequently Asked Questions) file to distribution.
TESTS = api-test compat-test align-test
-EXTRA_DIST = fileDiffer.py compatimage.img.bz2 align-test compat-test
+EXTRA_DIST = compatimage.img.bz2 align-test compat-test
+
+differ_SOURCES = differ.c
+differ_CFLAGS = -Wall -O2
api_test_SOURCES = api-test.c
api_test_LDADD = ../lib/libcryptsetup.la
api_test_LDFLAGS = -static
api_test_CFLAGS = -g -Wall -O0 -I$(top_srcdir)/lib/
-check_PROGRAMS = api-test
+check_PROGRAMS = api-test differ
compatimage.img:
@bzip2 -k -d compatimage.img.bz2
DEV_NAME2=dummy2
ORIG_IMG=luks-test-orig
IMG=luks-test
-IMG1=luks-test1
KEY1=key1
LUKS_HEADER="S0-5 S6-7 S8-39 S40-71 S72-103 S104-107 S108-111 R112-131 R132-163 S164-167 S168-207 A0-591"
-KEY_SLOT0="S208-211 S212-215 R216-247 S248-251 S251-255"
+KEY_SLOT0="S208-211 S212-215 R216-247 A248-251 A251-255"
KEY_MATERIAL0="R4096-68096"
KEY_MATERIAL0_EXT="R4096-68096"
-KEY_SLOT1="S256-259 S260-263 R264-295 S296-299 S300-303"
+KEY_SLOT1="S256-259 S260-263 R264-295 A296-299 A300-303"
KEY_MATERIAL1="R69632-133632"
KEY_MATERIAL1_EXT="S69632-133632"
[ -b /dev/mapper/$DEV_NAME2 ] && dmsetup remove $DEV_NAME2
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME
losetup -d $LOOPDEV >/dev/null 2>&1
- rm -f $ORIG_IMG $IMG $IMG1 $KEY1 >/dev/null 2>&1
+ rm -f $ORIG_IMG $IMG $KEY1 >/dev/null 2>&1
}
function fail()
function prepare()
{
- if [ $(id -u) != 0 ]; then
- echo "WARNING: You must be root to run this test, test skipped."
- exit 0
- fi
-
[ -b /dev/mapper/$DEV_NAME ] && dmsetup remove $DEV_NAME
- if [ ! -e $KEY1 ]; then
- dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1
- fi
-
- if [ ! -e $IMG ]; then
+ case "$2" in
+ wipe)
+ remove_mapping
+ dd if=/dev/zero of=$IMG bs=1k count=10000 >/dev/null 2>&1
+ sync
+ losetup $LOOPDEV $IMG
+ ;;
+ new)
+ remove_mapping
bzip2 -cd compatimage.img.bz2 > $IMG
- losetup -d $LOOPDEV >/dev/null 2>&1
losetup $LOOPDEV $IMG
+ ;;
+ reuse | *)
+ if [ ! -e $IMG ]; then
+ bzip2 -cd compatimage.img.bz2 > $IMG
+ losetup $LOOPDEV $IMG
+ fi
+ ;;
+ esac
+
+ if [ ! -e $KEY1 ]; then
+ dd if=/dev/urandom of=$KEY1 count=1 bs=32 >/dev/null 2>&1
fi
cp $IMG $ORIG_IMG
-
[ -n "$1" ] && echo "CASE: $1"
}
function check()
{
sync
- ./fileDiffer.py $IMG $ORIG_IMG $1|| fail
+ [ -z "$1" ] && return
+ ./differ $ORIG_IMG $IMG $1 || fail
}
function check_exists()
check $1
}
+if [ $(id -u) != 0 ]; then
+ echo "WARNING: You must be root to run this test, test skipped."
+ exit 0
+fi
+
# LUKS tests
-prepare "[1] open - compat image - acceptance check"
+prepare "[1] open - compat image - acceptance check" new
echo "compatkey" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail
check_exists
-prepare "[2] open - compat image - denial check"
+prepare "[2] open - compat image - denial check" new
echo "wrongkey" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME && fail
check
# All headers items and first key material section must change
-prepare "[3] format"
+prepare "[3] format" wipe
echo "key0" | $CRYPTSETUP -i 1000 -c aes-cbc-essiv:sha256 -s 128 luksFormat $LOOPDEV || fail
check "$LUKS_HEADER $KEY_SLOT0 $KEY_MATERIAL0"
-prepare "[4] format using hash sha512"
+prepare "[4] format using hash sha512" wipe
echo "key0" | $CRYPTSETUP -i 1000 -h sha512 -c aes-cbc-essiv:sha256 -s 128 luksFormat $LOOPDEV || fail
check "$LUKS_HEADER $KEY_SLOT0 $KEY_MATERIAL0"
# Unsuccessful Key Delete - nothing may change
prepare "[7] unsuccessful delete"
-echo "invalid" | $CRYPTSETUP luksDelKey $LOOPDEV 1 && fail
+echo "invalid" | $CRYPTSETUP luksKillSlot $LOOPDEV 1 && fail
check
# Delete Key Test
# Key Slot 1 and key material section 1 must change, the rest must not
prepare "[8] successful delete"
-$CRYPTSETUP -q luksDelKey $LOOPDEV 1 || fail
+$CRYPTSETUP -q luksKillSlot $LOOPDEV 1 || fail
check "$KEY_SLOT1 $KEY_MATERIAL1_EXT"
echo "key1" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME && fail
echo "key0" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME || fail
# Key Slot 1 and key material section 1 must change, the rest must not
prepare "[10] delete key test with key1 as remaining key"
-$CRYPTSETUP -d $KEY1 luksDelKey $LOOPDEV 0 || fail
+$CRYPTSETUP -d $KEY1 luksKillSlot $LOOPDEV 0 || fail
check "$KEY_SLOT0 $KEY_MATERIAL0_EXT"
echo "key0" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME && fail
$CRYPTSETUP luksOpen -d $KEY1 $LOOPDEV $DEV_NAME || fail
# Delete last slot
-prepare "[11] delete last key"
+prepare "[11] delete last key" wipe
echo "key0" | $CRYPTSETUP luksFormat $LOOPDEV || fail
echo "key0" | $CRYPTSETUP luksKillSlot $LOOPDEV 0 || fail
echo "key0" | $CRYPTSETUP luksOpen $LOOPDEV $DEV_NAME && fail
# Format test for ESSIV, and some other parameters.
-prepare "[12] parameter variation test"
+prepare "[12] parameter variation test" wipe
$CRYPTSETUP -q -i 1000 -c aes-cbc-essiv:sha256 -s 128 luksFormat $LOOPDEV $KEY1 || fail
check "$LUKS_HEADER $KEY_SLOT0 $KEY_MATERIAL0"
$CRYPTSETUP -d $KEY1 luksOpen $LOOPDEV $DEV_NAME || fail
-prepare "[13] open/close - stacked devices"
+prepare "[13] open/close - stacked devices" wipe
echo "key0" | $CRYPTSETUP -q luksFormat $LOOPDEV || fail
echo "key0" | $CRYPTSETUP -q luksOpen $LOOPDEV $DEV_NAME || fail
echo "key0" | $CRYPTSETUP -q luksFormat /dev/mapper/$DEV_NAME || fail
$CRYPTSETUP -q luksClose $DEV_NAME2 || fail
$CRYPTSETUP -q luksClose $DEV_NAME || fail
-prepare "[14] format/open - passphrase on stdin & new line"
+prepare "[14] format/open - passphrase on stdin & new line" wipe
# stdin defined by "-" must take even newline
echo -n $'foo\nbar' | $CRYPTSETUP -q luksFormat $LOOPDEV - || fail
echo -n $'foo\nbar' | $CRYPTSETUP -q --key-file=- luksOpen $LOOPDEV $DEV_NAME || fail
--- /dev/null
+/*
+ * cryptsetup file differ check (rewritten Clemens' fileDiffer in Python)
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+struct ffile {
+ char *name;
+ int fd;
+ unsigned char *addr;
+ size_t size;
+};
+
+enum df { OK , FAIL };
+
+static void print_diff(off_t from, int max,
+ const unsigned char *o,
+ const unsigned char *n)
+{
+ int i, len = max;
+
+ if (len > 16)
+ len = 16;
+
+ printf("OLD:");
+ for (i = 0; i < len; i++)
+ printf(" %02x", o[from + i]);
+ printf("%s\n ", max != len ? " ..." : "");
+ for (i = 0; i < len; i++)
+ printf(" %2c", o[from + i] > ' ' ? o[from + i]: '.');
+ printf("\nNEW:");
+ for (i = 0; i < len; i++)
+ printf(" %02x", n[from + i]);
+ printf("%s\n ", max != len ? " ..." : "");
+ for (i = 0; i < len; i++)
+ printf(" %2c", n[from + i] > ' ' ? n[from + i]: '.');
+ printf("\n");
+}
+
+/*
+ * Xfrom-to (e.g. R10-15)
+ * A - change allowed
+ * S - change required, semantic
+ * R - change required, random
+ * F - change forbidden
+ */
+static enum df check(const char *range, unsigned char *o, unsigned char *n)
+{
+ char strict;
+ unsigned long long from, to;
+ enum df ret;
+
+ if (sscanf(range, "%c%llu-%llu", &strict, &from, &to) != 3) {
+ printf("Unknown range format %s.\n", range);
+ return FAIL;
+ }
+
+ switch (toupper(strict)) {
+ case 'A':
+ ret = OK;
+ break;
+ case 'S':
+ ret = memcmp(&o[from], &n[from], to - from + 1) != 0 ? OK : FAIL;
+ break;
+ case 'R': /* FIXME - random test */
+ ret = memcmp(&o[from], &n[from], to - from + 1) != 0 ? OK : FAIL;
+ break;
+ case 'F':
+ ret = memcmp(&o[from], &n[from], to - from + 1) == 0 ? OK : FAIL;
+ break;
+ default:
+ ret = FAIL;
+ break;
+ }
+
+ if (ret == FAIL)
+ print_diff(from, to - from + 1, o, n);
+
+ return ret;
+}
+
+static int open_mmap(struct ffile *f)
+{
+ struct stat st;
+
+ f->fd = open(f->name, O_RDONLY);
+ if (f->fd == -1 || fstat(f->fd, &st) == -1)
+ return 0;
+
+ f->size = st.st_size;
+ f->addr = mmap(NULL, f->size, PROT_READ, MAP_PRIVATE, f->fd, 0);
+
+ return (f->addr == MAP_FAILED) ? 0 : 1;
+}
+
+static void close_mmap(struct ffile *f)
+{
+ if (f->addr != MAP_FAILED && !munmap(f->addr, f->size))
+ f->addr = MAP_FAILED;
+
+ if (f->fd != -1 && !close(f->fd))
+ f->fd = -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int i, r = 1;
+ struct ffile file_old = {
+ .fd = -1,
+ .addr = MAP_FAILED,
+ };
+ struct ffile file_new = {
+ .fd = -1,
+ .addr = MAP_FAILED,
+ };
+
+ if (argc < 3) {
+ printf("Use: differ old_file new_file change_list.\n");
+ goto bad;
+ }
+
+ file_old.name = argv[1];
+ if (!open_mmap(&file_old))
+ goto bad;
+
+ file_new.name = argv[2];
+ if (!open_mmap(&file_new))
+ goto bad;
+
+ for (i = 3; i < argc; i++)
+ if (check(argv[i], file_old.addr, file_new.addr) == FAIL) {
+ printf ("FAILED for %s\n", argv[i]);
+ r = 1;
+ goto bad;
+ }
+
+ r = 0;
+bad:
+ close_mmap(&file_new);
+ close_mmap(&file_old);
+
+ return r;
+}
+++ /dev/null
-#!/usr/bin/python
-
-#
-# Usage: fileDiffer <afile> <bfile> <list of disk changes>
-#
-
-# LUKS
-# quick regression test suite
-# Tests LUKS images for changes at certain disk offsets
-#
-# Does fast python code has to look ugly or is it just me?
-
-import sys
-
-class changes:
- pass
-
-def parseArgs(args):
- aFileName = args[1]
- bFileName = args[2]
- changelist = []
- args[0:3] = []
- for i in args:
- mychanges = changes();
- if i.startswith('A'):
- mychanges.mode = 'ALLOWED'
- if i.startswith('R'):
- mychanges.mode = 'REQUIRED'
- mychanges.strictness = 'RANDOM'
- if i.startswith('S'):
- mychanges.mode = 'REQUIRED'
- mychanges.strictness = 'SEMANTIC'
-
- dashIndex = i.find('-')
- if dashIndex == -1:
- mychanges.starts = int(i[1:])
- mychanges.ends = mychanges.starts
- else:
- mychanges.starts = int(i[1:dashIndex])
- mychanges.ends = int(i[dashIndex+1:])
- mychanges.miss = 0
- changelist.append(mychanges)
- mychanges = changes();
- mychanges.starts = 0
-# mychanges.ends will be fixed later
- mychanges.mode = 'FORBIDDEN'
- changelist.append(mychanges)
- return [aFileName, bFileName, changelist]
-
-def mode(i):
- for c in changelist:
- if i >= c.starts and i<=c.ends:
- return c
-def cleanchanges(i):
- newchangelist=[]
- for c in changelist:
- if i <= c.starts or i <= c.ends:
- newchangelist.append(c)
- return newchangelist
-
-[aFileName, bFileName, changelist] = parseArgs(sys.argv)
-
-aFile = open(aFileName,'r')
-bFile = open(bFileName,'r')
-
-aString = aFile.read()
-bString = bFile.read()
-
-if len(aString) != len(bString):
- sys.exit("Mismatch different file sizes")
-
-fileLen = len(aString)
-fileLen10th = fileLen/10
-
-# Create a catch all entry
-changelist[-1].ends = fileLen
-
-print "Changes list: (FORBIDDEN default)"
-print "start\tend\tmode\t\tstrictness"
-for i in changelist:
- if i.mode == 'REQUIRED':
- print "%d\t%d\t%s\t%s" % (i.starts, i.ends, i.mode, i.strictness)
- else:
- print "%d\t%d\t%s" % (i.starts, i.ends, i.mode)
-
-
-filepos = 0
-fileLen10thC = 0
-print "[..........]"
-sys.stdout.write("[")
-sys.stdout.flush()
-
-modeNotTrivial = 1
-while filepos < fileLen:
-
- if modeNotTrivial == 1:
- c = mode(filepos)
-# print (filepos, c.mode)
- if c.mode == 'REQUIRED':
- if aString[filepos] == bString[filepos]:
- c.miss = c.miss + 1
- else:
- if aString[filepos] != bString[filepos] and c.mode != 'ALLOWED':
- sys.exit("Mismatch at %d: change forbidden" % filepos)
-
- # Do some maintaince, print progress bar, and clean changelist
- #
- # Maintaining two counters appears to be faster than modulo operation
- if fileLen10thC == fileLen10th:
- fileLen10thC = 0
- sys.stdout.write(".")
- sys.stdout.flush()
- changelist = cleanchanges(filepos)
- if len(changelist) == 1:
- modeNotTrivial = 0
- filepos = filepos + 1
- fileLen10thC = fileLen10thC + 1
-
-for c in changelist:
- if c.mode == 'REQUIRED':
- if c.strictness == 'SEMANTIC' and c.miss == (c.ends-c.starts+1):
- sys.exit("Mismatch: not even a single change in region %d-%d." % (c.starts, c.ends))
- # This is not correct. We should do a statistical test
- # of the sampled data against the hypothetical distribution
- # of collision. Chi-Square Test.
- if c.strictness == 'RANDOM' and c.miss == (c.ends-c.starts+1):
- sys.exit("Mismatch: not even a single change in region %d-%d." % (c.starts, c.ends))
-
-print ".] - everything ok"