]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-dcrypt: istream-decrypt - Add support for seeking
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 5 Jun 2018 10:34:02 +0000 (13:34 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Wed, 6 Jun 2018 13:23:19 +0000 (16:23 +0300)
src/lib-dcrypt/istream-decrypt.c
src/lib-dcrypt/test-stream.c

index a2623f3a0615996c6d1fc19b81f59313b2245508..d94e804a2e5496ab9860dbde380fa6d85c915ffe 100644 (file)
@@ -21,6 +21,7 @@
 struct decrypt_istream {
        struct istream_private istream;
        buffer_t *buf;
+       bool symmetric;
 
        i_stream_decrypt_get_key_callback_t *key_callback;
        void *key_context;
@@ -41,6 +42,26 @@ struct decrypt_istream {
        enum decrypt_istream_format format;
 };
 
+static void i_stream_decrypt_reset(struct decrypt_istream *dstream)
+{
+       dstream->finalized = FALSE;
+       dstream->use_mac = FALSE;
+
+       dstream->ftr = 0;
+       dstream->pos = 0;
+       dstream->flags = 0;
+
+       if (!dstream->symmetric) {
+               dstream->initialized = FALSE;
+               if (dstream->ctx_sym != NULL)
+                       dcrypt_ctx_sym_destroy(&dstream->ctx_sym);
+               if (dstream->ctx_mac != NULL)
+                       dcrypt_ctx_hmac_destroy(&dstream->ctx_mac);
+       }
+       i_free(dstream->iv);
+       dstream->format = DECRYPT_FORMAT_V1;
+}
+
 enum decrypt_istream_format i_stream_encrypt_get_format(const struct istream *input)
 {
        return ((const struct decrypt_istream*)input->real_stream)->format;
@@ -818,6 +839,22 @@ i_stream_decrypt_read(struct istream_private *stream)
        }
 }
 
+static void
+i_stream_decrypt_seek(struct istream_private *stream, uoff_t v_offset,
+                     bool mark ATTR_UNUSED)
+{
+       struct decrypt_istream *dstream =
+               (struct decrypt_istream *)stream;
+
+       if (i_stream_nonseekable_try_seek(stream, v_offset))
+               return;
+
+       /* have to seek backwards - reset crypt state and retry */
+       i_stream_decrypt_reset(dstream);
+       if (!i_stream_nonseekable_try_seek(stream, v_offset))
+               i_unreached();
+}
+
 static
 void i_stream_decrypt_close(struct iostream_private *stream,
                                   bool close_parent)
@@ -857,12 +894,14 @@ struct decrypt_istream *i_stream_create_decrypt_common(struct istream *input)
        dstream = i_new(struct decrypt_istream, 1);
        dstream->istream.max_buffer_size = input->real_stream->max_buffer_size;
        dstream->istream.read = i_stream_decrypt_read;
+       if (input->seekable)
+               dstream->istream.seek = i_stream_decrypt_seek;
        dstream->istream.iostream.close = i_stream_decrypt_close;
        dstream->istream.iostream.destroy = i_stream_decrypt_destroy;
 
        dstream->istream.istream.readable_fd = FALSE;
        dstream->istream.istream.blocking = input->blocking;
-       dstream->istream.istream.seekable = FALSE;
+       dstream->istream.istream.seekable = input->seekable;
 
        dstream->buf = buffer_create_dynamic(default_pool, 512);
 
@@ -891,6 +930,7 @@ i_stream_create_sym_decrypt(struct istream *input, struct dcrypt_context_symmetr
        dstream = i_stream_create_decrypt_common(input);
        dstream->use_mac = FALSE;
        dstream->initialized = TRUE;
+       dstream->symmetric = TRUE;
 
        if (!dcrypt_ctx_sym_init(ctx, &error)) ec = -1;
        else ec = 0;
index 89c6e98c66f783b542c7e142beaf627321184d9a..da4bdc636de58cd0d5271c4c0c96ba93a28c66fb 100644 (file)
@@ -367,6 +367,16 @@ void test_write_read_v2(void)
        if (is_2->stream_errno != 0)
                i_debug("error: %s", i_stream_get_error(is_2));
 
+       /* test seeking */
+       for (size_t i = sizeof(payload)-100; i > 100; i -= 100) {
+               i_stream_seek(is_2, i);
+               test_assert_idx(i_stream_read_data(is_2, &ptr, &siz, 0) == 1, i);
+               test_assert_idx(memcmp(ptr, payload + i, siz) == 0, i);
+       }
+       i_stream_seek(is_2, 0);
+       test_assert(i_stream_read_data(is_2, &ptr, &siz, 0) == 1);
+       test_assert(memcmp(ptr, payload, siz) == 0);
+
        i_stream_unref(&is);
        i_stream_unref(&is_2);
        buffer_free(&buf);