From: David Llewellyn-Jones Date: Tue, 21 Apr 2020 21:37:20 +0000 (+0300) Subject: Add documentation for Contrac and Dtk classes. X-Git-Url: https://www.flypig.org.uk/git/?p=libcontrac.git;a=commitdiff_plain;h=f8c83387f5abffa94e59332382441a71f5b95545 Add documentation for Contrac and Dtk classes. --- diff --git a/README.md b/README.md index 51017a0..878b0e5 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,10 @@ Include header files. ### Broadcasting and uploading keys -Most of the functionality revolves around the opaque `Contrac` structure. +Most of the functionality is managed through the opaque `Contrac` structure. -Create and initialise the structure as follows. The day and interval number -should be set appropriately. +Create and initialise the structure as follows. The update call updates the +Daily Tracing Key and Rolling Proximity Identifier based on the current time. ``` Contrac * contrac = contrac_new(); @@ -44,14 +44,14 @@ contrac_update_current_time(data); Get the Rolling Proximity Identifier for broadcast in Bluetooth beacons. ``` // Returns a buffer containing RPI_SIZE bytes of data -const unsigned char * rpi = contrac_get_proximity_id(contrac); +unsigned char const * rpi = contrac_get_proximity_id(contrac); ``` Get the Daily Tracing Key to upload to a Diagnosis Server in case of a positive test result. ``` // Returns a buffer containing DTK_SIZE bytes of data -const unsigned char * dtk = contrac_get_daily_key(contrac); +unsigned char const * dtk = contrac_get_daily_key(contrac); ``` ### Receiving and matching keys @@ -63,10 +63,10 @@ RpiList * rpis = rpi_list_new(); rpi_list_add_beacon(rpis, captured_bytes, time_interval_number); ``` -Construct a list of DTKs from data downloaded from a Diagnosis Server. +Construct a list of DTKs using data downloaded from a Diagnosis Server. ``` DtkList * dtks = dtk_list_new(); -// Add data downloaded from the server to the list +// Add data downloaded from a Diagnosis Server to the list dtk_list_add_diagnosis(dtks, dtk_bytes, day_number); ``` diff --git a/include/contrac/contrac.h b/include/contrac/contrac.h index ca29847..e9a059e 100644 --- a/include/contrac/contrac.h +++ b/include/contrac/contrac.h @@ -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 + * @{ + */ + #ifndef __CONTRAC_H #define __CONTRAC_H @@ -25,11 +37,24 @@ // Defines // Data sizes in bytes + +/** + * The size in bytes of a Tracing Key in binary format + */ #define TK_SIZE (32) + +/** + * The size in bytes of a Tracing Key in base64 format + */ #define TK_SIZE_BASE64 (44) // Structures +/** + * An opaque structure for storing the main state. + * + * The internal structure can be found in contrac.c + */ typedef struct _Contrac Contrac; // Function prototypes @@ -43,19 +68,21 @@ bool contrac_set_time_interval_number(Contrac * data, uint8_t time_interval_numb bool contrac_update_current_time(Contrac * data); bool contrac_get_initialised(Contrac const * data); -const unsigned char * contrac_get_tracing_key(Contrac const * data); +unsigned char const * contrac_get_tracing_key(Contrac const * data); void contrac_get_tracing_key_base64(Contrac const * data, char * base64); void contrac_set_tracing_key(Contrac * data, unsigned char const * tracing_key); bool contrac_set_tracing_key_base64(Contrac * data, char const * tracing_key); -const unsigned char * contrac_get_daily_key(Contrac const * data); +unsigned char const * contrac_get_daily_key(Contrac const * data); void contrac_get_daily_key_base64(Contrac const * data, char * base64); -const unsigned char * contrac_get_proximity_id(Contrac const * data); +unsigned char const * contrac_get_proximity_id(Contrac const * data); void contrac_get_proximity_id_base64(Contrac const * data, char * base64); // Function definitions #endif // __CONTRAC_H +/** @} addtogroup KeyGeneration */ + diff --git a/include/contrac/dtk.h b/include/contrac/dtk.h index c263fe2..ee621e5 100644 --- a/include/contrac/dtk.h +++ b/include/contrac/dtk.h @@ -1,17 +1,24 @@ -/** \ingroup contrac +/** \ingroup DailyTracingKey * @file - * @author David Llewellyn-Jones + * @author David Llewellyn-Jones * @version $(VERSION) * * @section LICENSE * + * Copyright David Llewellyn-Jones, 2020 + * Released under the GPLv2. * - * - * @brief + * @brief Daily Tracing Key functionality * @section DESCRIPTION * + * This class is used to generate and manage the Daily Tracing Key. It's + * largely internal. The functionality from \ref Contrac should generally be + * used instead of these functions. * - * + */ + +/** \addtogroup DailyTracingKey + * @{ */ #ifndef __DTK_H @@ -21,11 +28,26 @@ // Defines +/** + * The size in bytes of a DTK in binary format. + * + */ #define DTK_SIZE (16) + +/** + * The size in bytes of a DTK in base64 format, not including the null + * terminator. + * + */ #define DTK_SIZE_BASE64 (24) // Structures +/** + * An opaque structure for representing a DTK. + * + * The internal structure can be found in dtk.c + */ typedef struct _Dtk Dtk; // Function prototypes @@ -42,4 +64,5 @@ void dtk_assign(Dtk * data, unsigned char const * dtk_bytes, uint32_t day_number #endif // __DTK_H +/** @} addtogroup DailyTracingKey */ diff --git a/include/contrac/rpi.h b/include/contrac/rpi.h index 9da8e62..eab1e09 100644 --- a/include/contrac/rpi.h +++ b/include/contrac/rpi.h @@ -25,8 +25,8 @@ // Defines #define RPI_SIZE (16) -#define RPI_INTERVAL_MAX (144) #define RPI_SIZE_BASE64 (24) +#define RPI_INTERVAL_MAX (144) // Structures 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 */ diff --git a/src/dtk.c b/src/dtk.c index e0c8eeb..a6db274 100644 --- a/src/dtk.c +++ b/src/dtk.c @@ -1,19 +1,26 @@ -/** \ingroup contrac +/** \ingroup DailyTracingKey * @file - * @author David Llewellyn-Jones + * @author David Llewellyn-Jones * @version $(VERSION) * * @section LICENSE * + * Copyright David Llewellyn-Jones, 2020 + * Released under the GPLv2. * - * - * @brief + * @brief Daily Tracing Key functionality * @section DESCRIPTION * - * + * This class is used to generate and manage the Daily Tracing Key. It's + * largely internal. The functionality from \ref Contrac should generally be + * used instead of these functions. * */ +/** \addtogroup DailyTracingKey + * @{ + */ + // Includes #include @@ -34,10 +41,25 @@ // Defines +/** + * Used internally. + * + * This is the prefix for the Info parameter provided to the HKDF and used to + * generate the DTK. + */ #define DTK_INFO_PREFIX "CT-DTK" // Structures +/** + * @brief The structure used to represent a Daily Tracing Key. + * + * This is an opaque structure that contains information about the DTK.. + * + * This must be passed as the first parameter of every non-static function. + * + * The structure typedef is in dtk.h + */ struct _Dtk { // Daily key unsigned char dtk[DTK_SIZE]; @@ -48,6 +70,11 @@ struct _Dtk { // Function definitions +/** + * Create a new instance of the class. + * + * @return The newly created object. + */ Dtk * dtk_new() { Dtk * data; @@ -56,6 +83,11 @@ Dtk * dtk_new() { return data; } +/** + * Delete an instance of the class, freeing up the memory allocated to it. + * + * @param data The instance to free. + */ void dtk_delete(Dtk * data) { if (data) { // Clear the data for security @@ -65,6 +97,18 @@ void dtk_delete(Dtk * data) { } } +/** + * Generate a random Daily Tracing Key. + * + * The operation may fail under certain circumstances, such as if the + * HKDF operation fails for some reason. + * + * For internal use. It generally makes more sense to use the + * contrac_set_day_number() function instead. + * + * @param data The context object to work with. + * @return true if the operation completed successfully, false otherwise. + */ bool dtk_generate_daily_key(Dtk * data, Contrac const * contrac, uint32_t day_number) { int result = 1; char encode[sizeof(DTK_INFO_PREFIX) + sizeof(day_number)]; @@ -136,4 +180,5 @@ void dtk_assign(Dtk * data, unsigned char const * dtk_bytes, uint32_t day_number data->day_number = day_number; } +/** @} addtogroup DailyTracingKey */ diff --git a/src/utils.c b/src/utils.c index 443f2a2..d71aafc 100644 --- a/src/utils.c +++ b/src/utils.c @@ -69,7 +69,7 @@ void base64_decode_base64_to_binary(unsigned char const *input, size_t input_siz uint32_t epoch_to_day_number(time_t epoch) { uint32_t day_number; - // DayNumber <- (Number of Seconds since Epoch) / 60 × 60 × 24 + // DayNumber <- (Number of Seconds since Epoch) / (60 * 60 * 24) day_number = epoch / (60 * 60 * 24); return day_number; @@ -80,7 +80,7 @@ uint8_t epoch_to_time_interval_number(time_t epoch) { uint32_t day_number; uint32_t seconds; - // TimeNumberInterval <- (Seconds Since Start of DayNumber) / 60 × 10 + // TimeNumberInterval <- (Seconds Since Start of DayNumber) / (60 * 10) day_number = epoch_to_day_number(epoch); seconds = epoch - (day_number * (60 * 60 * 24));