diff --git a/configure.ac b/configure.ac
index 0297390..0504dff 100644
--- a/configure.ac
+++ b/configure.ac
@@ -216,6 +216,9 @@ PKG_CHECK_MODULES([GLIB],[glib-2.0 >= $GLIB_REQUIRED])
 PKG_CHECK_MODULES([GOBJECT],[gobject-2.0])
 PKG_CHECK_MODULES([GTK],[gtk+-$GTK_API_VERSION >= $GTK_REQUIRED])
 
+### TODO: why is the 3rd arg needed, is it okay?
+PKG_CHECK_MODULES([LIBGNUTLS],[gnutls >= 3.2.0],[LIBS="$LIBS $LIBGNUTLS_LIBS"])
+
 wcs_funcs_includes="
 #ifdef HAVE_STRING_H
 # if !STDC_HEADERS && HAVE_MEMORY_H
diff --git a/src/vtestream-file.h b/src/vtestream-file.h
index 93ed6ea..23ba2c7 100644
--- a/src/vtestream-file.h
+++ b/src/vtestream-file.h
@@ -82,6 +82,9 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
 #include "vteutils.h"
 
 
@@ -566,6 +569,9 @@ typedef struct _VteFileStream {
 	gsize wbuf_len;
 
 	gsize head, tail;
+
+	gnutls_cipher_hd_t cipher_hd;
+	unsigned char iv[16];
 } VteFileStream;
 
 typedef VteStreamClass VteFileStreamClass;
@@ -584,11 +590,31 @@ _vte_file_stream_new (void)
 static void
 _vte_file_stream_init (VteFileStream *stream)
 {
+	unsigned char key[32];
+	gnutls_datum_t datum_key;
+
 	_vte_unbuffered_file_stream_init ((VteUnbufferedFileStream *) stream);
 
 	stream->rbuf = g_malloc(VTE_FILE_STREAM_BLOCKSIZE);
 	stream->wbuf = g_malloc(VTE_FILE_STREAM_BLOCKSIZE);
 	stream->rbuf_offset = 1;  /* Invalidate the read cache. */
+
+	gnutls_global_init ();
+
+	g_assert (gnutls_cipher_get_block_size(GNUTLS_CIPHER_AES_256_CBC) == 16);
+	g_assert (gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_256_CBC) == 16);
+
+	/* Some bytes of IV will contain the offset (gsize), some other bytes will be random. */
+	g_assert (gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_256_CBC) > (int) sizeof(gsize));
+
+	gnutls_rnd_refresh();
+	gnutls_rnd(GNUTLS_RND_KEY, key, 32);
+	gnutls_rnd(GNUTLS_RND_NONCE, stream->iv, 16);
+
+	datum_key.data = key;
+	datum_key.size = 32;
+	gnutls_cipher_init(&stream->cipher_hd, GNUTLS_CIPHER_AES_256_CBC, &datum_key, NULL);
+	memset(key, 0, 32);
 }
 
 static void
@@ -599,6 +625,10 @@ _vte_file_stream_finalize (GObject *object)
 	g_free(stream->rbuf);
 	g_free(stream->wbuf);
 
+	memset(stream->iv, 0, 16);
+	gnutls_cipher_deinit (stream->cipher_hd);
+	gnutls_global_deinit ();
+
 	G_OBJECT_CLASS (_vte_file_stream_parent_class)->finalize(object);
 }
 
@@ -616,6 +646,48 @@ _vte_file_stream_reset (VteStream *astream, gsize offset)
 }
 
 static void
