X-Git-Url: https://www.flypig.org.uk/git/?p=libcontrac.git;a=blobdiff_plain;f=src%2Fcontrac.c;h=3ffdebd4352929b3fef529237f4b82fef0f944e1;hp=ed925cbb74a54bbe1aade2f076c5c69b28e1db08;hb=f8c83387f5abffa94e59332382441a71f5b95545;hpb=37e2b9b3573a05390190a25052ceb23d8dab0132 diff --git a/src/contrac.c b/src/contrac.c index ed925cb..3ffdebd 100644 --- a/src/contrac.c +++ b/src/contrac.c @@ -1,19 +1,31 @@ -/** \ingroup contrac +/** \ingroup KeyGeneration * @file - * @author David Llewellyn-Jones + * @author David Llewellyn-Jones * @version $(VERSION) * * @section LICENSE * + * Copyright David Llewellyn-Jones, 2020 + * Released under the GPLv2. * - * - * @brief + * @brief Core Contact Tracing functionality * @section DESCRIPTION * + * This class provides the core Contact Tracing functionality. It provides an + * interfaces for: + * 1. Generating a random Tracing Key. + * 2. Generating a Daily Tracing Key based on the current day number. + * 3. Generating a Rolling Proximity Identifier based on the current time + * interval number. * + * Values can be extracted and set in binary or base64 format. * */ +/** \addtogroup KeyGeneration + * @{ + */ + // Includes #include @@ -34,13 +46,49 @@ // Defines +/** + * Inernal flag mask. + * + * When set the flag indicates that the Tracing Key has been correctly + * initialised. + */ #define STATUS_TK (1 << 0) + +/** + * Inernal flag mask. + * + * When set the flag indicates that the Daily Tracing Key has been correctly + * initialised. + */ #define STATUS_DTK (1 << 1) + +/** + * Inernal flag mask. + * + * When set the flag indicates that the Rolling Proximity Identifier has been + * correctly initialised. + */ #define STATUS_RPI (1 << 2) +/** + * Inernal flag mask. + * + * When all of these flags are set it indicates that the structure is fully + * initialised. + * . + */ #define STATUS_INITIALISED (STATUS_TK | STATUS_DTK | STATUS_RPI) // Structures +/** + * @brief The core structure for storing Contact Tracing state. + * + * This is an opaque structure that contains the core state for the library. + * + * This must be passed as the first parameter of every non-static function. + * + * The structure typedef is in contrac.h + */ struct _Contrac { // Tracing key unsigned char tk[TK_SIZE]; @@ -56,6 +104,11 @@ struct _Contrac { // Function definitions +/** + * Create a new instance of the class. + * + * @return The newly created object. + */ Contrac * contrac_new() { Contrac * data; @@ -66,6 +119,11 @@ Contrac * contrac_new() { return data; } +/** + * Delete an instance of the class, freeing up the memory allocated to it. + * + * @param data The instance to free. + */ void contrac_delete(Contrac * data) { if (data) { dtk_delete(data->dtk); @@ -78,6 +136,15 @@ void contrac_delete(Contrac * data) { } } +/** + * Generate a random Contact Tracing Key. + * + * The operation may fail under certain circumstances, such as there being + * insufficient entropy in the system to guarantee a random result. + * + * @param data The context object to work with. + * @return true if the operation completed successfully, false otherwise. + */ bool contrac_generate_tracing_key(Contrac * data) { int result; @@ -94,6 +161,24 @@ bool contrac_generate_tracing_key(Contrac * data) { return (result == 1); } +/** + * Set the current day number. + * + * This will result in a new Daily Tracing Key being generated based on the + * day provided. If neither the Tracing Key nor the day have changed, the DTK + * will remain the same. + * + * The day number is calculated as: + * (Number of Seconds since Epoch) / (60 * 60 * 24) + * + * Which can be caluclated from the current epoch using the + * epoch_to_day_number() function. + * + * The operation may fail if a Tracing Key has yet to be configured. + * + * @param data The context object to work with. + * @return true if the operation completed successfully, false otherwise. + */ bool contrac_set_day_number(Contrac * data, uint32_t day_number) { bool result; @@ -110,6 +195,28 @@ bool contrac_set_day_number(Contrac * data, uint32_t day_number) { return result; } +/** + * Set the current time interval number. + * + * This will result in a new Rolling Proximity Idetifier being generated based + * on the time interval number. If none of the Tracing Key, day nor time + * interval have changed, the RPI will stay the same. + * + * The time interval number is calculated as: + * (Seconds Since Start of DayNumber) / (60 * 10) + * + * and must fall in the interval [0, 143]. + * + * It can be caluclated from the current epoch using the + * epoch_to_time_interval_number() function. + * + * The operation may fail if a Tracing Key or Daily Tracing Key have yet to be + * configured. + * + * @param data The context object to work with. + * @param time_interval_number The time interval number to set. + * @return true if the operation completed successfully, false otherwise. + */ bool contrac_set_time_interval_number(Contrac * data, uint8_t time_interval_number) { bool result; @@ -126,20 +233,82 @@ bool contrac_set_time_interval_number(Contrac * data, uint8_t time_interval_numb return result; } +/** + * Get whether the internal state has been fully configured or not. + * + * The internal state must be fully configured before a Daily Tracing Key or + * Rolling Proximity Identifier can be calculated. This function returns whether + * it is in this state or not. + * + * In order to fully configure the structure, a Tracing Key must either be + * generated using contrac_generate_tracing_key(), or set using either + * contrac_set_tracing_key() or contrac_set_tracing_key_base64(). + * + * In addition the day number and time interval number must be set using + * contrac_set_day_number() and contrac_set_time_interval_number() respectively. + * + * Alternatively these can be set automatically based on the current time using + * contrac_update_current_time(). + * + * @param data The context object to work with. + * @return true if the state is fully initialised, false otherwise. + */ bool contrac_get_initialised(Contrac const * data) { return ((data->status & STATUS_INITIALISED) == STATUS_INITIALISED); } +/** + * Set the Tracing Key for the device in binary format. + * + * When first configuring a system, the Tracing Key must be generated + * randomly, e.g. using contrac_generate_tracing_key(). + * + * However, on future runs it's important that the Tracing Key stays the same. + * In this case the key can be restored using this function. + * + * The tracing_key buffer passed in must contain exactly TK_SIZE (32) bytes of + * data. + * + * @param data The context object to work with. + * @param tracing_key The Tracing Key to set in binary format. + */ void contrac_set_tracing_key(Contrac * data, unsigned char const * tracing_key) { memcpy(data->tk, tracing_key, TK_SIZE); data->status |= STATUS_TK; } -const unsigned char * contrac_get_tracing_key(Contrac const * data) { +/** + * Get the Tracing Key for the device in binary format. + * + * This allows the Tracing Key to be extracted. The Tracing Key should be kept + * secret (to maintain privacy), however it still may need to be extracted, for + * example so it can be saved in persistent storage between runs. + * + * The buffer returned will contain exactly TK_SIZE (32) bytes of data in binary + * format. This may therefore contain null bytes, and the buffer will not + * necessarily be null terminated. + * + * @param data The context object to work with. + * @return The Tracing Key in binary format, not null terminated. + */ +unsigned char const * contrac_get_tracing_key(Contrac const * data) { return data->tk; } -// base64 buffer must be at least 45 bytes (TK_SIZE_BASE64 + 1) +/** + * Get the Tracing Key for the device in base64 format. + * + * This allows the Tracing Key to be extracted. The Tracing Key should be kept + * secret (to maintain privacy), however it still may need to be extracted, for + * example so it can be saved in persistent storage between runs. + * + * The buffer provided must be at least TK_SIZE_BAS64 + 1 (45) bytes long and + * will be filled out with the Tracing Key in base64 format (TK_SIZE_BAS64 + * bytes) followed by a null terminator (1 byte). + * + * @param data The context object to work with. + * @param base64 A buffer of at least TK_SIZE_BAS64 + 1 bytes for the result. + */ void contrac_get_tracing_key_base64(Contrac const * data, char * base64) { size_t size = TK_SIZE_BASE64 + 1; base64_encode_binary_to_base64(data->tk, TK_SIZE, (unsigned char *)base64, &size); @@ -149,7 +318,22 @@ void contrac_get_tracing_key_base64(Contrac const * data, char * base64) { } } -// tracing_key input must be 44 bytes long +/** + * Set the Tracing Key for the device in base64 format. + * + * When first configuring a system, the Tracing Key must be generated + * randomly, e.g. using contrac_generate_tracing_key(). + * + * However, on future runs it's important that the Tracing Key stays the same. + * In this case the key can be restored using this function. + * + * The tracing_key buffer passed in must contain exactly TK_SIZE_BASE64 (44) + * bytes of base64-encoded data. It can be null terminated, but doesn't need to + * be. + * + * @param data The context object to work with. + * @param tracing_key The Tracing Key to set in base64 format. + */ bool contrac_set_tracing_key_base64(Contrac * data, char const * tracing_key) { bool result = true; unsigned char tk[TK_SIZE]; @@ -177,11 +361,40 @@ bool contrac_set_tracing_key_base64(Contrac * data, char const * tracing_key) { return result; } -const unsigned char * contrac_get_daily_key(Contrac const * data) { +/** + * Get the Daily Tracing Key for the device in binary format. + * + * This allows the Daily Tracing Key to be extracted. The Daily Tracing Key + * should be kept secret (to maintain privacy) until a positive test is + * confirmed, at which point the user may choose to upload the key to a + * Diagnosis Server, so that others can be notified. + * + * The buffer returned will contain exactly DTK_SIZE (16) bytes of data in + * binary format. This may therefore contain null bytes, and the buffer will not + * necessarily be null terminated. + * + * @param data The context object to work with. + * @return The Daily Tracing Key in binary format, not null terminated. + */ +unsigned char const * contrac_get_daily_key(Contrac const * data) { return dtk_get_daily_key(data->dtk); } -// base64 buffer must be at least 25 bytes (DTK_SIZE_BASE64 + 1) +/** + * Get the Daily Tracing Key for the device in base64 format. + * + * This allows the Daily Tracing Key to be extracted. The Daily Tracing Key + * should be kept secret (to maintain privacy) until a positive test is + * confirmed, at which point the user may choose to upload the key to a + * Diagnosis Server, so that others can be notified. + * + * The buffer provided must be at least DTK_SIZE_BASE64 + 1 (25) bytes long and + * will be filled out with the Tracing Key in base64 format (DTK_SIZE_BASE64 + * bytes) followed by a null terminator (1 byte). + * + * @param data The context object to work with. + * @param base64 A buffer of at least DTK_SIZE_BASE64 + 1 bytes for the result. + */ void contrac_get_daily_key_base64(Contrac const * data, char * base64) { size_t size = DTK_SIZE_BASE64 + 1; base64_encode_binary_to_base64(dtk_get_daily_key(data->dtk), DTK_SIZE, (unsigned char *)base64, &size); @@ -191,11 +404,39 @@ void contrac_get_daily_key_base64(Contrac const * data, char * base64) { } } -const unsigned char * contrac_get_proximity_id(Contrac const * data) { +/** + * Get the Rolling Proximity Identifier for the device in binary format. + * + * This allows the Rolling Proximity Identifier to be extracted. The Rolling + * Proximity Identifier is for broadcast to other devices using BLE and changes + * frequently. + * + * The buffer returned will contain exactly RPI_SIZE (16) bytes of data in + * binary format. This may therefore contain null bytes, and the buffer will not + * necessarily be null terminated. + * + * @param data The context object to work with. + * @return The Rolling Proximity Identifier in binary format, not null + * terminated. + */ +unsigned char const * contrac_get_proximity_id(Contrac const * data) { return rpi_get_proximity_id(data->rpi); } -// base64 buffer must be at least 25 bytes (RPI_SIZE_BASE64 + 1) +/** + * Get the Rolling Proximity Identifier for the device in base64 format. + * + * This allows the Rolling Proximity Identifier to be extracted. The Rolling + * Proximity Identifier is for broadcast to other devices using BLE and changes + * frequently. + * + * The buffer provided must be at least RPI_SIZE_BASE64 + 1 (25) bytes long and + * will be filled out with the Tracing Key in base64 format (RPI_SIZE_BASE64 + * bytes) followed by a null terminator (1 byte). + * + * @param data The context object to work with. + * @param base64 A buffer of at least RPI_SIZE_BASE64 + 1 bytes for the result. + */ void contrac_get_proximity_id_base64(Contrac const * data, char * base64) { size_t size = RPI_SIZE_BASE64 + 1; base64_encode_binary_to_base64(rpi_get_proximity_id(data->rpi), RPI_SIZE, (unsigned char *)base64, &size); @@ -205,6 +446,25 @@ void contrac_get_proximity_id_base64(Contrac const * data, char * base64) { } } +/** + * Update the Daily Tracing Key and Random Proxmity Identifer. + * + * The Daily Tracing Key changes every day, the Random Proximity Identifier + * changes every 10 minutes. + * + * Calling this function will update them both based on the current system + * time. + * + * Note that getting either the DTK or RPI does not cause an update, so if you + * want to get the correct values based on the time, it makes sense to call + * this function before getting them. + * + * The operation may fail if the state has not yet been fully initialised (for + * example if a Tracing Key has not yet been generated or set). + * + * @param data The context object to work with. + * @return true if the operation completed successfully, false otherwise. + */ bool contrac_update_current_time(Contrac * data) { bool result; time_t epoch; @@ -245,4 +505,5 @@ bool contrac_update_current_time(Contrac * data) { return result; } +/** @} addtogroup KeyGeneration */