--- sys/dev/vnd.c.orig	2006-08-07 11:03:59.000000000 +0100
+++ sys/dev/vnd.c	2006-08-09 13:34:41.000000000 +0100
@@ -165,6 +165,10 @@
 
 #include <dev/vndvar.h>
 
+#if defined(VND_ENCRYPTION) && defined(VND_COMPRESSION)
+#include <crypto/des/des.h>
+#endif
+
 #if defined(VNDDEBUG) && !defined(DEBUG)
 #define	DEBUG
 #endif
@@ -223,6 +227,9 @@
 static int	vndlock(struct vnd_softc *);
 static void	vndunlock(struct vnd_softc *);
 #ifdef VND_COMPRESSION
+#ifdef VND_ENCRYPTION
+static void	vnd_set_des_ivec(void *, void *, u_int32_t);
+#endif /* VND_ENCRYPTION */
 static void	compstrategy(struct buf *, off_t);
 static void	*vnd_alloc(void *, u_int, u_int);
 static void	vnd_free(void *, void *);
@@ -323,6 +330,19 @@
 	part = DISKPART(dev);
 	pmask = (1 << part);
 
+#if defined(VND_ENCRYPTION) && defined(VND_COMPRESSION)
+	/* 
+	 * If initialised and encrypted, we should not allow an open
+	 * until the cipher/key settings are configured with VNDIOCSETCIPHER
+	 */ 
+	if ((sc->sc_flags & (VNF_INITED|VNF_CRYPT)) == (VNF_INITED|VNF_CRYPT)) {
+		if(sc->sc_cipher == VNC_UNKNOWN) {
+			printf("vnd: must set cipher\n");
+			vndunlock(sc);
+			return (ENODEV);
+		}
+	}
+#endif	
 	/*
 	 * If we're initialized, check to see if there are any other
 	 * open partitions.  If not, then it's safe to update the
@@ -821,6 +841,9 @@
 #ifdef __HAVE_OLD_DISKLABEL
 	struct disklabel newlabel;
 #endif
+#if defined(VND_ENCRYPTION) && defined(VND_COMPRESSION)
+	struct vnd_cipher *vci;
+#endif
 
 #ifdef DEBUG
 	if (vnddebug & VDB_FOLLOW)
@@ -837,6 +860,7 @@
 	switch (cmd) {
 	case VNDIOCSET:
 	case VNDIOCCLR:
+	case VNDIOCSETCIPHER:
 	case DIOCSDINFO:
 	case DIOCWDINFO:
 #ifdef __HAVE_OLD_DISKLABEL
@@ -852,6 +876,7 @@
 	/* Must be initialized for these... */
 	switch (cmd) {
 	case VNDIOCCLR:
+	case VNDIOCSETCIPHER:
 	case DIOCGDINFO:
 	case DIOCSDINFO:
 	case DIOCWDINFO:
@@ -891,6 +916,18 @@
 			goto close_and_exit;
 		}
 
+		if (vio->vnd_flags & VNF_CRYPT) {
+#if defined(VND_ENCRYPTION) && defined(VND_COMPRESSION)
+			vnd->sc_cipher = VNC_UNKNOWN;
+			vnd->sc_cryptkey = NULL;
+                        vnd->sc_flags |= VNF_CRYPT | VNF_READONLY;
+#else /* !(VND_ENCRYPTION && VND_COMPRESSION) */
+			VOP_UNLOCK(nd.ni_vp, 0);
+			error = EOPNOTSUPP;
+			goto close_and_exit;
+#endif /* VND_ENCRYPTION && VND_COMPRESSION) */
+                }
+
                 /* If using a compressed file, initialize its info */
 		/* (or abort with an error if kernel has no compression) */
                 if (vio->vnd_flags & VNF_COMP) {
@@ -1101,8 +1138,9 @@
 		pool_init(&vnd->sc_vbpool, sizeof(struct vndbuf), 0,
 		    0, 0, "vndbpl", NULL);
 
-		/* Try and read the disklabel. */
-		vndgetdisklabel(dev);
+		/* Try and read the disklabel if we aren't encrypted. */
+		if((vnd->sc_flags & VNF_CRYPT) == 0)
+			vndgetdisklabel(dev);
 
 		vndunlock(vnd);
 
@@ -1199,6 +1237,85 @@
 		break;
 	}
 
+	case VNDIOCSETCIPHER:
+#if defined(VND_ENCRYPTION) && defined(VND_COMPRESSION)
+		/* If cipher is already set, then don't allow it to be changed */
+		if(vnd->sc_cipher != VNC_UNKNOWN)
+			return (EBUSY);
+			
+		if ((error = vndlock(vnd)) != 0)
+			return (error);
+		
+		vci = (struct vnd_cipher *)data;
+		error = 0;
+		switch (vci->vnc_cipher) {
+		case VNC_NONE:
+			break;
+		case VNC_DES:
+			{
+			struct vnd_cipher_des *key;
+			if (vci->vnc_key_length != 8) {
+				error=EINVAL;
+				break;
+			}
+			vnd->sc_key_length = vci->vnc_key_length;
+			vnd->sc_cryptkey = (void *)malloc(sizeof(struct vnd_cipher_des),
+				M_DEVBUF, M_WAITOK);
+			if (vnd->sc_cryptkey == NULL) {
+				error=ENOMEM;
+				break;
+			}
+			key=(struct vnd_cipher_des *)vnd->sc_cryptkey;
+			/* Copy key from userland to kernel */
+			error = copyin(vci->vnc_key, &key->dbk, vnd->sc_key_length);
+			if (error) break;
+			memcpy(&key->mdbk, &key->dbk, sizeof(des_cblock));
+			vnd->sc_cipher = vci->vnc_cipher;
+			des_set_key_unchecked(&key->dbk, key->dks);
+			}
+			break;
+		case VNC_3DES:
+			{
+			struct vnd_cipher_3des *key;
+			if (vci->vnc_key_length != 24) {
+				error=EINVAL;
+				break;
+			}
+			vnd->sc_key_length = vci->vnc_key_length;
+			vnd->sc_cryptkey = (void *)malloc(sizeof(struct vnd_cipher_3des),
+				M_DEVBUF, M_WAITOK);
+			if (vnd->sc_cryptkey == NULL) {
+				error=ENOMEM;
+				break;
+			}
+			key=(struct vnd_cipher_3des *)vnd->sc_cryptkey;
+			/* Copy key from userland to kernel */
+			error = copyin(vci->vnc_key, &key->key, vnd->sc_key_length);
+			if(error) break;
+			memcpy(&key->mdbk, &key->key, sizeof(des_cblock));
+			vnd->sc_cipher = vci->vnc_cipher;
+			des_set_key_unchecked((des_cblock *)key->key, key->dks1);
+			des_set_key_unchecked((des_cblock *)key->key + 1, key->dks2);
+			des_set_key_unchecked((des_cblock *)key->key + 2, key->dks3);
+			}
+			break;
+		default:
+			/* Unsupported cipher type */
+			error=EINVAL;
+			break;
+		}
+		if(error) {
+			vndunlock(vnd);
+			return (error);
+		}
+		/* Try to read disklabel now the cipher is set */
+		vndgetdisklabel(dev);
+		vndunlock(vnd);
+#else
+		return (ENODEV);
+#endif /* VND_ENCRYPTION && VND_COMPRESSION */
+		break;
+
 	case DIOCGDINFO:
 		*(struct disklabel *)data = *(vnd->sc_dkdev.dk_label);
 		break;
@@ -1410,6 +1527,17 @@
 	while (vnd->sc_flags & VNF_KTHREAD)
 		tsleep(&vnd->sc_kthread, PRIBIO, "vnthr", 0);
 
+#ifdef VND_ENCRYPTION
+	/* free the space for the encryption key */
+	if (vnd->sc_flags & VNF_CRYPT) {
+		if (vnd->sc_cryptkey) {
+			free(vnd->sc_cryptkey, M_DEVBUF);
+			vnd->sc_cryptkey = NULL;
+		}
+	}
+
+#endif /* VND_ENCRYPTION */
+
 #ifdef VND_COMPRESSION
         /* free the compressed file buffers */
         if(vnd->sc_flags & VNF_COMP) {
@@ -1607,6 +1735,22 @@
 
 #ifdef VND_COMPRESSION
 /* compressed file read */
+
+#ifdef VND_ENCRYPTION
+static void
+vnd_set_des_ivec(dst, src, v)
+	void *dst, *src;
+	u_int32_t v;
+{
+	unsigned char *c;
+	memcpy(dst,src,sizeof(des_cblock));
+	c=(unsigned char *)dst;
+	c[0] = v & 0xff;
+	c[1] = (v >> 8) & 0xff;
+	c[2] = (v >> 16) & 0xff;
+}
+#endif
+
 static void
 compstrategy(bp, bn)
        struct buf *bp;
@@ -1660,6 +1804,73 @@
 			       splx(s);
                                return;
                        }
