From: Timo Sirainen Date: Tue, 5 Jun 2018 10:34:02 +0000 (+0300) Subject: lib-dcrypt: istream-decrypt - Add support for seeking X-Git-Tag: 2.3.9~1739 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9a36e573ff9c683434def3787a93fa746ed95171;p=thirdparty%2Fdovecot%2Fcore.git lib-dcrypt: istream-decrypt - Add support for seeking --- diff --git a/src/lib-dcrypt/istream-decrypt.c b/src/lib-dcrypt/istream-decrypt.c index ba906a342c..ecce5a55d9 100644 --- a/src/lib-dcrypt/istream-decrypt.c +++ b/src/lib-dcrypt/istream-decrypt.c @@ -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; @@ -42,6 +43,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) { @@ -929,6 +950,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) { @@ -965,12 +1002,14 @@ 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); @@ -1001,6 +1040,7 @@ i_stream_create_sym_decrypt(struct istream *input, 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; diff --git a/src/lib-dcrypt/test-stream.c b/src/lib-dcrypt/test-stream.c index ebf36e7515..153e8b77bc 100644 --- a/src/lib-dcrypt/test-stream.c +++ b/src/lib-dcrypt/test-stream.c @@ -390,6 +390,16 @@ static 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);