[vte] stream: Encrypt the contents



commit 65bb9e38474b1dcefd21acd870a3e193668d1c49
Author: Egmont Koblinger <egmont gmail com>
Date:   Sun Jan 18 17:15:10 2015 +0100

    stream: Encrypt the contents
    
    The compressed scrollback block of at most 64kB in the "boa" layer is now
    encrypted with AES 256 GCM before hitting the disk.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=738601
    https://bugzilla.gnome.org/show_bug.cgi?id=664611

 configure.ac         |    2 +-
 src/vtestream-file.h |  513 +++++++++++++++++++++++++++++++++++--------------
 2 files changed, 367 insertions(+), 148 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 33aa8c5..12d1de5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -208,7 +208,7 @@ AC_CHECK_FUNCS([ceil floor round])
 
 # Search for the required modules.
 
-VTE_PKGS="glib-2.0 >= $GLIB_REQUIRED gobject-2.0 pango >= $PANGO_REQUIRED gtk+-$GTK_API_VERSION >= 
$GTK_REQUIRED gobject-2.0 gio-2.0 gio-unix-2.0 zlib"
+VTE_PKGS="glib-2.0 >= $GLIB_REQUIRED gobject-2.0 pango >= $PANGO_REQUIRED gtk+-$GTK_API_VERSION >= 
$GTK_REQUIRED gobject-2.0 gio-2.0 gio-unix-2.0 zlib gnutls >= 3.2.0"
 PKG_CHECK_MODULES([VTE],[$VTE_PKGS])
 AC_SUBST([VTE_PKGS])
 
diff --git a/src/vtestream-file.h b/src/vtestream-file.h
index 8b55a73..55d0685 100644
--- a/src/vtestream-file.h
+++ b/src/vtestream-file.h
@@ -42,29 +42,35 @@
  *   the head of the stream, and then appending again. In this layer and also
  *   in the next one, offering random-access-overwrite instead of truncation
  *   makes the implementation a lot easier. It's also essential to maintain a
- *   unique encryption IV in a forthcoming version.)
+ *   unique encryption IV in the current design.)
  *
  *   The name was chosen because VteFileStream's way of advancing the head and
  *   the tail is kinda like a snake, and the mapping to file offsets reminds
  *   me of the well-known game on old mobile phones.
  *
- * o The middle layer is called VteBoa. It does compression and is planned to
- *   do encryption along with integrity check. It has (almost) the same API as
- *   the snake, but the blocksize is a bit smaller to leave room for the
- *   required overhead.
+ * o The middle layer is called VteBoa. It does compression and encryption
+ *   along with integrity check. It has (almost) the same API as the snake,
+ *   but the blocksize is a bit smaller to leave room for the required
+ *   overhead. See below for the exact layout.
+ *
+ *   This overhead consists of the length of the compressed+encrypted payload,
+ *   an overwrite counter, and the encryption verification tag. The overwrite
+ *   counter is incremented each time the data at a certain logical offset is
+ *   overwritten, this is used in constructing a unique IV.
  *
  *   The name was chosen because the world of encryption is full of three
- *   letter abbreviations. At this moment we're planning to use GNU TLS's
- *   method for doing AES GCM. Also, because grown-ups might think it's a hat,
- *   when actually it's a boa constrictor digesting an elephant :)
+ *   letter abbreviations. At this moment we use GNU TLS's method for doing
+ *   AES GCM. Also, because grown-ups might think it's a hat, when actually
+ *   it's a boa constrictor digesting an elephant :)
  *
  * o The top layer is VteFileStream. It does buffering and caching. As opposed
  *   to the previous layers, this one provides methods on arbitrary amount of
  *   data. It doesn't offer random-access-writes, instead, it offers appending
  *   data, and truncating the head (undoing the latest appends). Write
- *   requests are batched up until there's a complete block to be compressed
- *   and written to disk. Read requests are answered by reading and decrypting
- *   possibly more underlying blocks, and sped up by caching the result.
+ *   requests are batched up until there's a complete block to be compressed,
+ *   encrypted and written to disk. Read requests are answered by reading,
+ *   decrypting and uncompressing possibly more underlying blocks, and sped up
+ *   by caching the result.
  *
  * Design discussions: https://bugzilla.gnome.org/show_bug.cgi?id=738601
  */
@@ -75,20 +81,34 @@
 #include <string.h>
 #include <unistd.h>
 #include <zlib.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
 
 #include "vteutils.h"
 
+/* Currently the code requires that a stream cipher (e.g. GCM) is used
+ * which can encrypt any amount of data without need for padding. */
+#define VTE_CIPHER_ALGORITHM    GNUTLS_CIPHER_AES_256_GCM
+#define VTE_CIPHER_KEY_SIZE     32
+#define VTE_CIPHER_IV_SIZE      12
+#define VTE_CIPHER_TAG_SIZE     16
+
 #ifndef VTESTREAM_MAIN
 # define VTE_SNAKE_BLOCKSIZE 65536
 typedef guint32 _vte_block_datalength_t;
+typedef guint32 _vte_overwrite_counter_t;
 #else
 /* Smaller sizes for unit testing */
-# define VTE_SNAKE_BLOCKSIZE     8
+# define VTE_SNAKE_BLOCKSIZE    10
 typedef guint8 _vte_block_datalength_t;
+typedef guint8 _vte_overwrite_counter_t;
+# undef VTE_CIPHER_TAG_SIZE
+# define VTE_CIPHER_TAG_SIZE     1
 #endif
 
 #define VTE_BLOCK_DATALENGTH_SIZE  sizeof(_vte_block_datalength_t)
-#define VTE_BOA_BLOCKSIZE (VTE_SNAKE_BLOCKSIZE - VTE_BLOCK_DATALENGTH_SIZE)
+#define VTE_OVERWRITE_COUNTER_SIZE sizeof(_vte_overwrite_counter_t)
+#define VTE_BOA_BLOCKSIZE (VTE_SNAKE_BLOCKSIZE - VTE_BLOCK_DATALENGTH_SIZE - VTE_OVERWRITE_COUNTER_SIZE - 
VTE_CIPHER_TAG_SIZE)
 
 #define OFFSET_BOA_TO_SNAKE(x) ((x) / VTE_BOA_BLOCKSIZE * VTE_SNAKE_BLOCKSIZE)
 #define ALIGN_BOA(x) ((x) / VTE_BOA_BLOCKSIZE * VTE_BOA_BLOCKSIZE)