+
+#ifdef VND_ENCRYPTION
+			/* decrypt the compressed buffer if required */
+			if (vnd->sc_flags & VNF_CRYPT) {
+				switch(vnd->sc_cipher) {
+				case VNC_DES:
+					{
+					struct vnd_cipher_des *key=(struct vnd_cipher_des *)vnd->sc_cryptkey;
+					int pad;
+					if (length%8 != 0) {
+						printf("Encrypted block short\n");
+						bp->b_error = EINVAL;
+						bp->b_flags |= B_ERROR;
+						VOP_UNLOCK(vnd->sc_vp, 0);
+						splx(s);
+						return;
+					}
+					/* Restore ivec */
+					vnd_set_des_ivec(&key->dbk, &key->mdbk, comp_block);
+					des_ncbc_encrypt(vnd->sc_comp_buff, vnd->sc_comp_buff, length,
+						key->dks, &key->dbk, DES_DECRYPT);
+					pad = vnd->sc_comp_buff[length-1];
+					if (pad > 8) {
+						/* Corrupt or wrong cipher */
+						printf("Encrypted block corrupt\n");
+						bp->b_error = EINVAL;
+						bp->b_flags |= B_ERROR;
+						VOP_UNLOCK(vnd->sc_vp, 0);
+						splx(s);
+						return;
+					}
+					length -= pad;
+					}
+					break;
+				case VNC_3DES:
+					{
+					struct vnd_cipher_3des *key=(struct vnd_cipher_3des *)vnd->sc_cryptkey;
+					int pad;
+					if (length%8 != 0) {
+						printf("Encrypted block short\n");
+						bp->b_error = EINVAL;
+						bp->b_flags |= B_ERROR;
+						VOP_UNLOCK(vnd->sc_vp, 0);
+						splx(s);
+						return;
+					}
+					/* Restore ivec */
+					vnd_set_des_ivec(&key->dbk, &key->mdbk, comp_block);
+					des_ede3_cbc_encrypt(vnd->sc_comp_buff, vnd->sc_comp_buff, length-(length%8),
+						key->dks1, key->dks2,
+						key->dks3, &key->dbk, DES_DECRYPT);
+					pad = vnd->sc_comp_buff[length-1];
+					if (pad > 8) {
+						/* Corrupt or wrong cipher */
+						printf("Encrypted block corrupt\n");
+						bp->b_error = EINVAL;
+						bp->b_flags |= B_ERROR;
+						VOP_UNLOCK(vnd->sc_vp, 0);
+						splx(s);
+						return;
+					}
+					length -= pad;
+					}
+					break;
+				}
+			}
+#endif
                        /* uncompress the buffer */
                        vnd->sc_comp_stream.next_in = vnd->sc_comp_buff;
                        vnd->sc_comp_stream.avail_in = length;
--- sys/dev/vndvar.h.orig	2006-08-07 11:03:59.000000000 +0100
+++ sys/dev/vndvar.h	2006-08-08 16:20:05.000000000 +0100
@@ -113,6 +113,16 @@
  *	@(#)vnioctl.h	8.1 (Berkeley) 6/10/93
  */
 
+#ifndef __VNDVAR_H__
+#define __VNDVAR_H__
+
+
+#ifdef _KERNEL
+#include <crypto/des/des.h>
+#else
+#include <des.h>
+#endif
+
 #include <sys/pool.h>
 
 /*
@@ -170,6 +180,9 @@
 	unsigned char	*sc_comp_decombuf;/* decompressed data buffer */
 	int32_t		 sc_comp_buffblk;/*current decompressed block */
 	z_stream	 sc_comp_stream;/* decompress descriptor */
+	unsigned char	*sc_cryptkey;	/* encryption key */
+	int		 sc_cipher;	/* cipher type */
+	int		 sc_key_length; /* cipher key length */
 };
 #endif
 
@@ -185,6 +198,7 @@
 #define	VNF_KTHREAD	0x100	/* thread is running */
 #define	VNF_VUNCONF	0x200	/* device is unconfiguring */
 #define VNF_COMP	0x400	/* file is compressed */
+#define VNF_CRYPT	0x800	/* file is encrypted */
 
 /* structure of header in a compressed file */
 struct vnd_comp_header
@@ -203,6 +217,30 @@
 	ino_t		vnu_ino;	/* ...at this inode */
 };
 
+struct vnd_cipher {
+	int	vnc_cipher;
+	int	vnc_key_length;
+	void 	*vnc_key;
+};
+
+struct vnd_cipher_des {
+	des_cblock dbk, mdbk;
+	des_key_schedule dks;
+};
+
+struct vnd_cipher_3des {
+	unsigned char key[24];
+	des_cblock dbk, mdbk;
+	des_key_schedule dks1, dks2, dks3;
+};	
+
+/* vnd_cipher types */
+#define VNC_UNKNOWN 0
+#define VNC_NONE 1
+#define VNC_DES 2
+#define VNC_3DES 3
+#define VNC_AES 4
+
 /*
  * Before you can use a unit, it must be configured with VNDIOCSET.
  * The configuration persists across opens and closes of the device;
@@ -212,3 +250,6 @@
 #define VNDIOCSET	_IOWR('F', 0, struct vnd_ioctl)	/* enable disk */
 #define VNDIOCCLR	_IOW('F', 1, struct vnd_ioctl)	/* disable disk */
 #define VNDIOCGET	_IOWR('F', 2, struct vnd_user)	/* get list */
+#define VNDIOCSETCIPHER	_IOWR('F', 3, struct vnd_cipher) /* Set cipher type */
+
+#endif /* __VNDVAR_H */
--- usr.bin/vndcompress/vndcompress.c.orig	2006-08-07 10:59:29.000000000 +0100
+++ usr.bin/vndcompress/vndcompress.c	2006-08-08 16:43:25.000000000 +0100
@@ -39,6 +39,8 @@
  */
 #include <arpa/inet.h>
 
