Coder Social home page Coder Social logo

libsignal-protocol-c's Introduction

Overview

This is a ratcheting forward secrecy protocol that works in synchronous and asynchronous messaging environments. See the Java library for more details.

Building libsignal-protocol-c

Development host setup

Build dependencies

Most of these dependencies are required just for the unit test suite and development of the library itself. When integrating into actual applications, you should not need anything beyond CMake. Alternatively, you may integrate the code using a build system of your choice. Items marked with *1 are required for tests, with *2 are additionally required for code coverage.

Setting up a fresh source tree

$ cd /path/to/libsignal-protocol-c
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Debug ..
$ make

Running the unit tests

$ cd /path/to/libsignal-protocol-c/build
$ cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=1 ..
$ cd tests
$ make
$ cd ..
$ ctest

Creating the code coverage report

$ cd /path/to/libsignal-protocol-c/build
$ cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=1 -DCOVERAGE=1 ..
$ make coverage

The generated code coverage report can be found in: /path/to/libsignal-protocol-c/build/coverage

Eclipse project setup

CMake provides a tutorial on Eclipse project setup here: https://cmake.org/Wiki/CMake:Eclipse_UNIX_Tutorial

It is recommended to follow the more manual "Option 2," since the Eclipse project generator built into CMake tends to be outdated and leads you toward a very awkward and occasionally broken project configuration.

Protocol Buffers compiler

This project uses serialization code based on Protocol Buffers. Since the official library does not support C, the protobuf-c generator is used instead. For the sake of convenience, the generated code and its dependencies are included in the source tree. The generated code can be regenerated at any time by installing the two mentioned packages and running "make" in the "protobuf/" subdirectory.

Target platforms

CMake toolchain files have been included from the following sources:

Using libsignal-protocol-c

Library initialization

Before using the library, a libsignal-protocol-c client needs to initialize a global context. This global context is used to provide callbacks for implementations of functions used across the library that need client-specific implementations. Refer to "signal_protocol.h" for detailed documentation on these functions, and the unit tests for example implementations.

signal_context *global_context;
signal_context_create(&global_context, user_data);
signal_context_set_crypto_provider(global_context, &provider);
signal_context_set_locking_functions(global_context, lock_function, unlock_function);

Client install time

At install time, a libsignal-protocol-c client needs to generate its identity keys, registration id, and prekeys.

ratchet_identity_key_pair *identity_key_pair;
uint32_t registration_id;
signal_protocol_key_helper_pre_key_list_node *pre_keys_head;
session_signed_pre_key *signed_pre_key;

signal_protocol_key_helper_generate_identity_key_pair(&identity_key_pair, global_context);
signal_protocol_key_helper_generate_registration_id(&registration_id, 0, global_context);
signal_protocol_key_helper_generate_pre_keys(&pre_keys_head, start_id, 100, global_context);
signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, identity_key_pair, 5, timestamp, global_context);

/* Store identity_key_pair somewhere durable and safe. */
/* Store registration_id somewhere durable and safe. */

/* Store pre keys in the pre key store. */
/* Store signed pre key in the signed pre key store. */

The above example is simplified for the sake of clarity. All of these functions return errors on failure, and those errors should be checked for in real usage.

There are also iteration and serialization methods for the above types that should be used as appropriate.

Building a session

A libsignal-protocol-c client needs to implement four data store callback interfaces: signal_protocol_identity_key_store, signal_protocol_pre_key_store, signal_protocol_signed_pre_key_store, and signal_protocol_session_store. These will manage loading and storing of identity, prekeys, signed prekeys, and session state.

These callback interfaces are designed such that implementations should treat all data flowing through them as opaque binary blobs. Anything necessary for referencing that data will be provided as separate function arguments to those callbacks. If it is ever necessary for clients to directly access stored data in terms of library data structures, they should use the accessor functions declared in "signal_protocol.h" for these data stores.

Once the callbacks for these data stores are implemented, building a session is fairly straightforward:

/* Create the data store context, and add all the callbacks to it */
signal_protocol_store_context *store_context;
signal_protocol_store_context_create(&store_context, context);
signal_protocol_store_context_set_session_store(store_context, &session_store);
signal_protocol_store_context_set_pre_key_store(store_context, &pre_key_store);
signal_protocol_store_context_set_signed_pre_key_store(store_context, &signed_pre_key_store);
signal_protocol_store_context_set_identity_key_store(store_context, &identity_key_store);

/* Instantiate a session_builder for a recipient address. */
signal_protocol_address address = {
    "+14159998888", 12, 1
};
session_builder *builder;
session_builder_create(&builder, store_context, &address, global_context);

/* Build a session with a pre key retrieved from the server. */
session_builder_process_pre_key_bundle(builder, retrieved_pre_key);

/* Create the session cipher and encrypt the message */
session_cipher *cipher;
session_cipher_create(&cipher, store_context, &address, global_context);

