Skip to content
Snippets Groups Projects
Commit 39c1f3b3 authored by Mark Haines's avatar Mark Haines
Browse files

Add methods for computing sha256 hashes and validating ed25519 signatures

parent 411109d8
No related branches found
No related tags found
No related merge requests found
...@@ -27,6 +27,7 @@ static const size_t OLM_MESSAGE_TYPE_MESSAGE = 1; ...@@ -27,6 +27,7 @@ static const size_t OLM_MESSAGE_TYPE_MESSAGE = 1;
struct OlmAccount; struct OlmAccount;
struct OlmSession; struct OlmSession;
struct OlmUtility;
/** The size of an account object in bytes */ /** The size of an account object in bytes */
size_t olm_account_size(); size_t olm_account_size();
...@@ -34,6 +35,9 @@ size_t olm_account_size(); ...@@ -34,6 +35,9 @@ size_t olm_account_size();
/** The size of a session object in bytes */ /** The size of a session object in bytes */
size_t olm_session_size(); size_t olm_session_size();
/** The size of a utility object in bytes */
size_t olm_utility_size();
/** Initialise an account object using the supplied memory /** Initialise an account object using the supplied memory
* The supplied memory must be at least olm_account_size() bytes */ * The supplied memory must be at least olm_account_size() bytes */
OlmAccount * olm_account( OlmAccount * olm_account(
...@@ -46,6 +50,12 @@ OlmSession * olm_session( ...@@ -46,6 +50,12 @@ OlmSession * olm_session(
void * memory void * memory
); );
/** Initialise a utility object using the supplied memory
* The supplied memory must be at least olm_session_size() bytes */
OlmUtility * olm_utility(
void * memory
);
/** The value that olm will return from a function if there was an error */ /** The value that olm will return from a function if there was an error */
size_t olm_error(); size_t olm_error();
...@@ -61,6 +71,12 @@ const char * olm_session_last_error( ...@@ -61,6 +71,12 @@ const char * olm_session_last_error(
OlmSession * session OlmSession * session
); );
/** A null terminated string describing the most recent error to happen to a
* utility */
const char * olm_utility_last_error(
OlmUtility * utility
);
/** Clears the memory used to back this account */ /** Clears the memory used to back this account */
size_t olm_clear_account( size_t olm_clear_account(
OlmAccount * account OlmAccount * account
...@@ -71,6 +87,11 @@ size_t olm_clear_session( ...@@ -71,6 +87,11 @@ size_t olm_clear_session(
OlmSession * session OlmSession * session
); );
/** Clears the memory used to back this utility */
size_t olm_clear_utility(
OlmUtility * utility
);
/** Returns the number of bytes needed to store an account */ /** Returns the number of bytes needed to store an account */
size_t olm_pickle_account_length( size_t olm_pickle_account_length(
OlmAccount * account OlmAccount * account
...@@ -370,7 +391,29 @@ size_t olm_decrypt( ...@@ -370,7 +391,29 @@ size_t olm_decrypt(
void * plaintext, size_t max_plaintext_length void * plaintext, size_t max_plaintext_length
); );
/** The length of the buffer needed to hold the SHA-256 hash. */
size_t olm_sha256_length(
OlmUtility * utility
);
/** Calculates the SHA-256 hash of the input and encodes it as base64. If the
* output buffer is smaller than olm_sha256_length() then
* olm_session_last_error() will be "OUTPUT_BUFFER_TOO_SMALL". */
size_t olm_sha256(
OlmUtility * utility,
void const * input, size_t input_length,
void * output, size_t output_length
);
/** Verify an ed25519 signature. If the key was too small then
* olm_session_last_error will be "INVALID_BASE64". If the signature was invalid
* then olm_session_last_error() will be "BAD_MESSAGE_MAC". */
size_t olm_ed25519_verify(
OlmUtility * utility,
void const * key, size_t key_length,
void const * message, size_t message_length,
void * signature, size_t signature_length
);
#ifdef __cplusplus #ifdef __cplusplus
} }
......
/* Copyright 2015 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef UTILITY_HH_
#define UTILITY_HH_
#include "olm/error.hh"
#include <cstddef>
#include <cstdint>
namespace olm {
class Ed25519PublicKey;
struct Utility {
Utility();
ErrorCode last_error;
std::size_t sha256_length();
std::size_t sha256(
std::uint8_t const * input, std::size_t input_length,
std::uint8_t * output, std::size_t output_length
);
std::size_t ed25519_verify(
Ed25519PublicKey const & key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t const * signature, std::size_t signature_length
);
};
} // namespace olm
#endif /* UTILITY_HH_ */
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "olm/olm.hh" #include "olm/olm.hh"
#include "olm/session.hh" #include "olm/session.hh"
#include "olm/account.hh" #include "olm/account.hh"
#include "olm/utility.hh"
#include "olm/base64.hh" #include "olm/base64.hh"
#include "olm/cipher.hh" #include "olm/cipher.hh"
#include "olm/memory.hh" #include "olm/memory.hh"
...@@ -28,16 +29,24 @@ static OlmAccount * to_c(olm::Account * account) { ...@@ -28,16 +29,24 @@ static OlmAccount * to_c(olm::Account * account) {
return reinterpret_cast<OlmAccount *>(account); return reinterpret_cast<OlmAccount *>(account);
} }
static OlmSession * to_c(olm::Session * account) { static OlmSession * to_c(olm::Session * session) {
return reinterpret_cast<OlmSession *>(account); return reinterpret_cast<OlmSession *>(session);
}
static OlmUtility * to_c(olm::Utility * utility) {
return reinterpret_cast<OlmUtility *>(utility);
} }
static olm::Account * from_c(OlmAccount * account) { static olm::Account * from_c(OlmAccount * account) {
return reinterpret_cast<olm::Account *>(account); return reinterpret_cast<olm::Account *>(account);
} }
static olm::Session * from_c(OlmSession * account) { static olm::Session * from_c(OlmSession * session) {
return reinterpret_cast<olm::Session *>(account); return reinterpret_cast<olm::Session *>(session);
}
static olm::Utility * from_c(OlmUtility * utility) {
return reinterpret_cast<olm::Utility *>(utility);
} }
static std::uint8_t * from_c(void * bytes) { static std::uint8_t * from_c(void * bytes) {
...@@ -200,6 +209,16 @@ const char * olm_session_last_error( ...@@ -200,6 +209,16 @@ const char * olm_session_last_error(
} }
} }
const char * olm_utility_last_error(
OlmUtility * utility
) {
unsigned error = unsigned(from_c(utility)->last_error);
if (error < sizeof(ERRORS)) {
return ERRORS[error];
} else {
return "UNKNOWN_ERROR";
}
}
size_t olm_account_size() { size_t olm_account_size() {
return sizeof(olm::Account); return sizeof(olm::Account);
...@@ -210,6 +229,9 @@ size_t olm_session_size() { ...@@ -210,6 +229,9 @@ size_t olm_session_size() {
return sizeof(olm::Session); return sizeof(olm::Session);
} }
size_t olm_utility_size() {
return sizeof(olm::Utility);
}
OlmAccount * olm_account( OlmAccount * olm_account(
void * memory void * memory
...@@ -227,6 +249,14 @@ OlmSession * olm_session( ...@@ -227,6 +249,14 @@ OlmSession * olm_session(
} }
OlmUtility * olm_utility(
void * memory
) {
olm::unset(memory, sizeof(olm::Utility));
return to_c(new(memory) olm::Utility());
}
size_t olm_clear_account( size_t olm_clear_account(
OlmAccount * account OlmAccount * account
) { ) {
...@@ -249,6 +279,17 @@ size_t olm_clear_session( ...@@ -249,6 +279,17 @@ size_t olm_clear_session(
} }
size_t olm_clear_utility(
OlmUtility * utility
) {
/* Clear the memory backing the session */
olm::unset(utility, sizeof(olm::Utility));
/* Initialise a fresh session object in case someone tries to use it */
new(utility) olm::Utility();
return sizeof(olm::Utility);
}
size_t olm_pickle_account_length( size_t olm_pickle_account_length(
OlmAccount * account OlmAccount * account
) { ) {
...@@ -558,7 +599,6 @@ size_t olm_session_id_length( ...@@ -558,7 +599,6 @@ size_t olm_session_id_length(
return b64_output_length(from_c(session)->session_id_length()); return b64_output_length(from_c(session)->session_id_length());
} }
size_t olm_session_id( size_t olm_session_id(
OlmSession * session, OlmSession * session,
void * id, size_t id_length void * id, size_t id_length
...@@ -724,4 +764,63 @@ size_t olm_decrypt( ...@@ -724,4 +764,63 @@ size_t olm_decrypt(
); );
} }
size_t olm_sha256_length(
OlmUtility * utility
) {
return b64_output_length(from_c(utility)->sha256_length());
}
size_t olm_sha256(
OlmUtility * utility,
void const * input, size_t input_length,
void * output, size_t output_length
) {
std::size_t raw_length = from_c(utility)->sha256_length();
if (output_length < b64_output_length(raw_length)) {
from_c(utility)->last_error =
olm::ErrorCode::OUTPUT_BUFFER_TOO_SMALL;
return std::size_t(-1);
}
std::size_t result = from_c(utility)->sha256(
from_c(input), input_length,
b64_output_pos(from_c(output), raw_length), raw_length
);
if (result == std::size_t(-1)) {
return result;
}
return b64_output(from_c(output), raw_length);
}
size_t olm_ed25519_verify(
OlmUtility * utility,
void const * key, size_t key_length,
void const * message, size_t message_length,
void * signature, size_t signature_length
) {
if (olm::decode_base64_length(key_length) != 32) {
from_c(utility)->last_error = olm::ErrorCode::INVALID_BASE64;
return std::size_t(-1);
}
olm::Ed25519PublicKey verify_key;
olm::decode_base64(
from_c(key), key_length,
verify_key.public_key
);
std::size_t raw_signature_length = b64_input(
from_c(signature), signature_length, from_c(utility)->last_error
);
if (raw_signature_length == std::size_t(-1)) {
return std::size_t(-1);
}
return from_c(utility)->ed25519_verify(
verify_key,
from_c(message), message_length,
from_c(signature), raw_signature_length
);
}
} }
/* Copyright 2015 OpenMarket Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "olm/utility.hh"
#include "olm/crypto.hh"
olm::Utility::Utility(
) : last_error(olm::ErrorCode::SUCCESS) {
}
size_t olm::Utility::sha256_length() {
return olm::HMAC_SHA256_OUTPUT_LENGTH;
}
size_t olm::Utility::sha256(
std::uint8_t const * input, std::size_t input_length,
std::uint8_t * output, std::size_t output_length
) {
if (output_length < sha256_length()) {
last_error = olm::ErrorCode::OUTPUT_BUFFER_TOO_SMALL;
return std::size_t(-1);
}
olm::sha256(input, input_length, output);
return 32;
}
size_t olm::Utility::ed25519_verify(
Ed25519PublicKey const & key,
std::uint8_t const * message, std::size_t message_length,
std::uint8_t const * signature, std::size_t signature_length
) {
if (signature_length < 64) {
last_error = olm::ErrorCode::BAD_MESSAGE_MAC;
return std::size_t(-1);
}
if (!olm::ed25519_verify(key, message, message_length, signature)) {
last_error = olm::ErrorCode::BAD_MESSAGE_MAC;
return std::size_t(-1);
}
return std::size_t(0);
}
#include "olm/olm.hh"
#include "unittest.hh"
int main() {
{
TestCase("Olm sha256 test");
std::uint8_t utility_buffer[::olm_utility_size()];
::OlmUtility * utility = ::olm_utility(utility_buffer);
assert_equals(std::size_t(43), ::olm_sha256_length(utility));
std::uint8_t output[43];
::olm_sha256(utility, "Hello, World", 12, output, 43);
std::uint8_t expected_output[] = "A2daxT/5zRU1zMffzfosRYxSGDcfQY3BNvLRmsH76KU";
assert_equals(output, expected_output, 43);
}
}
#include "olm/olm.hh"
#include "unittest.hh"
#include <cstddef>
#include <cstdint>
#include <cstring>
struct MockRandom {
MockRandom(std::uint8_t tag, std::uint8_t offset = 0)
: tag(tag), current(offset) {}
void operator()(
void * buf, std::size_t length
) {
std::uint8_t * bytes = (std::uint8_t *) buf;
while (length > 32) {
bytes[0] = tag;
std::memset(bytes + 1, current, 31);
length -= 32;
bytes += 32;
current += 1;
}
if (length) {
bytes[0] = tag;
std::memset(bytes + 1, current, length - 1);
current += 1;
}
}
std::uint8_t tag;
std::uint8_t current;
};
std::uint8_t * check_malloc(std::size_t size) {
if (size == std::size_t(-1)) {
assert_not_equals(std::size_t(-1), size);
}
return (std::uint8_t *)::malloc(size);
}
int main() {
{ /** Signing Test */
TestCase test_case("Signing test");
MockRandom mock_random_a('A', 0x00);
void * account_buffer = check_malloc(::olm_account_size());
::OlmAccount * account = ::olm_account(account_buffer);
std::size_t random_size = ::olm_create_account_random_length(account);
void * random = check_malloc(random_size);
mock_random_a(random, random_size);
::olm_create_account(account, random, random_size);
::free(random);
std::size_t message_size = 12;
void * message = check_malloc(message_size);
::memcpy(message, "Hello, World", message_size);
std::size_t signature_size = ::olm_account_signature_length(account);
void * signature = check_malloc(signature_size);
assert_not_equals(std::size_t(-1), ::olm_account_sign(
account, message, message_size, signature, signature_size
));
std::size_t id_keys_size = ::olm_account_identity_keys_length(account);
std::uint8_t * id_keys = (std::uint8_t *) check_malloc(id_keys_size);
assert_not_equals(std::size_t(-1), ::olm_account_identity_keys(
account, id_keys, id_keys_size
));
void * utility_buffer = check_malloc(::olm_utility_size());
::OlmUtility * utility = ::olm_utility(utility_buffer);
assert_not_equals(std::size_t(-1), ::olm_ed25519_verify(
utility, id_keys + 71, 43, message, message_size, signature, signature_size
));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment