Commit e643d623 authored by Derek Konigsberg's avatar Derek Konigsberg

Support for numeric fingerprint generation

This is a port of the features added to libaxolotl-java
by the following commits:
v1.3.4-7-g0620b76
v1.3.4-8-g074d079
parent 4c186748
package textsecure;
option java_package = "org.whispersystems.libaxolotl.fingerprint";
option java_outer_classname = "FingerprintProtos";
message FingerprintData {
optional bytes publicKey = 1;
optional bytes identifier = 2;
}
message CombinedFingerprint {
optional uint32 version = 1;
optional FingerprintData localFingerprint = 2;
optional FingerprintData remoteFingerprint = 3;
}
\ No newline at end of file
all:
protoc-c --c_out=../src/ WhisperTextProtocol.proto LocalStorageProtocol.proto
protoc-c --c_out=../src/ WhisperTextProtocol.proto LocalStorageProtocol.proto FingerprintProtocol.proto
......@@ -10,6 +10,7 @@ include_directories(
set(protobuf_SRCS
LocalStorageProtocol.pb-c.c
WhisperTextProtocol.pb-c.c
FingerprintProtocol.pb-c.c
)
set(axolotl_SRCS
......@@ -49,6 +50,8 @@ set(axolotl_SRCS
group_session_builder.h
group_cipher.c
group_cipher.h
fingerprint.c
fingerprint.h
)
add_subdirectory(curve25519)
......@@ -80,6 +83,7 @@ INSTALL(
sender_key_record.h
group_session_builder.h
group_cipher.h
fingerprint.h
DESTINATION include/axolotl
)
......
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: FingerprintProtocol.proto */
/* Do not generate deprecated warnings for self */
#ifndef PROTOBUF_C__NO_DEPRECATED
#define PROTOBUF_C__NO_DEPRECATED
#endif
#include "FingerprintProtocol.pb-c.h"
void textsecure__fingerprint_data__init
(Textsecure__FingerprintData *message)
{
static Textsecure__FingerprintData init_value = TEXTSECURE__FINGERPRINT_DATA__INIT;
*message = init_value;
}
size_t textsecure__fingerprint_data__get_packed_size
(const Textsecure__FingerprintData *message)
{
assert(message->base.descriptor == &textsecure__fingerprint_data__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t textsecure__fingerprint_data__pack
(const Textsecure__FingerprintData *message,
uint8_t *out)
{
assert(message->base.descriptor == &textsecure__fingerprint_data__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t textsecure__fingerprint_data__pack_to_buffer
(const Textsecure__FingerprintData *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &textsecure__fingerprint_data__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
Textsecure__FingerprintData *
textsecure__fingerprint_data__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (Textsecure__FingerprintData *)
protobuf_c_message_unpack (&textsecure__fingerprint_data__descriptor,
allocator, len, data);
}
void textsecure__fingerprint_data__free_unpacked
(Textsecure__FingerprintData *message,
ProtobufCAllocator *allocator)
{
assert(message->base.descriptor == &textsecure__fingerprint_data__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
void textsecure__combined_fingerprint__init
(Textsecure__CombinedFingerprint *message)
{
static Textsecure__CombinedFingerprint init_value = TEXTSECURE__COMBINED_FINGERPRINT__INIT;
*message = init_value;
}
size_t textsecure__combined_fingerprint__get_packed_size
(const Textsecure__CombinedFingerprint *message)
{
assert(message->base.descriptor == &textsecure__combined_fingerprint__descriptor);
return protobuf_c_message_get_packed_size ((const ProtobufCMessage*)(message));
}
size_t textsecure__combined_fingerprint__pack
(const Textsecure__CombinedFingerprint *message,
uint8_t *out)
{
assert(message->base.descriptor == &textsecure__combined_fingerprint__descriptor);
return protobuf_c_message_pack ((const ProtobufCMessage*)message, out);
}
size_t textsecure__combined_fingerprint__pack_to_buffer
(const Textsecure__CombinedFingerprint *message,
ProtobufCBuffer *buffer)
{
assert(message->base.descriptor == &textsecure__combined_fingerprint__descriptor);
return protobuf_c_message_pack_to_buffer ((const ProtobufCMessage*)message, buffer);
}
Textsecure__CombinedFingerprint *
textsecure__combined_fingerprint__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data)
{
return (Textsecure__CombinedFingerprint *)
protobuf_c_message_unpack (&textsecure__combined_fingerprint__descriptor,
allocator, len, data);
}
void textsecure__combined_fingerprint__free_unpacked
(Textsecure__CombinedFingerprint *message,
ProtobufCAllocator *allocator)
{
assert(message->base.descriptor == &textsecure__combined_fingerprint__descriptor);
protobuf_c_message_free_unpacked ((ProtobufCMessage*)message, allocator);
}
static const ProtobufCFieldDescriptor textsecure__fingerprint_data__field_descriptors[2] =
{
{
"publicKey",
1,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BYTES,
offsetof(Textsecure__FingerprintData, has_publickey),
offsetof(Textsecure__FingerprintData, publickey),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"identifier",
2,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_BYTES,
offsetof(Textsecure__FingerprintData, has_identifier),
offsetof(Textsecure__FingerprintData, identifier),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned textsecure__fingerprint_data__field_indices_by_name[] = {
1, /* field[1] = identifier */
0, /* field[0] = publicKey */
};
static const ProtobufCIntRange textsecure__fingerprint_data__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 2 }
};
const ProtobufCMessageDescriptor textsecure__fingerprint_data__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"textsecure.FingerprintData",
"FingerprintData",
"Textsecure__FingerprintData",
"textsecure",
sizeof(Textsecure__FingerprintData),
2,
textsecure__fingerprint_data__field_descriptors,
textsecure__fingerprint_data__field_indices_by_name,
1, textsecure__fingerprint_data__number_ranges,
(ProtobufCMessageInit) textsecure__fingerprint_data__init,
NULL,NULL,NULL /* reserved[123] */
};
static const ProtobufCFieldDescriptor textsecure__combined_fingerprint__field_descriptors[3] =
{
{
"version",
1,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_UINT32,
offsetof(Textsecure__CombinedFingerprint, has_version),
offsetof(Textsecure__CombinedFingerprint, version),
NULL,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"localFingerprint",
2,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_MESSAGE,
0, /* quantifier_offset */
offsetof(Textsecure__CombinedFingerprint, localfingerprint),
&textsecure__fingerprint_data__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
{
"remoteFingerprint",
3,
PROTOBUF_C_LABEL_OPTIONAL,
PROTOBUF_C_TYPE_MESSAGE,
0, /* quantifier_offset */
offsetof(Textsecure__CombinedFingerprint, remotefingerprint),
&textsecure__fingerprint_data__descriptor,
NULL,
0, /* flags */
0,NULL,NULL /* reserved1,reserved2, etc */
},
};
static const unsigned textsecure__combined_fingerprint__field_indices_by_name[] = {
1, /* field[1] = localFingerprint */
2, /* field[2] = remoteFingerprint */
0, /* field[0] = version */
};
static const ProtobufCIntRange textsecure__combined_fingerprint__number_ranges[1 + 1] =
{
{ 1, 0 },
{ 0, 3 }
};
const ProtobufCMessageDescriptor textsecure__combined_fingerprint__descriptor =
{
PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC,
"textsecure.CombinedFingerprint",
"CombinedFingerprint",
"Textsecure__CombinedFingerprint",
"textsecure",
sizeof(Textsecure__CombinedFingerprint),
3,
textsecure__combined_fingerprint__field_descriptors,
textsecure__combined_fingerprint__field_indices_by_name,
1, textsecure__combined_fingerprint__number_ranges,
(ProtobufCMessageInit) textsecure__combined_fingerprint__init,
NULL,NULL,NULL /* reserved[123] */
};
/* Generated by the protocol buffer compiler. DO NOT EDIT! */
/* Generated from: FingerprintProtocol.proto */
#ifndef PROTOBUF_C_FingerprintProtocol_2eproto__INCLUDED
#define PROTOBUF_C_FingerprintProtocol_2eproto__INCLUDED
#include <protobuf-c/protobuf-c.h>
PROTOBUF_C__BEGIN_DECLS
#if PROTOBUF_C_VERSION_NUMBER < 1000000
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
#elif 1001001 < PROTOBUF_C_MIN_COMPILER_VERSION
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
#endif
typedef struct _Textsecure__FingerprintData Textsecure__FingerprintData;
typedef struct _Textsecure__CombinedFingerprint Textsecure__CombinedFingerprint;
/* --- enums --- */
/* --- messages --- */
struct _Textsecure__FingerprintData
{
ProtobufCMessage base;
protobuf_c_boolean has_publickey;
ProtobufCBinaryData publickey;
protobuf_c_boolean has_identifier;
ProtobufCBinaryData identifier;
};
#define TEXTSECURE__FINGERPRINT_DATA__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&textsecure__fingerprint_data__descriptor) \
, 0,{0,NULL}, 0,{0,NULL} }
struct _Textsecure__CombinedFingerprint
{
ProtobufCMessage base;
protobuf_c_boolean has_version;
uint32_t version;
Textsecure__FingerprintData *localfingerprint;
Textsecure__FingerprintData *remotefingerprint;
};
#define TEXTSECURE__COMBINED_FINGERPRINT__INIT \
{ PROTOBUF_C_MESSAGE_INIT (&textsecure__combined_fingerprint__descriptor) \
, 0,0, NULL, NULL }
/* Textsecure__FingerprintData methods */
void textsecure__fingerprint_data__init
(Textsecure__FingerprintData *message);
size_t textsecure__fingerprint_data__get_packed_size
(const Textsecure__FingerprintData *message);
size_t textsecure__fingerprint_data__pack
(const Textsecure__FingerprintData *message,
uint8_t *out);
size_t textsecure__fingerprint_data__pack_to_buffer
(const Textsecure__FingerprintData *message,
ProtobufCBuffer *buffer);
Textsecure__FingerprintData *
textsecure__fingerprint_data__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void textsecure__fingerprint_data__free_unpacked
(Textsecure__FingerprintData *message,
ProtobufCAllocator *allocator);
/* Textsecure__CombinedFingerprint methods */
void textsecure__combined_fingerprint__init
(Textsecure__CombinedFingerprint *message);
size_t textsecure__combined_fingerprint__get_packed_size
(const Textsecure__CombinedFingerprint *message);
size_t textsecure__combined_fingerprint__pack
(const Textsecure__CombinedFingerprint *message,
uint8_t *out);
size_t textsecure__combined_fingerprint__pack_to_buffer
(const Textsecure__CombinedFingerprint *message,
ProtobufCBuffer *buffer);
Textsecure__CombinedFingerprint *
textsecure__combined_fingerprint__unpack
(ProtobufCAllocator *allocator,
size_t len,
const uint8_t *data);
void textsecure__combined_fingerprint__free_unpacked
(Textsecure__CombinedFingerprint *message,
ProtobufCAllocator *allocator);
/* --- per-message closures --- */
typedef void (*Textsecure__FingerprintData_Closure)
(const Textsecure__FingerprintData *message,
void *closure_data);
typedef void (*Textsecure__CombinedFingerprint_Closure)
(const Textsecure__CombinedFingerprint *message,
void *closure_data);
/* --- services --- */
/* --- descriptors --- */
extern const ProtobufCMessageDescriptor textsecure__fingerprint_data__descriptor;
extern const ProtobufCMessageDescriptor textsecure__combined_fingerprint__descriptor;
PROTOBUF_C__END_DECLS
#endif /* PROTOBUF_C_FingerprintProtocol_2eproto__INCLUDED */
......@@ -10,7 +10,7 @@ PROTOBUF_C__BEGIN_DECLS
#if PROTOBUF_C_VERSION_NUMBER < 1000000
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
#elif 1000002 < PROTOBUF_C_MIN_COMPILER_VERSION
#elif 1001001 < PROTOBUF_C_MIN_COMPILER_VERSION
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
#endif
......
......@@ -10,7 +10,7 @@ PROTOBUF_C__BEGIN_DECLS
#if PROTOBUF_C_VERSION_NUMBER < 1000000
# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers.
#elif 1000002 < PROTOBUF_C_MIN_COMPILER_VERSION
#elif 1001001 < PROTOBUF_C_MIN_COMPILER_VERSION
# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c.
#endif
......@@ -57,6 +57,9 @@ struct _Textsecure__PreKeyWhisperMessage
ProtobufCBinaryData basekey;
protobuf_c_boolean has_identitykey;
ProtobufCBinaryData identitykey;
/*
* WhisperMessage
*/
protobuf_c_boolean has_message;
ProtobufCBinaryData message;
};
......
......@@ -385,6 +385,13 @@ void axolotl_hmac_sha256_cleanup(axolotl_context *context, void *hmac_context)
context->crypto_provider.hmac_sha256_cleanup_func(hmac_context, context->crypto_provider.user_data);
}
int axolotl_sha512_digest(axolotl_context *context, axolotl_buffer **output, const uint8_t *data, size_t data_len)
{
assert(context);
assert(context->crypto_provider.sha512_digest_func);
return context->crypto_provider.sha512_digest_func(output, data, data_len, context->crypto_provider.user_data);
}
int axolotl_encrypt(axolotl_context *context,
axolotl_buffer **output,
int cipher,
......
......@@ -35,6 +35,8 @@ extern "C" {
#define AX_ERR_STALE_KEY_EXCHANGE -1009
#define AX_ERR_UNTRUSTED_IDENTITY -1010
#define AX_ERR_INVALID_PROTO_BUF -1100
#define AX_ERR_FP_VERSION_MISMATCH -1200
#define AX_ERR_FP_IDENT_MISMATCH -1201
/*
* Minimum negative error code value that this library may use.
......@@ -276,6 +278,17 @@ typedef struct axolotl_crypto_provider {
*/
void (*hmac_sha256_cleanup_func)(void *hmac_context, void *user_data);
/**
* Callback for a SHA512 message digest implementation.
* This function is currently only used by the fingerprint generator.
*
* @param output buffer to be allocated and populated with the ciphertext
* @param data pointer to the data
* @param data_len length of the data
* @return 0 on success, negative on failure
*/
int (*sha512_digest_func)(axolotl_buffer **output, const uint8_t *data, size_t data_len, void *user_data);
/**
* Callback for an AES encryption implementation.
*
......
......@@ -34,6 +34,8 @@ int axolotl_hmac_sha256_update(axolotl_context *context, void *hmac_context, con
int axolotl_hmac_sha256_final(axolotl_context *context, void *hmac_context, axolotl_buffer **output);
void axolotl_hmac_sha256_cleanup(axolotl_context *context, void *hmac_context);
int axolotl_sha512_digest(axolotl_context *context, axolotl_buffer **output, const uint8_t *data, size_t data_len);
int axolotl_encrypt(axolotl_context *context,
axolotl_buffer **output,
int cipher,
......
......@@ -118,6 +118,14 @@ typedef struct sender_key_record sender_key_record;
typedef struct group_session_builder group_session_builder;
typedef struct group_cipher group_cipher;
/*
* Fingerprint types
*/
typedef struct fingerprint fingerprint;
typedef struct displayable_fingerprint displayable_fingerprint;
typedef struct scannable_fingerprint scannable_fingerprint;
typedef struct fingerprint_generator fingerprint_generator;
#ifdef __cplusplus
}
#endif
......
This diff is collapsed.
#ifndef FINGERPRINT_H
#define FINGERPRINT_H
#include "axolotl_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Construct a fingerprint generator for 60 digit numerics.
*
* @param generator set to a freshly allocated generator instance
* @param iterations The number of internal iterations to perform in the process of
* generating a fingerprint. This needs to be constant, and synchronized
* across all clients.
*
* The higher the iteration count, the higher the security level:
*
* - 1024 ~ 109.7 bits
* - 1400 > 110 bits
* - 5200 > 112 bits
* @param global_context the global library context
* @return 0 on success, or negative on failure
*/
int fingerprint_generator_create(fingerprint_generator **generator, int iterations, axolotl_context *global_context);
/**
* Generate a scannable and displayble fingerprint.
*
* @param local_stable_identifier The client's "stable" identifier.
* @param local_identity_key The client's identity key.
* @param remote_stable_identifier The remote party's "stable" identifier.
* @param remote_identity_key The remote party's identity key.
* @param fingerprint Set to a freshly allocated unique fingerprint for this conversation
* @return 0 on success, or negative on failure
*/
int fingerprint_generator_create_for(fingerprint_generator *generator,
const char *local_stable_identifier, ec_public_key *local_identity_key,
const char *remote_stable_identifier, ec_public_key *remote_identity_key,
fingerprint **fingerprint_val);
void fingerprint_generator_free(fingerprint_generator *generator);
int fingerprint_create(fingerprint **fingerprint_val, displayable_fingerprint *displayable, scannable_fingerprint *scannable);
displayable_fingerprint *fingerprint_get_displayable(fingerprint *fingerprint_val);
scannable_fingerprint *fingerprint_get_scannable(fingerprint *fingerprint_val);
void fingerprint_destroy(axolotl_type_base *type);
int displayable_fingerprint_create(displayable_fingerprint **displayable, const char *local_fingerprint, const char *remote_fingerprint);
const char *displayable_fingerprint_local(displayable_fingerprint *displayable);
const char *displayable_fingerprint_remote(displayable_fingerprint *displayable);
const char *displayable_fingerprint_text(displayable_fingerprint *displayable);
void displayable_fingerprint_destroy(axolotl_type_base *type);
int scannable_fingerprint_create(scannable_fingerprint **scannable,
int version,
const char *local_stable_identifier, ec_public_key *local_identity_key,
const char *remote_stable_identifier, ec_public_key *remote_identity_key);
int scannable_fingerprint_serialize(axolotl_buffer **buffer, const scannable_fingerprint *scannable);
int scannable_fingerprint_deserialize(scannable_fingerprint **scannable, const uint8_t *data, size_t len, axolotl_context *global_context);
/**
* Compare a scanned QR code with what we expect.
* @param scannable The local scannable data
* @param other_scannable The data from the scanned code
* @retval 1 if the scannable codes match
* @retval 0 if the scannable codes do not match
* @retval AX_ERR_FP_VERSION_MISMATCH if the scanned fingerprint is the wrong version
* @retval AX_ERR_FP_IDENT_MISMATCH if the scanned fingerprint is for the wrong stable identifier
*/
int scannable_fingerprint_compare(scannable_fingerprint *scannable, const scannable_fingerprint *other_scannable);
void scannable_fingerprint_destroy(axolotl_type_base *type);
#ifdef __cplusplus
}
#endif
#endif /* FINGERPRINT_H */
......@@ -75,3 +75,7 @@ add_test(test_sender_key_record ${CMAKE_CURRENT_BINARY_DIR}/test_sender_key_reco
add_executable(test_group_cipher test_group_cipher.c ${common_SRCS})
target_link_libraries(test_group_cipher ${LIBS})
add_test(test_group_cipher ${CMAKE_CURRENT_BINARY_DIR}/test_group_cipher)
add_executable(test_fingerprint test_fingerprint.c ${common_SRCS})
target_link_libraries(test_fingerprint ${LIBS})
add_test(test_fingerprint ${CMAKE_CURRENT_BINARY_DIR}/test_fingerprint)
......@@ -4,6 +4,7 @@
#include <string.h>
#include <openssl/rand.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <check.h>
#include "axolotl.h"
......@@ -223,6 +224,47 @@ const EVP_CIPHER *aes_cipher(int cipher, size_t key_len)
return 0;
}
int test_sha512_digest_func(axolotl_buffer **output, const uint8_t *data, size_t data_len, void *user_data)
{
int result = 0;
axolotl_buffer *buffer = 0;
SHA512_CTX ctx;
buffer = axolotl_buffer_alloc(SHA512_DIGEST_LENGTH);
if(!buffer) {
result = AX_ERR_NOMEM;
goto complete;
}
result = SHA512_Init(&ctx);
if(!result) {
result = AX_ERR_UNKNOWN;
goto complete;
}
result = SHA512_Update(&ctx, data, data_len);
if(!result) {
result = AX_ERR_UNKNOWN;
goto complete;
}
complete:
if(buffer) {
result = SHA512_Final(axolotl_buffer_data(buffer), &ctx);
if(!result) {
result = AX_ERR_UNKNOWN;
}
}
if(result < 0) {
axolotl_buffer_free(buffer);
}
else {
*output = buffer;
}
return result;
}
int test_encrypt(axolotl_buffer **output,
int cipher,
const uint8_t *key, size_t key_len,
......@@ -379,6 +421,7 @@ void setup_test_crypto_provider(axolotl_context *context)
.hmac_sha256_update_func = test_hmac_sha256_update,
.hmac_sha256_final_func = test_hmac_sha256_final,
.hmac_sha256_cleanup_func = test_hmac_sha256_cleanup,
.sha512_digest_func = test_sha512_digest_func,
.encrypt_func = test_encrypt,
.decrypt_func = test_decrypt,
.user_data = 0
......
......@@ -21,6 +21,7 @@ int test_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_le
int test_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data);
int test_hmac_sha256_final(void *hmac_context, axolotl_buffer **output, void *user_data);
void test_hmac_sha256_cleanup(void *hmac_context, void *user_data);
int test_sha512_digest_func(axolotl_buffer **output, const uint8_t *data, size_t data_len, void *user_data);
int test_encrypt(axolotl_buffer **output,
int cipher,
const uint8_t *key, size_t key_len,
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment