Another sesame patch

W. Michael Petullo mike at flyn.org
Wed Jan 19 12:32:24 PST 2005


Attached you should find another patch vs. sesame CVS.

This patch contains the following changes from the previous one:

	* tools/check-common.c: Added some unit tests using the check
	framework -- preparation for refactoring

	* tools/common.c: Refactoring of some code

	* tools/sesame-format.c: Check if a device is mounted before
	formatting it

	* tools/sesame-format.c: Use a temporary DM device to format --
	hide device from hal until ready

	* tools/sesame-is-encrypted.c: Begin a program that checks if a
	device is encrypted using sesame

Using the programs is very similar to the previous patch.  I am
doing everything by hand right now -- eventually hald will handle the
sesame-setup automatically.  Here are the steps:

==== FORMAT ====

1.  Execute sesame-format.  This will block, waiting for a password on stdin:
./sesame-format -v /dev/sdb4

2.  Place the information printed by sesame-format into a sesame header:
uuid is <UUID>
encrypted key is <EKEY>

The header should look like this:
# SESAME_MAGIC
version = '0'
uuid = '<UUID>'
block_key_cipher = 'aes'
block_key_sha1 = 'FIXME'
enc_key_cipher = 'aes'
enc_key = '<EKEY>'

3.  Remove the dm-crypt device created in step 1:
cryptsetup remove DMDEVICE

4.  Install the sesame header (this should be done by sesame-format, but
libsetup does not yet support writing):
dd if=/dev/zero bs=1c count=512 of=/dev/sdb4
dd if=../../cryptheader bs=1c count=512 of=/dev/sdb4

==== SETUP (eventually will be performed by hald) ====

1.  Execute sesame-setup, entering the password from step 1.
./sesame-setup -v /dev/sdb4

2.  Mount the dm-crypt device.
mount /dev/mapper/sesame_crypto_<UUID> ...

-- 
Mike

:wq
-------------- next part --------------
diff -u --recursive --new-file sesame-cvs-vanilla/ChangeLog sesame-cvs/ChangeLog
--- sesame-cvs-vanilla/ChangeLog	2004-12-31 07:35:47.000000000 -0600
+++ sesame-cvs/ChangeLog	2005-01-19 14:17:04.119372424 -0600
@@ -1,3 +1,33 @@
+2005-01-19  W. Michael Petullo  <mike at flyn.org>
+
+	* tools/check-common.c: Added some unit tests using the check
+	framework -- preparation for refactoring
+
+	* tools/common.c: Refactoring of some code
+
+	* tools/sesame-format.c: Check if a device is mounted before
+	formatting it
+
+	* tools/sesame-format.c: Use a temporary DM device to format --
+	hide device from hal until ready
+
+	* tools/sesame-is-encrypted.c: Begin a program that checks if a
+	device is encrypted using sesame
+
+2004-01-19  W. Michael Petullo  <mike at flyn.org>
+
+	* tools/common.c: Moved some code to common.c
+
+	* tools/common.c: Fixed encode/decode leak
+
+	* tools/sesame-setup.c: Minor code changes
+
+	* tools/sesame-format.c: Began work on a new utility to format
+	a sesame-compliant disk
+
+	* tools/sesame-setup.c: Now takes aes as name of cipher and
+	resolved this to aes-128-ecb for OpenSSL calls.
+
 2004-12-31  David Zeuthen  <davidz at redhat.com>
 
 	Patch from W. Michael Petullo <mike at flyn.org>. I wrote a patch for
diff -u --recursive --new-file sesame-cvs-vanilla/configure.in sesame-cvs/configure.in
--- sesame-cvs-vanilla/configure.in	2004-12-31 07:35:47.000000000 -0600
+++ sesame-cvs/configure.in	2005-01-19 13:11:15.000000000 -0600
@@ -6,6 +6,11 @@
 AM_CONFIG_HEADER(config.h)
 AM_MAINTAINER_MODE
 
+AM_PATH_CHECK(,[have_check="yes"],
+  AC_MSG_WARN([Check not found; cannot run unit tests!])
+    [have_check="no"])
+    AM_CONDITIONAL(HAVE_CHECK, test x"$have_check" = "xyes")
+
 AC_ISC_POSIX
 AC_PROG_CC
 AM_PROG_CC_STDC
@@ -14,6 +19,7 @@
 AC_PROG_MAKE_SET
 AC_PROG_LN_S
 AC_SYS_LARGEFILE
