C sesame-setup implementation

W. Michael Petullo mike at flyn.org
Sat Jan 1 16:01:43 PST 2005


>> I wrote a patch for the sesame code in CVS that adds a C implementation
>> of sesame-setup.  I used OpenSSL's libraries for the crypto because this
>> is what I am familiar with.  Cryptsetup is also required.  It seems
>> to work.

> I think this looks pretty good and complete for sesame-setup apart from
> a few items such as maybe a flag to ask for the password on stdin for
> use in the initrd?

I hope to make this stuff initrd-friendly once I have the basics working.

> > --- sesame-vanilla/configure.in	2004-12-17 10:56:52.000000000 -0600
> > +++ sesame/configure.in	2004-12-21 20:40:55.427719336 -0600
> > @@ -103,6 +103,14 @@
> >  
> >  #pkg_modules="hal >= 0.4.0, hal-storage >= 0.4.0, openssl >= 0.9.7a"
> >  #PKG_CHECK_MODULES(PACKAGE, [$pkg_modules])
> > +AC_CHECK_LIB(crypto, EVP_DecryptInit_ex)
> > +AC_CHECK_LIB(ssl, SSL_load_error_strings)
> > +
> > +AC_PATH_PROG(CRYPTSETUP, cryptsetup, no)
> > +if test x"$CRYPTSETUP" = xno; then
> > +        AC_MSG_ERROR([cryptsetup executable not found in your path])
> > +fi
> > +AC_SUBST(CRYPTSETUP)
> 
> This only works for me if I put /sbin in my $PATH - on FC3, that binary
> is in /sbin. Any idea what to do here? I think we always want to assume
> that cryptsetup is in /sbin so sesame-setup works without /usr mounted,
> right?

This is probably a safe assumption.
 
> Btw, is there any good reason for relying on cryptsetup rather than just
> dmsetup? Either way is in principle fine with me.

Cryptsetup can perform hashing of passphrases.  Also, cryptsetup is now
statically linked on Fedora for the purpose of its use in initrds.
Using cryptsetup is consistent with other developments (encrypted swap
and encrypted root filesystem) in progress.  Other than that, I am not
really attached to either.

Attached you should find another patch vs. CVS.  This patch implements
the other side of the coin -- it formats a device in a sesame-compliant
way.  It's not done, but I wanted to submit it for comments.  Right now it
does everything except write the sesame header to the device.  This must
still be done by hand.

Here is an example of using sesame-format and sesame-setup:

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 sesame_crypto_<UUID>

4.  Install the sesame header:
dd if=../../cryptheader bs=1c count=512 of=/dev/sdb4

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