+_vte_file_stream_encrypt_and_append (VteStream *astream, gsize offset, char *data)
+{
+#ifndef VTESTREAM_MAIN
+	VteFileStream *stream = (VteFileStream *) astream;
+
+	memcpy (stream->iv, &offset, sizeof(gsize));
+	gnutls_cipher_set_iv (stream->cipher_hd, stream->iv, 16);
+	gnutls_cipher_encrypt (stream->cipher_hd, data, VTE_FILE_STREAM_BLOCKSIZE);
+#else
+	/* Fake encryption (lowercase<->uppercase) for unit testing */
+	data[0] ^= 0x20;
+	data[1] ^= 0x20;
+	data[2] ^= 0x20;
+	data[3] ^= 0x20;
+#endif
+
+	_vte_unbuffered_file_stream_append (astream, data, VTE_FILE_STREAM_BLOCKSIZE);
+}
+
+static gboolean
+_vte_file_stream_read_and_decrypt (VteStream *astream, gsize offset, char *data)
+{
+	VteFileStream *stream = (VteFileStream *) astream;
+
+	if (!_vte_unbuffered_file_stream_read (astream, offset, data, VTE_FILE_STREAM_BLOCKSIZE))
+		return FALSE;
+#ifndef VTESTREAM_MAIN
+	memcpy (stream->iv, &offset, sizeof(gsize));
+	gnutls_cipher_set_iv (stream->cipher_hd, stream->iv, 16);
+	gnutls_cipher_decrypt (stream->cipher_hd, data, VTE_FILE_STREAM_BLOCKSIZE);
+#else
+	/* Fake decryption (lowercase<->uppercase) for unit testing */
+	data[0] ^= 0x20;
+	data[1] ^= 0x20;
+	data[2] ^= 0x20;
+	data[3] ^= 0x20;
+	(void) stream;  /* silence gcc */
+#endif
+	return TRUE;
+}
+
+static void
 _vte_file_stream_append (VteStream *astream, const char *data, gsize len)
 {
 	VteFileStream *stream = (VteFileStream *) astream;
@@ -628,7 +700,7 @@ _vte_file_stream_append (VteStream *astream, const char *data, gsize len)
 		memcpy(stream->wbuf + stream->wbuf_len, data, l);
 		stream->wbuf_len += l; data += l; len -= l;
 		if (stream->wbuf_len == VTE_FILE_STREAM_BLOCKSIZE) {
-			_vte_unbuffered_file_stream_append (astream, stream->wbuf, VTE_FILE_STREAM_BLOCKSIZE);
+			_vte_file_stream_encrypt_and_append (astream, stream->parent.head /* TODO: find a nicer way of knowing the head? */, stream->wbuf);
 			stream->wbuf_len = 0;
 		}
 	}
@@ -657,7 +729,7 @@ _vte_file_stream_read (VteStream *astream, gsize offset, char *data, gsize len)
 		gsize l = MIN(VTE_FILE_STREAM_BLOCKSIZE - MOD(offset), len);
 		gsize offset_aligned = ALIGN(offset);
 		if (offset_aligned != stream->rbuf_offset) {
-			if (!_vte_unbuffered_file_stream_read (astream, offset_aligned, stream->rbuf, VTE_FILE_STREAM_BLOCKSIZE))
+			if (!_vte_file_stream_read_and_decrypt (astream, offset_aligned, stream->rbuf))
 				return FALSE;
 			stream->rbuf_offset = offset_aligned;
 		}
@@ -687,7 +759,7 @@ _vte_file_stream_truncate (VteStream *astream, gsize offset)
 		 * the code intact, that is, read back the new partial last
 		 * block to the write cache. */
 		gsize offset_aligned = ALIGN(offset);