+AM_PATH_GLIB_2_0(,,AC_MSG_ERROR(You are missing glib))
 
 AC_ARG_ENABLE(ansi,             [  --enable-ansi           enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no)
 
@@ -105,6 +111,7 @@
 #PKG_CHECK_MODULES(PACKAGE, [$pkg_modules])
 AC_CHECK_LIB(crypto, EVP_DecryptInit_ex)
 AC_CHECK_LIB(ssl, SSL_load_error_strings)
+AC_CHECK_LIB(uuid, uuid_generate)
 
 AC_PATH_PROG(CRYPTSETUP, cryptsetup, no)
 if test x"$CRYPTSETUP" = xno; then
@@ -112,6 +119,18 @@
 fi
 AC_SUBST(CRYPTSETUP)
 
+AC_PATH_PROG(DD, dd, no)
+if test x"$DD" = xno; then
+        AC_MSG_ERROR([dd executable not found in your path])
+fi
+AC_SUBST(DD)
+
+AC_PATH_PROG(MKFS, mkfs, no)
+if test x"$MKFS" = xno; then
+        AC_MSG_ERROR([mkfs executable not found in your path])
+fi
+AC_SUBST(MKFS)
+
 AS_AC_EXPAND(LOCALSTATEDIR, $localstatedir)
 AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
 AS_AC_EXPAND(DATADIR, $datadir)
Binary files sesame-cvs-vanilla/libsesame/libsesame.o and sesame-cvs/libsesame/libsesame.o differ
Binary files sesame-cvs-vanilla/tools/check_common and sesame-cvs/tools/check_common differ
diff -u --recursive --new-file sesame-cvs-vanilla/tools/check_common.c sesame-cvs/tools/check_common.c
--- sesame-cvs-vanilla/tools/check_common.c	1969-12-31 18:00:00.000000000 -0600
+++ sesame-cvs/tools/check_common.c	2005-01-19 13:21:37.120153184 -0600
@@ -0,0 +1,156 @@
+#include <stdlib.h>
+#include <check.h>
+#include <string.h>
+#include <common.h>
+#include <openssl/evp.h>
+#include <openssl/ssl.h>
+
+#ifndef EVP_MAX_BLOCK_LENGTH
+#define EVP_MAX_BLOCK_LENGTH 32 /* some older openssl versions need this */
+#endif
+
+START_TEST(test_strip_cr)
+{
+	char str[5];
+	strcpy(str, "foo\n");
+	fail_unless(strcmp(strip_cr(str), "foo") == 0,
+		    "strip_cr test failed");
+}
+END_TEST
+
+START_TEST(test_encode)
+{
+	char data[] = { 0x00, 0x01, 0x02, 0x0a, 0x0b, 0x0c, 0xfd, 0xfe, 
+		        0xff };
+	char edata[sizeof data * 2 + 1];
+	fail_unless(strcmp
+		    (encode(edata, data, sizeof data),
+		     "0001020a0b0cfdfeff") == 0, "encode test failed");
+}
+END_TEST 
+
+START_TEST(test_decode)
+{
+	char *data = "0001020a0b0cfdfeff";
+	char ddata[sizeof data / 2 - 1];
+	char answer[] = { 0x00, 0x01, 0x02, 0x0a, 0x0b, 0x0c, 0xfd, 0xfe, 
+			  0xff };
+	fail_unless(memcmp(decode(ddata, data), answer, sizeof answer) == 0,
+		    "decode test failed");
+}
+END_TEST
+
+START_TEST(test_encode_decode)
+{
+	char data[] = { 0x00, 0x01, 0x02, 0x0a, 0x0b, 0x0c, 0xfd, 0xfe, 
+		        0xff };
+	char edata[sizeof data * 2 + 1];
+	char ddata[sizeof data / 2 - 1];
+	fail_unless(memcmp
+		    (decode(ddata, encode(edata, data, sizeof data)), data,
+		     sizeof data) == 0, "encode_decode test failed");
+}
+END_TEST
+
+START_TEST(test_encrypt_it)
+{
+	char data[] = { 0x00, 0x01, 0x02, 0x0a, 0x0b, 0x0c, 0xfd, 0xfe, 
+		        0xff };
+	/* Salted__ + salt + padded ciphertext: */
+	char answer[] = { 0x53, 0x61, 0x6c, 0x74, 0x65, 0x64, 0x5f, 0x5f, 
+			  0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+			  0x08, 0xf0, 0xa5, 0x83, 0x6f, 0x7c, 0xfd, 0x31, 
+			  0xad, 0x0a, 0x53, 0x29, 0xc6, 0x18, 0xfb, 0x8c };
+	char edata[BUFSIZ + EVP_MAX_BLOCK_LENGTH];
+	int edata_len;
+	char salt[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+	fail_unless(crypt_it(edata, &edata_len, data, sizeof data, 
+			       "aes-128-ecb", "passphrase", salt,
+			       salt_write, EVP_EncryptInit_ex, 
+			       EVP_EncryptUpdate, EVP_EncryptFinal_ex) == 1);
+	fail_unless(memcmp(edata, answer, sizeof answer) == 0, 
+		    "encrypt_it test failed");
+}
+END_TEST
+
+START_TEST(test_decrypt_it)
+{
+	/* Salted__ + salt + padded ciphertext: */
+	char data[] = { 0x53, 0x61, 0x6c, 0x74, 0x65, 0x64, 0x5f, 0x5f, 
+			0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
+			0x08, 0xf0, 0xa5, 0x83, 0x6f, 0x7c, 0xfd, 0x31, 
+			0xad, 0x0a, 0x53, 0x29, 0xc6, 0x18, 0xfb, 0x8c };
+	char answer[] = { 0x00, 0x01, 0x02, 0x0a, 0x0b, 0x0c, 0xfd, 0xfe, 
+		          0xff };
+	char ddata[BUFSIZ + EVP_MAX_BLOCK_LENGTH];
+	int ddata_len;
+	char salt[PKCS5_SALT_LEN];
+
+	fail_unless(crypt_it(ddata, &ddata_len, data, sizeof data, 
+			       "aes-128-ecb", "passphrase", salt,
+			       salt_read, EVP_DecryptInit_ex, EVP_DecryptUpdate,
+			       EVP_DecryptFinal_ex) == 1);
+	fail_unless(memcmp(ddata, answer, sizeof answer) == 0, 
+		    "decrypt_it test failed");
+}
+END_TEST
+
+START_TEST(test_encrypt_decrypt_it)
+{
+	char data[] = { 0x00, 0x01, 0x02, 0x0a, 0x0b, 0x0c, 0xfd, 0xfe, 
+		        0xff };
+	char edata[BUFSIZ + EVP_MAX_BLOCK_LENGTH];
+	char ddata[BUFSIZ + EVP_MAX_BLOCK_LENGTH];
+	int edata_len;
+	int ddata_len;
+	char salt[PKCS5_SALT_LEN];
+
+	fail_unless(crypt_it(edata, &edata_len, data, sizeof data, 
+			       "aes-128-ecb", "passphrase", salt, salt_write, 
+			       EVP_EncryptInit_ex, EVP_EncryptUpdate,
+			       EVP_EncryptFinal_ex) == 1);
+	fail_unless(crypt_it(ddata, &ddata_len, edata, edata_len, 
+			       "aes-128-ecb", "passphrase", salt,
+			       salt_read, EVP_DecryptInit_ex, 
+			       EVP_DecryptUpdate, EVP_DecryptFinal_ex) == 1);
+	fail_unless(memcmp(ddata, data, sizeof data) == 0, 
+		    "encrypt_decrypt_it test failed");
+}
+END_TEST
+
+static Suite *common_suite(void)
+{
+	Suite *s = suite_create("common");
+
+	TCase *tc_strip_cr = tcase_create("test_strip_cr");
+	TCase *tc_encode = tcase_create("test_encode");
+	TCase *tc_encrypt_it = tcase_create("test_encrypt_it");
+
+	tcase_add_test(tc_strip_cr, test_strip_cr);
+
+	tcase_add_test(tc_encode, test_encode);
+	tcase_add_test(tc_encode, test_decode);
+	tcase_add_test(tc_encode, test_encode_decode);
+
+	tcase_add_test(tc_encrypt_it, test_encrypt_it);
+	tcase_add_test(tc_encrypt_it, test_decrypt_it);
+	tcase_add_test(tc_encrypt_it, test_encrypt_decrypt_it);
+
+	suite_add_tcase(s, tc_strip_cr);
+	suite_add_tcase(s, tc_encode);
+	suite_add_tcase(s, tc_encrypt_it);
+
+	return s;
+}
+
+int main(void)
+{
+	int nf;
+	Suite *s = common_suite();
+	SRunner *sr = srunner_create(s);
+	srunner_run_all(sr, CK_NORMAL);
+	nf = srunner_ntests_failed(sr);
+	srunner_free(sr);
+	return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
Binary files sesame-cvs-vanilla/tools/check_common.o and sesame-cvs/tools/check_common.o differ
diff -u --recursive --new-file sesame-cvs-vanilla/tools/common.c sesame-cvs/tools/common.c
--- sesame-cvs-vanilla/tools/common.c	1969-12-31 18:00:00.000000000 -0600
+++ sesame-cvs/tools/common.c	2005-01-19 12:42:47.000000000 -0600
@@ -0,0 +1,375 @@
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <openssl/evp.h>
+
+#include "common.h"
+
+#define SALTHEAD "Salted__"
+
+void sslerror(const char *msg)
+{
+	assert(msg);
+
+	unsigned long err = ERR_get_error();
+	if (err != 0)
+		fprintf(stderr, "%s: %s", msg,
+			ERR_error_string(err, NULL));
+}
+
+char *strip_cr(char *s)
+{
+	int len;
+
+	assert(s);
+
+	len = strlen(s);
+	s[len - 1] = s[len - 1] == '\n' ? 0x00 : s[len - 1];
+
+	return s;
+}
+
+int read_key(char *buf, int size)
+{
+	int fnval = 1;
+
+	assert(buf);
+	assert(size > 0);
+
+	if (fgets(buf, size, stdin) == NULL) {
+		fnval = 0;
+		goto _return;
+	}
+
+	strip_cr(buf);
+
+      _return:
+	return fnval;
+}
+
+void msg(int verbose, const char *format, ...)
+{
+	assert(format != NULL);
+
+	if (verbose) {
+		va_list args;
+
+		va_start(args, format);
+		vfprintf(stdout, format, args);
+		va_end(args);
+	}
+}
+
+int run_cryptsetup(const char *block_key_cipher, const char *prefix, 
+		   const char *device, const char *uuid, const char *key, 
+		   const int key_len)
+{
+	pid_t child;
+	int fnval = 1, pipefd[2], child_exit;
+	char dmname[PATH_MAX + 1], *key_len_str;
+
+	assert(block_key_cipher != NULL);
+	assert(prefix != NULL);
+	assert(device != NULL);
+	assert(uuid != NULL);
+	assert(key != NULL);
+	assert(key_len > 0);
+
+	if (asprintf(&key_len_str, "%d", key_len * 8) == -1) {
+		fprintf(stderr, "Failed to allocate memory, err=%s\n",
+			strerror(errno));
+		fnval = 0;
+		goto _return_no_free;
+	}
+
+	strcpy(dmname, prefix);
+	if (strlen(dmname) + strlen(uuid) > PATH_MAX) {
+                fprintf(stderr, "Uuid %s is too long\n", uuid);
+                fnval = 0;
+                goto _return;
+        }
+	strncat(dmname, uuid, sizeof dmname - strlen(dmname));
+
+	if (pipe(pipefd) == -1) {
+		fprintf(stderr, "Failed to create pipe, err=%s\n",
+			strerror(errno));
+		fnval = 0;
+		goto _return;
+	}
+
+	child = fork();
+
+	if (child < 0) {
+		fprintf(stderr, "Failed to fork, err=%s\n",
+			strerror(errno));
+		fnval = 0;
+		goto _return;
+	} else if (child == 0) {
+		close(0);
+		dup(pipefd[0]);
+		close(pipefd[0]);
+		close(pipefd[1]);
+		execl(CRYPTSETUP, "cryptsetup", "-s", key_len_str, "-c",
+		      block_key_cipher, "create", dmname, device, NULL);
+		fprintf(stderr, "Failed to execute %s, err=%s\n",
+			CRYPTSETUP, strerror(errno));
+		exit(EXIT_FAILURE);
+	} else {
+		close(pipefd[0]);
+		write(pipefd[1], key, key_len);
+		close(pipefd[1]);
+		waitpid(child, &child_exit, 0);
+		fnval = !WEXITSTATUS(child_exit);
+		goto _return;
+	}
+
+      _return:
+	free(key_len_str);
+      _return_no_free:
+	return fnval;
+}
+
+int run_cryptunsetup(const char *prefix, const char *device, const char *uuid)
+{
+	pid_t child;
+	int fnval = 1, child_exit;
+	char dmname[PATH_MAX + 1];
+
+	assert(prefix != NULL);
+	assert(device != NULL);
+	assert(uuid != NULL);
+
+	strcpy(dmname, prefix);
+	if (strlen(dmname) + strlen(uuid) > PATH_MAX) {
+                fprintf(stderr, "Uuid %s is too long\n", uuid);
+                fnval = 0;
+                goto _return;
+        }
+	strncat(dmname, uuid, sizeof dmname - strlen(dmname));
+
+	child = fork();
+
+	if (child < 0) {
+		fprintf(stderr, "Failed to fork, err=%s\n",
+			strerror(errno));
+		fnval = 0;
+		goto _return;
+	} else if (child == 0) {
+		execl(CRYPTSETUP, "cryptsetup", "remove", dmname, device, NULL);
+		fprintf(stderr, "Failed to execute %s, err=%s\n",
+			CRYPTSETUP, strerror(errno));
+		exit(EXIT_FAILURE);
+	} else {
+		waitpid(child, &child_exit, 0);
+		fnval = !WEXITSTATUS(child_exit);
+		goto _return;
+	}
+
+      _return:
+	return fnval;
+}
+
+char *encode(char *dest, const char *src, const size_t src_len)
+{
+	size_t i, j;
+
+	assert(dest);
+	assert(src);
+	assert(src_len > 0);
+
+	memset(dest, 0x00, (src_len * 2) + 1);
+
+	for (i = 0, j = 0; i < src_len; i++, j += 2) {
+		dest[j] =
+		    (src[i] >> 4) >
+		    9 ? (src[i] >> 4) + 87 : (src[i] >> 4) + 48;
+		dest[j + 1] =
+		    (src[i] & 0x0f) >
+		    9 ? (src[i] & 0x0f) + 87 : (src[i] & 0x0f) + 48;
+	}
+
+	return dest;
+}
+
+char *decode(char *dest, const char *src)
+{
+	size_t i;
+
+	assert(dest);
+	assert(src);
+
+	for (i = 0; i < strlen(src); i += 2) {
+		dest[i / 2] =
+		    isdigit(src[i]) ? (src[i] - 48) << 4 : (src[i] -
+							      87) << 4;
+		dest[i / 2] +=
+		    isdigit(src[i + 1]) ? src[i + 1] - 48 : src[i + 1] -
+		    87;
+	}
+	return dest;
+}
+
+char *cipher_lookup(char *real_cipher, const char *cipher)
+{
+	assert(real_cipher);
+	assert(cipher);
+
+	if (strcmp("aes", cipher) == 0)
+		return strcpy(real_cipher, "aes-128-ecb");
+	else
+		return NULL;
+}
+
+int hash_authtok(const EVP_CIPHER * const cipher,
+		 const char *const authtok,
+		 unsigned char *const hash, const unsigned char *salt,
+		 unsigned char *const iv)
+{
+	const EVP_MD *md;
+
+	assert(cipher != NULL);	/* FIXME: is cipher is valid OpenSSL cipher? */
+	assert(authtok != NULL);
+	assert(hash != NULL);
+	assert(salt != NULL);
+	assert(iv != NULL);
+
+	md = EVP_md5();
+	if (EVP_BytesToKey
+	    (cipher, md, salt, authtok, strlen(authtok), 1,
+	     hash, iv) <= 0) {
+		fprintf(stderr, "failed to hash passphrase");
+		return 0;
+	}
+
+	return 1;
+}
+
+int salt_read(unsigned char *salt, char **out, int *outl, char **in, int *inl)
+{
+	assert(salt != NULL);
+	assert(out != NULL);
+	assert(*out != NULL);
+	assert(in != NULL);
+	assert(*in != NULL);
+
+	if (memcmp(*in, "Salted__", sizeof "Salted__" - 1) != 0) {
+	   fprintf(stderr, "magic string Salted__ not in stream\n");
+	   return 0;
+	}
+	memcpy(salt, *in + sizeof "Salted__" - 1, PKCS5_SALT_LEN);
+	*in += (strlen("Salted__") + PKCS5_SALT_LEN);
+	*inl -= (strlen("Salted__") + PKCS5_SALT_LEN);
+
+	return 1;
+}
+
+int salt_write(unsigned char *salt, char **out, int *outl, char **in, int *inl)
+{
+	assert(salt != NULL);
+	assert(out != NULL);
+	assert(*out != NULL);
+	assert(in != NULL);
+	assert(*in != NULL);
+
+	memcpy(*out, SALTHEAD, strlen(SALTHEAD));
+	*out += strlen(SALTHEAD);
+	memcpy(*out, salt, PKCS5_SALT_LEN);
+	*out += PKCS5_SALT_LEN;
+	*outl = strlen(SALTHEAD) + PKCS5_SALT_LEN;
+
+	return 1;
+}
+
+int crypt_it(char *out, size_t * const out_len, char *in,
+	     size_t in_len, const char *cipher_name,
+	     const char *const authtok, unsigned char *salt,
+	     int (*salt_op) (unsigned char *salt, char **out,
+			     int *outl, char **in, int *inl),
+	     int (*crypt_init) (EVP_CIPHER_CTX * ctx,
+				const EVP_CIPHER * type, ENGINE * impl,
+				const unsigned char *key,
+				const unsigned char *iv),
+	     int (*crypt_update) (EVP_CIPHER_CTX * ctx, unsigned char *out,
+				  int *outl, const unsigned char *in, int inl),
+	     int (*crypt_final) (EVP_CIPHER_CTX * ctx, unsigned char *out,
+	     int *outl))
+{
+	int ret = 1;
+	int segment_len;
+	unsigned char hashed_authtok[EVP_MAX_KEY_LENGTH];
+	unsigned char iv[EVP_MAX_IV_LENGTH];
+	const EVP_CIPHER *cipher;
+	EVP_CIPHER_CTX ctx;
+
+	assert(out != NULL);
+	assert(out_len != NULL);
+	assert(in != NULL);
+	assert(cipher_name != NULL);
+	assert(authtok != NULL);
+
+	*out_len = 0;
+
+	memset(out, 0x00, BUFSIZ + EVP_MAX_BLOCK_LENGTH);
+	OpenSSL_add_all_ciphers();
+	EVP_CIPHER_CTX_init(&ctx);
+	SSL_load_error_strings();
+	if (!(cipher = EVP_get_cipherbyname(cipher_name))) {
+		fprintf(stderr, "error getting cipher \"%s\"\n",
+			(const char *) cipher_name);
+		ret = 0;
+		goto _return;
+	}
+	if (salt_op(salt, &out, out_len, &in, &in_len) == 0) {
+		ret = 0;
+		goto _return;
+	}
+	if (hash_authtok(cipher, authtok, hashed_authtok, salt, iv) == 0) {
+		ret = 0;
+		goto _return;
+	}
+	
+	if (crypt_init(&ctx, cipher, NULL, hashed_authtok, iv) ==
+	    0) {
+		sslerror("failed to initialize encryption code");
+		ret = 0;
+		goto _return;
+	}
+
+	/* assumes plaintexts is always <= ciphertext + EVP_MAX_BLOCK_LEN in length
+	 * OpenSSL's documentation seems to promise this */
+	if (crypt_update
+	    (&ctx, out, &segment_len, in, in_len) == 0) {
+		sslerror("failed to encrypt key");
+		ret = 0;
+		goto _return;
+	}
+	*out_len += segment_len;
+	out += segment_len;
+	if (crypt_final(&ctx, out, &segment_len) == 0) {
+		sslerror
+		    ("error completing encryption");
+		ret = 0;
+		goto _return;
+	}
+	*out_len += segment_len;
+      _return:
+	if (EVP_CIPHER_CTX_cleanup(&ctx) == 0) {
+		sslerror("error cleaning up cipher context");
+		ret = 0;
+	}
+
+	ERR_free_strings();
+	/* out_len is unsigned */
+	assert(ret == 0 || *out_len <= BUFSIZ + EVP_MAX_BLOCK_LENGTH);
+
+	return ret;
+}
diff -u --recursive --new-file sesame-cvs-vanilla/tools/common.h sesame-cvs/tools/common.h
--- sesame-cvs-vanilla/tools/common.h	1969-12-31 18:00:00.000000000 -0600
+++ sesame-cvs/tools/common.h	2005-01-19 12:45:12.000000000 -0600
@@ -0,0 +1,38 @@
+#define MAGICTAIL "SESAME0"
+#define DMCRYPT_PREFIX "sesame_crypto_"
+#define DMCRYPT_TMP_PREFIX "sesame_crypto_tmp_"
+#define DMDIR "/dev/mapper/"
+
+#include <openssl/evp.h>
+
+void sslerror(const char *msg);
+char *strip_cr(char *s);
+int read_key(char *buf, int size);
+void msg(int verbose, const char *format, ...);
+int run_cryptsetup(const char *block_key_cipher, const char *prefix,
+                   const char *device, const char *uuid, const char *key,
+		   const int key_len);
+int run_cryptunsetup(const char *prefix, const char *device, const char *uuid);
+char *encode(char *dest, const char *src, const size_t src_len);
+char *decode(char *dest, const char *src);
+char *cipher_lookup(char *real_cipher, const char *cipher);
+int hash_authtok(const EVP_CIPHER * cipher, const char *authtok,
+		 unsigned char *hash, const unsigned char *salt,
+		 unsigned char *iv);
+int salt_read(unsigned char *salt, char **out, int *outl,
+	      char **in, int *inl);
+int salt_write(unsigned char *salt, char **out, int *outl,
+	       char **in, int *inl);
+int crypt_it(char *out, size_t * const out_len, char *const in,
+	     size_t in_len, const char *cipher_name,
+	     const char *const authtok, unsigned char *salt,
+	     int (*salt_op) (unsigned char *salt, char **out,
+			     int *outl, char **in, int *inl),
+	     int (*crypt_init) (EVP_CIPHER_CTX * ctx,
+				const EVP_CIPHER * type, ENGINE * impl,
+				const unsigned char *key,
+			        const unsigned char *iv),
+	     int (*crypt_update) (EVP_CIPHER_CTX * ctx, unsigned char *out,
+				  int *outl, const unsigned char *in, int inl),
+	     int (*crypt_final) (EVP_CIPHER_CTX * ctx, unsigned char *out,
+	                         int *outl));
Binary files sesame-cvs-vanilla/tools/common.o and sesame-cvs/tools/common.o differ
diff -u --recursive --new-file sesame-cvs-vanilla/tools/Makefile.am sesame-cvs/tools/Makefile.am
--- sesame-cvs-vanilla/tools/Makefile.am	2004-12-31 07:35:47.000000000 -0600
+++ sesame-cvs/tools/Makefile.am	2005-01-19 13:37:07.176763088 -0600
@@ -1,16 +1,37 @@
 
 INCLUDES = \
 	-DCRYPTSETUP=\""$(CRYPTSETUP)\"" \
+	-DDD=\""$(DD)\"" \
+	-DMKFS=\""$(MKFS)\"" \
 	-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
 	-DPACKAGE_BIN_DIR=\""$(bindir)"\" \
 	-DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\"
 
-sbin_PROGRAMS = sesame-setup
+if HAVE_CHECK
+noinst_PROGRAMS = check_common
 
-sesame_setup_SOURCES = sesame-setup.c
+check_common_SOURCES = check_common.c common.c
+
+check_common_INCLUDES = @CHECK_CFLAGS@
+check_common_LDADD = @CHECK_LIBS@
+endif
+
+sbin_PROGRAMS = sesame-format sesame-setup sesame-is-encrypted
+
+sesame_format_SOURCES = sesame-format.c common.c
+
+sesame_setup_SOURCES = sesame-setup.c common.c
+
+sesame_is_encrypted_SOURCES = sesame-is-encrypted.c common.c
+
+test_crypto_SOURCES = test-crypto.c common.c
 
 # Add @PACKAGE_LIBS@ if using pkg-config packages; see configure.in
-sesame_setup_LDADD = $(top_builddir)/libsesame/libsesame.la
+sesame_format_LDADD = $(top_builddir)/libsesame/libsesame.la $(GLIB_LIBS)
+sesame_setup_LDADD  = $(top_builddir)/libsesame/libsesame.la
+sesame_is_encrypted_LDADD  = $(top_builddir)/libsesame/libsesame.la
+
+AM_CFLAGS = $(GLIB_CFLAGS) -Werror
 
 clean-local :
 	rm -f *~
diff -u --recursive --new-file sesame-cvs-vanilla/tools/sesame-format.c sesame-cvs/tools/sesame-format.c
--- sesame-cvs-vanilla/tools/sesame-format.c	1969-12-31 18:00:00.000000000 -0600
+++ sesame-cvs/tools/sesame-format.c	2005-01-19 13:02:08.000000000 -0600
@@ -0,0 +1,355 @@
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include <limits.h>
+#include <getopt.h>
+#include <glib.h>
+#include <mntent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#include <uuid/uuid.h>
+
+#ifndef EVP_MAX_BLOCK_LENGTH
+#define EVP_MAX_BLOCK_LENGTH 32	/* some older openssl versions need this */
+#endif
+
+#include "common.h"
+/* FIXME: what about LUKS? */
+#include "../libsesame/libsesame.h"
+
+static int verbose = 0;
+static int dry_run = 0;
+static char *fs_type = "ext2";
+static char *fs_cipher = "aes";
+static size_t fs_keylen = 16;
+static char *key_cipher = "aes";
+static char *device = NULL;
+
+static void print_usage(const int exitcode, const char *error,
+			const char *more)
+{
+	if (error)
+		assert(more);
+
+	fprintf(stderr, "sesame-setup [options] device\n\n"
+		"-h, --help\n"
+		"	print a list of options\n\n"
+		"-v, --verbose\n"
+		"	verbose display of messages\n\n"
+		"-d, --dry-run\n"
+		"	do not actually perform any operations on device\n\n"
+		"-t, --fs-type type\n"
+		"	set the filesystem type to use		[%s]\n\n"
+		"-c, --fs-cipher cipher\n"
+		"	cipher used to encrypt the filesystem	[%s]\n\n"
+		"-c, --fs-keylen length\n"
+		"	length in bits of encryption key	[%d]\n\n"
+		"-k, --key-cipher cipher\n"
+		"	cipher used to encrypt the key		[%s]\n\n",
+		fs_type, fs_cipher, fs_keylen * 8, key_cipher);
+
+	if (error)
+		fprintf(stderr, "%s: %s\n", error, more);
+
+	exit(exitcode);
+}
+
+/* FIXME: do all Unices have an /etc/mtab? */
+static int mounted(const char* match)
+{
+	int mounted = 0;
+	FILE *mtab;
+	struct mntent *mtab_record;
+
+	assert(match != NULL);	
+
+	if (!(mtab = fopen("/etc/mtab", "r"))) {
+		fprintf(stderr, "Could not open /etc/mtab, assuming mounted\n");
+		mounted = 1;
+		goto _return;
+	}
+	while ((mtab_record = getmntent(mtab)) != NULL) {
+		char const *mnt_fsname = mtab_record->mnt_fsname;
+		if (!strcasecmp(mnt_fsname, match)) {
+			mounted = 1;
+			fprintf(stderr, "Volume %s currently mounted at %s\n",
+			        device, mtab_record->mnt_dir);
+		}
+	}
+_return:
+	fclose(mtab);
+	return mounted;
+}
+
+static void print_output(FILE * out, int in)
+{
+	char c[1];
+
+	assert(out);
+	assert(in >= 0);
+
+	/* unbuffered I/O so we can catch progress indicators */
+	while (read(in, c, 1) != 0)
+		fprintf(out, "%c", *c);
+}
+
+static int run_mkfs(const char *uuid, const char *fs_type)
+{
+	pid_t pid;
+	GError *err = NULL;
+	char dmname[PATH_MAX + 1];
+	int fnval = 1, child_exit, pstderr = -1;
+	const char *argv[] = { MKFS, "-t", fs_type, "", NULL };
+
+	assert(uuid);
+	assert(fs_type);
+
+	strcpy(dmname, DMDIR);
+	strncat(dmname, DMCRYPT_TMP_PREFIX, sizeof dmname - strlen(dmname));
+	if (strlen(device) + strlen(uuid) > PATH_MAX) {
+		fprintf(stderr, "Uuid %s is too long\n", uuid);
+		fnval = 0;
+		goto _return;
+	}
+	strncat(dmname, uuid, sizeof dmname - strlen(dmname));
+	argv[3] = dmname;
+
+	if (g_spawn_async_with_pipes
+	    (NULL, (char **) argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL,
+	     NULL, &pid, NULL, NULL, &pstderr, &err) == FALSE) {
+		fprintf(stderr, "%s\n", err->message);
+		g_error_free(err);
+		fnval = 0;
+		goto _return;
+	}
+
+	print_output(stderr, pstderr);
+
+	if (waitpid(pid, &child_exit, 0) == -1) {
+		fprintf(stderr, "Error waiting for child\n");
+		fnval = 0;
+		goto _return;
+	}
+
+	fnval = !WEXITSTATUS(child_exit);
+
+      _return:
+	return fnval;
+}
+
+static int run_randomize(const char *device)
+{
+	pid_t pid;
+	GError *err = NULL;
+	char of[BUFSIZ + 1];
+	int fnval = 1, child_exit, pstderr = -1;
+	const char *argv[] = { DD, "if=/dev/urandom", "", NULL };
+
+	assert(device);
+
+	strcpy(of, "of=");
+	if (strlen(device) + strlen(of) > BUFSIZ) {
+		fprintf(stderr, "Device name %s is too long\n", device);
+		fnval = 0;
+		goto _return;
+	}
+	strcat(of, device);
+	argv[2] = of;
+
+	if (g_spawn_async_with_pipes
+	    (NULL, (char **) argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL,
+	     NULL, &pid, NULL, NULL, &pstderr, &err) == FALSE) {
+		fprintf(stderr, "%s\n", err->message);
+		g_error_free(err);
+		fnval = 0;
+		goto _return;
+	}
+
+	print_output(stderr, pstderr);
+
+	if (waitpid(pid, &child_exit, 0) == -1) {
+		fprintf(stderr, "Error waiting for child\n");
+		fnval = 0;
+		goto _return;
+	}
+
+	fnval = !WEXITSTATUS(child_exit);
+
+      _return:
+	return fnval;
+}
+
+int main(int argc, char *argv[])
+{
+	uuid_t uuid;
+	size_t efs_keylen;
+	char buf[BUFSIZ + 1];
+	char passphrase[BUFSIZ + 1];
+	int c, opt_index = 0, status = EXIT_SUCCESS;
+	char real_key_cipher[BUFSIZ + 1];
+	unsigned char uuid_str[36 + 1], salt[PKCS5_SALT_LEN];
+	char fs_key[EVP_MAX_KEY_LENGTH + sizeof(MAGICTAIL) - 1],
+	    efs_key[BUFSIZ + EVP_MAX_BLOCK_LENGTH];
+	struct option opts[] = {
+		{"help", 0, 0, 'h'},
+		{"dry-run", 0, 0, 'd'},
+		{"verbose", 0, 0, 'v'},
+		{"fs-type", 1, 0, 't'},
+		{"fs-cipher", 1, 0, 'c'},
+		{"fs-keylen", 1, 0, 'l'},
+		{"key-cipher", 1, 0, 'k'},
+		{0, 0, 0, 0}
+	};
+
+	while ((c =
+		getopt_long(argc, argv, "hvdt:c:l:k:", opts, &opt_index))
+	       >= 0) {
+		switch (c) {
+		case 'h':
+			print_usage(EXIT_SUCCESS, NULL, NULL);
+		case 'v':
+			verbose = 1;
+			break;
+		case 'd':
+			dry_run = 1;
+			break;
+		case 't':
+			fs_type = optarg;
+			break;
+		case 'c':
+			fs_cipher = optarg;
+			break;
+		case 'l':
+			fs_keylen = atoi(optarg) / 8;
+			break;
+		case 'k':
+			key_cipher = optarg;
+			break;
+		default:
+			print_usage(EXIT_FAILURE, NULL, NULL);
+		}
+	}
+
+	if (argv[optind] == NULL)
+		print_usage(EXIT_FAILURE, NULL, NULL);
+	device = argv[optind];
+
+	if (mounted(device)) {
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+
+	if (read_key(passphrase, BUFSIZ) == 0) {
+		fprintf(stderr, "Could not read key\n");
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+
+	msg(verbose, "generating UUID\n");
+	uuid_generate(uuid);
+	uuid_unparse(uuid, uuid_str);
+
+	msg(verbose, "randomizing %s\n", device);
+	// FIXME
+	if (0 && run_randomize(device) == 0) {
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+
+	msg(verbose, "creating random key for %s\n", device);
+	/* FIXME: is this used right?  The documentation seems to state
+	 * that this is seeded using /dev/urandom if it exists.  What if
+	 * it does not exist? */
+	if (RAND_bytes(fs_key, fs_keylen) == 0) {
+		fprintf(stderr, "Error generating random key\n");
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+	if (RAND_bytes(salt, PKCS5_SALT_LEN) == 0) {
+		fprintf(stderr, "Error generating salt key\n");
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+
+	msg(verbose,
+	    "creating dm-crypt device for %s using %s (%d bit key)\n",
+	    device, fs_cipher, fs_keylen * 8);
+	if (!dry_run)
+		if (run_cryptsetup
+		    (fs_cipher, DMCRYPT_TMP_PREFIX, device, uuid_str, fs_key,
+		     fs_keylen) == 0) {
+			status = EXIT_FAILURE;
+			goto _exit;
+		}
+
+	msg(verbose, "creating %s filesystem\n", fs_type);
+	if (!dry_run)
+		if (run_mkfs(uuid_str, fs_type) == 0) {
+			status = EXIT_FAILURE;
+			goto _exit;
+		}
+
+	msg(verbose, "appending %s onto random key\n", MAGICTAIL);
+	memcpy(fs_key + fs_keylen, MAGICTAIL, strlen(MAGICTAIL));
+
+	msg(verbose, "looking up real key cipher for %s\n", key_cipher);
+	if (cipher_lookup(real_key_cipher, key_cipher) == NULL) {
+		fprintf(stderr, "Do not recognize %s\n", key_cipher);
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+
+	msg(verbose, "encrypting key using %s and passphrase\n",
+	    real_key_cipher);
+	if (crypt_it
+	    (efs_key, &efs_keylen, fs_key, fs_keylen + strlen(MAGICTAIL),
+	     real_key_cipher, passphrase, salt, salt_write,
+	     EVP_EncryptInit_ex, EVP_EncryptUpdate,
+	     EVP_EncryptFinal_ex) == 0) {
+		fprintf(stderr, "Cannot encrypt key\n");
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+
+	/* FIXME: what about LUKS? */
+	msg(verbose, "storing sesame data on %s\n", device);
+	if (!dry_run) {
+		/* FIXME */
+	}
+
+	msg(verbose, "uuid is %s\n", uuid_str);
+	msg(verbose, "encrypted key is %s\n",
+	    encode(buf, efs_key, efs_keylen));
+
+	msg(verbose, "removing temporary dm-crypt device\n");
+	if (!dry_run)
+		if (run_cryptunsetup (DMCRYPT_TMP_PREFIX, device, 
+				      uuid_str) == 0) {
+			status = EXIT_FAILURE;
+			goto _exit;
+		}
+
+	msg(verbose, "re-initializing dm-crypt device for hald\n");
+	if (!dry_run) {
+		if (run_cryptsetup
+		    (fs_cipher, DMCRYPT_PREFIX, device, uuid_str, fs_key,
+		     fs_keylen) == 0) {
+			status = EXIT_FAILURE;
+			goto _exit;
+		}
+	}
+
+      _exit:
+	exit(status);
+}
Binary files sesame-cvs-vanilla/tools/sesame-format.o and sesame-cvs/tools/sesame-format.o differ
diff -u --recursive --new-file sesame-cvs-vanilla/tools/sesame-is-encrypted.c sesame-cvs/tools/sesame-is-encrypted.c
--- sesame-cvs-vanilla/tools/sesame-is-encrypted.c	1969-12-31 18:00:00.000000000 -0600
+++ sesame-cvs/tools/sesame-is-encrypted.c	2005-01-19 13:45:43.409283816 -0600
@@ -0,0 +1,157 @@
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "common.h"
+/* FIXME: what about LUKS? */
+#include "../libsesame/libsesame.h"
+
+static int verbose = 0;
+static char *device = NULL;
+
+static void print_usage(const int exitcode, const char *error,
+			const char *more)
+{
+	if (error)
+		assert(more);
+
+	fprintf(stderr, "sesame-is-encrypted [options] device\n\n"
+		"-h, --help\n"
+		"       print a list of options\n\n"
+		"-v, --verbose\n" "     verbose display of messages\n\n");
+
+	if (error)
+		fprintf(stderr, "%s: %s\n", error, more);
+
+	exit(exitcode);
+}
+
+int main(int argc, char *argv[])
+{
+	int c, opt_index = 0, status = EXIT_SUCCESS;
+	char buf[1024];
+	int fd_metadata;
+	struct option opts[] = {
+		{"help", 0, 0, 'h'},
+		{"verbose", 0, 0, 'v'},
+		{0, 0, 0, 0}
+	};
+	SesameMetaData *md;
+	const char *uuid, *enc_key, *enc_key_cipher, *block_key_cipher,
+	    *block_key_sha1;
+
+	while ((c = getopt_long(argc, argv, "hv", opts, &opt_index)) >= 0) {
+		switch (c) {
+		case 'h':
+			print_usage(EXIT_SUCCESS, NULL, NULL);
+		case 'v':
+			verbose = 1;
+			break;
+		default:
+			print_usage(EXIT_FAILURE, NULL, NULL);
+		}
+	}
+
+	if (argv[optind] == NULL)
+		print_usage(EXIT_FAILURE, NULL, NULL);
+	device = argv[optind];
+
+	msg(verbose, "opening %s\n", device);
+	fd_metadata = open(device, O_RDONLY);
+	if (fd_metadata == -1) {
+		fprintf(stderr, "Cannot open %s, err=%s\n", device,
+			strerror(errno));
+		goto _exit;
+	}
+
+	msg(verbose, "reading from %s\n", device);
+	if (read(fd_metadata, buf, sizeof(buf)) == -1) {
+		fprintf(stderr, "Cannot read from %s, err=%s\n",
+			device, strerror(errno));
+		status = EXIT_FAILURE;
+		goto _exit_close;
+	}
+
+	/* FIXME: what about LUKS? */
+	msg(verbose, "parsing metadata\n");
+	md = sesame_get_metadata_from_buf(buf);
+	if (md == NULL) {
+		fprintf(stderr, "Cannot not parse metadata\n");
+		status = EXIT_FAILURE;
+		goto _exit_close;
+	}
+
+	/* FIXME: what about LUKS? */
+	msg(verbose, "getting uuid\n");
+	uuid = sesame_get(md, "uuid");
+	if (uuid == NULL) {
+		fprintf(stderr, "Cannot read uuid from %s\n", device);
+		status = EXIT_FAILURE;
+		goto _exit_free;
+	}
+
+	/* FIXME: what about LUKS? */
+	msg(verbose, "getting enc_key\n");
+	enc_key = sesame_get(md, "enc_key");
+	if (enc_key == NULL) {
+		fprintf(stderr, "Cannot read enc_key from %s\n", device);
+		status = EXIT_FAILURE;
+		goto _exit_free;
+	}
+
+	/* FIXME: what about LUKS? */
+	msg(verbose, "getting enc_key_cipher\n");
+	enc_key_cipher = sesame_get(md, "enc_key_cipher");
+	if (enc_key == NULL) {
+		fprintf(stderr, "Cannot read enc_key_cipher from %s\n",
+			device);
+		status = EXIT_FAILURE;
+		goto _exit_free;
+	}
+
+	/* FIXME: what about LUKS? */
+	msg(verbose, "getting block_key_cipher\n");
+	block_key_cipher = sesame_get(md, "block_key_cipher");
+	if (block_key_cipher == NULL) {
+		fprintf(stderr, "Cannot read block_key_cipher from %s\n",
+			device);
+		status = EXIT_FAILURE;
+		goto _exit_free;
+	}
+
+	/* FIXME: what about LUKS? */
+	msg(verbose, "getting block_key_sha1\n");
+	block_key_sha1 = sesame_get(md, "block_key_sha1");
+	if (block_key_sha1 == NULL) {
+		fprintf(stderr, "Cannot read block_key_sha1 from %s\n",
+			device);
+		status = EXIT_FAILURE;
+		goto _exit_free;
+	}
+
+      _exit_free:
+	msg(verbose, "freeing memory\n");
+	/* FIXME: what about LUKS? */
+	sesame_free(md);
+
+      _exit_close:
+	close(fd_metadata);
+
+      _exit:
+	if (status == EXIT_SUCCESS)
+		fprintf(stdout, "Device %s seems to be encrypted\n",
+			device);
+	else
+		fprintf(stdout, "Device %s does not seem to be encrypted\n",
+			device);
+	exit(status);
+}
Binary files sesame-cvs-vanilla/tools/sesame-is-encrypted.o and sesame-cvs/tools/sesame-is-encrypted.o differ
diff -u --recursive --new-file sesame-cvs-vanilla/tools/sesame-setup.c sesame-cvs/tools/sesame-setup.c
--- sesame-cvs-vanilla/tools/sesame-setup.c	2004-12-31 07:35:47.000000000 -0600
+++ sesame-cvs/tools/sesame-setup.c	2005-01-19 13:00:18.000000000 -0600
@@ -2,6 +2,7 @@
 #define _GNU_SOURCE
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -13,20 +14,17 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
-#include <openssl/ssl.h>
-#include <openssl/evp.h>
-#include <openssl/err.h>
 
 #ifndef EVP_MAX_BLOCK_LENGTH
 #define EVP_MAX_BLOCK_LENGTH 32	/* some older openssl versions need this */
 #endif
 
+#include "common.h"
+/* FIXME: what about LUKS? */
 #include "../libsesame/libsesame.h"
 
-#define MAGICTAIL "SESAME0"
-
-int verbose = 0;
-char *device = NULL;
+static int verbose = 0;
+static char *device = NULL;
 
 static void print_usage(const int exitcode, const char *error,
 			const char *more)
@@ -44,250 +42,19 @@
 	exit(exitcode);
 }
 
-static void sslerror(const char *msg)
-{
-	assert(msg);
-
-	unsigned long err = ERR_get_error();
-	if (err != 0)
-		fprintf(stderr, "%s: %s", msg,
-			ERR_error_string(err, NULL));
-}
-
-static int hash_authtok(const char *data, const EVP_CIPHER * const cipher,
-			const char *const authtok,
-			unsigned char *const hash, unsigned char *const iv)
-{
-	const EVP_MD *md;
-	unsigned char salt[PKCS5_SALT_LEN];
-
-	assert(data != NULL);
-	assert(cipher != NULL);	/* FIXME: is cipher is valid OpenSSL cipher? */
-	assert(authtok != NULL);
-	assert(hash != NULL);	/* FIXME: check hash is big enough? */
-	assert(iv != NULL);	/* FIXME: check iv is big enough? */
-
-	if (memcmp(data, "Salted__", sizeof "Salted__" - 1) != 0) {
-		fprintf(stderr, "magic string Salted__ not in stream\n");
-		return 0;
-	}
-	memcpy(salt, data + sizeof "Salted__" - 1, PKCS5_SALT_LEN);
-	md = EVP_md5();
-	if (EVP_BytesToKey
-	    (cipher, md, salt, authtok, strlen(authtok), 1,
-	     hash, iv) <= 0) {
-		fprintf(stderr, "failed to hash passphrase");
-		return 0;
-	}
-
-	return 1;
-}
-
-static int
-decrypt(char *const out, size_t * const out_len,
-	const char *const in, const size_t in_len,
-	const char *const cipher_name, const char *const authtok)
-{
-	int ret = 1;
-	int segment_len;
-	size_t data_len;
-	const char *data;
-	unsigned char hashed_authtok[EVP_MAX_KEY_LENGTH];
-	unsigned char iv[EVP_MAX_IV_LENGTH];
-	const EVP_CIPHER *cipher;
-	EVP_CIPHER_CTX ctx;
-
-	assert(out != NULL);
-	assert(out_len != NULL);
-	assert(cipher_name != NULL);
-	assert(in != NULL);
-	assert(authtok != NULL);
-
-	memset(out, 0x00, BUFSIZ + EVP_MAX_BLOCK_LENGTH);
-	OpenSSL_add_all_ciphers();
-	EVP_CIPHER_CTX_init(&ctx);
-	SSL_load_error_strings();
-	if (!(cipher = EVP_get_cipherbyname(cipher_name))) {
-		fprintf(stderr, "error getting cipher \"%s\"\n", (const char *)cipher);
-		ret = 0;
-		goto _return;
-	}
-	if (hash_authtok(in, cipher, authtok, hashed_authtok, iv) == 0) {
-		ret = 0;
-		goto _return;
-	}
-	if (EVP_DecryptInit_ex(&ctx, cipher, NULL, hashed_authtok, iv) ==
-	    0) {
-		sslerror("failed to initialize decryption code");
-		ret = 0;
-		goto _return;
-	}
-	data = in + (sizeof "Salted__" - 1) + PKCS5_SALT_LEN;
-	data_len = in_len - (sizeof "Salted__" - 1) - PKCS5_SALT_LEN;
-	/* assumes plaintexts is always <= ciphertext + EVP_MAX_BLOCK_LEN in length
-	 * OpenSSL's documentation seems to promise this */
-	if (EVP_DecryptUpdate
-	    (&ctx, out, &segment_len, data, data_len) == 0) {
-		sslerror("failed to decrypt key");
-		ret = 0;
-		goto _return;
-	}
-	*out_len = segment_len;
-	if (EVP_DecryptFinal_ex(&ctx, &out[*out_len], &segment_len) == 0) {
-		sslerror
-		    ("bad pad on end of encrypted file (wrong algorithm or key size?)");
-		ret = 0;
-		goto _return;
-	}
-	*out_len += segment_len;
-      _return:
-	if (EVP_CIPHER_CTX_cleanup(&ctx) == 0) {
-		sslerror("error cleaning up cipher context");
-		ret = 0;
-	}
-
-	ERR_free_strings();
-	/* out_len is unsigned */
-	assert(ret == 0 || *out_len <= BUFSIZ + EVP_MAX_BLOCK_LENGTH);
-
-	return ret;
-}
-
-static unsigned char *decode(char *data)
-{
-	size_t i;
-	unsigned char *decoded =
-	    (char *) malloc((strlen(data) / 2) * sizeof(char));
-	if (decoded == NULL)
-		return NULL;
-	for (i = 0; i < strlen(data); i += 2) {
-		decoded[i / 2] =
-		    isdigit(data[i]) ? (data[i] - 48) << 4 : (data[i] -
-							      87) << 4;
-		decoded[i / 2] +=
-		    isdigit(data[i + 1]) ? data[i + 1] - 48 : data[i + 1] -
-		    87;
-	}
-	return decoded;
-}
-
-static char *strip_cr(char *s)
-{
-	int len;
-
-	assert(s);
-
-	len = strlen(s);
-	s[len - 1] = s[len - 1] == '\n' ? 0x00 : s[len - 1];
-
-	return s;
-}
-
-static int read_key(char *buf, int size)
-{
-	int fnval = 1;
-
-	assert(buf);
-	assert(size > 0);
-
-	if (fgets(buf, size, stdin) == NULL) {
-		fnval = 0;
-		goto _return;
-	}
-
-	strip_cr(buf);
-
-      _return:
-	return fnval;
-}
-
-static void msg(const char *format, ...)
-{
-	assert(format != NULL);
-
-	if (verbose) {
-		/* Used to log issues that cause pam_mount to fail. */
-		va_list args;
-
-		va_start(args, format);
-		vfprintf(stdout, format, args);
-		va_end(args);
-	}
-}
-
-static int run_cryptsetup(const char *block_key_cipher, const char *device,
-			  const char *uuid, const char *key,
-			  const int key_len)
-{
-	pid_t child;
-	int fnval = 1, pipefd[2], child_exit;
-	char dmname[PATH_MAX + 1], *key_len_str;
-
-	assert(block_key_cipher != NULL);
-	assert(device != NULL);
-	assert(uuid != NULL);
-	assert(key != NULL);
-	assert(key_len > 0);
-
-	if (asprintf(&key_len_str, "%d", key_len) == -1) {
-		fprintf(stderr, "Failed to allocate memory, err=%s\n",
-			strerror(errno));
-		fnval = 0;
-		goto _return_no_free;
-	}
-
-	strcpy(dmname, "sesame_crypto_");
-	strncat(dmname, uuid, sizeof dmname - strlen(dmname));
-
-	if (pipe(pipefd) == -1) {
-		fprintf(stderr, "Failed to create pipe, err=%s\n",
-			strerror(errno));
-		fnval = 0;
-		goto _return;
-	}
-
-	child = fork();
-
-	if (child < 0) {
-		fprintf(stderr, "Failed to fork, err=%s\n",
-			strerror(errno));
-		fnval = 0;
-		goto _return;
-	} else if (child == 0) {
-		close(0);
-		dup(pipefd[0]);
-		close(pipefd[0]);
-		close(pipefd[1]);
-		execl(CRYPTSETUP, "cryptsetup", "-s", key_len_str, "-c",
-		      block_key_cipher, "create", dmname, device, NULL);
-		fprintf(stderr, "Failed to execute %s, err=%s\n",
-			CRYPTSETUP, strerror(errno));
-		exit(EXIT_FAILURE);
-	} else {
-		close(pipefd[0]);
-		write(pipefd[1], key, key_len);
-		close(pipefd[1]);
-		waitpid(child, &child_exit, 0);
-		fnval = !WEXITSTATUS(child_exit);
-		goto _return;
-	}
-
-      _return:
-	free(key_len_str);
-      _return_no_free:
-	return fnval;
-}
-
 int main(int argc, char *argv[])
 {
-	int c, opt_index = 0;
+	int c, opt_index = 0, status = EXIT_SUCCESS;
 	char passphrase[BUFSIZ + 1];
-	char dec_key[BUFSIZ + EVP_MAX_KEY_LENGTH];
+	char salt[PKCS5_SALT_LEN];
+	char dec_key[BUFSIZ + EVP_MAX_BLOCK_LENGTH];
+	char codebuf[BUFSIZ + 1];
 	int dec_key_len, real_dec_key_len;
 	char buf[1024];
 	int fd_metadata;
 	const char *uuid, *enc_key, *enc_key_cipher, *block_key_cipher,
 	    *block_key_sha1;
+	char real_key_cipher[BUFSIZ + 1];
 	struct option opts[] = {
 		{"help", 0, 0, 'h'},
 		{"verbose", 0, 0, 'v'},
@@ -311,99 +78,129 @@
 		print_usage(EXIT_FAILURE, NULL, NULL);
 	device = argv[optind];
 
-	msg("opening %s\n", device);
+	msg(verbose, "opening %s\n", device);
 	fd_metadata = open(device, O_RDONLY);
 	if (fd_metadata == -1) {
 		fprintf(stderr, "Cannot open %s, err=%s\n", device,
 			strerror(errno));
-		goto error;
+		goto _exit;
 	}
 
-	msg("reading from %s\n", device);
+	msg(verbose, "reading from %s\n", device);
 	if (read(fd_metadata, buf, sizeof(buf)) == -1) {
 		fprintf(stderr, "Cannot read from %s, err=%s\n",
 			device, strerror(errno));
-		goto error1;
+		status = EXIT_FAILURE;
+		goto _exit_close;
 	}
 
-	msg("parsing metadata\n");
+	/* FIXME: what about LUKS? */
+	msg(verbose, "parsing metadata\n");
 	md = sesame_get_metadata_from_buf(buf);
 	if (md == NULL) {
 		fprintf(stderr, "Cannot not parse metadata\n");
-		goto error1;
+		status = EXIT_FAILURE;
+		goto _exit_close;
 	}
 
-	msg("getting uuid\n");
+	/* FIXME: what about LUKS? */
+	msg(verbose, "getting uuid\n");
 	uuid = sesame_get(md, "uuid");
 	if (uuid == NULL) {
 		fprintf(stderr, "Cannot read uuid from %s\n", device);
-		goto error2;
+		status = EXIT_FAILURE;
+		goto _exit_free;
 	}
 
-	msg("getting enc_key\n");
+	/* FIXME: what about LUKS? */
+	msg(verbose, "getting enc_key\n");
 	enc_key = sesame_get(md, "enc_key");
 	if (enc_key == NULL) {
 		fprintf(stderr, "Cannot read enc_key from %s\n", device);
-		goto error2;
+		status = EXIT_FAILURE;
+		goto _exit_free;
 	}
 
-	msg("getting enc_key_cipher\n");
+	/* FIXME: what about LUKS? */
+	msg(verbose, "getting enc_key_cipher\n");
 	enc_key_cipher = sesame_get(md, "enc_key_cipher");
 	if (enc_key == NULL) {
 		fprintf(stderr, "Cannot read enc_key_cipher from %s\n",
 			device);
-		goto error2;
+		status = EXIT_FAILURE;
+		goto _exit_free;
 	}
 
-	msg("getting block_key_cipher\n");
+	/* FIXME: what about LUKS? */
+	msg(verbose, "getting block_key_cipher\n");
 	block_key_cipher = sesame_get(md, "block_key_cipher");
 	if (block_key_cipher == NULL) {
 		fprintf(stderr, "Cannot read block_key_cipher from %s\n",
 			device);
-		goto error2;
+		status = EXIT_FAILURE;
+		goto _exit_free;
 	}
 
-	msg("getting block_key_sha1\n");
+	/* FIXME: what about LUKS? */
+	msg(verbose, "getting block_key_sha1\n");
 	block_key_sha1 = sesame_get(md, "block_key_sha1");
 	if (block_key_sha1 == NULL) {
 		fprintf(stderr, "Cannot read block_key_sha1 from %s\n",
 			device);
-		goto error2;
+		status = EXIT_FAILURE;
+		goto _exit_free;
 	}
 
 	if (read_key(passphrase, BUFSIZ) == 0) {
 		fprintf(stderr, "Could not read key\n");
-		goto error2;
+		status = EXIT_FAILURE;
+		goto _exit_free;
 	}
 
-	msg("decrypting key using passphrase\n");
-	if (decrypt
-	    (dec_key, &dec_key_len, decode(enc_key), strlen(enc_key) / 2,
-	     enc_key_cipher, passphrase) == 0) {
+	msg(verbose, "looking up real key cipher for %s\n", enc_key_cipher);
+        if (cipher_lookup(real_key_cipher, enc_key_cipher) == NULL) {
+                fprintf(stderr, "Do not recognize %s\n", enc_key_cipher);
+                status = EXIT_FAILURE;
+                goto _exit_free;
+        }
+
+	msg(verbose, "decrypting key using %s and passphrase\n",
+	    enc_key_cipher);
+	if (crypt_it
+	    (dec_key, &dec_key_len, decode(codebuf, enc_key), strlen(enc_key) / 2,
+	     real_key_cipher, passphrase, salt, salt_read, EVP_DecryptInit_ex,
+                               EVP_DecryptUpdate, EVP_DecryptFinal_ex) == 0) {
 		fprintf(stderr, "Cannot decrypt key\n");
-		goto error2;
+		status = EXIT_FAILURE;
+		goto _exit_free;
 	}
 
-	msg("checking for MAGICTAIL tail in key\n");
+	msg(verbose, "checking for %s tail in key\n", MAGICTAIL);
 	real_dec_key_len = dec_key_len - strlen(MAGICTAIL);
 	if (memcmp
 	    (dec_key + real_dec_key_len, MAGICTAIL, strlen(MAGICTAIL))) {
 		fprintf(stderr, "Key does not end in %s\n", MAGICTAIL);
-		goto error2;
-	}
-
-	msg("executing cryptsetup\n");
-	if (run_cryptsetup(block_key_cipher, device, uuid, dec_key,
-			   real_dec_key_len) == 0) {
-		goto error2;
-	}
-
-error2:
-	msg("freeing memory\n");
+		fprintf(stderr, "Last bytes are %s\n", encode(codebuf, dec_key + real_dec_key_len, strlen(MAGICTAIL)));
+		fprintf(stderr, "Should be %s\n", encode(codebuf, MAGICTAIL, strlen(MAGICTAIL)));
+		status = EXIT_FAILURE;
+		goto _exit_free;
+	}
+
+	msg(verbose, "executing cryptsetup\n");
+	if (run_cryptsetup(block_key_cipher, DMCRYPT_PREFIX, device, uuid,
+			   dec_key, real_dec_key_len) == 0) {
+		status = EXIT_FAILURE;
+		goto _exit_free;
+	}
+
+_exit_free:
+	msg(verbose, "freeing memory\n");
+	/* FIXME: what about LUKS? */
 	sesame_free(md);
 
-error1:
+_exit_close:
 	close(fd_metadata);
-error:
-	return 0;
+
+_exit:
+	exit(status);
 }
Binary files sesame-cvs-vanilla/tools/sesame-setup.o and sesame-cvs/tools/sesame-setup.o differ
Binary files sesame-cvs-vanilla/tools/test-crypto and sesame-cvs/tools/test-crypto differ
diff -u --recursive --new-file sesame-cvs-vanilla/tools/test-crypto.c sesame-cvs/tools/test-crypto.c
--- sesame-cvs-vanilla/tools/test-crypto.c	1969-12-31 18:00:00.000000000 -0600
+++ sesame-cvs/tools/test-crypto.c	2005-01-01 14:29:54.000000000 -0600
@@ -0,0 +1,126 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <assert.h>
+
+#ifndef EVP_MAX_BLOCK_LENGTH
+#define EVP_MAX_BLOCK_LENGTH 32	/* some older openssl versions need this */
+#endif
+
+#include "common.h"
+
+char *plaintext  = "abcdefghijklmnopqrstuvwxyz";
+char *passphrase = "passphrase";
+char *cipher     = "aes";
+int   keylen     = 128;
+char *salt       = "aaaaaaaa";
+
+static void print_usage(const int exitcode, const char *error,
+			const char *more)
+{
+	if (error)
+		assert(more);
+
+	fprintf(stderr, "sesame-setup [options] device\n\n"
+		"-h, --help\n"
+		"	print a list of options\n\n"
+		"-p, --plaintext text\n"
+		"	plaintext to use for test	[%s]\n\n"
+		"-w, --passphrase pass\n"
+		"	passphrase to use for test	[%s]\n\n"
+		"-c, --cipher cipher\n"
+		"	cipher used for test		[%s]\n\n"
+		"-k, --keylen length\n"
+		"	length in bits of encryption key	[%d]\n\n"
+		"-s, --salt str\n"
+		"	salt to use for test		[%d]\n\n",
+		plaintext, passphrase, cipher, keylen, salt);
+
+	if (error)
+		fprintf(stderr, "%s: %s\n", error, more);
+
+	exit(exitcode);
+}
+
+int main(int argc, char *argv[])
+{
+	int c, opt_index = 0, status = EXIT_SUCCESS;
+	char pt[BUFSIZ + EVP_MAX_BLOCK_LENGTH];
+	char ct[BUFSIZ + EVP_MAX_BLOCK_LENGTH];
+	char real_cipher[BUFSIZ + 1];
+	int pt_len, ct_len;
+	struct option opts[] = {
+		{"help", 0, 0, 'h'},
+		{"plaintext", 1, 0, 'v'},
+		{"passphrase", 1, 0, 'w'},
+		{"cipher", 1, 0, 'c'},
+		{"keylen", 1, 0, 'k'},
+		{"salt", 1, 0, 's'},
+		{0, 0, 0, 0}
+	};
+
+	while ((c =
+		getopt_long(argc, argv, "hp:w:c:k:", opts, &opt_index))
+	       >= 0) {
+		switch (c) {
+		case 'h':
+			print_usage(EXIT_SUCCESS, NULL, NULL);
+		case 'p':
+			plaintext = optarg;
+			break;
+		case 'w':
+			passphrase = optarg;
+			break;
+		case 'c':
+			cipher = optarg;
+			break;
+		case 'k':
+			keylen = optarg;
+			break;
+		case 's':
+			salt = optarg;
+			break;
+		default:
+			print_usage(EXIT_FAILURE, NULL, NULL);
+		}
+	}
+
+	if (strlen(plaintext) >= BUFSIZ + EVP_MAX_BLOCK_LENGTH) {
+		fprintf(stderr, "%s is too long\n", plaintext);
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+
+	if (strlen(salt) != PKCS5_SALT_LEN) {
+		fprintf(stderr, "salt must be %d bytes\n", PKCS5_SALT_LEN);
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+
+	if (cipher_lookup(real_cipher, cipher) == NULL) {
+                fprintf(stderr, "Do not recognize %s\n", cipher);
+                status = EXIT_FAILURE;
+                goto _exit;
+        }
+
+	fprintf(stdout, "original plaintext is: %s\n", plaintext);
+	if (encrypt_it(ct, &ct_len, plaintext, strlen(plaintext),
+	   salt, real_cipher, passphrase) == 0) {
+		fprintf(stderr, "failed to encrypt %s\n", plaintext);
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+	fprintf(stdout, "ciphertext is %s\n", encode(ct, ct_len));
+	if (decrypt_it(pt, &pt_len, ct, ct_len, real_cipher, 
+	    passphrase) == 0) {
+		fprintf(stderr, "failed to decrypt %s\n", encode(ct, ct_len));
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+	fprintf(stdout, "decrypted plaintext is: %s\n", pt);
+
+_exit:
+	exit(status);
+}
-------------- next part --------------
_______________________________________________
hal mailing list
hal at lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/hal


More information about the Hal mailing list