diff --git a/configure.ac b/configure.ac
index cc6d9c0..63df398 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 9e2f7da..a6b9cf6 100644
--- a/src/vtestream-file.h
+++ b/src/vtestream-file.h
@@ -78,6 +78,9 @@
 #include <stdio.h>  // TODO: remove (it's temporary for debugging only)
 #include <unistd.h>
 
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
+
 #include "vteutils.h"
 
 
@@ -107,12 +110,34 @@ pwrite (int fd, char *data, gsize len, gsize offset)
 typedef struct
 {
 	int fd;
+	gnutls_cipher_hd_t cipher_hd;
+	unsigned char iv[16];
 } _file_t;
 
 static inline void
 _file_init (_file_t *f)
 {
+	unsigned char key[16];
+	gnutls_datum_t datum_key;
+
 	f->fd = -1;
+
+	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, 16);
+	gnutls_rnd(GNUTLS_RND_NONCE, f->iv, 16);
+
+	datum_key.data = key;
+	datum_key.size = 16;
+	gnutls_cipher_init(&f->cipher_hd, GNUTLS_CIPHER_AES_256_CBC, &datum_key, NULL);
+	memset(key, 0, 16);
 }
 
 static inline void
@@ -134,6 +159,10 @@ _file_close (_file_t *f)
 		return;
 
 	close (f->fd);
+
+	memset(f->iv, 0, 16);
+	gnutls_cipher_deinit (f->cipher_hd);
+	gnutls_global_deinit ();
 }
 
 
@@ -526,6 +555,10 @@ _vte_file_stream_buffered_append (VteStream *astream, const char *data, gsize le
 		memcpy(stream->wbuf + stream->wbuf_len, data, l);
 		stream->wbuf_len += l; data += l; len -= l;
 		if (stream->wbuf_len == 4096) {
+			memcpy (stream->file.iv, &stream->head /* TODO: find a nicer way of knowing the head? */, sizeof(gsize));
+			gnutls_cipher_set_iv (stream->file.cipher_hd, stream->file.iv, 16);
+			gnutls_cipher_encrypt (stream->file.cipher_hd, stream->wbuf, 4096);
+
 			_vte_file_stream_append (astream, stream->wbuf, 4096);
 			stream->wbuf_len = 0;
 		}
@@ -545,6 +578,11 @@ _vte_file_stream_buffered_read (VteStream *astream, gsize offset, char *data, gs
 		if (offset_aligned != stream->rbuf_offset) {
 			gboolean ret = _vte_file_stream_read (astream, offset_aligned, stream->rbuf, 4096);
 			g_assert (ret == TRUE);  // TODO ???
+
+			memcpy (stream->file.iv, &offset_aligned, sizeof(gsize));
+			gnutls_cipher_set_iv (stream->file.cipher_hd, stream->file.iv, 16);
+			gnutls_cipher_decrypt (stream->file.cipher_hd, stream->rbuf, 4096);
+
 			stream->rbuf_offset = offset_aligned;
 		}
 		memcpy(data, stream->rbuf + offset % 4096, l);
@@ -574,6 +612,11 @@ _vte_file_stream_buffered_truncate (VteStream *astream, gsize offset)
 		gsize offset_aligned = offset / 4096 * 4096;
 		gboolean ret = _vte_file_stream_read (astream, offset_aligned, stream->wbuf, 4096);
 		g_assert (ret == TRUE);  // TODO ???
+
+		memcpy (stream->file.iv, &offset, sizeof(gsize));
+		gnutls_cipher_set_iv (stream->file.cipher_hd, stream->file.iv, 16);
+		gnutls_cipher_decrypt (stream->file.cipher_hd, stream->wbuf, 4096);
+
 		_vte_file_stream_truncate (astream, offset_aligned);
 
 		if (stream->rbuf_offset >= offset_aligned) {
