/* Copyright (c) 2016-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "randgen.h"
#include "safe-memset.h"
#include "hash-method.h"
#include "sha2.h"
#include "dcrypt.h"
#include "istream.h"
#include "istream-decrypt.h"
#include "istream-private.h"
#include "dcrypt-iostream.h"
#include "hex-binary.h"
struct decrypt_istream {
void *key_context;
bool initialized;
bool finalized;
bool use_mac;
};
{
}
{
}
static
{
int ec, i = 0;
if (mlen < 2)
return 0;
/* try to read more */
return 0;
}
data+=2;
mlen-=2;
break;
data += 2;
mlen -= 2;
pos += 2;
switch(i++) {
case 0:
break;
case 1:
/* public key id */
digest_pos = data;
digest_len = len;
break;
case 2:
/* encryption key digest */
break;
case 3:
/* encrypted key data */
key_ct_pos = data;
key_ct_len = len;
break;
}
}
if (i < 4) {
/* was it consumed? */
return -1;
}
/* we don't have a private key */
/* see if we can get one */
if (ret < 0) {
return -1;
}
if (ret == 0) {
return -1;
}
} else {
return -1;
}
}
return -1;
} else {
return -1;
}
}
/* derive shared secret */
return -1;
}
/* run it thru SHA256 once */
/* NB! The old code was broken and used this kind of IV - it is not correct, but
we need to stay compatible with old data */
/* use it to decrypt the actual encryption key */
return -1;
}
ec = 0;
dcrypt_ctx_sym_set_iv(dctx, (const unsigned char*)"\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16);
ec = -1;
}
if (ec != 0) {
return -1;
}
/* see if we got the correct key */
if (key_digest_size != sizeof(hres)) {
return -1;
}
return -1;
}
/* prime context with key */
return -1;
}
/* Again, old code used this IV, so we have to use it too */
dcrypt_ctx_sym_set_iv(stream->ctx_sym, (const unsigned char*)"\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0", 16);
return -1;
}
/* now we are ready to decrypt stream */
}
{
return FALSE;
*_data += 4;
return TRUE;
}
static
{
unsigned int len;
return FALSE;
/* get us DER encoded length */
/* two byte length */
return FALSE;
} else {
}
return FALSE;
return TRUE;
}
static
{
const char *error;
int keys;
return 0;
/* if we have a key, prefab the digest */
return -1;
}
&error)) {
"dcrypt_key_id_private failed: %s",
error);
return -1;
}
}
/* for each key */
return 0;
/* hope you going to give us right key.. */
if (ret < 0) {
return -1;
}
if (ret > 0) {
break;
}
} else {
/* see if key matches to the one we have */
break;
}
}
/* wasn't correct key, skip over some data */
return 0;
}
/* didn't find matching key */
if (!have_key) {
return -1;
}
const unsigned char *ephemeral_key;
const unsigned char *encrypted_key;
const unsigned char *ekhash;
/* read ephemeral key (can be missing for RSA) */
return 0;
data += ep_key_len;
/* read encrypted key */
return 0;
/* read key data hash */
return 0;
data += ekhash_len;
/* decrypt the seed */
if (ktype == DCRYPT_KEY_RSA) {
return -1;
}
} else if (ktype == DCRYPT_KEY_EC) {
/* perform ECDHE */
return -1;
}
/* use shared secret and peer key to generate decryption key, AES-256-CBC has 32 byte key and 16 byte IV */
return -1;
}
io_stream_set_error(&stream->istream.iostream, "Cannot perform key decryption: invalid temporary key");
return -1;
}
return -1;
}
/* we use ephemeral_key for IV */
int ec = 0;
ec = -1;
}
io_stream_set_error(&stream->istream.iostream, "Cannot perform key decryption: invalid key length");
ec = -1;
}
} else {
io_stream_set_error(&stream->istream.iostream, "Decryption error: unsupported key type 0x%02x", ktype);
return -1;
}
/* make sure we were able to decrypt the encrypted key correctly */
io_stream_set_error(&stream->istream.iostream, "Decryption error: unsupported hash algorithm: %s", malg);
return -1;
}
for(int i = 1; i < 2049; i++) {
}
/* do the comparison */
return -1;
}
return 1;
}
static
{
/* read cipher OID */
const char *calg;
return 0;
io_stream_set_error(&stream->istream.iostream, "Decryption error: unsupported/invalid cipher: %s", calg);
return -1;
}
/* read MAC oid (MAC is used for PBKDF2 and key data digest, too) */
const char *malg;
return 0;
io_stream_set_error(&stream->istream.iostream, "Decryption error: unsupported/invalid MAC algorithm: %s", malg);
return -1;
}
/* read rounds (for PBKDF2) */
return 0;
/* read key data length */
return 0;
} else {
tagsize = 0;
}
/* how much key data we should be getting */
size_t kl = dcrypt_ctx_sym_get_key_length(stream->ctx_sym) + dcrypt_ctx_sym_get_iv_length(stream->ctx_sym) + tagsize;
/* try to decrypt the keydata with a private key */
int ret;
return ret;
/* oh, it worked! */
/* but returned wrong amount of data */
return -1;
}
/* prime contexts */
/* based on the chosen MAC, initialize HMAC or AEAD */
const char *error;
}
} else {
}
/* destroy private key data */
}
static
{
const char *error;
/* check magic */
if (mlen < sizeof(IOSTREAM_CRYPT_MAGIC))
return 0;
return -1;
}
data += sizeof(IOSTREAM_CRYPT_MAGIC);
return 0; /* read more? */
/* check version */
if (*data == '\x01') {
} else if (*data != '\x02') {
return -1;
}
data++;
/* read flags */
return 0;
/* get the total length of header */
return 0;
/* do not forget stream format */
return 0;
int ret;
return -1;
else if (ret == 0) {
return -1;
}
/* if it all went well, try to initialize decryption context */
return -1;
}
return hdr_len;
}
static ssize_t
{
(struct decrypt_istream *)stream;
const unsigned char *data;
int ret;
/* not if it's broken */
return -1;
for (;;) {
/* remove skipped data from buffer */
}
/* stream buffer still at maximum */
return -2;
}
/* if something is already decrypted, return as much of it as
we can */
/* only return up to max_buffer_size bytes, even when buffer
actually has more, as not to confuse the caller */
} else {
}
}
/* all data decrypted */
return -1;
}
/* need to read more input */
if (ret == 0)
return ret;
/* file was empty */
return -1;
}
return -1;
if (!dstream->initialized) {
"Decryption error: %s",
"Input truncated in decryption header");
return -1;
}
/* final block */
continue;
}
"MAC error: %s", error);
return -1;
}
if (!dstream->initialized) {
if (hret < 0) {
/* assume temporary failure */
return -1;
}
/* not encrypted by us */
"Truncated header");
return -1;
}
}
if (hret == 0) {
/* see if we can get more data */
if (ret == -2) {
return -1;
}
continue;
} else {
/* clean up buffer */
}
}
decrypt_size = size;
"Decryption error: footer is longer than data");
return -1;
}
} else {
/* ignore footer's length of data until we
reach EOF */
}
"MAC error: %s", error);
return -1;
}
}
}
if (check_mac) {
"Cannot verify MAC: %s", error);
return -1;
}
"Cannot verify MAC: mismatch");
return -1;
}
}
}
"Decryption error: %s", error);
return -1;
}
}
}
static
bool close_parent)
{
(struct decrypt_istream *)stream;
if (close_parent)
}
static
{
(struct decrypt_istream *)stream;
}
static
{
i_stream_get_fd(input), 0);
return dstream;
}
struct istream *
{
}
struct istream *
{
const char *error;
int ec;
else ec = 0;
if (ec != 0) {
};
}
struct istream *
void *context)
{
}