@@ -553,17 +573,54 @@ _vte_snake_class_init (VteSnakeClass *klass)
 /******************************************************************************************/
 
 /*
- * VteBoa: Compress the data.
+ * VteBoa: Compress and encrypt an elephant to make it look like a hat.
+ *
+ *                 _.----._
+ *                /         \._______
+ *               /                    \.
+ *              |                       \
+ *              |                        \
+ *             /                          \
+ *   ________/                             \_________________
+ *  '------------------------------------------------------'-'
+ *
+ *
+ * A boa block is converted to a snake block and vice versa as follows.
+ * (Numbers in parentheses are the offsets/lengths used for unit testing.)
  *
- * The data is stored as 4 bytes (1 byte for unit testing) denoting the length
- * of the compressed block, followed by the compressed data. The data is
- * stored uncompressed if compression didn't result in a smaller size.
+ *                        snake block 65536(10)
+ * ├───────┬───────┬────────────────────┬───────┬────────────────────┤
+ * 0  dat  4  owr  8   compressed and   D  enc  T      implicit    65536
+ *    len (1) cnt (2)  encrypted data   ╵  tag          zeros       (10)
+ *    4(1)    4(1) ╵     <= 65512(7)    ╵ 16(1)          >= 0
+ *                 ╵                    ╵
+ * ┌ ─ ─ ─ ─ ─ ─ ─ ┘                    └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐
+ * ├────────────────────────────────────────────────────────────┤
+ *                       boa block 65512(7)
+ *
+ * Structure of the block that we give to the snake:
+ * - 0..4 (0..1): The length of the compressed and encrypted Data, that is D-8 (D-2) 
[VTE_BLOCK_DATALENGTH_SIZE bytes]
+ * - 4..8 (1..2): Overwrite counter [VTE_OVERWRITE_COUNTER_SIZE bytes]
+ * - 8..D (2..D): The compressed and encrypted Data [<= VTE_BOA_BLOCKSIZE bytes]
+ * - D..T: Encryption verification Tag [VTE_CIPHER_TAG_SIZE bytes]
+ * - T..64k (T..10): Area not written to the file, most of that leaving sparse FS blocks (dots for unit 
testing)
  */
 
 typedef struct _VteBoa {
         VteSnake parent;
         gsize tail, head;
 
+        gnutls_cipher_hd_t cipher_hd;
+        /* The IV (nonce) consists of the offset within the stream, and an overwrite counter so that
+         * we don't reuse the same IVs when a block at a certain logical offset is overwritten.
+         * The padding is there to make sure the structure is at least VTE_CIPHER_IV_SIZE bytes large.
+         * Assertion is made later that the real data fits in its first VTE_CIPHER_IV_SIZE bytes.
+         */
+        struct _VteIv {
+                gsize offset;
+                guint32 overwrite_counter;
+                unsigned char padding[VTE_CIPHER_IV_SIZE];
+        } iv;
         int compressBound;
 } VteBoa;
 
@@ -586,7 +643,63 @@ G_DEFINE_TYPE (VteBoa, _vte_boa, VTE_TYPE_SNAKE)
 
 /*----------------------------------------------------------------------------------------*/
 
-/* Thin wrapper layers above the compression routines, for unit testing. */
+/* Thin wrapper layers above the compression and encryption routines, for unit testing. */
+
+/* Encrypt: len bytes are overwritten in place, followed by VTE_CIPHER_TAG_SIZE more bytes for the tag. */
+static void
+_vte_boa_encrypt (VteBoa *boa, gsize offset, guint32 overwrite_counter, char *data, unsigned int len)
+{
+#ifndef VTESTREAM_MAIN
+        boa->iv.offset = offset;
+        boa->iv.overwrite_counter = overwrite_counter;
+        gnutls_cipher_set_iv (boa->cipher_hd, &boa->iv, VTE_CIPHER_IV_SIZE);
+        gnutls_cipher_encrypt (boa->cipher_hd, data, len);
+        gnutls_cipher_tag (boa->cipher_hd, data + len, VTE_CIPHER_TAG_SIZE);
+#else
+        /* Fake encryption for unit testing: uppercase <-> lowercase, followed by verification tag which is
+         * 5 bits: block sequence number (offset divided by blocksize)
+         * 3 bits: overwrite counter
+         * (This is easy to read and write as octal constant.) */
+        unsigned int i;
+        for (i = 0; i < len; i++) {
+                unsigned char c = data[i];
+                if (c >= 0x40) c ^= 0x20;
+                data[i] = c;
+        }
+        data[len] = (((offset / VTE_BOA_BLOCKSIZE) & 037) << 3) | (overwrite_counter & 007);
+#endif
+}
+
+/* Decrypt: data is len bytes of data + VTE_CIPHER_TAG_SIZE more bytes of tag. Returns FALSE on tag 
mismatch. */
+static gboolean
+_vte_boa_decrypt (VteBoa *boa, gsize offset, guint32 overwrite_counter, char *data, unsigned int len)
+{
+        unsigned char tag[VTE_CIPHER_TAG_SIZE];
+        unsigned int i, j;
+        guint8 faulty = 0;
+
+#ifndef VTESTREAM_MAIN
+        boa->iv.offset = offset;
+        boa->iv.overwrite_counter = overwrite_counter;
+        gnutls_cipher_set_iv (boa->cipher_hd, &boa->iv, VTE_CIPHER_IV_SIZE);
+        gnutls_cipher_decrypt (boa->cipher_hd, data, len);
+        gnutls_cipher_tag (boa->cipher_hd, tag, VTE_CIPHER_TAG_SIZE);
+#else
+        /* Fake decryption for unit testing; see above. */
+        for (i = 0; i < len; i++) {
+                unsigned char c = data[i];
+                if (c >= 0x40) c ^= 0x20;
+                data[i] = c;
+        }
+        *tag = (((offset / VTE_BOA_BLOCKSIZE) & 037) << 3) | (overwrite_counter & 007);
+#endif
+
+        /* Constant time tag verification: 738601#c66 */
+        for (i = 0, j = len; i < VTE_CIPHER_TAG_SIZE; i++, j++) {
+                faulty |= tag[i] ^ data[j];
+        }
+        return !faulty;
+}
 
 static int
 _vte_boa_compressBound (unsigned int len)
@@ -669,12 +782,48 @@ _vte_boa_uncompress (char *dst, unsigned int dstlen, const char *src, unsigned i
 static void
 _vte_boa_init (VteBoa *boa)
 {
+#ifndef VTESTREAM_MAIN
+        unsigned char key[VTE_CIPHER_KEY_SIZE];
+        gnutls_datum_t datum_key;
+
+        gnutls_global_init ();
+
+        /* Assert that VTE_CIPHER_* constants are defined correctly. Should happen compile-time, nevermind. 
*/
+        g_assert_cmpuint (gnutls_cipher_get_iv_size(VTE_CIPHER_ALGORITHM), ==, VTE_CIPHER_IV_SIZE);
+        g_assert_cmpuint (gnutls_cipher_get_tag_size(VTE_CIPHER_ALGORITHM), ==, VTE_CIPHER_TAG_SIZE);
+
+        /* Assert that IV does indeed include all the data we want to use (offset and overwrite_counter). */
+        g_assert_cmpuint (offsetof(struct _VteIv, padding), <=, VTE_CIPHER_IV_SIZE);
+
+        /* Strong random for the key. */
+        gnutls_rnd(GNUTLS_RND_KEY, key, VTE_CIPHER_KEY_SIZE);
+
+        datum_key.data = key;
+        datum_key.size = VTE_CIPHER_KEY_SIZE;
+        gnutls_cipher_init(&boa->cipher_hd, VTE_CIPHER_ALGORITHM, &datum_key, NULL);
+        /* FIXME: 738601#c52 the compiler might optimize this away, how to make sure it's erased?
+         * It's on the stack so maybe we can rest assured it'll be overwritten pretty soon. */
+        memset(key, 0, VTE_CIPHER_KEY_SIZE);
+
+        /* Empty IV. */
+        memset(&boa->iv, 0, sizeof(boa->iv));
+#endif
+
         boa->compressBound = _vte_boa_compressBound(VTE_BOA_BLOCKSIZE);
 }
 
 static void
 _vte_boa_finalize (GObject *object)
 {
+        VteBoa *boa = (VteBoa *) object;
+
+        memset(&boa->iv, 0, sizeof(boa->iv));
+
+#ifndef VTESTREAM_MAIN
+        gnutls_cipher_deinit (boa->cipher_hd);
+        gnutls_global_deinit ();
+#endif
+
         G_OBJECT_CLASS (_vte_boa_parent_class)->finalize(object);
 }
 
@@ -683,14 +832,20 @@ _vte_boa_reset (VteBoa *boa, gsize offset)
 {
         g_assert_cmpuint (offset % VTE_BOA_BLOCKSIZE, ==, 0);
 
+        /* _vte_ring_reset() is designed never to actually reset the logical offset.
+         * It's important for the encryption so that we don't reuse the same IV.
+         * Hence this is probably the best place to double check this. */
+        g_assert_cmpuint (offset, >=, boa->head);
+
         _vte_snake_reset (&boa->parent, OFFSET_BOA_TO_SNAKE(offset));
 
         boa->tail = boa->head = offset;
 }
 
-/* Place VTE_BOA_BLOCKSIZE bytes at data. */
+/* Place VTE_BOA_BLOCKSIZE bytes at data.
+ * data can be NULL if we're only interested in integrity verification and the overwrite_counter. */
 static gboolean
-_vte_boa_read (VteBoa *boa, gsize offset, char *data)
+_vte_boa_read_with_overwrite_counter (VteBoa *boa, gsize offset, char *data, _vte_overwrite_counter_t 
*overwrite_counter)
 {
         _vte_block_datalength_t compressed_len;
         gboolean ret = FALSE;
@@ -703,18 +858,25 @@ _vte_boa_read (VteBoa *boa, gsize offset, char *data)
                 goto out;
 
         compressed_len = *((_vte_block_datalength_t *) buf);
+        *overwrite_counter = *((_vte_overwrite_counter_t *) (buf + VTE_BLOCK_DATALENGTH_SIZE));
 
         /* We could have read an empty block due to a previous disk full. Treat that as an error too. 
Perform other sanity checks. */
-        if (G_UNLIKELY (compressed_len <= 0 || compressed_len > VTE_BOA_BLOCKSIZE))
+        if (G_UNLIKELY (compressed_len <= 0 || compressed_len > VTE_BOA_BLOCKSIZE || *overwrite_counter <= 
0))
+                goto out;
+
+        /* Decrypt, bail out on tag mismatch */
+        if (G_UNLIKELY (!_vte_boa_decrypt (boa, offset, *overwrite_counter, buf + VTE_BLOCK_DATALENGTH_SIZE 
+ VTE_OVERWRITE_COUNTER_SIZE, compressed_len)))
                 goto out;
 
         /* Uncompress, or copy if wasn't compressable */
-        if (G_UNLIKELY (compressed_len >= VTE_BOA_BLOCKSIZE)) {
-                memcpy (data, buf + VTE_BLOCK_DATALENGTH_SIZE, VTE_BOA_BLOCKSIZE);
-        } else {
-                unsigned int uncompressed_len;
-                uncompressed_len = _vte_boa_uncompress(data, VTE_BOA_BLOCKSIZE, buf + 
VTE_BLOCK_DATALENGTH_SIZE, compressed_len);
-                g_assert_cmpuint (uncompressed_len, ==, VTE_BOA_BLOCKSIZE);
+        if (G_LIKELY (data != NULL)) {
+                if (G_UNLIKELY (compressed_len >= VTE_BOA_BLOCKSIZE)) {
+                        memcpy (data, buf + VTE_BLOCK_DATALENGTH_SIZE + VTE_OVERWRITE_COUNTER_SIZE, 
VTE_BOA_BLOCKSIZE);
+                } else {
+                        unsigned int uncompressed_len;
+                        uncompressed_len = _vte_boa_uncompress(data, VTE_BOA_BLOCKSIZE, buf + 
VTE_BLOCK_DATALENGTH_SIZE + VTE_OVERWRITE_COUNTER_SIZE, compressed_len);
+                        g_assert_cmpuint (uncompressed_len, ==, VTE_BOA_BLOCKSIZE);
+                }
         }
         ret = TRUE;
 
@@ -723,6 +885,13 @@ out:
         return ret;
 }
 
+static gboolean
+_vte_boa_read (VteBoa *boa, gsize offset, char *data)
+{
+        _vte_overwrite_counter_t overwrite_counter;
+        return _vte_boa_read_with_overwrite_counter (boa, offset, data, &overwrite_counter);
+}
+
 /*
  * offset is either within the stream (overwrite data), or at its head (append data).
  * data is VTE_BOA_BLOCKSIZE bytes large.
@@ -732,32 +901,61 @@ _vte_boa_write (VteBoa *boa, gsize offset, const char *data)
 {
         _vte_block_datalength_t compressed_len = boa->compressBound;
 
+        /* The overwrite counter is 1-based.  This is to make sure that the IV is never 0: 738601#c88,
+           to make sure that an empty block (e.g. after a previous write failure) is always invalid,
+           and to make unit testing easier */
+        _vte_overwrite_counter_t overwrite_counter = 1;
+
         /* The helper buffer should be large enough to contain a whole snake block,
          * and also large enough to compress data that actually grows bigger during compression. */
         char *buf = g_malloc(MAX(VTE_SNAKE_BLOCKSIZE,
-                                 VTE_BLOCK_DATALENGTH_SIZE + boa->compressBound));
+                                 VTE_BLOCK_DATALENGTH_SIZE + VTE_OVERWRITE_COUNTER_SIZE + 
boa->compressBound));
 
         g_assert_cmpuint (offset, >=, boa->tail);
         g_assert_cmpuint (offset, <=, boa->head);
         g_assert_cmpuint (offset % VTE_BOA_BLOCKSIZE, ==, 0);
 
