Beispiel #1
0
static
void test_hmac_test_vectors(void)
{
	test_begin("test_hmac_test_vectors");

	buffer_t *pt, *ct, *key, *res;
	pt = buffer_create_dynamic(pool_datastack_create(), 50);
	key = buffer_create_dynamic(pool_datastack_create(), 20);
	ct = buffer_create_dynamic(pool_datastack_create(), 32);
	res = buffer_create_dynamic(pool_datastack_create(), 32);

	hex_to_binary("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", key);
	hex_to_binary("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", pt);
	hex_to_binary("773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", res);

	struct dcrypt_context_hmac *hctx;
	if (!dcrypt_ctx_hmac_create("sha256", &hctx, NULL)) {
		test_assert_failed("dcrypt_ctx_hmac_create", __FILE__, __LINE__-1);
	} else {
		dcrypt_ctx_hmac_set_key(hctx, key->data, key->used);
		test_assert(dcrypt_ctx_hmac_init(hctx, NULL));
		test_assert(dcrypt_ctx_hmac_update(hctx, pt->data, pt->used, NULL));
		test_assert(dcrypt_ctx_hmac_final(hctx, ct, NULL));
		test_assert(buffer_cmp(ct, res));
		dcrypt_ctx_hmac_destroy(&hctx);
	}

	test_end();
}
Beispiel #2
0
static ssize_t
i_stream_decrypt_read(struct istream_private *stream)
{
	struct decrypt_istream *dstream =
		(struct decrypt_istream *)stream;
	const unsigned char *data;
	size_t size, decrypt_size;
	const char *error = NULL;
	int ret;
	bool check_mac = FALSE;

	/* not if it's broken */
	if (stream->istream.stream_errno != 0)
		return -1;

	for (;;) {
		/* remove skipped data from buffer */
		if (stream->skip > 0) {
			i_assert(stream->skip <= dstream->buf->used);
			buffer_delete(dstream->buf, 0, stream->skip);
			stream->pos -= stream->skip;
			stream->skip = 0;
		}

		stream->buffer = dstream->buf->data;

		i_assert(stream->pos <= dstream->buf->used);
		if (stream->pos >= dstream->istream.max_buffer_size) {
			/* stream buffer still at maximum */
			return -2;
		}

		/* if something is already decrypted, return as much of it as
		   we can */
		if (dstream->initialized && dstream->buf->used > 0) {
			size_t new_pos, bytes;

			/* only return up to max_buffer_size bytes, even when buffer
			   actually has more, as not to confuse the caller */
			if (dstream->buf->used <= dstream->istream.max_buffer_size) {
				new_pos = dstream->buf->used;
				if (dstream->finalized)
					stream->istream.eof = TRUE;
			} else {
				new_pos = dstream->istream.max_buffer_size;
			}

			bytes = new_pos - stream->pos;
			stream->pos = new_pos;
			return (ssize_t)bytes;
		}
		if (dstream->finalized) {
			/* all data decrypted */
			stream->istream.eof = TRUE;
			return -1;
		}
		/* need to read more input */
		ret = i_stream_read(stream->parent);
		if (ret == 0 || ret == -2)
			return ret;
		data = i_stream_get_data(stream->parent, &size);

		if (ret == -1 && (size == 0 || stream->parent->stream_errno != 0)) {
			stream->istream.stream_errno = stream->parent->stream_errno;

			/* file was empty */
			if (!dstream->initialized && size == 0 && stream->parent->eof) {
				stream->istream.eof = TRUE;
				return -1;
			}

			if (stream->istream.stream_errno != 0)
				return -1;

			if (!dstream->initialized) {
				io_stream_set_error(&stream->iostream,
					"Decryption error: %s",
					"Input truncated in decryption header");
				stream->istream.stream_errno = EINVAL;
				return -1;
			}

			/* final block */
			if (dcrypt_ctx_sym_final(dstream->ctx_sym,
				dstream->buf, &error)) {
				dstream->finalized = TRUE;
				continue;
			}
			io_stream_set_error(&stream->iostream,
				"MAC error: %s", error);
			stream->istream.stream_errno = EINVAL;
			return -1;
		}

		if (!dstream->initialized) {
			ssize_t hret;

			if ((hret=i_stream_decrypt_read_header(dstream, data, size)) <= 0) {
				if (hret < 0) {
					if (stream->istream.stream_errno == 0)
						/* assume temporary failure */
						stream->istream.stream_errno = EIO;
					return -1;
				}

				if (hret == 0 && stream->parent->eof) {
					/* not encrypted by us */
					stream->istream.stream_errno = EINVAL;
					io_stream_set_error(&stream->iostream,
						"Truncated header");
					return -1;
				}
			}

			if (hret == 0) {
				/* see if we can get more data */
				continue;
			} else {
				/* clean up buffer */
				safe_memset(buffer_get_modifiable_data(dstream->buf, 0), 0, dstream->buf->used);
				buffer_set_used_size(dstream->buf, 0);
				i_stream_skip(stream->parent, hret);
			}

			data = i_stream_get_data(stream->parent, &size);
		}
		decrypt_size = size;

		if (dstream->use_mac) {
			if (stream->parent->eof) {
				if (decrypt_size < dstream->ftr) {
					io_stream_set_error(&stream->iostream,
						"Decryption error: footer is longer than data");
					stream->istream.stream_errno = EINVAL;
					return -1;
				}
				check_mac = TRUE;
			} else {
				/* ignore footer's length of data until we
				   reach EOF */
				size -= dstream->ftr;
			}
			decrypt_size -= dstream->ftr;
			if ((dstream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) == IO_STREAM_ENC_INTEGRITY_HMAC) {
				if (!dcrypt_ctx_hmac_update(dstream->ctx_mac,
				    data, decrypt_size, &error)) {
					io_stream_set_error(&stream->iostream,
						"MAC error: %s", error);
					stream->istream.stream_errno = EINVAL;
					return -1;
				}
			}
		}

		if (check_mac) {
			if ((dstream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) == IO_STREAM_ENC_INTEGRITY_HMAC) {
				unsigned char dgst[dcrypt_ctx_hmac_get_digest_length(dstream->ctx_mac)];
				buffer_t db;
				buffer_create_from_data(&db, dgst, sizeof(dgst));
				if (!dcrypt_ctx_hmac_final(dstream->ctx_mac, &db, &error)) {
					io_stream_set_error(&stream->iostream,
						"Cannot verify MAC: %s", error);
					stream->istream.stream_errno = EINVAL;
					return -1;
				}
				if (memcmp(dgst, data + decrypt_size, dcrypt_ctx_hmac_get_digest_length(dstream->ctx_mac)) != 0) {
					io_stream_set_error(&stream->iostream,
						"Cannot verify MAC: mismatch");
					stream->istream.stream_errno = EINVAL;
					return -1;
				}
			} else if ((dstream->flags & IO_STREAM_ENC_INTEGRITY_AEAD) == IO_STREAM_ENC_INTEGRITY_AEAD) {
				dcrypt_ctx_sym_set_tag(dstream->ctx_sym, data + decrypt_size, dstream->ftr);
			}
		}

		if (!dcrypt_ctx_sym_update(dstream->ctx_sym,
		    data, decrypt_size, dstream->buf, &error)) {
			io_stream_set_error(&stream->iostream,
				"Decryption error: %s", error);
			stream->istream.stream_errno = EINVAL;
			return -1;
		}
		i_stream_skip(stream->parent, size);
	}
}