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

Introduce new Secure Message API #389

Merged
merged 22 commits into from Feb 25, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
ef65c98
Introduce new Secure Message API
ilammy Feb 20, 2019
54aefce
Cast test message as uint8_t
ilammy Feb 20, 2019
aaaccdb
Implement new Secure Message API using primitives
ilammy Feb 20, 2019
609a6bf
Mark old Secure Message API as deprecated
ilammy Feb 20, 2019
02b38ea
Merge branch 'master' into new-smessage-api
ilammy Feb 20, 2019
acb767b
Use new Secure Message API: ThemisPP
ilammy Feb 20, 2019
9ff2cf0
Use new Secure Message API: rust-themis
ilammy Feb 20, 2019
c21a87f
Use new Secure Message API: Java/Android Themis
ilammy Feb 20, 2019
ac107b4
Use new Secure Message API: JsThemis
ilammy Feb 20, 2019
8306f70
Avoid magic constants in tests
ilammy Feb 20, 2019
7f4f939
Improve wording in comments and deprecations
vixentael Feb 21, 2019
35e3cde
Move key kind validation to Themis Core
ilammy Feb 21, 2019
c341511
Key kind checks in Secure Message
ilammy Feb 21, 2019
0d3edf5
Key kind checks in Secure Message: ThemisPP
ilammy Feb 21, 2019
7075209
Key kind checks in Secure Message: JsThemis
ilammy Feb 21, 2019
3549f9d
Move keygen and validation into a new file
ilammy Feb 21, 2019
fdc4bc6
Move key checking utilities to secure_keygen.hpp (ThemisPP)
ilammy Feb 21, 2019
7e75bb7
Move key checking utilities to secure_keygen.hpp (JsThemis)
ilammy Feb 21, 2019
dfbd1b3
Remove redundant checks for null and empty keys
ilammy Feb 21, 2019
ec67c84
Provide more detailed key validation
ilammy Feb 21, 2019
27970d3
Improve key validation accuracy
ilammy Feb 22, 2019
2f02158
Rename key validation functions
ilammy Feb 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
68 changes: 68 additions & 0 deletions src/themis/secure_message.c
Expand Up @@ -77,6 +77,74 @@ themis_status_t themis_gen_ec_key_pair(uint8_t* private_key,
return themis_gen_key_pair(SOTER_SIGN_ecdsa_none_pkcs8, private_key, private_key_length, public_key, public_key_length);
}

themis_status_t themis_secure_message_encrypt(const uint8_t* private_key,
const size_t private_key_length,
const uint8_t* public_key,
const size_t public_key_length,
const uint8_t* message,
const size_t message_length,
uint8_t* encrypted_message,
size_t* encrypted_message_length)
{
THEMIS_CHECK_PARAM(private_key!=NULL);
ilammy marked this conversation as resolved.
Show resolved Hide resolved
THEMIS_CHECK_PARAM(private_key_length!=0);
THEMIS_CHECK_PARAM(public_key!=NULL);
THEMIS_CHECK_PARAM(public_key_length!=0);
THEMIS_CHECK_PARAM(message!=NULL);
THEMIS_CHECK_PARAM(message_length!=0);
THEMIS_CHECK_PARAM(encrypted_message_length!=NULL);
return themis_secure_message_wrap(private_key, private_key_length, public_key, public_key_length, message, message_length, encrypted_message, encrypted_message_length);
}

themis_status_t themis_secure_message_decrypt(const uint8_t* private_key,
const size_t private_key_length,
const uint8_t* public_key,
const size_t public_key_length,
const uint8_t* encrypted_message,
const size_t encrypted_message_length,
uint8_t* message,
size_t* message_length)
{
THEMIS_CHECK_PARAM(private_key!=NULL);
THEMIS_CHECK_PARAM(private_key_length!=0);
THEMIS_CHECK_PARAM(public_key!=NULL);
THEMIS_CHECK_PARAM(public_key_length!=0);
THEMIS_CHECK_PARAM(encrypted_message!=NULL);
THEMIS_CHECK_PARAM(encrypted_message_length!=0);
THEMIS_CHECK_PARAM(message_length!=NULL);
return themis_secure_message_unwrap(private_key, private_key_length, public_key, public_key_length, encrypted_message, encrypted_message_length, message, message_length);
}