+        if (G_UNLIKELY (offset < boa->head)) {
+                /* Overwriting an existing block. This only happens around a window resize.
+                 * We need to read back that block and verify its integrity to get the previous 
overwrite_counter,
+                 * which will be incremented for the new block.
+                 * Then the new block is encrypted with the new IV.
+                 * This is to never reuse the same IV/nonce for encryption.
+                 * In case of read failure, do our best to destroy that block (overwrite with zeros, then 
punch a hole)
+                 * and return, forcing this and all subsequent reads and writes to fail. */
+                if (G_UNLIKELY (!_vte_boa_read_with_overwrite_counter (boa, offset, NULL, 
&overwrite_counter))) {
+                        /* Try to overwrite with explicit zeros */
+                        memset (buf, 0, VTE_SNAKE_BLOCKSIZE);
+                        _vte_snake_write (&boa->parent, OFFSET_BOA_TO_SNAKE(offset), buf, 
VTE_SNAKE_BLOCKSIZE);
+                        /* Try to punch out from the FS */
+                        _vte_snake_write (&boa->parent, OFFSET_BOA_TO_SNAKE(offset), "", 0);
+                        goto out;
+                }
+                overwrite_counter++;
+        }
+
         /* Compress, or copy if uncompressable */
-        compressed_len = _vte_boa_compress (buf + VTE_BLOCK_DATALENGTH_SIZE, boa->compressBound,
+        compressed_len = _vte_boa_compress (buf + VTE_BLOCK_DATALENGTH_SIZE + VTE_OVERWRITE_COUNTER_SIZE, 
boa->compressBound,
                                             data, VTE_BOA_BLOCKSIZE);
         if (G_UNLIKELY (compressed_len >= VTE_BOA_BLOCKSIZE)) {
-                memcpy (buf + VTE_BLOCK_DATALENGTH_SIZE, data, VTE_BOA_BLOCKSIZE);
+                memcpy (buf + VTE_BLOCK_DATALENGTH_SIZE + VTE_OVERWRITE_COUNTER_SIZE, data, 
VTE_BOA_BLOCKSIZE);
                 compressed_len = VTE_BOA_BLOCKSIZE;
         }
 
         *((_vte_block_datalength_t *) buf) = (_vte_block_datalength_t) compressed_len;
+        *((_vte_overwrite_counter_t *) (buf + VTE_BLOCK_DATALENGTH_SIZE)) = (_vte_overwrite_counter_t) 
overwrite_counter;
+
+        /* Encrypt */
+        _vte_boa_encrypt (boa, offset, overwrite_counter, buf + VTE_BLOCK_DATALENGTH_SIZE + 
VTE_OVERWRITE_COUNTER_SIZE, compressed_len);
 
         /* Write */
-        _vte_snake_write (&boa->parent, OFFSET_BOA_TO_SNAKE(offset), buf, VTE_BLOCK_DATALENGTH_SIZE + 
compressed_len);
+        _vte_snake_write (&boa->parent, OFFSET_BOA_TO_SNAKE(offset), buf, VTE_BLOCK_DATALENGTH_SIZE + 
VTE_OVERWRITE_COUNTER_SIZE + compressed_len + VTE_CIPHER_TAG_SIZE);
 
         if (G_LIKELY (offset == boa->head)) {
                 boa->head += VTE_BOA_BLOCKSIZE;
         }
 
+out:
         g_free(buf);
 }
 
@@ -865,6 +1063,10 @@ _vte_file_stream_reset (VteStream *astream, gsize offset)
        VteFileStream *stream = (VteFileStream *) astream;
         gsize offset_aligned = ALIGN_BOA(offset);
 
+        /* This is the same assertion as in boa, repeated here for the buffering layer
+         * to catch if this expectation is broken within a block. */
+        g_assert_cmpuint (offset, >=, stream->head);
+
         _vte_boa_reset (stream->boa, offset_aligned);
         stream->tail = stream->head = offset;
 
@@ -1072,6 +1274,23 @@ test_fakes (void)
         char buf[100], buf2[100];
         VteBoa *boa = g_object_new (VTE_TYPE_BOA, NULL);
 
+        /* Encrypt */
+        strcpy(buf, "abcdXYZ1234!!!");
+        _vte_boa_encrypt (boa, 35, 6, buf, 14);
+        g_assert(strncmp (buf, "ABCDxyz1234!!!\056", 15) == 0);
+
+        /* Decrypt */
+        g_assert_true(_vte_boa_decrypt (boa, 35, 6, buf, 14));
+        g_assert(strncmp (buf, "abcdXYZ1234!!!", 14) == 0);
+
+        /* Encrypt again */
+        _vte_boa_encrypt (boa, 35, 6, buf, 14);
+        g_assert(strncmp (buf, "ABCDxyz1234!!!\056", 15) == 0);
+
+        /* Decrypting with corrupted tag should fail */
+        buf[14]++;
+        g_assert_false(_vte_boa_decrypt (boa, 35, 6, buf, 14));
+
         /* Compress, but becomes bigger */
         strcpy(buf, "abcdef");
         g_assert_cmpuint(_vte_boa_compress (buf2, 100, buf, 6), ==, 7);
@@ -1118,89 +1337,89 @@ test_snake (void)
         VteSnake *snake = g_object_new (VTE_TYPE_SNAKE, NULL);
 
         /* Test overwriting data */
-        snake_write (snake, 0, "Antelope");
-        assert_snake (snake, 1, 0, 8, "Antelope");
+        snake_write (snake, 0, "Armadillo");
+        assert_snake (snake, 1, 0, 10, "Armadillo.");
 
-        snake_write (snake, 8, "Bobcat");
-        assert_file (snake->fd, "AntelopeBobcat..");
-        assert_snake (snake, 1, 0, 16, "AntelopeBobcat..");
+        snake_write (snake, 10, "Bobcat");
+        assert_file (snake->fd, "Armadillo.Bobcat....");
+        assert_snake (snake, 1, 0, 20, "Armadillo.Bobcat....");
 