+#include <dev/vndvar.h>
+#include <openssl/des.h>
 #include <err.h>
 #include <fcntl.h>
 #include <stdarg.h>
@@ -61,6 +63,7 @@
  */
 static const char *cloop_sh = "#!/bin/sh\n" "#V2.0 Format\n" "insmod cloop.o file=$0 && mount -r -t iso9660 /dev/cloop $1\n" "exit $?\n";
 
+char *encryptkey=NULL;
 int opmode;
 
 /*
@@ -70,23 +73,81 @@
 usage(void)
 {
 	if (opmode == OM_COMPRESS) {
-		printf("usage: vndcompress [-cd] disk/fs-image compressed-image [blocksize]\n");
+		printf("usage: vndcompress [-cd] [-e key] disk/fs-image compressed-image [blocksize]\n");
 	} else {
-		printf("usage: vnduncompress [-cd] compressed-image disk/fs-image\n");
+		printf("usage: vnduncompress [-cd] [-e key] compressed-image disk/fs-image\n");
 	}
 			   
 	exit(EXIT_FAILURE);
 }
 
+int
+getcryptkey(const char *key, unsigned char *blkp, int *rlen)
+{
+	int np=0;
+	unsigned char ch;
+	int len=0;
+	int type=VNC_UNKNOWN;
+	const char *k;
+	
+	if (!strncmp(key,"des:",4)) {
+		len=8;
+		type=VNC_DES;
+		k=key+4;
+	} else if(!strncmp(key,"none",4)) {
+		*rlen=0;
+		return VNC_NONE;
+	} else if(!strncmp(key,"3des:",5)) {
+		len=24;
+		k=key+5;
+		type=VNC_3DES;
+	} else {
+		return VNC_UNKNOWN;
+	}
+	
+	if (strlen(k) == len) {
+		for(np=0;np<len;np++) *blkp++=k[np];
+	} else if (strlen(k) == 2+(2*len) && k[0] == '0' && k[1] == 'x') {
+		for(np=2;np<2+(2*len);np+=2) {
+			ch=(unsigned char)k[np];
+			if (ch >= '0' && ch <= '9') *blkp=ch;
+			else if (ch >= 'a' && ch <= 'f') *blkp=ch='a';
+			else if (ch >= 'A' && ch <= 'F') *blkp=ch-'A';
+			ch=(unsigned char)k[np+1];
+			if (ch >= '0' && ch <= '9') *blkp|=ch;
+			else if (ch >= 'a' && ch <= 'f') *blkp|=ch='a';
+			else if (ch >= 'A' && ch <= 'F') *blkp|=ch-'A';
+			*blkp++;
+		}
+	} else {
+		fprintf(stderr, "Encryption key must be %d bytes long. It can be specified either as\n",len);
+		fprintf(stderr, "a text string or hexadecimal (if preceded by 0x)\n");
+		exit(EXIT_FAILURE);
+	}
+	*rlen=len;
+	return type;
+}
+
+void
+set_des_ivec(DES_cblock *dst, DES_cblock *src, int v)
+{
+	unsigned char *c;
+	memcpy(dst, src, sizeof(DES_cblock));
+	c=(unsigned char *)dst;
+	c[0] = v & 0xff;
+	c[1] = (v >> 8) & 0xff;
+	c[2] = (v >> 16) & 0xff;
+}
+
 /*
  * Compress a given file system
  */
 void
-vndcompress(const char *fs, const char *comp, uint32_t blocksize)
+vndcompress(const char *fs, const char *comp, uint32_t blocksize, struct vnd_cipher *vnc)
 {
 	int fd_in, fd_out;
 	int total_blocks, offtable_size;
-	int i;
+	int i, pad;
 	int read_blocksize;
 	off_t fsize, diffatom, cursize;
 	struct cloop_header clh;
@@ -196,12 +257,51 @@
 			err(EXIT_FAILURE, "Cannot read input file \"%s\"", fs);
 			/* NOTREACHED */		
 		
-		complen = blocksize * 2;
+		complen = (blocksize * 2) - 8;
 			
 		if (compress2(cb, &complen, ucb, blocksize, Z_BEST_COMPRESSION) != Z_OK)
 			errx(EXIT_FAILURE, "Compression failed in block %d", i);
 			/* NOTREACHED */
 
+		switch(vnc->vnc_cipher) {
+		case VNC_NONE:
+			break;
+		case VNC_DES:
+			/*
+			 * DES encrypts a multiple of 8 bytes, so we need to extend the block
+			 * by padding it with between 1 and 8 bytes. The last byte is the number
+			 * of bytes added (c.f. man bdes(1))
+			 */
+			pad = 8-(complen%8);
+			complen += pad;
+			cb[complen-1] = pad;
+			{
+			struct vnd_cipher_des *key=(struct vnd_cipher_des *)vnc->vnc_key;
+			/* Restore ivec */
+			set_des_ivec(&key->dbk, &key->mdbk, i);
+			DES_ncbc_encrypt(cb, cb, complen, (DES_key_schedule *)&key->dks, &key->dbk, DES_ENCRYPT);
+			}
+			break;
+		case VNC_3DES:
+			/*
+			 * DES encrypts a multiple of 8 bytes, so we need to extend the block
+			 * by padding it with between 1 and 8 bytes. The last byte is the number
+			 * of bytes added (c.f. man bdes(1))
+			 */
+			pad = 8-(complen%8);
+			complen += pad;
+			cb[complen-1] = pad;
+			{
+			struct vnd_cipher_3des *key=(struct vnd_cipher_3des *)vnc->vnc_key;
+			/* Restore master key */
+			set_des_ivec(&key->dbk, &key->mdbk, i);
+			DES_ede3_cbc_encrypt(cb, cb, complen,
+				(DES_key_schedule *)&key->dks1, (DES_key_schedule *)&key->dks2,
+				(DES_key_schedule *)&key->dks3, &key->dbk, DES_ENCRYPT);
+			}
+			break;
+		}			
+		
 		if (write(fd_out, cb, complen) < complen)
 			err(EXIT_FAILURE, "Cannot write to output file \"%s\"", comp);
 			/* NOTREACHED */
@@ -232,7 +332,6 @@
 		memset(cb, 0, blocksize * 2);
 		write(fd_out, cb, diffatom);
 	}
-	
 	free(cb);
 	free(ucb);
 	free(offtable);
@@ -275,7 +374,7 @@
  * Decompress a given file system image
  */
 void
-vnduncompress(const char *comp, const char *fs)
+vnduncompress(const char *comp, const char *fs, struct vnd_cipher *vnc)
 {
 	int fd_in, fd_out;
 	int i;
@@ -284,7 +383,7 @@
 	off_t imgofs, datastart;
 	unsigned long complen, uncomplen;
 	unsigned char *cb, *ucb;
-	
+		
 	/*
 	 * Setup decompression, read in header tables
 	 */
@@ -327,6 +426,39 @@
 			err(EXIT_FAILURE, "Cannot read compressed block %d from \"%s\"", i, comp);
 			/* NOTREACHED */
 
+		switch(vnc->vnc_cipher) {
+		case VNC_NONE:
+			break;
+		case VNC_DES:
+			{
+			struct vnd_cipher_des *key=(struct vnd_cipher_des *)vnc->vnc_key;
+			int pad;
+			if(complen%8 != 0) err(EXIT_FAILURE, "Encrypted block %d short\n", i);
+			/* Restore master ivec */
+			set_des_ivec(&key->dbk, &key->mdbk, i);
+			DES_ncbc_encrypt(cb, cb, complen, (DES_key_schedule *)&key->dks, &key->dbk, DES_DECRYPT);
+			pad = cb[complen-1];
+			if(pad > 8) err(EXIT_FAILURE, "Encrypted block %d corrupt (wrong cipher?)\n", i);
+			complen -=pad;
+			}
+			break;
+		case VNC_3DES:
+			{
+			struct vnd_cipher_3des *key=(struct vnd_cipher_3des *)vnc->vnc_key;
+			int pad;
+			if(complen%8 != 0) err(EXIT_FAILURE, "Encrypted block %d short\n", i);
+			/* Restore master ivec */
+			set_des_ivec(&key->dbk, &key->mdbk, i);
+			DES_ede3_cbc_encrypt(cb, cb, complen,
+				(DES_key_schedule *)&key->dks1, (DES_key_schedule *)&key->dks2,
+				(DES_key_schedule *)&key->dks3, &key->dbk, DES_DECRYPT);
+			pad = cb[complen-1];
+			if(pad > 8) err(EXIT_FAILURE, "Encrypted block %d corrupt (wrong cipher?)\n", i);
+			complen -=pad;
+			}
+			break;
+		}			
+		
 		uncomplen = clh.block_size;
 		rc = uncompress(ucb, &uncomplen, cb, complen);
 		if (rc != Z_OK)
@@ -340,7 +472,7 @@
 	free(cb);
 	free(ucb);
 	free(offtable);	
-		
+	
 	close(fd_in);
 	close(fd_out);	
 }