themis_status_t themis_secure_message_sign(const uint8_t* private_key,
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe it's time to verify the type of key to avoid misusage incorrect type of key (public/private)? : )
we can do simple check on prefix of key value for known prefixes of private keys:

if (memcmp(private_key, RSA_PRIV_KEY_PREF, sizeof(RSA_PRIV_KEY_PREF) != 0 && 
    memcmp(private_key, RSA_PRIV_KEY_PREF, sizeof(EC_PRIV_KEY_PREF) != 0) { 
return THEMIS_INVALID_PARAMETER;
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

but better will be to extend api and add some functions that will validate keys: validate_private_key/validate_public_key and for now, it will check the only prefix. In the future we can extend these validations with verifying full key's structure

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Come to think of it... I've added the following utilities for the Rust wrapper to query the key kind and validate its content:

enum themis_key_kind
{
THEMIS_KEY_INVALID,
THEMIS_KEY_RSA_PRIVATE,
THEMIS_KEY_RSA_PUBLIC,
THEMIS_KEY_EC_PRIVATE,
THEMIS_KEY_EC_PUBLIC,
};
/// Checks if the buffer contains a valid Themis key.
themis_status_t themis_is_valid_key(const uint8_t *key, size_t length);
/// Extracts the presumed key kind from the buffer.
enum themis_key_kind themis_get_key_kind(const uint8_t *key, size_t length);

Can they be of some use? What do you think of moving these functions to the core library (and using them for checks internally as well)? I believe this API may be useful for applications to verify key content independently.

As for Secure Messages, I guess we can even go a bit further and verify that both private and public keys are of ECDSA or RSA flavor. Ideally, we'd also verify that both use the same public parameters, but that's harder to do.

Copy link
Collaborator

Choose a reason for hiding this comment

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

good checks, I think it's good to move into the core themis library

Copy link
Contributor

Choose a reason for hiding this comment

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

agree, good checks, make sense at core lvl

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@Lagovas @vixentael I've moved the key validation routines to Themis core, added some tests for them, added validation to new Secure Message API, and added some early checks to ThemisPP and JsThemis which are most affected by poor error reporting. Please give it a look.

const size_t private_key_length,
const uint8_t* message,
const size_t message_length,
uint8_t* signed_message,
size_t* signed_message_length)
{
THEMIS_CHECK_PARAM(private_key!=NULL);
THEMIS_CHECK_PARAM(private_key_length!=0);
THEMIS_CHECK_PARAM(message!=NULL);
THEMIS_CHECK_PARAM(message_length!=0);
THEMIS_CHECK_PARAM(signed_message_length!=NULL);
return themis_secure_message_wrap(private_key, private_key_length, NULL, 0, message, message_length, signed_message, signed_message_length);
}

themis_status_t themis_secure_message_verify(const uint8_t* public_key,
const size_t public_key_length,
const uint8_t* signed_message,
const size_t signed_message_length,
uint8_t* message,
size_t* message_length)
{
THEMIS_CHECK_PARAM(public_key!=NULL);
THEMIS_CHECK_PARAM(public_key_length!=0);
THEMIS_CHECK_PARAM(signed_message!=NULL);
THEMIS_CHECK_PARAM(signed_message_length!=0);
THEMIS_CHECK_PARAM(message_length!=NULL);
return themis_secure_message_unwrap(NULL, 0, public_key, public_key_length, signed_message, signed_message_length, message, message_length);
}

themis_status_t themis_secure_message_wrap(const uint8_t* private_key,
const size_t private_key_length,
const uint8_t* public_key,
Expand Down
92 changes: 92 additions & 0 deletions src/themis/secure_message.h
Expand Up @@ -64,6 +64,98 @@ themis_status_t themis_gen_ec_key_pair(uint8_t* private_key,
uint8_t* public_key,
size_t* public_key_length);

/**
* @brief encrypt message to secure message
* @param [in] private_key private key
* @param [in] private_key_length length of private_key
* @param [in] public_key peer public key
* @param [in] public_key_length length of public_key
* @param [in] message message to encrypt
* @param [in] message_length length of message
* @param [out] encrypted_message buffer for encrypted message.
* May be set to NULL to determine expected length of encrypted message
* @param [in, out] encrypted_message_length length of encrypted_message
* @return THEMIS_SUCCESS on success or an error code on failure
* @note If encrypted_message is NULL or encrypted_message_length is not enough to store the encrypted message
* then THEMIS_BUFFER_TOO_SMALL will be returned and encrypted_message_length will contain
* the length of the buffer needed to store the encrypted message.
*/
themis_status_t themis_secure_message_encrypt(const uint8_t* private_key,
const size_t private_key_length,
const uint8_t* public_key,
const size_t public_key_length,
const uint8_t* message,
const size_t message_length,
uint8_t* encrypted_message,
size_t* encrypted_message_length);

/**
* @brief decrypt secure message to plaintext message
* @param [in] private_key private key
* @param [in] private_key_length length of private_key
* @param [in] public_key peer public key
* @param [in] public_key_length length of public_key
* @param [in] encrypted_message encrypted message to decrypt
* @param [in] encrypted_message_length length of encrypted_message
* @param [out] message buffer for plaintext message.
* May be set to NULL to determine expected length of plaintext message
* @param [in, out] message_length length of message
* @return THEMIS_SUCCESS on success or an error code on failure
* @note If message is NULL or message_length is not enough to store the plaintext message
* then THEMIS_BUFFER_TOO_SMALL will be returned and message_length will contain
* the length of the buffer needed to store the encrypted message.
*/
themis_status_t themis_secure_message_decrypt(const uint8_t* private_key,
const size_t private_key_length,
const uint8_t* public_key,
const size_t public_key_length,
const uint8_t* encrypted_message,
const size_t encrypted_message_length,
uint8_t* message,
size_t* message_length);

/**
* @brief securely sign a message
* @param [in] private_key private key
* @param [in] private_key_length length of private_key
* @param [in] message message to sign
* @param [in] message_length length of message
* @param [out] signed_message buffer for signed message.
* May be set to NULL to determine expected length of signed message
* @param [in, out] signed_message_length length of signed_message
* @return THEMIS_SUCCESS on success or an error code on failure
* @note If signed_message is NULL or signed_message_length is not enough to store the signed message
* then THEMIS_BUFFER_TOO_SMALL will be returned and signed_message_length will contain
* the length of the buffer needed to store the signed message.
*/
themis_status_t themis_secure_message_sign(const uint8_t* private_key,
const size_t private_key_length,
const uint8_t* message,
const size_t message_length,
uint8_t* signed_message,
size_t* signed_message_length);

/**
* @brief verify signature on a signed message
* @param [in] public_key peer public key
* @param [in] public_key_length length of public_key
* @param [in] signed_message signed message to verify
* @param [in] signed_message_length length of signed_message
* @param [out] message buffer for original message (without signature).
* May be set to NULL to determine expected length of original message
* @param [in, out] message_length length of message
* @return THEMIS_SUCCESS on success or an error code on failure
* @note If message is NULL or message_length is not enough to store the original message
* then THEMIS_BUFFER_TOO_SMALL will be returned and message_length will contain
* the length of the buffer needed to store the original message.
*/
themis_status_t themis_secure_message_verify(const uint8_t* public_key,
const size_t public_key_length,
const uint8_t* signed_message,
const size_t signed_message_length,
uint8_t* message,
size_t* message_length);

/**
* @brief wrap message to secure message
* @param [in] private_key private key
Expand Down