-        snake_write (snake, 8, "Camel");
-        assert_file (snake->fd, "AntelopeCamel...");
-        assert_snake (snake, 1, 0, 16, "AntelopeCamel...");
+        snake_write (snake, 10, "Chinchilla");
+        assert_file (snake->fd, "Armadillo.Chinchilla");
+        assert_snake (snake, 1, 0, 20, "Armadillo.Chinchilla");
 
         snake_write (snake, 0, "Duck");
-        assert_file (snake->fd, "Duck....Camel...");
-        assert_snake (snake, 1, 0, 16, "Duck....Camel...");
+        assert_file (snake->fd, "Duck......Chinchilla");
+        assert_snake (snake, 1, 0, 20, "Duck......Chinchilla");
 
-        snake_write (snake, 16, "");
-        assert_file (snake->fd, "Duck....Camel...........");
-        assert_snake (snake, 1, 0, 24, "Duck....Camel...........");
+        snake_write (snake, 20, "");
+        assert_file (snake->fd, "Duck......Chinchilla..........");
+        assert_snake (snake, 1, 0, 30, "Duck......Chinchilla..........");
 
-        snake_write (snake, 24, "Ferret");
-        assert_file (snake->fd, "Duck....Camel...........Ferret..");
-        assert_snake (snake, 1, 0, 32, "Duck....Camel...........Ferret..");
+        snake_write (snake, 30, "Ferret");
+        assert_file (snake->fd, "Duck......Chinchilla..........Ferret....");
+        assert_snake (snake, 1, 0, 40, "Duck......Chinchilla..........Ferret....");
 
         /* Reset */
         _vte_snake_reset (snake, 0);
         assert_snake (snake, 1, 0, 0, "");
 
         /* State 1 */
-        snake_write (snake, 0, "Antelope");
-        snake_write (snake, 8, "Bobcat");
-        assert_file (snake->fd, "AntelopeBobcat..");
-        assert_snake (snake, 1, 0, 16, "AntelopeBobcat..");
+        snake_write (snake, 0, "Armadillo");
+        snake_write (snake, 10, "Bobcat");
+        assert_file (snake->fd, "Armadillo.Bobcat....");
+        assert_snake (snake, 1, 0, 20, "Armadillo.Bobcat....");
 
         /* Stay in state 1 */
-        _vte_snake_advance_tail (snake, 8);
-        snake_write (snake, 16, "Camel");
-        assert_file (snake->fd, "........Bobcat..Camel...");
-        assert_snake (snake, 1, 8, 24, "Bobcat..Camel...");
+        _vte_snake_advance_tail (snake, 10);
+        snake_write (snake, 20, "Chinchilla");
+        assert_file (snake->fd, "..........Bobcat....Chinchilla");
+        assert_snake (snake, 1, 10, 30, "Bobcat....Chinchilla");
 
         /* State 1 -> 2 */
-        _vte_snake_advance_tail (snake, 16);
-        snake_write (snake, 24, "Duck");
-        assert_file (snake->fd, "Duck............Camel...");
-        assert_snake (snake, 2, 16, 32, "Camel...Duck....");
+        _vte_snake_advance_tail (snake, 20);
+        snake_write (snake, 30, "Duck");
+        assert_file (snake->fd, "Duck................Chinchilla");
+        assert_snake (snake, 2, 20, 40, "ChinchillaDuck......");
 
         /* Stay in state 2 */
-        snake_write (snake, 32, "Elephant");
-        assert_file (snake->fd, "Duck....ElephantCamel...");
-        assert_snake (snake, 2, 16, 40, "Camel...Duck....Elephant");
+        snake_write (snake, 40, "Elephant");
+        assert_file (snake->fd, "Duck......Elephant..Chinchilla");
+        assert_snake (snake, 2, 20, 50, "ChinchillaDuck......Elephant..");
 
         /* State 2 -> 3 */
-        snake_write (snake, 40, "Ferret");
-        assert_file (snake->fd, "Duck....ElephantCamel...Ferret..");
-        assert_snake (snake, 3, 16, 48, "Camel...Duck....ElephantFerret..");
+        snake_write (snake, 50, "Ferret");
+        assert_file (snake->fd, "Duck......Elephant..ChinchillaFerret....");
+        assert_snake (snake, 3, 20, 60, "ChinchillaDuck......Elephant..Ferret....");
 
         /* State 3 -> 4 */
-        _vte_snake_advance_tail (snake, 24);
-        assert_file (snake->fd, "Duck....Elephant........Ferret..");
-        assert_snake (snake, 4, 24, 48, "Duck....ElephantFerret..");
+        _vte_snake_advance_tail (snake, 30);
+        assert_file (snake->fd, "Duck......Elephant............Ferret....");
+        assert_snake (snake, 4, 30, 60, "Duck......Elephant..Ferret....");
 
         /* Stay in state 4 */
-        _vte_snake_advance_tail (snake, 32);
-        assert_file (snake->fd, "........Elephant........Ferret..");
-        assert_snake (snake, 4, 32, 48, "ElephantFerret..");
+        _vte_snake_advance_tail (snake, 40);
+        assert_file (snake->fd, "..........Elephant............Ferret....");
+        assert_snake (snake, 4, 40, 60, "Elephant..Ferret....");
 
         /* State 4 -> 1 */
-        _vte_snake_advance_tail (snake, 40);
-        assert_file (snake->fd, "........................Ferret..");
-        assert_snake (snake, 1, 40, 48, "Ferret..");
+        _vte_snake_advance_tail (snake, 50);
+        assert_file (snake->fd, "..............................Ferret....");
+        assert_snake (snake, 1, 50, 60, "Ferret....");
 
         /* State 1 -> 2 */
-        snake_write (snake, 48, "Giraffe");
-        assert_file (snake->fd, "Giraffe.................Ferret..");
-        assert_snake (snake, 2, 40, 56, "Ferret..Giraffe.");
+        snake_write (snake, 60, "Giraffe");
+        assert_file (snake->fd, "Giraffe.......................Ferret....");
+        assert_snake (snake, 2, 50, 70, "Ferret....Giraffe...");
 
         /* Reset, back to state 1 */
-        _vte_snake_reset (snake, 200);
-        assert_snake (snake, 1, 200, 200, "");
+        _vte_snake_reset (snake, 250);
+        assert_snake (snake, 1, 250, 250, "");
 
         /* Stay in state 1 */
-        snake_write (snake, 200, "Zebra");
-        assert_file (snake->fd, "Zebra...");
-        assert_snake (snake, 1, 200, 208, "Zebra...");
+        snake_write (snake, 250, "Zebra");
+        assert_file (snake->fd, "Zebra.....");
+        assert_snake (snake, 1, 250, 260, "Zebra.....");
 
         g_object_unref (snake);
 }
