19557f192d37cd54a1a090a8a26d9d47265e4413Aki Tuomi/* file struct dcrypt_public_key syntax
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * magic (14 bytes)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * version (1 bytes)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * flags (4 bytes)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * size of header (4 bytes)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * sha1 of key id (20 bytes)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * cipher oid
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * mac oid
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * rounds (4 bytes)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * key data size (4 bytes)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * key data
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * cipher data
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi * mac data (mac specific bytes)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "lib.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "buffer.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "randgen.h"
17fbd200b78112bd0d89e89598aa01cea72a74e5Martti Rannanjärvi#include "dcrypt-iostream.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "ostream-encrypt.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "ostream-private.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "hash-method.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "sha2.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "safe-memset.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include "dcrypt.h"
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#include <arpa/inet.h>
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#define IO_STREAM_ENCRYPT_SEED_SIZE 32
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi#define IO_STREAM_ENCRYPT_ROUNDS 2048
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistruct encrypt_ostream {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct ostream_private ostream;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dcrypt_context_symmetric *ctx_sym;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dcrypt_context_hmac *ctx_mac;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi enum io_stream_encrypt_flags flags;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dcrypt_public_key *pub;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char *key_data;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi size_t key_data_len;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_t *cipher_oid;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_t *mac_oid;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi size_t block_size;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi bool finalized;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi bool failed;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi bool prefix_written;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi};
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint o_stream_encrypt_send(struct encrypt_ostream *stream,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const unsigned char *data, size_t size)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ssize_t ec;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ec = o_stream_send(stream->ostream.parent, data, size);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (ec == (ssize_t)size)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi else if (ec < 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi o_stream_copy_error_from_parent(&stream->ostream);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } else {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi "ostream-encrypt: Unexpectedly short write to parent stream");
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi stream->ostream.ostream.stream_errno = EINVAL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint o_stream_encrypt_send_header_v1(struct encrypt_ostream *stream)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char c;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned short s;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(!stream->prefix_written);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi stream->prefix_written = TRUE;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi buffer_t *values = t_buffer_create(256);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, IOSTREAM_CRYPT_MAGIC, sizeof(IOSTREAM_CRYPT_MAGIC));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* version */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi c = 1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, &c, 1);
a84b413ef72378bbe235a13846fe6a84899eaedcTimo Sirainen /* key data length */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi s = htons(stream->key_data_len);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, &s, 2);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* then write key data */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, stream->key_data, stream->key_data_len);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_free_and_null(stream->key_data);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* then send it to stream */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return o_stream_encrypt_send(stream, values->data, values->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint o_stream_encrypt_send_header_v2(struct encrypt_ostream *stream)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char c;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned int i;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(!stream->prefix_written);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi stream->prefix_written = TRUE;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi buffer_t *values = t_buffer_create(256);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, IOSTREAM_CRYPT_MAGIC, sizeof(IOSTREAM_CRYPT_MAGIC));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi c = 2;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, &c, 1);
32340fe8f461f6ae56c4cb3ee8392ba14c9f539aAki Tuomi i = cpu32_to_be(stream->flags);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, &i, 4);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* store total length of header
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi 9 = version + flags + length
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi 8 = rounds + key data length
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi */
32340fe8f461f6ae56c4cb3ee8392ba14c9f539aAki Tuomi i = cpu32_to_be(sizeof(IOSTREAM_CRYPT_MAGIC) + 9 + stream->cipher_oid->used + stream->mac_oid->used + 8 + stream->key_data_len);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, &i, 4);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append_buf(values, stream->cipher_oid, 0, (size_t)-1);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append_buf(values, stream->mac_oid, 0, (size_t)-1);
32340fe8f461f6ae56c4cb3ee8392ba14c9f539aAki Tuomi i = cpu32_to_be(IO_STREAM_ENCRYPT_ROUNDS);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, &i, 4);
32340fe8f461f6ae56c4cb3ee8392ba14c9f539aAki Tuomi i = cpu32_to_be(stream->key_data_len);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, &i, 4);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(values, stream->key_data, stream->key_data_len);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_free_and_null(stream->key_data);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return o_stream_encrypt_send(stream, values->data, values->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint o_stream_encrypt_keydata_create_v1(struct encrypt_ostream *stream)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_t *encrypted_key, *ephemeral_key, *secret, *res, buf;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *error = NULL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const struct hash_method *hash = &hash_method_sha256;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* various temporary buffers */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char seed[IO_STREAM_ENCRYPT_SEED_SIZE];
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char pkhash[hash->digest_size];
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char ekhash[hash->digest_size];
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char hres[hash->digest_size];
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char hctx[hash->context_size];
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* hash the public key first */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_create_from_data(&buf, pkhash, sizeof(pkhash));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_key_id_public_old(stream->pub, &buf, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Key hash failed: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* hash the key base */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->init(hctx);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->loop(hctx, seed, sizeof(seed));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->result(hctx, ekhash);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi ephemeral_key = t_buffer_create(256);
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi encrypted_key = t_buffer_create(256);
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi secret = t_buffer_create(256);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ecdh_derive_secret_peer(stream->pub, ephemeral_key, secret, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Cannot perform ECDH: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* hash the secret data */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->init(hctx);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->loop(hctx, secret->data, secret->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->result(hctx, hres);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi safe_memset(buffer_get_modifiable_data(secret, 0), 0, secret->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* use it to encrypt the actual encryption key */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dcrypt_context_symmetric *dctx;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_sym_create("aes-256-ctr", DCRYPT_MODE_ENCRYPT, &dctx, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Key encryption error: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi random_fill(seed, sizeof(seed));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->init(hctx);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->loop(hctx, seed, sizeof(seed));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->result(hctx, ekhash);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi int ec = 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* NB! The old code was broken and used this kind of IV - it is not correct, but
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi we need to stay compatible with old data */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_sym_set_iv(dctx, (const unsigned char*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_sym_set_key(dctx, hres, sizeof(hres));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_sym_init(dctx, &error) ||
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi !dcrypt_ctx_sym_update(dctx, seed, sizeof(seed), encrypted_key, &error) ||
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi !dcrypt_ctx_sym_final(dctx, encrypted_key, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ec = -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_sym_destroy(&dctx);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (ec != 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi safe_memset(seed, 0, sizeof(seed));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Key encryption error: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
d82c8af717c383d37a836b8d29316a3375803fabTimo Sirainen /* same as above */
d82c8af717c383d37a836b8d29316a3375803fabTimo Sirainen dcrypt_ctx_sym_set_iv(stream->ctx_sym, (const unsigned char*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
d82c8af717c383d37a836b8d29316a3375803fabTimo Sirainen dcrypt_ctx_sym_set_key(stream->ctx_sym, seed, sizeof(seed));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi safe_memset(seed, 0, sizeof(seed));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_sym_init(stream->ctx_sym, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Encryption init error: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi res = buffer_create_dynamic(default_pool, 256);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* ephemeral key */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned short s;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi s = htons(ephemeral_key->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, &s, 2);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, ephemeral_key->data, ephemeral_key->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* public key hash */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi s = htons(sizeof(pkhash));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, &s, 2);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, pkhash, sizeof(pkhash));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* encrypted key hash */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi s = htons(sizeof(ekhash));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, &s, 2);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, ekhash, sizeof(ekhash));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* encrypted key */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi s = htons(encrypted_key->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, &s, 2);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, encrypted_key->data, encrypted_key->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi stream->key_data_len = res->used;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi stream->key_data = buffer_free_without_data(&res);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint o_stream_encrypt_key_for_pubkey_v2(struct encrypt_ostream *stream, const char *malg,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const unsigned char *key, size_t key_len, struct dcrypt_public_key *pubkey, buffer_t *res)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi enum dcrypt_key_type ktype;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *error;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_t *encrypted_key, *ephemeral_key, *temp_key;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi ephemeral_key = t_buffer_create(256);
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi encrypted_key = t_buffer_create(256);
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi temp_key = t_buffer_create(48);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
394391e78f26cba1d7fca19d4b8617453a7041b8Timo Sirainen ktype = dcrypt_key_type_public(pubkey);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (ktype == DCRYPT_KEY_RSA) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* encrypt key as R (as we don't need DH with RSA)*/
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_rsa_encrypt(pubkey, key, key_len, encrypted_key, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Cannot encrypt key data: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } else if (ktype == DCRYPT_KEY_EC) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* R = our ephemeral public key */
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi buffer_t *secret = t_buffer_create(256);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* derive ephemeral key and shared secret */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ecdh_derive_secret_peer(pubkey, ephemeral_key, secret, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Cannot perform ECDH: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* use shared secret and ephemeral key to generate encryption key/iv */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_pbkdf2(secret->data, secret->used, ephemeral_key->data, ephemeral_key->used,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi malg, IO_STREAM_ENCRYPT_ROUNDS, temp_key, 48, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi safe_memset(buffer_get_modifiable_data(secret, 0), 0, secret->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Cannot perform key encryption: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi safe_memset(buffer_get_modifiable_data(secret, 0), 0, secret->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* encrypt key with shared secret */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dcrypt_context_symmetric *dctx;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_sym_create("AES-256-CBC", DCRYPT_MODE_ENCRYPT, &dctx, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi safe_memset(buffer_get_modifiable_data(temp_key, 0), 0, temp_key->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Cannot perform key encryption: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const unsigned char *ptr = temp_key->data;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(temp_key->used == 48);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_sym_set_key(dctx, ptr, 32);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_sym_set_iv(dctx, ptr+32, 16);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi safe_memset(buffer_get_modifiable_data(temp_key, 0), 0, temp_key->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi int ec = 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_sym_init(dctx, &error) ||
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi !dcrypt_ctx_sym_update(dctx, key, key_len, encrypted_key, &error) ||
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi !dcrypt_ctx_sym_final(dctx, encrypted_key, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Cannot perform key encryption: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ec = -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_sym_destroy(&dctx);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (ec != 0) return ec;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } else {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Unsupported key type");
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* store key type */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi char kt = ktype;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, &kt, 1);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* store hash of public key as ID */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_key_id_public(stream->pub, "sha256", res, NULL);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* store ephemeral key (if present) */
32340fe8f461f6ae56c4cb3ee8392ba14c9f539aAki Tuomi unsigned int val = cpu32_to_be(ephemeral_key->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, &val, 4);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append_buf(res, ephemeral_key, 0, (size_t)-1);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* store encrypted key */
32340fe8f461f6ae56c4cb3ee8392ba14c9f539aAki Tuomi val = cpu32_to_be(encrypted_key->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, &val, 4);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append_buf(res, encrypted_key, 0, (size_t)-1);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint o_stream_encrypt_keydata_create_v2(struct encrypt_ostream *stream, const char *malg)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const struct hash_method *hash = hash_method_lookup(malg);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *error;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi size_t tagsize;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const unsigned char *ptr;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi size_t kl;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned int val;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_t *keydata, *res;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (hash == NULL) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi "Encryption init error: Hash algorithm '%s' not supported", malg);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* key data length for internal use */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if ((stream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) == IO_STREAM_ENC_INTEGRITY_HMAC) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi tagsize = IOSTREAM_TAG_SIZE;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } else if ((stream->flags & IO_STREAM_ENC_INTEGRITY_AEAD) == IO_STREAM_ENC_INTEGRITY_AEAD) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi tagsize = IOSTREAM_TAG_SIZE;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } else {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* do not include MAC */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi tagsize = 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* generate keydata length of random data for key/iv/mac */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi kl = dcrypt_ctx_sym_get_key_length(stream->ctx_sym) + dcrypt_ctx_sym_get_iv_length(stream->ctx_sym) + tagsize;
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi keydata = t_buffer_create(kl);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi random_fill(buffer_append_space_unsafe(keydata, kl), kl);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_set_used_size(keydata, kl);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ptr = keydata->data;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi res = buffer_create_dynamic(default_pool, 256);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* store number of public key(s) */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, "\1", 1); /* one key for now */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* we can do multiple keys at this point, but do it only once now */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (o_stream_encrypt_key_for_pubkey_v2(stream, malg, ptr, kl, stream->pub, res) != 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_free(&res);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* create hash of the key data */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char hctx[hash->context_size];
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char hres[hash->digest_size];
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->init(hctx);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->loop(hctx, ptr, kl);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->result(hctx, hres);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi for(int i = 1; i < 2049; i++) {
32340fe8f461f6ae56c4cb3ee8392ba14c9f539aAki Tuomi uint32_t i_msb = cpu32_to_be(i);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->init(hctx);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->loop(hctx, hres, sizeof(hres));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->loop(hctx, &i_msb, sizeof(i_msb));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi hash->result(hctx, hres);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* store key data hash */
32340fe8f461f6ae56c4cb3ee8392ba14c9f539aAki Tuomi val = cpu32_to_be(sizeof(hres));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, &val, 4);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_append(res, hres, sizeof(hres));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* pick up key data that goes into stream */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi stream->key_data_len = res->used;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi stream->key_data = buffer_free_without_data(&res);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* prime contexts */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_sym_set_key(stream->ctx_sym, ptr, dcrypt_ctx_sym_get_key_length(stream->ctx_sym));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ptr += dcrypt_ctx_sym_get_key_length(stream->ctx_sym);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_sym_set_iv(stream->ctx_sym, ptr, dcrypt_ctx_sym_get_iv_length(stream->ctx_sym));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ptr += dcrypt_ctx_sym_get_iv_length(stream->ctx_sym);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if ((stream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) == IO_STREAM_ENC_INTEGRITY_HMAC) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_hmac_set_key(stream->ctx_mac, ptr, tagsize);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_hmac_init(stream->ctx_mac, &error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } else if ((stream->flags & IO_STREAM_ENC_INTEGRITY_AEAD) == IO_STREAM_ENC_INTEGRITY_AEAD) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_sym_set_aad(stream->ctx_sym, ptr, tagsize);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* clear out private key data */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi safe_memset(buffer_get_modifiable_data(keydata, 0), 0, keydata->used);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_sym_init(stream->ctx_sym, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->ostream.iostream, "Encryption init error: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomissize_t o_stream_encrypt_sendv(struct ostream_private *stream,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const struct const_iovec *iov, unsigned int iov_count)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct encrypt_ostream *estream = (struct encrypt_ostream *)stream;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *error;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ssize_t ec,total = 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* not if finalized */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(!estream->finalized);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* write prefix */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!estream->prefix_written) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi T_BEGIN {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if ((estream->flags & IO_STREAM_ENC_VERSION_1) == IO_STREAM_ENC_VERSION_1)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ec = o_stream_encrypt_send_header_v1(estream);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi else
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ec = o_stream_encrypt_send_header_v2(estream);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } T_END;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (ec < 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* buffer for encrypted data */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi unsigned char ciphertext[IO_BLOCK_SIZE];
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_t buf;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_create_from_data(&buf, ciphertext, sizeof(ciphertext));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* encrypt & send all blocks of data at max ciphertext buffer's length */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi for(unsigned int i = 0; i < iov_count; i++) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi size_t bl, off = 0, len = iov[i].iov_len;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const unsigned char *ptr = iov[i].iov_base;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi while(len > 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_set_used_size(&buf, 0);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* update can emite twice the size of input */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi bl = I_MIN(sizeof(ciphertext)/2, len);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_sym_update(estream->ctx_sym, ptr + off, bl, &buf, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->iostream, "Encryption failure: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if ((estream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) == IO_STREAM_ENC_INTEGRITY_HMAC) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* update mac */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_hmac_update(estream->ctx_mac, buf.data, buf.used, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&stream->iostream, "MAC failure: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
19557f192d37cd54a1a090a8a26d9d47265e4413Aki Tuomi /* hopefully upstream can accommodate */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (o_stream_encrypt_send(estream, buf.data, buf.used) < 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi len -= bl;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi off += bl;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi total += bl;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi stream->ostream.offset += total;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return total;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
f2edbc51be62d7da4a4b37a72f9832851f669caaTimo Sirainenint o_stream_encrypt_finalize(struct ostream_private *stream)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *error;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct encrypt_ostream *estream = (struct encrypt_ostream *)stream;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
f52366af688c5663f3491c63042500ac51ad7780Timo Sirainen if (estream->finalized) {
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen /* we've already flushed the encrypted output. */
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen return 0;
f52366af688c5663f3491c63042500ac51ad7780Timo Sirainen }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->finalized = TRUE;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen /* if nothing was written, we are done */
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen if (!estream->prefix_written) return 0;
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* acquire last block */
c147bff818798a979d93537f72f5c1f68f5d5ba8Aki Tuomi buffer_t *buf = t_buffer_create(dcrypt_ctx_sym_get_block_size(estream->ctx_sym));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_sym_final(estream->ctx_sym, buf, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&estream->ostream.iostream, "Encryption failure: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* sometimes final does not emit anything */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (buf->used > 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* update mac */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (((estream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) == IO_STREAM_ENC_INTEGRITY_HMAC)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_hmac_update(estream->ctx_mac, buf->data, buf->used, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&estream->ostream.iostream, "MAC failure: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (o_stream_encrypt_send(estream, buf->data, buf->used) < 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* write last mac bytes */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi buffer_set_used_size(buf, 0);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if ((estream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) == IO_STREAM_ENC_INTEGRITY_HMAC) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_hmac_final(estream->ctx_mac, buf, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&estream->ostream.iostream, "MAC failure: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } else if ((estream->flags & IO_STREAM_ENC_INTEGRITY_AEAD) == IO_STREAM_ENC_INTEGRITY_AEAD) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi dcrypt_ctx_sym_get_tag(estream->ctx_sym, buf);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi i_assert(buf->used > 0);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (buf->used > 0 && o_stream_encrypt_send(estream, buf->data, buf->used) < 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen return 0;
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen}
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainenstatic
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainenint o_stream_encrypt_flush(struct ostream_private *stream)
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen{
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen struct encrypt_ostream *estream = (struct encrypt_ostream *)stream;
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen if (stream->finished && estream->ctx_sym != NULL &&
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen !estream->finalized) {
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen if (o_stream_encrypt_finalize(&estream->ostream) < 0)
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen return -1;
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen }
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen
8109f3187f5ece5565de1813209af42dc7bb768bTimo Sirainen return o_stream_flush_parent(stream);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid o_stream_encrypt_close(struct iostream_private *stream,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi bool close_parent)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct encrypt_ostream *estream = (struct encrypt_ostream *)stream;
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen i_assert(estream->finalized || estream->ctx_sym == NULL ||
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen estream->ostream.ostream.stream_errno != 0);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (close_parent) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi o_stream_close(estream->ostream.parent);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomivoid o_stream_encrypt_destroy(struct iostream_private *stream)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct encrypt_ostream *estream = (struct encrypt_ostream *)stream;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* release resources */
c5e46dba179864f6f1adf196d46e7a0371b11914Josef 'Jeff' Sipek if (estream->ctx_sym != NULL) dcrypt_ctx_sym_destroy(&estream->ctx_sym);
c5e46dba179864f6f1adf196d46e7a0371b11914Josef 'Jeff' Sipek if (estream->ctx_mac != NULL) dcrypt_ctx_hmac_destroy(&estream->ctx_mac);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (estream->key_data != NULL) i_free(estream->key_data);
c5e46dba179864f6f1adf196d46e7a0371b11914Josef 'Jeff' Sipek if (estream->cipher_oid != NULL) buffer_free(&estream->cipher_oid);
c5e46dba179864f6f1adf196d46e7a0371b11914Josef 'Jeff' Sipek if (estream->mac_oid != NULL) buffer_free(&estream->mac_oid);
c5e46dba179864f6f1adf196d46e7a0371b11914Josef 'Jeff' Sipek if (estream->pub != NULL) dcrypt_key_unref_public(&estream->pub);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi o_stream_unref(&estream->ostream.parent);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomiint o_stream_encrypt_init(struct encrypt_ostream *estream, const char *algorithm)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *error;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi char *calg, *malg;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if ((estream->flags & IO_STREAM_ENC_VERSION_1) == IO_STREAM_ENC_VERSION_1) {
c5e46dba179864f6f1adf196d46e7a0371b11914Josef 'Jeff' Sipek if (!dcrypt_ctx_sym_create("AES-256-CTR", DCRYPT_MODE_ENCRYPT, &estream->ctx_sym, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&estream->ostream.iostream, "Cannot create ostream-encrypt: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->flags |= IO_STREAM_ENC_INTEGRITY_NONE; /* disable MAC */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* then do keying */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return o_stream_encrypt_keydata_create_v1(estream);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } else {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi calg = t_strdup_noconst(algorithm);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi malg = strrchr(calg, '-');
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (malg == NULL) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&estream->ostream.iostream, "Invalid algorithm (must be cipher-mac)");
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi (*malg++) = '\0';
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
c5e46dba179864f6f1adf196d46e7a0371b11914Josef 'Jeff' Sipek if (!dcrypt_ctx_sym_create(calg, DCRYPT_MODE_ENCRYPT, &estream->ctx_sym, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&estream->ostream.iostream, "Cannot create ostream-encrypt: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* create cipher and mac context, take note of OIDs */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->cipher_oid = buffer_create_dynamic(default_pool, 12);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->block_size = dcrypt_ctx_sym_get_block_size(estream->ctx_sym);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_name2oid(calg, estream->cipher_oid, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&estream->ostream.iostream, "Cannot create ostream-encrypt: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi /* mac context is optional */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if ((estream->flags & IO_STREAM_ENC_INTEGRITY_HMAC) == IO_STREAM_ENC_INTEGRITY_HMAC) {
c5e46dba179864f6f1adf196d46e7a0371b11914Josef 'Jeff' Sipek if (!dcrypt_ctx_hmac_create(malg, &estream->ctx_mac, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&estream->ostream.iostream, "Cannot create ostream-encrypt: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->mac_oid = buffer_create_dynamic(default_pool, 12);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_name2oid(malg, estream->mac_oid, &error)) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&estream->ostream.iostream, "Cannot create ostream-encrypt: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
211c638d81d382517d196ad47565e0d85012c927klemens /* MAC algorithm is used for PBKDF2 and keydata hashing */
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return o_stream_encrypt_keydata_create_v2(estream, malg);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistatic
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistruct encrypt_ostream *
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomio_stream_create_encrypt_common(enum io_stream_encrypt_flags flags)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct encrypt_ostream *estream;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream = i_new(struct encrypt_ostream, 1);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->ostream.sendv = o_stream_encrypt_sendv;
6630a5734436953a61ce6ec471d0d91a5f206083Timo Sirainen estream->ostream.flush = o_stream_encrypt_flush;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->ostream.iostream.close = o_stream_encrypt_close;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->ostream.iostream.destroy = o_stream_encrypt_destroy;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->flags = flags;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return estream;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistruct ostream *
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomio_stream_create_encrypt(struct ostream *output, const char *algorithm,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct dcrypt_public_key *box_pub, enum io_stream_encrypt_flags flags)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct encrypt_ostream *estream = o_stream_create_encrypt_common(flags);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi int ec;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
55a7fe1e4637a8dbc6184b54edeb74ac8276b2c1Aki Tuomi dcrypt_key_ref_public(box_pub);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->pub = box_pub;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi T_BEGIN {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi ec = o_stream_encrypt_init(estream, algorithm);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi } T_END;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct ostream *os = o_stream_create(&estream->ostream, output,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi o_stream_get_fd(output));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (ec != 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi os->stream_errno = EINVAL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return os;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomistruct ostream *
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomio_stream_create_sym_encrypt(struct ostream *output, struct dcrypt_context_symmetric *ctx)
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi{
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct encrypt_ostream *estream = o_stream_create_encrypt_common(IO_STREAM_ENC_INTEGRITY_NONE);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi const char *error;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi int ec;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->prefix_written = TRUE;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (!dcrypt_ctx_sym_init(estream->ctx_sym, &error)) ec = -1;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi else ec = 0;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi estream->ctx_sym = ctx;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi struct ostream *os = o_stream_create(&estream->ostream, output,
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi o_stream_get_fd(output));
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi if (ec != 0) {
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi io_stream_set_error(&estream->ostream.iostream, "Could not initialize stream: %s", error);
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi os->stream_errno = EINVAL;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi }
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi return os;
316cbe323513a0f20d1cf519fe9405e231d633e2Aki Tuomi}