Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test and deprecate Themis 0.9.6 compatibility path #614

Merged
merged 15 commits into from
Apr 1, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -389,12 +389,6 @@ endif
CFLAGS += $(SANITIZERS)
LDFLAGS += $(SANITIZERS)

# Binary format compatibility with Themis 0.9.6 on x86_64 architecture.
# https://github.com/cossacklabs/themis/pull/279
ifeq ($(NO_SCELL_COMPAT),)
CFLAGS += -DSCELL_COMPAT
endif

########################################################################

include src/soter/soter.mk
Expand Down
292 changes: 167 additions & 125 deletions src/themis/sym_enc_message.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ static themis_status_t themis_auth_sym_kdf_context(uint32_t message_length,
return THEMIS_SUCCESS;
}

#ifdef SCELL_COMPAT
/*
* Themis 0.9.6 incorrectly used 64-bit message length for this field.
*/
Expand All @@ -214,7 +213,6 @@ static themis_status_t themis_auth_sym_kdf_context_compat(uint32_t message_lengt
*kdf_context_length = sizeof(uint64_t);
return THEMIS_SUCCESS;
}
#endif

static themis_status_t themis_auth_sym_derive_encryption_key(const struct themis_scell_auth_token_key* hdr,
const uint8_t* key,
Expand Down Expand Up @@ -458,8 +456,7 @@ themis_status_t themis_auth_sym_decrypt_message_(const uint8_t* key,
* Themis 0.9.6 used slightly different KDF. If decryption fails,
* maybe it was encrypted with that incorrect key. Try it out.
*/
#ifdef SCELL_COMPAT
if (res != THEMIS_SUCCESS && res != THEMIS_BUFFER_TOO_SMALL && sizeof(size_t) == sizeof(uint64_t)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used sizeof check to minimize scope and do extra step only when needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but it also disables the compatibility path for 32-bit machines. They will not be able to decrypt data produced earlier by 64-bit machines. We have quite a few 32-bit platforms that we care about: ARM, WebAssembly, simulators/emulators.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR 279 has compatibility matrix.

not compatible
0.9.6 x64 can't decrypt messages encrypted by 0.9.7 x64/x32. Users should update to 0.9.7.
0.9.7 x32 can't decrypt messages encrypted by 0.9.6 x64. Users should update to 0.9.7.

These are the only incompatible pathes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am really suspicious of historical statements like this, based on memory and old writing with no data. So I tried reproducing the results.

“I’m gonna science the heck outta this!”

Works only on 64-bit Linux with 32-bit libraries. On Debian they can be installed like this:

sudo apt install gcc-multilib libssl-dev:amd64 libssl-dev:i386

Does not really work on macOS because of multiple reasons. Older versions of Themis are not as good at locating modern OpenSSL on macOS, and modern macOS does not include proper 32-bit support for OpenSSL.

  1. Check out Themis git repo.

  2. Put this as scell_seal_string_echo.c in the root:

#include <stdio.h>
#include <string.h>
#include <stdint.h>

#include <themis/themis.h>

static int do_it(const char *command,
                 const uint8_t *key, size_t key_length,
                 const uint8_t *context, size_t context_length,
                 const uint8_t *message, size_t message_length)
{
    themis_status_t res = THEMIS_FAIL;
    uint8_t *output = NULL;
    size_t output_length = 0;

    if (strcmp(command, "enc") == 0) {
        res = themis_secure_cell_encrypt_seal(key,
                                              key_length,
                                              context,
                                              context_length,
                                              message,
                                              message_length,
                                              NULL,
                                              &output_length);
        if (res != THEMIS_BUFFER_TOO_SMALL) {
            fprintf(stderr, "failed to measure output size: %d\n", res);
            return 1;
        }

        output = malloc(output_length);
        if (!output) {
            fprintf(stderr, "cannot allocate %zu bytes\n", output_length);
            return 1;
        }

        res = themis_secure_cell_encrypt_seal(key,
                                              key_length,
                                              context,
                                              context_length,
                                              message,
                                              message_length,
                                              output,
                                              &output_length);
        if (res != THEMIS_SUCCESS) {
            fprintf(stderr, "failed to encrypt: %d\n", res);
            return 1;
        }
    } else if (strcmp(command, "dec") == 0) {
        res = themis_secure_cell_decrypt_seal(key,
                                              key_length,
                                              context,
                                              context_length,
                                              message,
                                              message_length,
                                              NULL,
                                              &output_length);
        if (res != THEMIS_BUFFER_TOO_SMALL) {
            fprintf(stderr, "failed to measure output size: %d\n", res);
            return 1;
        }

        output = malloc(output_length);
        if (!output) {
            fprintf(stderr, "cannot allocate %zu bytes\n", output_length);
            return 1;
        }

        res = themis_secure_cell_decrypt_seal(key,
                                              key_length,
                                              context,
                                              context_length,
                                              message,
                                              message_length,
                                              output,
                                              &output_length);
        if (res != THEMIS_SUCCESS) {
            fprintf(stderr, "failed to encrypt: %d\n", res);
            return 1;
        }
    } else {
        fprintf(stderr, "unknown command: \"%s\", expected \"enc\" or \"dec\"\n",
                command);
        return 1;
    }

    fwrite(output, 1, output_length, stdout);
    free(output);

    return 0;
}

#define MAX_MESSAGE 4096

int main(int argc, char *argv[])
{
    uint8_t message[MAX_MESSAGE] = {0};
    size_t message_length = 0;

    if (argc != 4) {
        fprintf(stderr, "usage:\n\t%s {enc|dec} <key> <context>\n",
                argv[0]);
        return 1;
    }

    message_length = fread(message, 1, sizeof(message), stdin);

    return do_it(argv[1],
                 (const uint8_t*)argv[2], strlen(argv[2]),
                 (const uint8_t*)argv[3], strlen(argv[3]),
                 message, message_length);
}
  1. Put this as whatever.sh in the root:
#!/bin/sh

set -e

build_themis() {
    local bin_name=$1
    local version=$2
    local arch=$3
    local extra=$4

    echo "Building tool with Themis $version $arch $extra..."
    git checkout --detach $version
    make clean
    CFLAGS="$arch" make themis_static soter_static $extra
    cc -o $bin_name $arch scell_seal_string_echo.c -Isrc \
        build/libthemis.a build/libsoter.a -lcrypto
    echo "Complete: $bin_name"
    echo
}

build_binaries() {
    build_themis scell_test_0.9.6_i386       0.9.6  -m32
    build_themis scell_test_0.9.6_x86_64     0.9.6  -m64
    build_themis scell_test_0.10.0_i386      0.10.0 -m32
    build_themis scell_test_0.10.0_x86_64    0.10.0 -m64
    build_themis scell_test_0.10.0_i386_nc   0.10.0 -m32 NO_SCELL_COMPAT=1
    build_themis scell_test_0.10.0_x86_64_nc 0.10.0 -m64 NO_SCELL_COMPAT=1
    build_themis scell_test_THIS-PR_i386     always-compat -m32
    build_themis scell_test_THIS-PR_x86_64   always-compat -m64
}

test_binaries() {
    for encrypt_with in scell_test_*
    do
        for decrypt_with in scell_test_*
        do
            echo -n "$encrypt_with,$decrypt_with,"
            echo "ok" | ./$encrypt_with enc "key" "context" | ./$decrypt_with dec "key" "context" || true
        done
    done
}

build_binaries
test_binaries
  1. Make it executable and run:
chmod +x whatever.sh
./whatever.sh

Parse results:

[ build output skipped ]

scell_test_0.10.0_i386,scell_test_0.10.0_i386,ok
scell_test_0.10.0_i386,scell_test_0.10.0_i386_nc,ok
scell_test_0.10.0_i386,scell_test_0.10.0_x86_64,ok
scell_test_0.10.0_i386,scell_test_0.10.0_x86_64_nc,ok
scell_test_0.10.0_i386,scell_test_0.9.6_i386,ok
scell_test_0.10.0_i386,scell_test_0.9.6_x86_64,failed to encrypt: 11
scell_test_0.10.0_i386,scell_test_THIS-PR_i386,ok
scell_test_0.10.0_i386,scell_test_THIS-PR_x86_64,ok
scell_test_0.10.0_i386_nc,scell_test_0.10.0_i386,ok
scell_test_0.10.0_i386_nc,scell_test_0.10.0_i386_nc,ok
scell_test_0.10.0_i386_nc,scell_test_0.10.0_x86_64,ok
scell_test_0.10.0_i386_nc,scell_test_0.10.0_x86_64_nc,ok
scell_test_0.10.0_i386_nc,scell_test_0.9.6_i386,ok
scell_test_0.10.0_i386_nc,scell_test_0.9.6_x86_64,failed to encrypt: 11
scell_test_0.10.0_i386_nc,scell_test_THIS-PR_i386,ok
scell_test_0.10.0_i386_nc,scell_test_THIS-PR_x86_64,ok
scell_test_0.10.0_x86_64,scell_test_0.10.0_i386,ok
scell_test_0.10.0_x86_64,scell_test_0.10.0_i386_nc,ok
scell_test_0.10.0_x86_64,scell_test_0.10.0_x86_64,ok
scell_test_0.10.0_x86_64,scell_test_0.10.0_x86_64_nc,ok
scell_test_0.10.0_x86_64,scell_test_0.9.6_i386,ok
scell_test_0.10.0_x86_64,scell_test_0.9.6_x86_64,failed to encrypt: 11
scell_test_0.10.0_x86_64,scell_test_THIS-PR_i386,ok
scell_test_0.10.0_x86_64,scell_test_THIS-PR_x86_64,ok
scell_test_0.10.0_x86_64_nc,scell_test_0.10.0_i386,ok
scell_test_0.10.0_x86_64_nc,scell_test_0.10.0_i386_nc,ok
scell_test_0.10.0_x86_64_nc,scell_test_0.10.0_x86_64,ok
scell_test_0.10.0_x86_64_nc,scell_test_0.10.0_x86_64_nc,ok
scell_test_0.10.0_x86_64_nc,scell_test_0.9.6_i386,ok
scell_test_0.10.0_x86_64_nc,scell_test_0.9.6_x86_64,failed to encrypt: 11
scell_test_0.10.0_x86_64_nc,scell_test_THIS-PR_i386,ok
scell_test_0.10.0_x86_64_nc,scell_test_THIS-PR_x86_64,ok
scell_test_0.9.6_i386,scell_test_0.10.0_i386,ok
scell_test_0.9.6_i386,scell_test_0.10.0_i386_nc,ok
scell_test_0.9.6_i386,scell_test_0.10.0_x86_64,ok
scell_test_0.9.6_i386,scell_test_0.10.0_x86_64_nc,ok
scell_test_0.9.6_i386,scell_test_0.9.6_i386,ok
scell_test_0.9.6_i386,scell_test_0.9.6_x86_64,failed to encrypt: 11
scell_test_0.9.6_i386,scell_test_THIS-PR_i386,ok
scell_test_0.9.6_i386,scell_test_THIS-PR_x86_64,ok
scell_test_0.9.6_x86_64,scell_test_0.10.0_i386,failed to encrypt: 11
scell_test_0.9.6_x86_64,scell_test_0.10.0_i386_nc,failed to encrypt: 11
scell_test_0.9.6_x86_64,scell_test_0.10.0_x86_64,ok
scell_test_0.9.6_x86_64,scell_test_0.10.0_x86_64_nc,failed to encrypt: 11
scell_test_0.9.6_x86_64,scell_test_0.9.6_i386,failed to encrypt: 11
scell_test_0.9.6_x86_64,scell_test_0.9.6_x86_64,ok
scell_test_0.9.6_x86_64,scell_test_THIS-PR_i386,ok
scell_test_0.9.6_x86_64,scell_test_THIS-PR_x86_64,ok
scell_test_THIS-PR_i386,scell_test_0.10.0_i386,ok
scell_test_THIS-PR_i386,scell_test_0.10.0_i386_nc,ok
scell_test_THIS-PR_i386,scell_test_0.10.0_x86_64,ok
scell_test_THIS-PR_i386,scell_test_0.10.0_x86_64_nc,ok
scell_test_THIS-PR_i386,scell_test_0.9.6_i386,ok
scell_test_THIS-PR_i386,scell_test_0.9.6_x86_64,failed to encrypt: 11
scell_test_THIS-PR_i386,scell_test_THIS-PR_i386,ok
scell_test_THIS-PR_i386,scell_test_THIS-PR_x86_64,ok
scell_test_THIS-PR_x86_64,scell_test_0.10.0_i386,ok
scell_test_THIS-PR_x86_64,scell_test_0.10.0_i386_nc,ok
scell_test_THIS-PR_x86_64,scell_test_0.10.0_x86_64,ok
scell_test_THIS-PR_x86_64,scell_test_0.10.0_x86_64_nc,ok
scell_test_THIS-PR_x86_64,scell_test_0.9.6_i386,ok
scell_test_THIS-PR_x86_64,scell_test_0.9.6_x86_64,failed to encrypt: 11
scell_test_THIS-PR_x86_64,scell_test_THIS-PR_i386,ok
scell_test_THIS-PR_x86_64,scell_test_THIS-PR_x86_64,ok
Encrypted withDecrypted by
0.9.6 (32-bit) 0.9.6 (64-bit) 0.10.0+ (32-bit) 0.10.0+ (64-bit) 0.10.0 (32-bit) 0.10.0 (64-bit) this PR (32-bit) this PR (64-bit)
0.9.6 (32-bit)
0.9.6 (64-bit)
0.10.0+ (32-bit)
0.10.0+ (64-bit)
0.10.0 (32-bit)
0.10.0 (64-bit)
this PR (32-bit)
this PR (64-bit)

Where 0.10.0+ is the version with workaround enabled (the default one) and 0.10.0 is the one with NO_SCELL_COMPAT=1.

So the statement seems to be correct.

Note how 0.9.6 (64-bit) fails to interoperate with anything but itself, and produces data that cannot be decrypted without the compatibility code.

But also note how removal of sizeof comparison in this PR makes it possible for 32-bit platforms to decrypt data produced by 0.9.6 (64-bit).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are freak :D

But also note how removal of sizeof comparison in this PR makes it possible for 32-bit platforms to decrypt data produced by 0.9.6 (64-bit).

Agree. I used it to limit the double decryption surface 🤔

if (res != THEMIS_SUCCESS && res != THEMIS_BUFFER_TOO_SMALL) {
kdf_context_length = sizeof(kdf_context);
res = themis_auth_sym_kdf_context_compat(hdr.message_length, kdf_context, &kdf_context_length);
if (res != THEMIS_SUCCESS) {
Expand Down Expand Up @@ -491,7 +488,6 @@ themis_status_t themis_auth_sym_decrypt_message_(const uint8_t* key,
hdr.auth_tag,
hdr.auth_tag_length);
}
#endif

/* Sanity check of resulting message length */
if (*message_length != encrypted_message_length) {
Expand Down Expand Up @@ -551,11 +547,66 @@ themis_status_t themis_auth_sym_decrypt_message(const uint8_t* key,
message_length);
}

typedef struct themis_sym_message_hdr_type {
uint32_t alg;
uint32_t iv_length;
uint32_t message_length;
} themis_sym_message_hdr_t;
static themis_status_t themis_sym_derive_encryption_key(const uint8_t* key,
size_t key_length,
size_t message_length,
uint8_t* derived_key,
size_t derived_key_length)
{
uint8_t kdf_context[sizeof(uint32_t)];
/*
* Note that we use only the least significant 32 bits of size_t here.
* If message_length is longer that 4 GB then the context value gets
* truncated here. (And on 16-bit platforms it will be zero-padded.)
*/
stream_write_uint32LE(kdf_context, (uint32_t)message_length);
return themis_sym_kdf(key,
key_length,
THEMIS_SYM_KDF_KEY_LABEL,
kdf_context,
sizeof(kdf_context),
NULL,
0,
derived_key,
derived_key_length);
}

/*
* Themis 0.9.6 used 64-bit message length in computations, so here we go.
*/
static themis_status_t themis_sym_derive_encryption_key_compat(const uint8_t* key,
size_t key_length,
size_t message_length,
uint8_t* derived_key,
size_t derived_key_length)
{
uint8_t kdf_context[sizeof(uint64_t)];
stream_write_uint64LE(kdf_context, (uint64_t)message_length);
return themis_sym_kdf(key,
key_length,
THEMIS_SYM_KDF_KEY_LABEL,
kdf_context,
sizeof(kdf_context),
NULL,
0,
derived_key,
derived_key_length);
}

static themis_status_t themis_sym_derive_encryption_iv(const uint8_t* key,
size_t key_length,
const uint8_t* context,
size_t context_length,
uint8_t* iv,
size_t iv_length)
{
/*
* Yes, you are reading it correct. We do derive IV with a KDF.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice comment

* Context Imprint mode needs to be completely deterministic.
* That's why it has lower security than Seal or Token Protect.
*/
return themis_sym_kdf(key, key_length, THEMIS_SYM_KDF_IV_LABEL, context, context_length, NULL, 0, iv, iv_length);
}

themis_status_t themis_sym_encrypt_message_u_(const uint8_t* key,
const size_t key_length,
Expand All @@ -566,35 +617,34 @@ themis_status_t themis_sym_encrypt_message_u_(const uint8_t* key,
uint8_t* encrypted_message,
size_t* encrypted_message_length)
{
themis_status_t res = THEMIS_FAIL;
uint8_t iv[THEMIS_SYM_IV_LENGTH];

THEMIS_CHECK_PARAM(message != NULL && message_length != 0);
THEMIS_CHECK_PARAM(context != NULL && context_length != 0);

if ((*encrypted_message_length) < message_length) {
(*encrypted_message_length) = message_length;
return THEMIS_BUFFER_TOO_SMALL;
}
(*encrypted_message_length) = message_length;
uint8_t iv[THEMIS_SYM_IV_LENGTH];
THEMIS_STATUS_CHECK(themis_sym_kdf(key,
key_length,
THEMIS_SYM_KDF_IV_LABEL,
context,
context_length,
NULL,
0,
iv,
THEMIS_SYM_IV_LENGTH),
THEMIS_SUCCESS);
THEMIS_STATUS_CHECK(themis_sym_plain_encrypt(THEMIS_SYM_ALG,
key,
key_length,
iv,
THEMIS_SYM_IV_LENGTH,
message,
message_length,
encrypted_message,
encrypted_message_length),
THEMIS_SUCCESS);
return THEMIS_SUCCESS;

res = themis_sym_derive_encryption_iv(key, key_length, context, context_length, iv, sizeof(iv));
if (res != THEMIS_SUCCESS) {
return res;
}

res = themis_sym_plain_encrypt(THEMIS_SYM_ALG,
key,
key_length,
iv,
sizeof(iv),
message,
message_length,
encrypted_message,
encrypted_message_length);
soter_wipe(iv, sizeof(iv));
return res;
}

themis_status_t themis_sym_encrypt_message_u(const uint8_t* key,
Expand All @@ -606,28 +656,26 @@ themis_status_t themis_sym_encrypt_message_u(const uint8_t* key,
uint8_t* encrypted_message,
size_t* encrypted_message_length)
{
uint8_t key_[THEMIS_SYM_KEY_LENGTH / 8];

// TODO: TYPE WARNING Should update `sizeof(uint32_t)` to `sizeof(message_length)` after
// changing encrypted_message_length type to uint32_t
THEMIS_STATUS_CHECK(themis_sym_kdf(key,
key_length,
THEMIS_SYM_KDF_KEY_LABEL,
(uint8_t*)(&message_length),
sizeof(uint32_t),
NULL,
0,
key_,
sizeof(key_)),
THEMIS_SUCCESS);
return themis_sym_encrypt_message_u_(key_,
sizeof(key_),
message,
message_length,
context,
context_length,
encrypted_message,
encrypted_message_length);
themis_status_t res = THEMIS_FAIL;
uint8_t derived_key[THEMIS_SYM_KEY_LENGTH / 8];

res = themis_sym_derive_encryption_key(key, key_length, message_length, derived_key, sizeof(derived_key));
if (res != THEMIS_SUCCESS) {
return res;
}

res = themis_sym_encrypt_message_u_(derived_key,
sizeof(derived_key),
message,
message_length,
context,
context_length,
encrypted_message,
encrypted_message_length);

soter_wipe(derived_key, sizeof(derived_key));

return res;
}

themis_status_t themis_sym_decrypt_message_u_(const uint8_t* key,
Expand All @@ -639,35 +687,34 @@ themis_status_t themis_sym_decrypt_message_u_(const uint8_t* key,
uint8_t* message,
size_t* message_length)
{
themis_status_t res = THEMIS_FAIL;
uint8_t iv[THEMIS_SYM_IV_LENGTH];

THEMIS_CHECK_PARAM(encrypted_message != NULL && encrypted_message_length != 0);
THEMIS_CHECK_PARAM(context != NULL && context_length != 0);

if ((*message_length) < encrypted_message_length) {
(*message_length) = encrypted_message_length;
return THEMIS_BUFFER_TOO_SMALL;
}
(*message_length) = encrypted_message_length;
uint8_t iv[THEMIS_SYM_IV_LENGTH];
THEMIS_STATUS_CHECK(themis_sym_kdf(key,
key_length,
THEMIS_SYM_KDF_IV_LABEL,
context,
context_length,
NULL,
0,
iv,
THEMIS_SYM_IV_LENGTH),
THEMIS_SUCCESS);
THEMIS_STATUS_CHECK(themis_sym_plain_decrypt(THEMIS_SYM_ALG,
key,
key_length,
iv,
THEMIS_SYM_IV_LENGTH,
encrypted_message,
encrypted_message_length,
message,
message_length),
THEMIS_SUCCESS);
return THEMIS_SUCCESS;

res = themis_sym_derive_encryption_iv(key, key_length, context, context_length, iv, sizeof(iv));
if (res != THEMIS_SUCCESS) {
return res;
}

res = themis_sym_plain_decrypt(THEMIS_SYM_ALG,
key,
key_length,
iv,
sizeof(iv),
encrypted_message,
encrypted_message_length,
message,
message_length);
soter_wipe(iv, sizeof(iv));
return res;
}

themis_status_t themis_sym_decrypt_message_u(const uint8_t* key,
Expand All @@ -679,56 +726,51 @@ themis_status_t themis_sym_decrypt_message_u(const uint8_t* key,
uint8_t* message,
size_t* message_length)
{
uint8_t key_[THEMIS_SYM_KEY_LENGTH / 8];

// TODO: TYPE WARNING Should update `sizeof(uint32_t)` to `sizeof(encrypted_message_length)`
// after changing encrypted_message_length type to uint32_t
THEMIS_STATUS_CHECK(themis_sym_kdf(key,
key_length,
THEMIS_SYM_KDF_KEY_LABEL,
(uint8_t*)(&encrypted_message_length),
sizeof(uint32_t),
NULL,
0,
key_,
sizeof(key_)),
THEMIS_SUCCESS);
themis_status_t decryption_result = themis_sym_decrypt_message_u_(key_,
sizeof(key_),
context,
context_length,
encrypted_message,
encrypted_message_length,
message,
message_length);

#ifdef SCELL_COMPAT

// we are on x64, should sizeof(uin64_t) for backwards compatibility with themis 0.9.6 x64
if (sizeof(size_t) == sizeof(uint64_t)) {
if (decryption_result != THEMIS_SUCCESS && decryption_result != THEMIS_BUFFER_TOO_SMALL) {
// TODO: TYPE WARNING `sizeof(uint64_t)`. Fix that on next versions
THEMIS_STATUS_CHECK(themis_sym_kdf(key,
key_length,
THEMIS_SYM_KDF_KEY_LABEL,
(uint8_t*)(&encrypted_message_length),
sizeof(uint64_t),
NULL,
0,
key_,
sizeof(key_)),
THEMIS_SUCCESS);
decryption_result = themis_sym_decrypt_message_u_(key_,
sizeof(key_),
context,
context_length,
encrypted_message,
encrypted_message_length,
message,
message_length);
themis_status_t res = THEMIS_FAIL;
uint8_t derived_key[THEMIS_SYM_KEY_LENGTH / 8];

res = themis_sym_derive_encryption_key(key,
key_length,
encrypted_message_length,
derived_key,
sizeof(derived_key));
if (res != THEMIS_SUCCESS) {
return res;
}

res = themis_sym_decrypt_message_u_(derived_key,
sizeof(derived_key),
context,
context_length,
encrypted_message,
encrypted_message_length,
message,
message_length);
/*
* Themis 0.9.6 used slightly different KDF. If decryption fails,
* maybe it was encrypted with that incorrect key. Try it out.
*/
if (res != THEMIS_SUCCESS && res != THEMIS_BUFFER_TOO_SMALL) {
res = themis_sym_derive_encryption_key_compat(key,
key_length,
encrypted_message_length,
derived_key,
sizeof(derived_key));
if (res != THEMIS_SUCCESS) {
goto error;
}
res = themis_sym_decrypt_message_u_(derived_key,
sizeof(derived_key),
context,
context_length,
encrypted_message,
encrypted_message_length,
message,
message_length);
}
#endif

return decryption_result;
error:
soter_wipe(derived_key, sizeof(derived_key));

return res;
}
Loading