@@ -1214,45 +1433,45 @@ test_boa (void)
         /* State 1 */
         _vte_boa_write (boa, 0, "axolotl");
         _vte_boa_write (boa, 7, "beeeeee");
-        assert_file (snake->fd, "\007axolotl" "\0041b6e...");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\0041b6e...");
+        assert_file (snake->fd, "\007\001AXOLOTL\001" "\004\0011B6E\011...");
+        assert_snake (snake, 1, 0, 20, "\007\001AXOLOTL\001" "\004\0011B6E\011...");
         assert_boa (boa, 0, 14, "axolotl" "beeeeee");
 
-        /* Test overwrites */
+        /* Test overwrites: overwrite counter increases separately for each block */
         _vte_boa_write (boa, 7, "buffalo");
-        assert_file (snake->fd, "\007axolotl" "\007buffalo");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\007buffalo");
+        assert_file (snake->fd, "\007\001AXOLOTL\001" "\007\002BUFFALO\012");
+        assert_snake (snake, 1, 0, 20, "\007\001AXOLOTL\001" "\007\002BUFFALO\012");
         assert_boa (boa, 0, 14, "axolotl" "buffalo");
 
         _vte_boa_write (boa, 7, "beeeeee");
-        assert_file (snake->fd, "\007axolotl" "\0041b6e...");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\0041b6e...");
+        assert_file (snake->fd, "\007\001AXOLOTL\001" "\004\0031B6E\013...");
+        assert_snake (snake, 1, 0, 20, "\007\001AXOLOTL\001" "\004\0031B6E\013...");
         assert_boa (boa, 0, 14, "axolotl" "beeeeee");
 
         _vte_boa_write (boa, 0, "axolotl");
-        assert_file (snake->fd, "\007axolotl" "\0041b6e...");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\0041b6e...");
+        assert_file (snake->fd, "\007\002AXOLOTL\002" "\004\0031B6E\013...");
+        assert_snake (snake, 1, 0, 20, "\007\002AXOLOTL\002" "\004\0031B6E\013...");
         assert_boa (boa, 0, 14, "axolotl" "beeeeee");
 
         /* Stay in state 1 */
         _vte_boa_advance_tail (boa, 7);
         _vte_boa_write (boa, 14, "cheetah");
-        assert_file (snake->fd, "........" "\0041b6e..." "\007cheetah");
-        assert_snake (snake, 1, 8, 24, "\0041b6e..." "\007cheetah");
+        assert_file (snake->fd, ".........." "\004\0031B6E\013..." "\007\001CHEETAH\021");
+        assert_snake (snake, 1, 10, 30, "\004\0031B6E\013..." "\007\001CHEETAH\021");
         assert_boa (boa, 7, 21, "beeeeee" "cheetah");
 
         /* State 1 -> 2 */
         _vte_boa_advance_tail (boa, 14);
         _vte_boa_write (boa, 21, "deeeeer");
-        assert_file (snake->fd, "\0061d5e1r." "........" "\007cheetah");
-        assert_snake (snake, 2, 16, 32, "\007cheetah" "\0061d5e1r.");
+        assert_file (snake->fd, "\006\0011D5E1R\031." ".........." "\007\001CHEETAH\021");
+        assert_snake (snake, 2, 20, 40, "\007\001CHEETAH\021" "\006\0011D5E1R\031.");
         assert_boa (boa, 14, 28, "cheetah" "deeeeer");
 
         /* Skip some state changes that we tested in test_snake() */
 
         /* Reset, back to state 1 */
         _vte_boa_reset (boa, 175);
-        assert_snake (snake, 1, 200, 200, "");
+        assert_snake (snake, 1, 250, 250, "");
         assert_boa (boa, 175, 175, "");
 
         /* Stay in state 1.
@@ -1263,8 +1482,8 @@ test_boa (void)
          * don't try to decompress.
          */
         _vte_boa_write (boa, 175, "zebraaa");
-        assert_file (snake->fd, "\007zebraaa");
-        assert_snake (snake, 1, 200, 208, "\007zebraaa");
+        assert_file (snake->fd, "\007\001ZEBRAAA\311");
+        assert_snake (snake, 1, 250, 260, "\007\001ZEBRAAA\311");
         assert_boa (boa, 175, 182, "zebraaa");
 
         g_object_unref (boa);
@@ -1292,40 +1511,40 @@ test_stream (void)
         assert_stream (astream, 0, 6, "axolot");
 
         stream_append (astream, "l");
-        assert_file (snake->fd, "\007axolotl");
-        assert_snake (snake, 1, 0, 8, "\007axolotl");
+        assert_file (snake->fd, "\007\001AXOLOTL\001");
+        assert_snake (snake, 1, 0, 10, "\007\001AXOLOTL\001");
         assert_boa (boa, 0, 7, "axolotl");
         assert_stream (astream, 0, 7, "axolotl");
 
         stream_append (astream, "beeee");
-        assert_file (snake->fd, "\007axolotl");
-        assert_snake (snake, 1, 0, 8, "\007axolotl");
+        assert_file (snake->fd, "\007\001AXOLOTL\001");
+        assert_snake (snake, 1, 0, 10, "\007\001AXOLOTL\001");
         assert_boa (boa, 0, 7, "axolotl");
         assert_stream (astream, 0, 12, "axolotl" "beeee");
 
         stream_append (astream, "es" "cat");
-        assert_file (snake->fd, "\007axolotl" "\0061b5e1s.");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1s.");
+        assert_file (snake->fd, "\007\001AXOLOTL\001" "\006\0011B5E1S\011.");
+        assert_snake (snake, 1, 0, 20, "\007\001AXOLOTL\001" "\006\0011B5E1S\011.");
         assert_boa (boa, 0, 14, "axolotl" "beeeees");
         assert_stream (astream, 0, 17, "axolotl" "beeeees" "cat");
 
         /* Truncate */
         _vte_stream_truncate (astream, 14);
-        assert_file (snake->fd, "\007axolotl" "\0061b5e1s.");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1s.");
+        assert_file (snake->fd, "\007\001AXOLOTL\001" "\006\0011B5E1S\011.");
+        assert_snake (snake, 1, 0, 20, "\007\001AXOLOTL\001" "\006\0011B5E1S\011.");
         assert_boa (boa, 0, 14, "axolotl" "beeeees");
         assert_stream (astream, 0, 14, "axolotl" "beeeees");
 
         _vte_stream_truncate (astream, 10);