-		if (!_vte_unbuffered_file_stream_read (astream, offset_aligned, stream->wbuf, VTE_FILE_STREAM_BLOCKSIZE)) {
+		if (!_vte_file_stream_read_and_decrypt (astream, offset_aligned, stream->wbuf)) {
 			/* what now? */
 			memset(stream->wbuf, 0, VTE_FILE_STREAM_BLOCKSIZE);
 		}
@@ -1162,32 +1234,32 @@ test_buffer (void)
 	_vte_stream_append (as, "d", 1);
 	g_assert (s->head == 4);
 	g_assert (s->parent.head == 4);
-	assert_file_contents (s->parent.file.fd, "abcd");
+	assert_file_contents (s->parent.file.fd, "ABCD");
 	assert_stream_contents (as, "abcd");
 
 	_vte_stream_append (as, "efghij", 6);
 	g_assert (s->head == 10);
 	g_assert (s->parent.head == 8);
-	assert_file_contents (s->parent.file.fd, "abcdefgh");
+	assert_file_contents (s->parent.file.fd, "ABCDEFGH");
 	assert_stream_contents (as, "abcdefghij");
 
 	_vte_stream_append (as, "klm", 3);
 	g_assert (s->head == 13);
 	g_assert (s->parent.head == 12);
-	assert_file_contents (s->parent.file.fd, "abcdefghijkl");
+	assert_file_contents (s->parent.file.fd, "ABCDEFGHIJKL");
 	assert_stream_contents (as, "abcdefghijklm");
 
 	/* Truncate */
 	_vte_stream_truncate (as, 12);
 	g_assert (s->head == 12);
 	g_assert (s->parent.head == 12);
-	assert_file_contents (s->parent.file.fd, "abcdefghijkl");
+	assert_file_contents (s->parent.file.fd, "ABCDEFGHIJKL");
 	assert_stream_contents (as, "abcdefghijkl");
 
 	_vte_stream_truncate (as, 9);
 	g_assert (s->head == 9);
 	g_assert (s->parent.head == 8);
-	assert_file_contents (s->parent.file.fd, "abcdefgh");
+	assert_file_contents (s->parent.file.fd, "ABCDEFGH");
 	assert_stream_contents (as, "abcdefghi");
 
 	/* Test that the read cache is invalidated on truncate */
@@ -1204,19 +1276,19 @@ test_buffer (void)
 	_vte_stream_advance_tail (as, 1);
 	g_assert (s->tail == 1);
 	g_assert (s->parent.tail == 0);
-	assert_file_contents (s->parent.file.fd, "abcdefgm");
+	assert_file_contents (s->parent.file.fd, "ABCDEFGM");
 	assert_stream_contents (as, "bcdefgmn");
 
 	_vte_stream_advance_tail (as, 3);
 	g_assert (s->tail == 3);
 	g_assert (s->parent.tail == 0);
-	assert_file_contents (s->parent.file.fd, "abcdefgm");
+	assert_file_contents (s->parent.file.fd, "ABCDEFGM");
 	assert_stream_contents (as, "defgmn");
 
 	_vte_stream_advance_tail (as, 4);
 	g_assert (s->tail == 4);
 	g_assert (s->parent.tail == 4);
-	assert_file_contents (s->parent.file.fd, "abcdefgm");
+	assert_file_contents (s->parent.file.fd, "ABCDEFGM");
 	assert_stream_contents (as, "efgmn");
 
 	/* Tail and head within the same block (causes a reset in the underlying layer) */
@@ -1248,7 +1320,7 @@ test_buffer (void)
 	_vte_stream_append (as, "rs", 2);
 	g_assert (s->head == 14);
 	g_assert (s->parent.head == 12);
-	assert_file_contents_starts_with (s->parent.file.fd, "nopq");
+	assert_file_contents_starts_with (s->parent.file.fd, "NOPQ");
 	assert_stream_contents (as, "pqrs");
 
 	/* Reset */
@@ -1258,7 +1330,7 @@ test_buffer (void)
 	g_assert (s->parent.tail == 12);
 	g_assert (s->head == 17);
 	g_assert (s->parent.head == 16);
-	assert_file_contents_starts_with_n (s->parent.file.fd, "\0tuv", 4);
+	assert_file_contents_starts_with (s->parent.file.fd, " TUV");  /* Note: the space is the fake-encrypted '\0' */
 	assert_stream_contents (as, "tuvw");
 
 	g_object_unref (as);
