diff --git a/include/olm/olm.hh b/include/olm/olm.hh index f08fb9f..a5a50de 100644 --- a/include/olm/olm.hh +++ b/include/olm/olm.hh @@ -257,6 +257,19 @@ size_t olm_create_inbound_session_from( void * one_time_key_message, size_t message_length ); +/** The length of the buffer needed to return the id for this session. */ +size_t olm_session_id_length( + OlmSession * session +); + +/** An identifier for this session. Will be the same for both ends of the + * conversation. If the id buffer is too small then olm_session_last_error() + * will be "OUTPUT_BUFFER_TOO_SMALL". */ +size_t olm_session_id( + OlmSession * session, + void * id, size_t id_length +); + /** Checks if the PRE_KEY message is for this in-bound session. This can happen * if multiple messages are sent to this account before this account sends a * message in reply. Returns olm_error() on failure. If the base64 diff --git a/include/olm/session.hh b/include/olm/session.hh index b70ce6a..993a8da 100644 --- a/include/olm/session.hh +++ b/include/olm/session.hh @@ -54,6 +54,12 @@ struct Session { std::uint8_t const * one_time_key_message, std::size_t message_length ); + std::size_t session_id_length(); + + std::size_t session_id( + std::uint8_t * id, std::size_t id_length + ); + bool matches_inbound_session( Curve25519PublicKey const * their_identity_key, std::uint8_t const * one_time_key_message, std::size_t message_length diff --git a/javascript/olm_post.js b/javascript/olm_post.js index 60876b1..94d3e82 100644 --- a/javascript/olm_post.js +++ b/javascript/olm_post.js @@ -222,6 +222,29 @@ Session.prototype['create_inbound'] = restore_stack(function( ); }); +Session.prototype['create_inbound_from'] = restore_stack(function( + account, identity_key, one_time_key_message +) { + var identity_key_array = array_from_string(identity_key); + var identity_key_buffer = stack(identity_key_array); + var message_array = array_from_string(one_time_key_message); + var message_buffer = stack(message_array); + session_method(Module['_olm_create_inbound_session_from'])( + this.ptr, account.ptr, + identity_key_buffer, identity_key_array.length, + message_buffer, message_array.length + ); +}); + +Session.prototype['session_id'] = restore_stack(function() { + var id_length = session_method(Module['_olm_session_id_length'])(this.ptr); + var id_buffer = stack(id_length); + session_method(Module['_olm_session_id'])( + this.ptr, id_buffer, id_length + ); + return Pointer_stringify(id_buffer, id_length); +}); + Session.prototype['matches_inbound'] = restore_stack(function( account, one_time_key_message ) { @@ -232,6 +255,20 @@ Session.prototype['matches_inbound'] = restore_stack(function( ) ? true : false; }); +Session.prototype['matches_inbound_from'] = restore_stack(function( + account, identity_key, one_time_key_message +) { + var identity_key_array = array_from_string(identity_key); + var identity_key_buffer = stack(identity_key_array); + var message_array = array_from_string(one_time_key_message); + var message_buffer = stack(message_array); + return session_method(Module['_olm_matches_inbound_session_from'])( + this.ptr, account.ptr, + identity_key_buffer, identity_key_array.length, + message_buffer, message_array.length + ) ? true : false; +}); + Session.prototype['encrypt'] = restore_stack(function( plaintext ) { diff --git a/python/olm.py b/python/olm.py index 8d484fc..4bd85f0 100755 --- a/python/olm.py +++ b/python/olm.py @@ -185,7 +185,20 @@ session_function( c_void_p, # Account c_void_p, c_size_t, # Pre Key Message ) +session_function( + lib.olm_create_inbound_session_from, + c_void_p, # Account + c_void_p, c_size_t, # Identity Key + c_void_p, c_size_t, # Pre Key Message +) +session_function(lib.olm_session_id_length) +session_function(lib.olm_session_id, c_void_p, c_size_t) session_function(lib.olm_matches_inbound_session, c_void_p, c_size_t) +session_function( + lib.olm_matches_inbound_session_from, + c_void_p, c_size_t, # Identity Key + c_void_p, c_size_t, # Pre Key Message +) session_function(lib.olm_encrypt_message_type) session_function(lib.olm_encrypt_random_length) session_function(lib.olm_encrypt_message_length, c_size_t) @@ -204,7 +217,7 @@ session_function( lib.olm_decrypt, c_size_t, # Message Type c_void_p, c_size_t, # Message - c_void_p, c_size_t, # Plaintext + c_void_p, c_size_t, # Plaintext ) class Session(object): @@ -250,6 +263,22 @@ class Session(object): one_time_key_message_buffer, len(one_time_key_message) ) + def create_inbound_from(self, account, identity_key, one_time_key_message): + identity_key_buffer = create_string_buffer(identity_key) + one_time_key_message_buffer = create_string_buffer(one_time_key_message) + lib.olm_create_inbound_session_from( + self.ptr, + account.ptr, + identity_key_buffer, len(identity_key), + one_time_key_message_buffer, len(one_time_key_message) + ) + + def session_id(self): + id_length = lib.olm_session_id_length(self.ptr) + id_buffer = create_string_buffer(id_length) + lib.olm_session_id(self.ptr, id_buffer, id_length); + return id_buffer.raw + def matches_inbound(self, one_time_key_message): one_time_key_message_buffer = create_string_buffer(one_time_key_message) return bool(lib.olm_matches_inbound_session( @@ -257,6 +286,15 @@ class Session(object): one_time_key_message_buffer, len(one_time_key_message) )) + def matches_inbound_from(self, identity_key, one_time_key_message): + identity_key_buffer = create_string_buffer(identity_key) + one_time_key_message_buffer = create_string_buffer(one_time_key_message) + return bool(lib.olm_matches_inbound_session( + self.ptr, + identity_key_buffer, len(identity_key), + one_time_key_message_buffer, len(one_time_key_message) + )) + def encrypt(self, plaintext): r_length = lib.olm_encrypt_random_length(self.ptr) random = read_random(r_length) @@ -421,7 +459,7 @@ if __name__ == '__main__': def do_inbound(args): if os.path.exists(args.session_file): sys.stderr.write("Session %r file already exists" % ( - args.account_file, + args.session_file, )) sys.exit(1) account = Account() @@ -443,6 +481,17 @@ if __name__ == '__main__': inbound.set_defaults(func=do_inbound) + session_id = commands.add_parser("session_id", help="Session ID") + session_id.add_argument("session_file", help="Local session file") + + def do_session_id(args): + session = Session() + with open(args.session_file, "rb") as f: + session.unpickle(args.key, f.read()) + sys.stdout.write(session.session_id() + "\n") + + session_id.set_defaults(func=do_session_id) + encrypt = commands.add_parser("encrypt", help="Encrypt a message") encrypt.add_argument("session_file", help="Local session file") encrypt.add_argument("plaintext_file", help="Plaintext", default="-") diff --git a/src/olm.cpp b/src/olm.cpp index 17461fe..cb4291e 100644 --- a/src/olm.cpp +++ b/src/olm.cpp @@ -552,6 +552,33 @@ size_t olm_create_inbound_session_from( } +size_t olm_session_id_length( + OlmSession * session +) { + return b64_output_length(from_c(session)->session_id_length()); +} + + +size_t olm_session_id( + OlmSession * session, + void * id, size_t id_length +) { + std::size_t raw_length = from_c(session)->session_id_length(); + if (id_length < b64_output_length(raw_length)) { + from_c(session)->last_error = + olm::ErrorCode::OUTPUT_BUFFER_TOO_SMALL; + return std::size_t(-1); + } + std::size_t result = from_c(session)->session_id( + b64_output_pos(from_c(id), raw_length), raw_length + ); + if (result == std::size_t(-1)) { + return result; + } + return b64_output(from_c(id), raw_length); +} + + size_t olm_matches_inbound_session( OlmSession * session, void * one_time_key_message, size_t message_length @@ -649,12 +676,15 @@ size_t olm_encrypt( olm::ErrorCode::OUTPUT_BUFFER_TOO_SMALL; return std::size_t(-1); } - from_c(session)->encrypt( + std::size_t result = from_c(session)->encrypt( from_c(plaintext), plaintext_length, from_c(random), random_length, b64_output_pos(from_c(message), raw_length), raw_length ); olm::unset(random, random_length); + if (result == std::size_t(-1)) { + return result; + } return b64_output(from_c(message), raw_length); } diff --git a/src/session.cpp b/src/session.cpp index 0249e6c..b17a059 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -189,6 +189,27 @@ std::size_t olm::Session::new_inbound_session( } +std::size_t olm::Session::session_id_length() { + return 32; +} + + +std::size_t olm::Session::session_id( + std::uint8_t * id, std::size_t id_length +) { + if (id_length < session_id_length()) { + last_error = olm::ErrorCode::OUTPUT_BUFFER_TOO_SMALL; + return std::size_t(-1); + } + std::uint8_t tmp[96]; + std::memcpy(tmp, alice_identity_key.public_key, 32); + std::memcpy(tmp + 32, alice_base_key.public_key, 32); + std::memcpy(tmp + 64, bob_one_time_key.public_key, 32); + olm::sha256(tmp, sizeof(tmp), id); + return session_id_length(); +} + + bool olm::Session::matches_inbound_session( olm::Curve25519PublicKey const * their_identity_key, std::uint8_t const * one_time_key_message, std::size_t message_length diff --git a/tests/test_olm.cpp b/tests/test_olm.cpp index 551b3cd..fbc14cf 100644 --- a/tests/test_olm.cpp +++ b/tests/test_olm.cpp @@ -216,6 +216,19 @@ assert_equals(std::size_t(-1), ::olm_decrypt( plaintext_2, sizeof(plaintext_2) )); +std::uint8_t a_session_id[::olm_session_id_length(a_session)]; +assert_not_equals(std::size_t(-1), ::olm_session_id( + a_session, a_session_id, sizeof(a_session_id) +)); + +std::uint8_t b_session_id[::olm_session_id_length(b_session)]; +assert_not_equals(std::size_t(-1), ::olm_session_id( + b_session, b_session_id, sizeof(b_session_id) +)); + +assert_equals(sizeof(a_session_id), sizeof(b_session_id)); +assert_equals(a_session_id, b_session_id, sizeof(b_session_id)); + } { /** More messages test */