@@ -353,8 +485,9 @@
 int
 main(int argc, char **argv)
 {
-	char *ep, *p;
+	char *ep, *p, *key;
 	int ch;
+	struct vnd_cipher vnc;
 	
 	setprogname(argv[0]);
 	
@@ -370,7 +503,7 @@
 		warnx("unknown program name '%s'", p);
 	
 	/* Process command-line options */	
-	while ((ch = getopt(argc, argv, "cd")) != -1) {
+	while ((ch = getopt(argc, argv, "cde:")) != -1) {
 		switch (ch) {
 		case 'c':
 			opmode = OM_COMPRESS;
@@ -379,7 +512,11 @@
 		case 'd':
 			opmode = OM_UNCOMPRESS;
 			break;
-			
+
+		case 'e':
+			encryptkey = optarg;
+			break;
+
 		default:
 			usage();
 			/* NOTREACHED */
@@ -393,20 +530,70 @@
 		usage();
 		/* NOTREACHED */
 	}
+	
+	vnc.vnc_key=NULL;
+	if (encryptkey) {
+		/* Initialise the encryption */	
+		key=strdup(encryptkey);
+		if(!key) {
+			perror("strdup");
+			exit(EXIT_FAILURE);
+		}
+		vnc.vnc_cipher=getcryptkey(encryptkey, key, &vnc.vnc_key_length);
+		switch(vnc.vnc_cipher) {
+		case VNC_NONE:
+			break;
+		case VNC_DES:
+			{
+			struct vnd_cipher_des *vncd;
+			vnc.vnc_key=(void *)malloc(sizeof(struct vnd_cipher_des));
+			if(!vnc.vnc_key) {
+				perror("malloc");
+				exit(EXIT_FAILURE);
+			}
+			vncd=(struct vnd_cipher_des *)vnc.vnc_key;
+			memcpy(vncd->dbk, key, sizeof(DES_cblock));
+			memcpy(vncd->mdbk, key, sizeof(DES_cblock));
+			DES_set_key_unchecked(&vncd->dbk,(DES_key_schedule *)&vncd->dks);
+			}
+			break;
+		case VNC_3DES:
+			{
+			struct vnd_cipher_3des *vncd;
+			vnc.vnc_key=(void *)malloc(sizeof(struct vnd_cipher_3des));
+			if(!vnc.vnc_key) {
+				perror("malloc");
+				exit(EXIT_FAILURE);
+			}
+			vncd=(struct vnd_cipher_3des *)vnc.vnc_key;
+			memcpy(vncd->dbk, key, sizeof(DES_cblock));
+			memcpy(vncd->mdbk, key, sizeof(DES_cblock));
+			DES_set_key_unchecked((DES_cblock *)key, (DES_key_schedule *)&vncd->dks1);
+			DES_set_key_unchecked((DES_cblock *)key + 1, (DES_key_schedule *)&vncd->dks2);
+			DES_set_key_unchecked((DES_cblock *)key + 2, (DES_key_schedule *)&vncd->dks3);
+			}
+			break;
+		default:
+			fprintf(stderr,"Unknown cipher type\n");
+			exit(EXIT_FAILURE);
+			break;
+		}
+		free(key);
+	}
 		
 	switch (opmode) {
 	case OM_COMPRESS:
 		if (argc > 2) {
-			vndcompress(argv[0], argv[1], strtoul(argv[2], &ep, 10));
+			vndcompress(argv[0], argv[1], strtoul(argv[2], &ep, 10), &vnc);
 		} else {
-			vndcompress(argv[0], argv[1], DEF_BLOCKSIZE);
+			vndcompress(argv[0], argv[1], DEF_BLOCKSIZE, &vnc);
 		}
 		break;
 		
 	case OM_UNCOMPRESS:
-		vnduncompress(argv[0], argv[1]);
+		vnduncompress(argv[0], argv[1], &vnc);
 		break;
 	}
-
+	if (vnc.vnc_key) free(vnc.vnc_key);
 	exit(EXIT_SUCCESS);
 }
--- usr.bin/vndcompress/vndcompress.1.orig	2006-08-07 10:33:49.000000000 +0100
+++ usr.bin/vndcompress/vndcompress.1	2006-08-08 11:06:41.000000000 +0100
@@ -40,11 +40,13 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl cd
+.Op Fl e Ar key
 .Ar disk/fs-image
 .Ar compressed-image
 .Op Ar blocksize
 .Nm vnduncompress
 .Op Fl cd
+.Op Fl e Ar key
 .Ar compressed-image
 .Ar disk/fs-image
 .Sh DESCRIPTION
@@ -74,6 +76,16 @@
 .Fl t
 option to
 .Xr mount 8 .
+.Pp
+The
+compressed image can be optionally encrypted with a choice of different
+ciphers. Encrypting the image will mean that the image is no longer cloop2
+compatible. To use the encrypted image, the same cipher type and key must
+be specified with the
+.Fl e
+option of the
+.Xr vnconfig 8
+program.
 .Sh OPTIONS
 The following options are available:
 .Bl -tag -width indent
@@ -83,6 +95,13 @@
 .It Fl d
 Always uncompress (decompress), even if the program was started as
 .Nm .
+.It Fl e Ar key
+Encrypt the image with the given key and cipher type. The argument consists
+of the cipher type (one of des, 3des or none) followed by a colon and then the
+key. The key can be specified either as a string or as hexadecimal digits
+(if it begins with 0x). For DES encryption, the key must be 64-bits (8
+characters) long. For 3DES, it must be 192-bits (24 characters). The 'none'
+encryption type does not require a key and performs no encryption.
 .El
 .Sh EXIT STATUS
 The
@@ -183,6 +202,18 @@
 # rm /tmp/include.img.cloop2
 # rm /tmp/include.img
 .Ed
+.Pp
+The compressed image can also be encrypted:
+.Bd -literal -offset indent
+# vndcompress -e des:private1 include.fs include.fs.crypt
+# vnconfig -z -e des:private1 vnd0 include.fs.crypt
+.Ed
+.Pp
+Alternatively, you can specify a key in hexadecimal
+.Bd -literal -offset indent
+# vndcompress -e des:0x0123456789abcdef include.fs include.fs.crypt
+# vnconfig -z -e des:0x0123456789abcdef vnd0 include.fs.crypt
+.Ed
 .Sh SEE ALSO
 .Xr gzip 1 ,
 .Xr vnd 4 ,
@@ -196,6 +227,9 @@
 utility was written by
 .An Florian Stoehr
 .Aq netbsd@wolfnode.de .
+The encryption option was added by
+.An Stephen Borrill
+.Aq netbsd@precedence.co.uk .
 The
 .Nm
 manual page was written by
--- usr.sbin/vnconfig/vnconfig.c.orig	2006-08-07 10:52:12.000000000 +0100
+++ usr.sbin/vnconfig/vnconfig.c	2006-08-09 11:54:15.000000000 +0100
@@ -122,6 +122,8 @@
 
 #include <dev/vndvar.h>
 
+#include <des.h>
+
 #include <disktab.h>
 #include <err.h>
 #include <errno.h>
@@ -131,6 +133,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <util.h>
+#include <openssl/des.h>
 
 #define VND_CONFIG	1
 #define VND_UNCONFIG	2
@@ -140,8 +143,10 @@
 int	readonly = 0;
 int	force = 0;
 int	compressed = 0;
+char	*cryptkey = NULL;
 char	*tabname;
 
+int	getcryptkey(const char *, unsigned char *, int *);
 int	config __P((char *, char *, char *, int));
 int	getgeom __P((struct vndgeom *, char *));
 int	main __P((int, char **));
@@ -155,7 +160,7 @@
 {
 	int ch, rv, action = VND_CONFIG;
 
-	while ((ch = getopt(argc, argv, "Fcf:lrt:uvz")) != -1) {
+	while ((ch = getopt(argc, argv, "Fce:f:lrt:uvz")) != -1) {
 		switch (ch) {
 		case 'F':
 			force = 1;
@@ -163,6 +168,11 @@
 		case 'c':
 			action = VND_CONFIG;
 			break;
+		case 'e':
+			compressed = 1;
+			readonly = 1;
+			cryptkey = optarg;
+			break;
 		case 'f':
 			if (setdisktab(optarg) == -1)
 				usage();
@@ -279,14 +289,62 @@
 }
 
 int
+getcryptkey(const char *key, unsigned char *blkp, int *rlen)
+{
+	int np=0;
+	unsigned char ch;
+	int len=0;
+	int type=VNC_UNKNOWN;
+	const char *k;
+	
+	if (!strncmp(key,"des:",4)) {
+		len=8;
+		type=VNC_DES;
+		k=key+4;
+	} else if(!strncmp(key,"none",4)) {
+		*rlen=0;
+		return VNC_NONE;
+	} else if(!strncmp(key,"3des:",5)) {
+		len=24;
+		k=key+5;
+		type=VNC_3DES;
+	} else {
+		return VNC_UNKNOWN;
+	}
+	
+	if (strlen(k) == len) {
+		for(np=0;np<len;np++) *blkp++=k[np];
+	} else if (strlen(k) == 2+(2*len) && k[0] == '0' && k[1] == 'x') {
+		for(np=2;np<2+(2*len);np+=2) {
+			ch=(unsigned char)k[np];
+			if (ch >= '0' && ch <= '9') *blkp=ch;
+			else if (ch >= 'a' && ch <= 'f') *blkp=ch='a';
+			else if (ch >= 'A' && ch <= 'F') *blkp=ch-'A';
+			ch=(unsigned char)k[np+1];
+			if (ch >= '0' && ch <= '9') *blkp|=ch;
+			else if (ch >= 'a' && ch <= 'f') *blkp|=ch='a';
+			else if (ch >= 'A' && ch <= 'F') *blkp|=ch-'A';
+			*blkp++;
+		}
+	} else {
+		fprintf(stderr, "Encryption key must be %d bytes long. It can be specified either as\n",len);
+		fprintf(stderr, "a text string or hexadecimal (if preceded by 0x)\n");
+		exit(EXIT_FAILURE);
+	}
+	*rlen=len;
+	return type;
+}
+
+int
 config(dev, file, geom, action)
 	char *dev, *file, *geom;
 	int action;
 {
 	struct vnd_ioctl vndio;
+	struct vnd_cipher vndcipher;
 	struct disklabel *lp;
 	char rdev[MAXPATHLEN + 1];
-	int fd, rv;
+	int fd, rv, crtype, crlen;
 
 	fd = opendisk(dev, O_RDWR, rdev, sizeof(rdev), 0);
 	if (fd < 0) {
@@ -321,6 +379,9 @@
 
 	if (compressed)
 		vndio.vnd_flags |= VNF_COMP;
+	
+	if (cryptkey)
+		vndio.vnd_flags |= VNF_CRYPT;
 
 	/*
 	 * Clear (un-configure) the device
@@ -339,7 +400,24 @@
 	 */
 	if (action == VND_CONFIG) {
 		int	ffd;
-
+		
+		vndcipher.vnc_key=NULL;
+		if(cryptkey) {
+			/* Final key length will be no longer than the input string length */
+			vndcipher.vnc_key = (unsigned char *)strdup(cryptkey);
+			if(!vndcipher.vnc_key) {
+				perror("strdup");
+				exit(EXIT_FAILURE);
+			}				
+			crtype = getcryptkey(cryptkey, vndcipher.vnc_key, &crlen);
+			if(crtype == VNC_UNKNOWN) {
+				fprintf(stderr,"Unknown cipher type\n");
+				exit(EXIT_FAILURE);
+			}
+			vndcipher.vnc_cipher=crtype;
+			vndcipher.vnc_key_length=crlen;
+		}
+		
 		ffd = open(file, readonly ? O_RDONLY : O_RDWR);
 		if (ffd < 0)
 			warn("%s", file);
@@ -349,18 +427,27 @@
 			rv = ioctl(fd, VNDIOCSET, &vndio);
 			if (rv)
 				warn("%s: VNDIOCSET", rdev);
-			else if (verbose) {
-				printf("%s: %d bytes on %s", rdev,
-				    vndio.vnd_size, file);
-				if (vndio.vnd_flags & VNDIOF_HASGEOM)
-					printf(" using geometry %d/%d/%d/%d",
-					    vndio.vnd_geom.vng_secsize,
-					    vndio.vnd_geom.vng_nsectors,
-					    vndio.vnd_geom.vng_ntracks,
-				    vndio.vnd_geom.vng_ncylinders);
-				printf("\n");
+			else {
+				if (verbose) {
+					printf("%s: %d bytes on %s", rdev,
+					    vndio.vnd_size, file);
+					if (vndio.vnd_flags & VNDIOF_HASGEOM)
+						printf(" using geometry %d/%d/%d/%d",
+						    vndio.vnd_geom.vng_secsize,
+						    vndio.vnd_geom.vng_nsectors,
+						    vndio.vnd_geom.vng_ntracks,
+					    vndio.vnd_geom.vng_ncylinders);
+					printf("\n");
+				}
+				if (cryptkey) {
+					rv = ioctl(fd, VNDIOCSETCIPHER, &vndcipher);
+					if (rv)
+						warn("%s: VNDIOCSETCIPHER", rdev);
+						
+				}
 			}
 		}
+		if (vndcipher.vnc_key) free(vndcipher.vnc_key);
 	}
 
 	(void) close(fd);
@@ -417,7 +504,7 @@
 {
 
 	(void)fprintf(stderr, "%s%s",
-	    "usage: vnconfig [-crvz] [-f disktab] [-t typename] vnode_disk"
+	    "usage: vnconfig [-crvz] [-f disktab] [-t typename] [-e key] vnode_disk"
 		" regular-file [geomspec]\n",
 	    "       vnconfig -u [-Fv] vnode_disk\n"
 	    "       vnconfig -l [vnode_disk]\n");
--- usr.sbin/vnconfig/vnconfig.8.orig	2006-08-07 10:51:40.000000000 +0100
+++ usr.sbin/vnconfig/vnconfig.8	2006-08-08 11:12:28.000000000 +0100
@@ -110,6 +110,7 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl crvz
+.Op Fl e Ar key
 .Op Fl f Ar disktab
 .Op Fl t Ar typename
 .Ar vnode_disk
@@ -207,6 +208,18 @@
 See the
 .Xr vndcompress 1
 manpage on how to create such an image. 
+.It Fl e
+Assume that
+.Ar regular file
+is an encrypted, compressed disk image, and configures it read-only by using the
+given key and cipher type to decrypt it. The argument consists of the cipher type
+(one of des, 3des or none) followed by a colon and then the key. The key can be
+specified either as a string or as hexadecimal digits (if it begins
+with 0x). For DES encryption, the key must be 64-bits (8 characters) long. For 3DES, it
+must be 192-bits (24 characters) long. The 'none' encryption type does not require
+a key. See the
+.Xr vndcompress 1
+manpage on how to create such an image. 
 .El
 .Pp
 If no action option is given,
@@ -250,6 +263,7 @@
 .Pa vnd0
 device.
 .Sh SEE ALSO
+.Xr vndcompress 1 ,
 .Xr opendisk 3 ,
 .Xr vnd 4 ,
 .Xr mount 8 ,