6.  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-01 17:47:32.341394408 -0600
@@ -1,3 +1,17 @@
+2004-01-01  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	2004-12-31 12:48:13.000000000 -0600
@@ -14,6 +14,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 +106,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 +114,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)
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-01 17:29:11.677720720 -0600
@@ -0,0 +1,364 @@
+#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"
+
+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 *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 * 8) == -1) {
+		fprintf(stderr, "Failed to allocate memory, err=%s\n",
+			strerror(errno));
+		fnval = 0;
+		goto _return_no_free;
+	}
+
+	strcpy(dmname, DMCRYPT_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;
+}
+
+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
+encrypt_it(char * out, size_t * const out_len,
+	const char *const in, const size_t in_len, const unsigned char *salt,
+	const char *cipher_name, const char *const authtok)
+{
+	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(salt != NULL);
+	assert(cipher_name != 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_name);
+		ret = 0;
+		goto _return;
+	}
+	if (hash_authtok(cipher, authtok, hashed_authtok, salt, iv) == 0) {
+		ret = 0;
+		goto _return;
+	}
+	
+	if (EVP_EncryptInit_ex(&ctx, cipher, NULL, hashed_authtok, iv) ==
+	    0) {
+		sslerror("failed to initialize encryption code");
+		ret = 0;
+		goto _return;
+	}
+
+	memcpy(out, "Salted__", strlen("Salted__"));
+	out += strlen("Salted__");
+	memcpy(out, salt, PKCS5_SALT_LEN);
+	out += PKCS5_SALT_LEN;
+	*out_len = strlen("Salted__") + PKCS5_SALT_LEN;
+
+	/* assumes plaintexts is always <= ciphertext + EVP_MAX_BLOCK_LEN in length
+	 * OpenSSL's documentation seems to promise this */
+	if (EVP_EncryptUpdate
+	    (&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 (EVP_EncryptFinal_ex(&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;
+}
+
+int
+decrypt_it(char *const out, size_t * const out_len,
+	const char *in, size_t in_len,
+	const char *const cipher_name, const char *const authtok)
+{
+	int ret = 1;
+	int segment_len;
+	unsigned char salt[PKCS5_SALT_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(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_name);
+		ret = 0;
+		goto _return;
+	}
+
+	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);
+
+	if (hash_authtok(cipher, authtok, hashed_authtok, salt, 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;
+	}
+	in += (strlen("Salted__") + PKCS5_SALT_LEN);
+	in_len -= (strlen("Salted__") + 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, in, in_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;
+}
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-01 16:55:40.000000000 -0600
@@ -0,0 +1,24 @@
+#define MAGICTAIL "SESAME0"
+#define DMCRYPT_PREFIX "sesame_crypto_"
+#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 *device,
+		   const char *uuid, const char *key, const int key_len);
+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
+encrypt_it(char * out, size_t * const out_len,
+        const char *const in, const size_t in_len, const unsigned char *salt,
+        const char *cipher_name, const char *const authtok);
+int
+decrypt_it(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);
Binary files sesame-cvs-vanilla/tools/foo and sesame-cvs/tools/foo 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-01 16:51:14.000000000 -0600
@@ -1,16 +1,27 @@
 
 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
+EXTRA_PROGRAMS = test-crypto
 
-sesame_setup_SOURCES = sesame-setup.c
+sbin_PROGRAMS = sesame-format sesame-setup
+
+sesame_format_SOURCES = sesame-format.c common.c
+
+sesame_setup_SOURCES = sesame-setup.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
+
+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-01 17:29:38.854589208 -0600
@@ -0,0 +1,301 @@
+
+#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 <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"
+#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);
+}
+
+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_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;
+	char buf[BUFSIZ + 1];
+	char passphrase[BUFSIZ + 1];
+	char real_key_cipher[BUFSIZ + 1];
+	int c, opt_index = 0, status =
+	    EXIT_SUCCESS;
+	size_t efs_keylen;
+	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 (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, 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 (encrypt_it
+	    (efs_key, &efs_keylen, fs_key, fs_keylen + strlen(MAGICTAIL),
+	     salt, real_key_cipher, passphrase) == 0) {
+		fprintf(stderr, "Cannot encrypt key\n");
+		status = EXIT_FAILURE;
+		goto _exit;
+	}
+
+	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));
+
+      _exit:
+	exit(status);
+}
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-01 17:29:00.552412024 -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,16 @@
 #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"
 #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 +41,18 @@
 	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 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 +76,121 @@
 		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");
+	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");
+	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");
+	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");
+	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");
+	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");
+	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 (decrypt_it
+	    (dec_key, &dec_key_len, decode(codebuf, enc_key), strlen(enc_key) / 2,
+	     real_key_cipher, passphrase) == 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;
+		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("executing cryptsetup\n");
+	msg(verbose, "executing cryptsetup\n");
 	if (run_cryptsetup(block_key_cipher, device, uuid, dec_key,
 			   real_dec_key_len) == 0) {
-		goto error2;
+		status = EXIT_FAILURE;
+		goto _exit_free;
 	}
 
-error2:
-	msg("freeing memory\n");
+_exit_free:
+	msg(verbose, "freeing memory\n");
 	sesame_free(md);
 
-error1:
+_exit_close:
 	close(fd_metadata);
-error:
-	return 0;
+
+_exit:
+	exit(status);
 }
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