ciphertext_message *encrypted_message;
session_cipher_encrypt(cipher, message, message_len, &encrypted_message);

/* Get the serialized content and deliver it */
signal_buffer *serialized = ciphertext_message_get_serialized(encrypted_message);

deliver(signal_buffer_data(serialized), signal_buffer_len(serialized));

/* Cleanup */
SIGNAL_UNREF(encrypted_message);
session_cipher_free(cipher);
session_builder_free(builder);
signal_protocol_store_context_destroy(store_context);

The above example is simplified for the sake of clarity. All of these functions return errors on failure, and those errors should be checked for in real usage.

Memory management notes

For every custom data type that the libsignal-protocol-c library can allocate and return, a corresponding way of deallocating an instance of that data type is provided.

The more basic and higher level data types provide a type-specific free or destroy function. These types include signal_context, signal_protocol_store_context, signal_buffer, signal_buffer_list, signal_int_list, signal_protocol_key_helper_pre_key_list_node, session_builder, session_cipher, group_session_builder, group_cipher, and fingerprint_generator.

Most of the other data types, including everything internal, use a reference counting mechanism. If you are going to hold onto a reference to one of these types, use the SIGNAL_REF(x) macro to increment its count. If you are done with a reference, use SIGNAL_UNREF(x) to decrement its count. When the count reaches 0, the type's destructor function is called.

Legal things

Cryptography Notice

This distribution includes cryptographic software. The country in which you currently reside may have restrictions on the import, possession, use, and/or re-export to another country, of encryption software. BEFORE using any encryption software, please check your country's laws, regulations and policies concerning the import, possession, or use, and re-export of encryption software, to see if this is permitted. See http://www.wassenaar.org/ for more information.

The U.S. Government Department of Commerce, Bureau of Industry and Security (BIS), has classified this software as Export Commodity Control Number (ECCN) 5D002.C.1, which includes information security software using or performing cryptographic functions with asymmetric algorithms. The form and manner of this distribution makes it eligible for export under the License Exception ENC Technology Software Unrestricted (TSU) exception (see the BIS Export Administration Regulations, Section 740.13) for both object code and source code.

License

Copyright 2015-2016 Open Whisper Systems

Licensed under the GPLv3: http://www.gnu.org/licenses/gpl-3.0.html