-        assert_file (snake->fd, "\007axolotl" "\0061b5e1s.");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1s.");
+        assert_file (snake->fd, "\007\001AXOLOTL\001" "\006\0011B5E1S\011.");
+        assert_snake (snake, 1, 0, 20, "\007\001AXOLOTL\001" "\006\0011B5E1S\011.");
         assert_boa (boa, 0, 14, "axolotl" "beeeees");
         assert_stream (astream, 0, 10, "axolotl" "bee");
 
         /* Increase overwrite counter, overwrite with shorter block */
         stream_append (astream, "eeee" "cat");
-        assert_file (snake->fd, "\007axolotl" "\0041b6e...");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\0041b6e...");
+        assert_file (snake->fd, "\007\001AXOLOTL\001" "\004\0021B6E\012...");
+        assert_snake (snake, 1, 0, 20, "\007\001AXOLOTL\001" "\004\0021B6E\012...");
         assert_boa (boa, 0, 14, "axolotlbeeeeee");
         assert_stream (astream, 0, 17, "axolotl" "beeeeee" "cat");
 
@@ -1339,28 +1558,28 @@ test_stream (void)
         g_assert_cmpuint (stream->rbuf_offset, ==, 7);
         buf[2] = '\0';
         g_assert_cmpstr (buf, ==, "ez");
-        assert_file (snake->fd, "\007axolotl" "\0061b5e1z.");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1z.");
+        assert_file (snake->fd, "\007\001AXOLOTL\001" "\006\0031B5E1Z\013.");
+        assert_snake (snake, 1, 0, 20, "\007\001AXOLOTL\001" "\006\0031B5E1Z\013.");
         assert_boa (boa, 0, 14, "axolotl" "beeeeez");
         assert_stream (astream, 0, 17, "axolotl" "beeeeez" "cat");
 
         /* Truncate again */
         _vte_stream_truncate (astream, 10);
-        assert_file (snake->fd, "\007axolotl" "\0061b5e1z.");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1z.");
+        assert_file (snake->fd, "\007\001AXOLOTL\001" "\006\0031B5E1Z\013.");
+        assert_snake (snake, 1, 0, 20, "\007\001AXOLOTL\001" "\006\0031B5E1Z\013.");
         assert_boa (boa, 0, 14, "axolotl" "beeeeez");
         assert_stream (astream, 0, 10, "axolotl" "bee");
 
         /* Advance_tail */
         _vte_stream_advance_tail (astream, 6);
-        assert_file (snake->fd, "\007axolotl" "\0061b5e1z.");
-        assert_snake (snake, 1, 0, 16, "\007axolotl" "\0061b5e1z.");
+        assert_file (snake->fd, "\007\001AXOLOTL\001" "\006\0031B5E1Z\013.");
+        assert_snake (snake, 1, 0, 20, "\007\001AXOLOTL\001" "\006\0031B5E1Z\013.");
         assert_boa (boa, 0, 14, "axolotl" "beeeeez");
         assert_stream (astream, 6, 10, "l" "bee");
 
         _vte_stream_advance_tail (astream, 7);
-        assert_file (snake->fd, "........" "\0061b5e1z.");
-        assert_snake (snake, 1, 8, 16, "\0061b5e1z.");
+        assert_file (snake->fd, ".........." "\006\0031B5E1Z\013.");
+        assert_snake (snake, 1, 10, 20, "\006\0031B5E1Z\013.");
         assert_boa (boa, 7, 14, "beeeeez");
         assert_stream (astream, 7, 10, "bee");
 
@@ -1368,15 +1587,15 @@ test_stream (void)
          * but not in underlying layers (due to a previous truncate).
          * Nothing special. */
         _vte_stream_advance_tail (astream, 9);
-        assert_file (snake->fd, "........" "\0061b5e1z.");
-        assert_snake (snake, 1, 8, 16, "\0061b5e1z.");
+        assert_file (snake->fd, ".........." "\006\0031B5E1Z\013.");
+        assert_snake (snake, 1, 10, 20, "\006\0031B5E1Z\013.");
         assert_boa (boa, 7, 14, "beeeeez");
         assert_stream (astream, 9, 10, "e");
 
         /* Tail reaches head. Still nothing special. */
         _vte_stream_advance_tail (astream, 10);
-        assert_file (snake->fd, "........" "\0061b5e1z.");
-        assert_snake (snake, 1, 8, 16, "\0061b5e1z.");
+        assert_file (snake->fd, ".........." "\006\0031B5E1Z\013.");
+        assert_snake (snake, 1, 10, 20, "\006\0031B5E1Z\013.");
         assert_boa (boa, 7, 14, "beeeeez");
         assert_stream (astream, 10, 10, "");
 
@@ -1384,8 +1603,8 @@ test_stream (void)
         stream_append (astream, "eeee" "catfish");
         _vte_stream_advance_tail (astream, 15);
         stream_append (astream, "dolphin" "echi");
-        assert_file (snake->fd, "\007dolphin" "........" "\007catfish");
-        assert_snake (snake, 2, 16, 32, "\007catfish" "\007dolphin");
+        assert_file (snake->fd, "\007\001DOLPHIN\031" ".........." "\007\001CATFISH\021");
+        assert_snake (snake, 2, 20, 40, "\007\001CATFISH\021" "\007\001DOLPHIN\031");
         assert_boa (boa, 14, 28, "catfish" "dolphin");
         assert_stream (astream, 15, 32, "atfish" "dolphin" "echi");
 
@@ -1393,67 +1612,67 @@ test_stream (void)
          * The snake resets itself to state 1, ...
          * (Note: despite advance_tail, "ec" is still there in the write buffer) */
         _vte_stream_advance_tail (astream, 30);
-        assert_snake (snake, 1, 32, 32, "");
+        assert_snake (snake, 1, 40, 40, "");
         assert_boa (boa, 28, 28, "");
         assert_stream (astream, 30, 32, "hi");
 
         /* ... and the next write goes to beginning of the file */
         stream_append (astream, "dna");
-        assert_file (snake->fd, "\007echidna");
-        assert_snake (snake, 1, 32, 40, "\007echidna");
+        assert_file (snake->fd, "\007\001ECHIDNA\041");
+        assert_snake (snake, 1, 40, 50, "\007\001ECHIDNA\041");
         assert_boa (boa, 28, 35, "echidna");
         assert_stream (astream, 30, 35, "hidna");
 
         /* Test a bit what happens when "accidentally" writing aligned blocks. */
         _vte_stream_advance_tail (astream, 35);
         stream_append (astream, "flicker" "grizzly");