Additional Permissions For Submission to Apple App Store: Provided that you are otherwise in compliance with the GPLv3 for each covered work you convey (including without limitation making the Corresponding Source available in compliance with Section 6 of the GPLv3), Open Whisper Systems also grants you the additional permission to convey through the Apple App Store non-source executable versions of the Program as incorporated into each applicable covered work as Executable Versions only under the Mozilla Public License version 2.0 (https://www.mozilla.org/en-US/MPL/2.0/).

libsignal-protocol-c's People

Contributors

a-kao avatar blackgnezdo avatar chrisballinger avatar dcsommer avatar dkonigsberg avatar drizt avatar jubalh avatar linuxfan2718 avatar michaelforney avatar mmdriley avatar moxie0 avatar readmecritic avatar roobre avatar sjaeckel avatar smattr avatar tklauser avatar toabctl avatar trevp avatar wbbradley avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

libsignal-protocol-c's Issues

missing link with math library

running cmake with the following (standard, for my distro) switches:

'-GUnix Makefiles' -DCMAKE_INSTALL_PREFIX:PATH=/usr -DINCLUDE_INSTALL_DIR:PATH=/usr/include -DLIB_INSTALL_DIR:PATH=/usr/lib64 -DSYSCONF_INSTALL_DIR:PATH=/etc -DSHARE_INSTALL_PREFIX:PATH=/usr/share -DCMAKE_INSTALL_LIBDIR:PATH=/usr/lib64 -DCMAKE_BUILD_TYPE=RelWithDebInfo '-DCMAKE_C_FLAGS=-fmessage-length=0 -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -DNDEBUG' '-DCMAKE_CXX_FLAGS=-fmessage-length=0 -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -DNDEBUG' '-DCMAKE_Fortran_FLAGS=-fmessage-length=0 -grecord-gcc-switches -O2 -Wall -D_FORTIFY_SOURCE=2 -fstack-protector-strong -funwind-tables -fasynchronous-unwind-tables -DNDEBUG' '-DCMAKE_EXE_LINKER_FLAGS=-Wl,--as-needed -Wl,--no-undefined -Wl,-z,now' '-DCMAKE_MODULE_LINKER_FLAGS=-Wl,--as-needed -Wl,--no-undefined -Wl,-z,now' '-DCMAKE_SHARED_LINKER_FLAGS=-Wl,--as-needed -Wl,--no-undefined -Wl,-z,now' -DLIB_SUFFIX=64 -DCMAKE_SKIP_RPATH:BOOL=ON -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON -DBUILD_SHARED_LIBS:BOOL=ON -DBUILD_STATIC_LIBS:BOOL=OFF -DCMAKE_COLOR_MAKEFILE:BOOL=OFF -DCMAKE_INSTALL_DO_STRIP:BOOL=OFF -DCMAKE_MODULES_INSTALL_DIR=/usr/share/cmake/Modules

I get

In function `hkdf_expand':
libsignal-protocol-c-2.3.0/src/hkdf.c:109: undefined reference to `ceil'

Seems like -lm is missing

is there any safe way to convert signal_buffer * to std::string object?

Hi,

I have:

  • searched open and closed issues for duplicates

Bug description

currently I am using following way to convert from signal_buffer * to std::string:
std::string strMsg;
signal_buffer *eMsg = ciphertext_message_get_serialized(cipherMsg); // or some other function which returns signal_buffer *
retVal.assign((const char *)eMsg->data, eMsg->len);

and following way to convert std::string to signal_buffer *
std::string msg = "some text";
signal_buffer *eMsgBuf = signal_buffer_create((uint8_t *)msg.data(), msg.length());

while doing this conversion, I am facing few issues of not getting proper values in both directions.
e.g. session_cipher_decrypt_pre_key_signal_message() is failed after the above serialise call.
Its possible that the conversion from uint8_t to char is creating the issue in my implementation.

So just wanted to know, if there is any safer way/method to convert signal_buffer* to std::string or char*!

Thanks,
MJ

Dynamic Library

How can I create a libsignal-protocol.dylib from the source code?

Clearing the confusion about one-time prekeys; are they necessary?

Hello,

I was wondering if someone could clear the air about this issue before I dig into implementing the callback functions for the code. There is a bit of confusion about whether a one-time prekey bundle is required to create a session or not. [1]

Let's take the example from the README.MD, if we were to omit the following would the session creation still work? I'm currently under the assumption it would as that would align with the behavior as specified in technical whitepaper of whatsapp. 1

/* Build a session with a pre key retrieved from the server. */ session_builder_process_pre_key_bundle(builder, retrieved_pre_key);


Sessions are built from one of three different possible vectors:

  • - A session_pre_key_bundle retrieved from a server
  • - A pre_key_signal_message received from a client
  • - A key_exchange_message sent to or received from a client

I'm really interested in the procedure that is best described as a "a non-interactive one-time setup" such as using pre_key_signal_message as building block for a session but there are no test suites available for the functions used by two other vectors (aside from retrieving pre_key_bundle from a server). Not that those are necessary to comprehend the code, the required parameters and setup seem pretty straight forward.

Untested function of interest:

int session_builder_process_pre_key_signal_message(session_builder *builder,
        session_record *record, pre_key_signal_message *message, uint32_t *unsigned_pre_key_id)

PS:
I haven't had the time to compile and play with it yet, would certainly yield the answers I seek but I thought this might be a valuable addition to the README or any documentation for that matter.

intentional ignoring of message_version in signal_message_verify_mac?

The function signal_message_verify_mac takes a parameter message_version, but instead accesses the version through message->message_version. From what I can see, this is still correct because the only call of this function has these two values equal. However, it leads to a potentially misleading interface to this functionality. Is this a deliberate layout to support future extension?

Unused field 'device_id' in session_pre_key_bundle

I figured this is for legacy reasons, but since you were talking about a to-do list for cleaning up the code in similar issues I think this should go on it as well.

session_pre_key_bundle_create() takes the parameter device_id, which as far as I can tell (Eclipse reference search), is never used.
Especially session_builder_process_pre_key_bundle(), which seems to be the only function that deals with the bundle, does not use it.
It seems registration_id (of proper uint32_t instead of just int) is used instead.

While not tragic, it creates some confusion about how to properly call session_pre_key_bundle_create() and should be included in an overhaul.

(As a sidenote, do you take pull requests with just documentation comments?)

Bad MAC error with OpenSSL/external lib

I have 2 related issues:

  1. I am getting INCONSISTENT "Bad MAC" error while decrypting message in signal_message_verify_mac() function with one of my HMAC_SHA256 library.
  2. When I am using openssl for HMAC_SHA256 operation, I am getting "Bad MAC" error EVERY TIME. Is the openssl not supported with this library?

I have:

  • searched open and closed issues for duplicates
    Not sure if it related to issue #65 .

Bug description

sometimes "Bad MAC" error is coming when I run the test with attached SHA256 files during decrypt call.
When I use openssl library for the HMAC_SHA256 operations (init, update, final), each time I am getting this Bad MAC error.
Note: I am using this library as a native side (C++) implementation for one of my Android application. Since CommonCrypto is not available in android, I am using the attached HMAC lib/openssl lib for HMAC and aes encryption.

hmac_sha256.zip

Steps to reproduce

  • Run the test_basic_session_v3 test present in test_session_cipher.c with attached library function for HMAC operation

Actual result: Out of 50 Interaction between Alice and Bob only 10 were success rest were failed due to Bad MAC error.

Expected result: 50 out of 50 interaction should be completed.

Tests don't build with check 0.9.9

Tested with 2.3.1
It looks like, cmake don't check the version of check.
0.9.9 will fails with:

CMakeFiles/test_device_consistency.dir/test_device_consistency.c.o: In function `generate_code':
/builddir/build/BUILD/libsignal-protocol-c-2.3.1/tests/test_device_consistency.c:208: undefined reference to `ck_assert_ptr_ne'
/builddir/build/BUILD/libsignal-protocol-c-2.3.1/tests/test_device_consistency.c:219: undefined reference to `ck_assert_ptr_ne'
CMakeFiles/test_device_consistency.dir/test_device_consistency.c.o: In function `test_device_consistency':
/builddir/build/BUILD/libsignal-protocol-c-2.3.1/tests/test_device_consistency.c:55: undefined reference to `ck_assert_ptr_ne'
/builddir/build/BUILD/libsignal-protocol-c-2.3.1/tests/test_device_consistency.c:68: undefined reference to `ck_assert_ptr_ne'
/builddir/build/BUILD/libsignal-protocol-c-2.3.1/tests/test_device_consistency.c:81: undefined reference to `ck_assert_ptr_ne'
/builddir/build/BUILD/libsignal-protocol-c-2.3.1/tests/test_group_cipher.c:565: undefined reference to `ck_assert_ptr_eq'
CMakeFiles/test_group_cipher.dir/test_group_cipher.c.o: In function `test_basic_ratchet':
/builddir/build/BUILD/libsignal-protocol-c-2.3.1/tests/test_group_cipher.c:288: undefined reference to `ck_assert_ptr_eq'
CMakeFiles/test_group_cipher.dir/test_group_cipher.c.o: In function `test_message_key_limit':
/builddir/build/BUILD/libsignal-protocol-c-2.3.1/tests/test_group_cipher.c:708: undefined reference to `ck_assert_ptr_ne'
/builddir/build/BUILD/libsignal-protocol-c-2.3.1/tests/test_group_cipher.c:714: undefined reference to `ck_assert_ptr_ne'
collect2: error: ld returned 1 exit status
make[2]: *** [tests/test_group_cipher] Error 1

Invalid max in signal_protocol_key_helper_get_random_sequence

From signal_protocol_key_helper_get_random_sequence documentation is not obviously that return value will less than max parameter. I mean that when user use signal_protocol_key_helper_get_random_sequence(3) he suppose possible vallues 0, 1, 2 and 3. But by fact this function will return only 0, 1 or 2, not 3.

/**
 * Generate a random number bounded by the provided maximum
 *
 * @param value set to the next random number
 * @param max the maximum value of the random number
 * @return 0 on success, or negative on failure
 */
int signal_protocol_key_helper_get_random_sequence(int *value, int max, signal_context *global_context);

Need beginner tutorials for open whisper system

Me and my team have developed chat application for ios, android and windows using xmpp server. Now we are planning to implement Whisper Systems in our application. Already i have searched all your libraries and application from GitHub but i want some beginner step by step documentation to implement Whisper Systems in our application.

failure in ratcheting_session_alice_initialize can go unnoticed

This function calls session_state_add_receiver_chain that can fail with OOM. The call is made on a branch which can result in 0 being returned from ratcheting_session_alice_initialize. I would fix this myself by checking the return value from session_state_add_receiver_chain, but it's not clear if we can just bail out at this point. It's past the point of commit (the complete label) which makes me think we're in an inconsistent state here. Do you have a suggested fix? Apologies if I've misdiagnosed what's going on here.

VXEDDSA compliance with libsodium keys?

Hello,

I'm trying to use VXEDDSA functions from existing Ed25519 keys, generated by Scrypt.

I've tried to take an example from test test_unique_signatures which was working as expected, and changed the public/private keys with the ones I get. But I finally got:

05:f7:d6:8d:a9:19:33:1a:9b:d5:2a:4f:f8:1c:8c:74:0e:6f:76:63:52:24:89:5d:4c:37:1e:68:d5:c7:f3:10:32
c8:df:2f:9e:7f:0c:e8:83:33:cd:6e:f7:3c:5b:bc:dc:75:46:a1:65:fc:5a:62:f6:ba:24:e4:89:03:29:1d:b0
54:68:69:73:20:69:73:20:75:6e:69:71:75:65:2e
45:dc:7b:81:6b:01:b3:6c:fa:16:45:dc:ae:8a:c9:bc:8e:52:3c:d8:6d:00:7d:19:95:3f:03:e7:d5:45:54:a0
curve_decode_point: 0
curve_decode_private_point: 0
curve_calculate_vrf_signature: 0
curve_verify_vrf_signature: -1011

Is this key generated by Scrypt supposed to work with libsignal VXEDDSA functions?

I do not master the crypto functions very well, so I need your help. A hint would be enough, I need to know which path to follow.

#include <math.h>
#include <printf.h>
#include <memory.h>
#include "../src/signal_protocol.h"
#include "../src/signal_protocol_internal.h"
#include "randombytes/randombytes.h"
#include <iostream>

#include <openssl/opensslv.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/rand.h>
#include <openssl/sha.h>
#include <stdbool.h>

signal_context *global_context;

static void hex_dump(const uint8_t *data, size_t size)
{
  for (size_t i = 0; i < size; i++) {
    bool last = i + 1 == size;
    printf("%02x%c", (unsigned int)data[i], last ? '\n' : ':');
  }
}

int test_random_generator(uint8_t *data, size_t len, void *user_data)
{
  if(randombytes(data, len)) {
    return 0;
  }
  else {
    return SG_ERR_UNKNOWN;
  }
}

int main(int argc, char **argv) {

  int result;
  result = signal_context_create(&global_context, 0);

  global_context->crypto_provider.random_func = test_random_generator;


  size_t i;
  size_t r;

  uint8_t publicKey[] = {
      0x05,
      0xf7, 0xd6, 0x8d, 0xa9, 0x19, 0x33, 0x1a, 0x9b,
      0xd5, 0x2a, 0x4f, 0xf8, 0x1c, 0x8c, 0x74, 0x0e,
      0x6f, 0x76, 0x63, 0x52, 0x24, 0x89, 0x5d, 0x4c,
      0x37, 0x1e, 0x68, 0xd5, 0xc7, 0xf3, 0x10, 0x32};
  uint8_t privateKey[] = {
      0xc8, 0xdf, 0x2f, 0x9e, 0x7f, 0x0c, 0xe8, 0x83,
      0x33, 0xcd, 0x6e, 0xf7, 0x3c, 0x5b, 0xbc, 0xdc,
      0x75, 0x46, 0xa1, 0x65, 0xfc, 0x5a, 0x62, 0xf6,
      0xba, 0x24, 0xe4, 0x89, 0x03, 0x29, 0x1d, 0xb0};
  uint8_t message[] = {
      0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
      0x75, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x2e};
  uint8_t vrf[] = {
      0x45, 0xDC, 0x7B, 0x81, 0x6B, 0x01, 0xB3, 0x6C,
      0xFA, 0x16, 0x45, 0xDC, 0xAE, 0x8A, 0xC9, 0xBC,
      0x8E, 0x52, 0x3C, 0xD8, 0x6D, 0x00, 0x7D, 0x19,
      0x95, 0x3F, 0x03, 0xE7, 0xD5, 0x45, 0x54, 0xA0
  };

  hex_dump(publicKey, sizeof(publicKey));
  hex_dump(privateKey, sizeof(privateKey));
  hex_dump(message, sizeof(message));
  hex_dump(vrf, sizeof(vrf));

//  int result;
  ec_public_key *public_key = 0;
  ec_private_key *private_key = 0;
  signal_buffer *signature = 0;
  signal_buffer *vrf_output = 0;

  result = curve_decode_point(&public_key, publicKey, sizeof(publicKey), global_context);
  printf("curve_decode_point: %d\n", result);

  result = curve_decode_private_point(&private_key, privateKey, sizeof(privateKey), global_context);
  printf("curve_decode_private_point: %d\n", result);

  result = curve_calculate_vrf_signature(global_context, &signature,
                                         private_key, message, sizeof(message));
  printf("curve_calculate_vrf_signature: %d\n", result);


//  message[r % 2] ^= 0x01;

  result = curve_verify_vrf_signature(global_context, &vrf_output,
                                      public_key, message, sizeof(message),
                                      signal_buffer_data(signature), signal_buffer_len(signature));
  printf("curve_verify_vrf_signature: %d\n", result);

  printf("signal_buffer_len(vrf_output): %d\n", signal_buffer_len(vrf_output));
  printf("sizeof(vrf): %d\n", sizeof(vrf));
  printf("sizeof(signature): %d\n", sizeof(signature));
  printf("signal_buffer_len(signature): %d\n", signal_buffer_len(signature));
  printf("sizeof(signature): %d\n", sizeof(signature));
  printf("memcmp(signal_buffer_data(vrf_output), vrf, sizeof(vrf)): %d\n", memcmp(signal_buffer_data(vrf_output), vrf, sizeof(vrf)));
//  ck_assert_int_eq(signal_buffer_len(vrf_output), sizeof(vrf));

  /* Cleanup */
  signal_buffer_free(signature);
  signal_buffer_free(vrf_output);
  SIGNAL_UNREF(public_key);
  SIGNAL_UNREF(private_key);

  printf("Blabla 2: %d", result);
  return 0;
}

podspec needed

Hi all,

It would be nice to have a podspec file to make it easy to integrate using CocoaPods.

Invalid PreKey bundles and malformed PreKeyMessages

I have:

  • searched open and closed issues for duplicates

Bug description

After updating to the latest master branch of libsignal-protocol-c I have seen a huge increase in the number of invalid bundles generated, and bad MACs on messages. I cannot definitely point the problem at this library and not some (yet to be determined) external cause, but I have a strong feeling that something is amiss. I will be rolling back to an earlier version to see if this helps, but this problem may have existed in the past (explaining some user reports) and I wasn't able to reproduce it as reliably.

First I thought that I would simply check if the generated bundle was invalid, so I added a utility function that borrowed the sanity checks from session_builder_process_pre_key_bundle.

/** This will do a rough check if bundle is considered valid */
- (BOOL) checkValidity:(NSError **)error {
    // session_builder.c:191
    // int session_builder_process_pre_key_bundle(session_builder *builder, session_pre_key_bundle *bundle)
    

Bundles stored for any period of time seem to fail validation, which wasn't the case before updating to latest master. Clients would occasionally publish invalid bundles to the server, preventing sessions from being created, so bundles are a lot fresher lately.

Which brings me to the next problem, that I hadn't seen before. Now I am very frequently seeing "Bad MAC" errors being returned from libsignal-protocol-c when receiving PreKeyMessages. My theory was that they were caused by starting a session with an invalid bundle, but now that invalid bundles are never uploaded to the server, I am not sure what is happening.

One question I just realized that may be related. If the SignedPreKey changes, do all existing PreKeys need to be invalided as well?

The biggest problem is that I can't tell from the outgoing side that the session is corrupted, so once it gets broken it never is able to fix itself, and there is no way to know the receiving side couldn't decrypt other than lack of delivery receipt.

Steps to reproduce

I don't have a unit test strictly limited to libsignal-protocol-c itself, so I know it is difficult to accept a bug report of nebulous origin, but I really haven't been able to determine a cause for an increase in these errors other than updating the library.

Here is a failing unit test that used to pass before updating the library and adding additional bundle validation checks: https://github.com/ChatSecure/ChatSecure-iOS/blob/78d0898c1d2103ee3127760260c3d9ec80869632/ChatSecureTests/OTROmemoStorageTest.swift#L174

Actual result: Generated bundles are sometimes corrupted. Message MACs are sometimes broken.
Expected result: Bundles and message MACs always validate.

Link to logs

2017-04-25 15:47:33.681 ChatSecure[95818:6196770] SignalProtocol (2): Bad MAC
2017-04-25 15:47:33.681 ChatSecure[95818:6196770] SignalProtocol (1): Message mac not verified
2017-04-25 15:47:33.686 ChatSecure[95818:6196770] SignalProtocol (2): Bad MAC
2017-04-25 15:47:33.686 ChatSecure[95818:6196770] SignalProtocol (1): Message mac not verified
2017-04-25 15:47:33.687 ChatSecure[95818:6196770] SignalProtocol (1): No valid sessions

How to get serialized sender key distribution message?

After using group_session_builder to create a group session for sending messages, how do we get the serialized copy of the resulting sender_key_distribution_message so that we can send it to each member of the group?

In protocol.h, we see a function named sender_key_message_get_ciphertext but not one named sender_key_distribution_message_get_ciphertext.

Note: We posted this question on the Open Whisper Systems Community discussion forum but didn't get a response.

Can't build shared library

Error when linking shared library on Linux x86_64

$ cmake -DBUILD_SHARED_LIBS=ON ..
...
$ make
...
[100%] Linking C shared library libsignal-protocol-c.so
/usr/bin/ld: curve25519/CMakeFiles/curve25519.dir/ed25519/fe_isnonzero.c.o: relocation R_X86_64_32 against `.bss' can not be used when making a shared object; recompile with -fPIC
curve25519/CMakeFiles/curve25519.dir/ed25519/fe_isnonzero.c.o: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
src/CMakeFiles/signal-protocol-c.dir/build.make:706: recipe for target 'src/libsignal-protocol-c.so' failed
make[2]: *** [src/libsignal-protocol-c.so] Error 1
CMakeFiles/Makefile2:91: recipe for target 'src/CMakeFiles/signal-protocol-c.dir/all' failed
make[1]: *** [src/CMakeFiles/signal-protocol-c.dir/all] Error 2
Makefile:127: recipe for target 'all' failed
make: *** [all] Error 2

Fails to compile on SmartOS (Illumos/OpenSolaris)

src/vpool.h includes the non-standard <sys/cdefs.h>, which is a Linux and glibc-specific header not found on other platforms such as Solaris and its derivatives.

The following patch fixes this:

diff --git a/src/vpool.h b/src/vpool.h
index 0eb714c..04707cb 100644
--- a/src/vpool.h
+++ b/src/vpool.h
@@ -21,7 +21,7 @@
 #define _VPOOL_H_
 
 #include <sys/types.h>
-#ifndef _WINDOWS
+#if !defined(_WINDOWS) && !defined(__sun__)
 #include <sys/cdefs.h>
 #else
 #ifdef __cplusplus

Integer type confusion and unchecked pointer in test_encrypt() (64-bit systems)

In test_encrypt() and test_decrypt() (defined in test_common.c), the following line passes int arguments (out_len + final_len) where signal_buffer_create() expects a size_t:

*output = signal_buffer_create(out_buf, out_len + final_len);

In
https://github.com/WhisperSystems/libsignal-protocol-c/blob/master/tests/test_common.c#L332
and
https://github.com/WhisperSystems/libsignal-protocol-c/blob/master/tests/test_common.c#L406

On 64-bit systems where size_t is 64-bit and int is 32-bit this may yield an incorrect size_t value, then the malloc() within signal_buffer_create() will fail, giving a NULL *output, which won't be detected. Null dereference will ensue.

For example, if group_cipher_encrypt() uses test_encrypt() as encrypt_func, it will crash when called with a plaintext_len equal to 0x7ffffff2.

make internal protobuf-c optional

Most Linux distributions will still have protobuf-c, so the system one shout be uses instant the internal one. And the internal only if the system don't provide it.

Occasionally failing signature verification

I have:

  • searched open and closed issues for duplicates

Bug description

Several users reported that they cannot build a session because of a failing signature verification.
Each time, the signature/bundle was created by the Android application Conversations, and could still be verified by other users of Conversations.
It seems to be quite rare as it only was reported to me 3 times, therefore I suspect a weird corner case incompatibility between the C and Java implementations.

I asked the last user this happened to for some more information and was able to reproduce it.

The exact error happens inside session_builder_process_pre_key_bundle, returning SG_ERR_INVALID_KEY.

Steps to reproduce

  • Identity Key is BYWn3EDjfglMKjah4LmSs7KIttsPHK3Qdb58cEaEOLgD
  • Signed Pre Key is BTHuga+hZTPOq7aRAWL0fLljxTWexm+3h6VOKMDjQ/9e
  • Signature is CbQkjmEK+nyT+urIj5WOZzQkqvno3qilQhV+ZFS8PehoXUMkEvyF6kvDNHyo5j1s6gaFq5a0eRtP /M9CgEiFCg==

(All in base64.)

fingerprint_generator_create_display_string free()'s local variable

  char *displayable_local = 0;
  result = fingerprint_generator_create_display_string(generator, &displayable_local,
                  local_stable_identifier, local_identity_key);
int fingerprint_generator_create_display_string(fingerprint_generator *generator,
    char **display_string, const char *stable_identifier, ec_public_key *identity_key)
...
  if(display_string) {
      free(display_string);

did you mean

  if(*display_string) {
      free(*display_string);

?

Intermittent failing encryption/decryption

I have a java client producing SignalMessage and sending them to an iOS client.

I have a strange situation where after having successfully processed/decrypted the PreSignalMessage, calling encryptData in the iOS app to create a response message fails with a 'Code 0 - Unknown error'

After some investigation, I found that if simply repeating the call to SignalSessionCipher.encryptData step recursively it will eventually succeed.

Sometimes it works on the first invocation but other times it can take 10-15 attempts.

(With java to java clients I do not see this issue)

Can anyone shed some light on this or point me in the direction of how to isolate the problem?

Compilation warning with DEBUG_REFCOUNT

[ 48%] Building C object libsignal-protocol-c/src/CMakeFiles/signal-protocol-c.dir/signal_protocol.c.o
/home/taurus/develop/libsignal-protocol-qt/libsignal-protocol-c/src/signal_protocol.c: In function 'signal_type_ref_count':
/home/taurus/develop/libsignal-protocol-qt/libsignal-protocol-c/src/signal_protocol.c:75:12: warning: conversion to 'int' from 'unsigned int' may change the sign of the result [-Wsign-conversion]
     return instance->ref_count;
            ^

signal_type_ref_count returns int here but signal_type_base::ref_count is unsigned int here.

Pass signal_address instead of name to identity_key_store.save_identity

We'd like the device_id in addition to the name that's on the signal_address in the save_identity/is_trusted_identity callbacks.

To maintain backwards compatibility we could do something like this:

//
// signal_protocol.h
//

// existing
int signal_protocol_identity_save_identity(signal_protocol_store_context *context, const char *name, size_t name_len, ec_public_key *identity_key);
int signal_protocol_identity_is_trusted_identity(signal_protocol_store_context *context, const char *name, size_t name_len, ec_public_key *identity_key);

// proposed addition
int signal_protocol_identity_save_identity_address(signal_protocol_store_context *context, const signal_protocol_address *address, ec_public_key *identity_key);
int signal_protocol_identity_is_trusted_identity_address(signal_protocol_store_context *context, const signal_protocol_address *address, ec_public_key *identity_key);

typedef struct signal_protocol_identity_key_store {
...
// existing
    int (*save_identity)(const char *name, size_t name_len, uint8_t *key_data, size_t key_len, void *user_data);
    int (*is_trusted_identity)(const char *name, size_t name_len, uint8_t *key_data, size_t key_len, void *user_data);

// proposed addition

    int (*save_identity_address)(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data);
    int (*is_trusted_identity_address)(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data);
...
} signal_protocol_identity_key_store;

GPG signatures for source validation

As we all know, today more than ever before, it is crucial to be able to trust
our computing environments. One of the main difficulties that package
maintainers of Linux distributions face, is the difficulty to verify the
authenticity and the integrity of the source code.

The Arch Linux team would appreciate it if you would provide us GPG signatures
in order to verify easily and quickly your source code releases.

Overview of the required tasks:

  • Create and/or use a 4096-bit RSA keypair for the file signing.
  • Keep your key secret, use a strong unique passphrase for the key.
  • Upload the public key to a key server and publish the full fingerprint.
  • Sign every new git commit and tag.
  • Create signed compressed (xz --best) release archives
  • Upload a strong message digest (sha512) of the archive
  • Configure https for your download server

GPGit is meant to bring GPG to the masses.
It is not only a shell script that automates the process of creating new signed
git releases with GPG but also comes with this step-by-step readme guide for
learning how to use GPG.

Additional Information:

Please rethink your decision in #60 .
Thanks in advance.

Add option for PIC in static lib

I want to statically link this library into a shared library (it is actually a libpurple plugin, and I believe this is not an uncommon format for plugins in general).
In order to achieve this as it is, I added -fPIC to the makefile flags by hand, so I can't just reference this library e.g. by adding it as a submodule.

Could I ask you to add a target that generates PIC in an .a for more linking options? It would be greatly appreciated.
If such an option automatically exists through CMake (somehow), I would like to ask to put the different CMake options on the README - I dug through old closed issues to find the option for building a shared lib.

check for errors in session_builder.c

these can fail for example if out of memory:
line 579: symmetric_axolotl_parameters_create
line 596: ratcheting_session_symmetric_initialize
line 705: ratcheting_session_symmetric_initialize

Decrypt own messages

I have:

  • searched open and closed issues for duplicates

Bug description

We are using https://github.com/WhisperSystems/libsignal-protocol-c/ in our chat application to encrypt messages end to end. We have an use case where we want to store encrypted messages on the server and retrieve them in the chat app.

In order to display the messages in the chat interface, we need to decrypt them. We are able to decrypt the messages the user received but not the messages which were sent by the user.

It is looking for the private key of the receiving user during decryption which is not available. Can you let us know if we are doing something wrong, can you help us resolve the issue.

no method to create a new ec_public_key

The ec_public_key structure is defined inside curve.c

It appears that the only way to obtain a ec_public_key is by generating one using the curve functions or loading from a store.

How is the client suppose to load new ec_public_key received from a webserver?
The structure is private so I cannot malloc it outside afaik.

Versioned library

I want to package this project for openSUSE.

Unfortunately I saw that you only create a .so file and don't seem to use library versioning. Any reason for that? Could that be changed?

PQC

Please consider exploring possible use of post-quantum crypto algorithms like NTRU and SIDH for signal protocol.

Int overflow in test_encrypt() (32-bit systems)

In test_encrypt() (defined in test_common.c) the following malloc() will overflow on 32-bit systems if plaintext_len is greater than SIZE_MAX - EVP_MAX_BLOCK_LENGTH:

out_buf = malloc(sizeof(uint8_t) * (plaintext_len + EVP_MAX_BLOCK_LENGTH));

Similar issue in test_decrypt.

Potential integer overflow in Axolotl

This issue refers to the Axolotl allocation functions in https://github.com/WhisperSystems/libsignal-protocol-c/blob/master/src/axolotl.c.

IIUC axolotl_buffer_alloc checks for integer overflow before malloc (axolotl.c:80-82):

if(len > (SIZE_MAX - sizeof(struct axolotl_buffer)) / sizeof(uint8_t)) {
    return 0;
}

Then in axolotl_buffer_append we have a calculation of the currently allocated size that should never overflow (axolotl.c:10):

size_t previous_alloc = sizeof(struct axolotl_buffer) + (sizeof(uint8_t) * previous_size);

However, it seems to me the immediately following calculation of the length to pass to realloc can overflow (axolotl.c:111):

axolotl_buffer *tmp_buffer = realloc(buffer, previous_alloc + (sizeof(uint8_t) * len));

The effect of this would be that the memcpy that follows this does an out-of-bounds write.

I haven't checked yet whether this issue is exploitable as I just wanted to double check I was understanding things correctly. However, it looks like the call in protocol.c could trigger this with a long enough cipher text. Is there an external reason for why this execution flow is not possible?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.