-        assert_file (snake->fd, "\007flicker" "\007grizzly");
-        assert_snake (snake, 1, 40, 56, "\007flicker" "\007grizzly");
+        assert_file (snake->fd, "\007\001FLICKER\051" "\007\001GRIZZLY\061");
+        assert_snake (snake, 1, 50, 70, "\007\001FLICKER\051" "\007\001GRIZZLY\061");
         assert_boa (boa, 35, 49, "flicker" "grizzly");
         assert_stream (astream, 35, 49, "flicker" "grizzly");
 
         stream_append (astream, "hamster");
-        assert_file (snake->fd, "\007flicker" "\007grizzly" "\007hamster");
-        assert_snake (snake, 1, 40, 64, "\007flicker" "\007grizzly" "\007hamster");
+        assert_file (snake->fd, "\007\001FLICKER\051" "\007\001GRIZZLY\061" "\007\001HAMSTER\071");
+        assert_snake (snake, 1, 50, 80, "\007\001FLICKER\051" "\007\001GRIZZLY\061" "\007\001HAMSTER\071");
         assert_boa (boa, 35, 56, "flicker" "grizzly" "hamster");
         assert_stream (astream, 35, 56, "flicker" "grizzly" "hamster");
 
         _vte_stream_advance_tail (astream, 49);
-        assert_file (snake->fd, "........" "........" "\007hamster");
-        assert_snake (snake, 1, 56, 64, "\007hamster");
+        assert_file (snake->fd, ".........." ".........." "\007\001HAMSTER\071");
+        assert_snake (snake, 1, 70, 80, "\007\001HAMSTER\071");
         assert_boa (boa, 49, 56, "hamster");
         assert_stream (astream, 49, 56, "hamster");
 
         /* State 2 */
         stream_append (astream, "ibexxxx");
-        assert_file (snake->fd, "\0061ibe4x." "........" "\007hamster");
-        assert_snake (snake, 2, 56, 72, "\007hamster" "\0061ibe4x.");
+        assert_file (snake->fd, "\006\0011IBE4X\101." ".........." "\007\001HAMSTER\071");
+        assert_snake (snake, 2, 70, 90, "\007\001HAMSTER\071" "\006\0011IBE4X\101.");
         assert_boa (boa, 49, 63, "hamster" "ibexxxx");
         assert_stream (astream, 49, 63, "hamster" "ibexxxx");
 
         stream_append (astream, "jjjjjjj");
-        assert_file (snake->fd, "\0061ibe4x." "\0027j....." "\007hamster");
-        assert_snake (snake, 2, 56, 80, "\007hamster" "\0061ibe4x." "\0027j.....");
+        assert_file (snake->fd, "\006\0011IBE4X\101." "\002\0017J\111....." "\007\001HAMSTER\071");
+        assert_snake (snake, 2, 70, 100, "\007\001HAMSTER\071" "\006\0011IBE4X\101." "\002\0017J\111.....");
         assert_boa (boa, 49, 70, "hamster" "ibexxxx" "jjjjjjj");
         assert_stream (astream, 49, 70, "hamster" "ibexxxx" "jjjjjjj");
 
         /* State 3 */
         stream_append (astream, "karakul");
-        assert_file (snake->fd, "\0061ibe4x." "\0027j....." "\007hamster" "\007karakul");
-        assert_snake (snake, 3, 56, 88, "\007hamster" "\0061ibe4x." "\0027j....." "\007karakul");
+        assert_file (snake->fd, "\006\0011IBE4X\101." "\002\0017J\111....." "\007\001HAMSTER\071" 
"\007\001KARAKUL\121");
+        assert_snake (snake, 3, 70, 110, "\007\001HAMSTER\071" "\006\0011IBE4X\101." "\002\0017J\111....." 
"\007\001KARAKUL\121");
         assert_boa (boa, 49, 77, "hamster" "ibexxxx" "jjjjjjj" "karakul");
         assert_stream (astream, 49, 77, "hamster" "ibexxxx" "jjjjjjj" "karakul");
 
         /* State 4 */
         _vte_stream_advance_tail (astream, 56);
-        assert_file (snake->fd, "\0061ibe4x." "\0027j....." "........" "\007karakul");
-        assert_snake (snake, 4, 64, 88, "\0061ibe4x." "\0027j....." "\007karakul");
+        assert_file (snake->fd, "\006\0011IBE4X\101." "\002\0017J\111....." ".........." 
"\007\001KARAKUL\121");
+        assert_snake (snake, 4, 80, 110, "\006\0011IBE4X\101." "\002\0017J\111....." "\007\001KARAKUL\121");
         assert_boa (boa, 56, 77, "ibexxxx" "jjjjjjj" "karakul");
         assert_stream (astream, 56, 77, "ibexxxx" "jjjjjjj" "karakul");
 
         stream_append (astream, "llllama");
-        assert_file (snake->fd, "\0061ibe4x." "\0027j....." "........" "\007karakul" "\0064l1ama.");
-        assert_snake (snake, 4, 64, 96, "\0061ibe4x." "\0027j....." "\007karakul" "\0064l1ama.");
+        assert_file (snake->fd, "\006\0011IBE4X\101." "\002\0017J\111....." ".........." 
"\007\001KARAKUL\121" "\006\0014L1AMA\131.");
+        assert_snake (snake, 4, 80, 120, "\006\0011IBE4X\101." "\002\0017J\111....." "\007\001KARAKUL\121" 
"\006\0014L1AMA\131.");
         assert_boa (boa, 56, 84, "ibexxxx" "jjjjjjj" "karakul" "llllama");
         assert_stream (astream, 56, 84, "ibexxxx" "jjjjjjj" "karakul" "llllama");
 
@@ -1461,16 +1680,16 @@ test_stream (void)
         _vte_stream_reset (astream, 88);
         stream_append (astream, "kat");
         /* Unused leading blocks are filled with dashes */
-        assert_file (snake->fd, "\0064-1kat.");
-        assert_snake (snake, 1, 96, 104, "\0064-1kat.");
+        assert_file (snake->fd, "\006\0014-1KAT\141.");
+        assert_snake (snake, 1, 120, 130, "\006\0014-1KAT\141.");
         assert_boa (boa, 84, 91, "----kat");
         assert_stream (astream, 88, 91, "kat");
 
         /* Explicit reset to a block boundary */
         _vte_stream_reset (astream, 175);
         stream_append (astream, "zebraaa");
-        assert_file (snake->fd, "\007zebraaa");
-        assert_snake (snake, 1, 200, 208, "\007zebraaa");
+        assert_file (snake->fd, "\007\001ZEBRAAA\311");
+        assert_snake (snake, 1, 250, 260, "\007\001ZEBRAAA\311");
         assert_boa (boa, 175, 182, "zebraaa");
         assert_stream (astream, 175, 182, "zebraaa");
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]