bool contrac_set_time_interval_number(Contrac * data, uint8_t time_interval_number);
bool contrac_update_current_time(Contrac * data);
bool contrac_get_initialised(Contrac const * data);
+uint32_t contrac_get_day_number(Contrac * data);
+uint8_t contrac_get_time_interval_number(Contrac * data);
unsigned char const * contrac_get_tracing_key(Contrac const * data);
void contrac_get_tracing_key_base64(Contrac const * data, char * base64);
-/** \ingroup contrac
+/** \ingroup KeyGeneration
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Private header for the Core Contact Tracing functionality
* @section DESCRIPTION
*
- *
+ * This provides access to private functionality in the \ref Contrac class.
*
*/
+/** \addtogroup KeyGeneration
+ * @{
+ */
+
#ifndef __CONTRAC_PRIVATE_H
#define __CONTRAC_PRIVATE_H
#endif // __CONTRAC_PRIVATE_H
+/** @} addtogroup KeyGeneration */
+
* @brief Daily Tracing Key functionality
* @section DESCRIPTION
*
- * This class is used to generate and manage the Daily Tracing Key. It's
+ * This class is used to generate and manage the Daily Tracing Key (DTK). It's
* largely internal. The functionality from \ref Contrac should generally be
- * used instead of these functions.
+ * used in preference to this.
*
*/
void dtk_delete(Dtk * data);
bool dtk_generate_daily_key(Dtk * data, Contrac const * contrac, uint32_t day_number);
-const unsigned char * dtk_get_daily_key(Dtk const * data);
+unsigned char const * dtk_get_daily_key(Dtk const * data);
uint32_t dtk_get_day_number(Dtk const * data);
void dtk_assign(Dtk * data, unsigned char const * dtk_bytes, uint32_t day_number);
-/** \ingroup contrac
+/** \ingroup KeyGeneration
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Provides a list of DTKs
* @section DESCRIPTION
*
+ * This class allows the simplified management of lists of Dtk objects. This is
+ * useful when checking DTKs received from a Diagnosis Server with RPIs
+ * captured over Bluetooth. Combined with the \ref RpiList class the two can
+ * be easily stored and passed into the \ref match_list_find_matches() function.
*
- *
+ */
+
+/** \addtogroup Containers
+ * @{
*/
#ifndef __DTK_LIST_H
// Structures
+/**
+ * An opaque structure that represents the head of the list.
+ *
+ * The internal structure can be found in dtk_list.c
+ */
typedef struct _DtkList DtkList;
+
+/**
+ * An opaque structure that represents an item in the list.
+ *
+ * The internal structure can be found in dtk_list.c
+ */
typedef struct _DtkListItem DtkListItem;
// Function prototypes
#endif // __DTK_LIST_H
+/** @} addtogroup Containers*/
-/** \ingroup contrac
+/** \ingroup Logging
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Allows output to be sent to the log
* @section DESCRIPTION
*
- *
+ * This is a simple set of functions and macros that allows strings to be
+ * recorded in the syslog.
*
*/
+/** \addtogroup Logging
+ * @{
+ */
+
#ifndef __LOG_H
#define __LOG_H
// Defines
+/**
+ * Log a string to syslog.
+ *
+ * Constructs a message using the supplied format and parameters and records it
+ * in the system log. The format is the same as for printf.
+ *
+ * The logging levels are the standard syslog levels:
+ *
+ * LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, etc.
+ *
+ * @param priority The log level priority.
+ * @param format The format for the message, the same as for printf.
+ * @param ... parameters to combine with the format to create the message.
+ */
#define LOG(level, ...) log_priority(level, __VA_ARGS__);
// Structures
// Function definitions
#endif // __LOG_H
+
+/** @} addtogroup Logging*/
-/** \ingroup contrac
+/** \ingroup Matching
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Provides a way to match collected RPIs with downloaded DTKs
* @section DESCRIPTION
*
+ * This class provides functionality allowing RPIs that have been collected
+ * over Bluetooth to be matched against DTKs downloaded from a Diagnosis
+ * Server.
*
+ * The list of RPIs and DTKs can be constructed easily using the
+ * \ref Container functions.
*
*/
+/** \addtogroup Matching
+ * @{
+ */
+
#ifndef __MATCH_H
#define __MATCH_H
// Structures
+/**
+ * An opaque structure that represents the head of the list.
+ *
+ * The internal structure can be found in match.c
+ */
typedef struct _MatchList MatchList;
+
+/**
+ * An opaque structure that represents an item in the list.
+ *
+ * The internal structure can be found in match.c
+ */
typedef struct _MatchListItem MatchListItem;
// Function prototypes
#endif // __MATCH_H
+/** @} addtogroup Matching*/
-/** \ingroup contrac
+/** \ingroup RandomProximityIdentifier
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Random Proximity Identifier functionality
* @section DESCRIPTION
*
+ * This class is used to generate and manage the Random Proximity Identifier
+ * (RPI). It's largely internal. The functionality from \ref Contrac should
+ * generally be used in preference to this.
*
- *
+ */
+
+/** \addtogroup RandomProximityIdentifier
+ * @{
*/
#ifndef __RPI_H
// Defines
+/**
+ * The size in bytes of an RPI in binary format.
+ *
+ */
#define RPI_SIZE (16)
+
+/**
+ * The size in bytes of an RPI in base64 format, not including the null
+ * terminator.
+ *
+ */
#define RPI_SIZE_BASE64 (24)
+
+/**
+ * The maximum value a time interval number can take. Time interval numbers
+ * are measured from the start of the day and increment every 10 minutes, so
+ * must fall within the interval [0, 143].
+ *
+ */
#define RPI_INTERVAL_MAX (144)
// Structures
+/**
+ * An opaque structure for representing a DTK.
+ *
+ * The internal structure can be found in rpi.c
+ */
typedef struct _Rpi Rpi;
// Function prototypes
void rpi_delete(Rpi * data);
bool rpi_generate_proximity_id(Rpi * data, Dtk const * dtk, uint8_t time_interval_number);
-const unsigned char * rpi_get_proximity_id(Rpi const * data);
+unsigned char const * rpi_get_proximity_id(Rpi const * data);
uint8_t rpi_get_time_interval_number(Rpi const * data);
void rpi_assign(Rpi * data, unsigned char const * rpi_bytes, uint8_t time_interval_number);
bool rpi_compare(Rpi const * data, Rpi const * comparitor);
#endif // __RPI_H
+/** @} addtogroup RandomProximityIdentifier */
-/** \ingroup contrac
+/** \ingroup KeyGeneration
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Provides a list of RPIs
* @section DESCRIPTION
*
+ * This class allows the simplified management of lists of Rpi objects. This is
+ * useful when checking DTKs received from a Diagnosis Server with RPIs
+ * captured over Bluetooth. Combined with the \ref DtkList class the two can
+ * be easily stored and passed into the \ref match_list_find_matches() function.
*
- *
+ */
+
+/** \addtogroup Containers
+ * @{
*/
#ifndef __RPI_LIST_H
// Structures
+/**
+ * An opaque structure that represents the head of the list.
+ *
+ * The internal structure can be found in rpi_list.c
+ */
typedef struct _RpiList RpiList;
+
+/**
+ * An opaque structure that represents an item in the list.
+ *
+ * The internal structure can be found in rpi_list.c
+ */
typedef struct _RpiListItem RpiListItem;
// Function prototypes
#endif // __RPI_LIST_H
+/** @} addtogroup Containers*/
-/** \ingroup contrac
+/** \ingroup Utils
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Static utility functions
* @section DESCRIPTION
*
+ * Provides various static utitlity functions. In particular:
*
+ * base64 encoding and decoding functionality.
+ * Time conversion: from epoch to day numbers and time interval numbers.
*
*/
+/** \addtogroup Utils
+ * @{
+ */
#ifndef __UTILS_H
#define __UTILS_H
#endif // __UTILS_H
-
-
-
+/** @} addtogroup Utils */
* Copyright David Llewellyn-Jones, 2020
* Released under the GPLv2.
*
- * @brief Core Contact Tracing functionality
+ * @brief Core Contact Tracing functionality
* @section DESCRIPTION
*
* This class provides the core Contact Tracing functionality. It provides an
// Defines
/**
- * Inernal flag mask.
+ * A mask used internally with the status flags.
*
* When set the flag indicates that the Tracing Key has been correctly
* initialised.
#define STATUS_TK (1 << 0)
/**
- * Inernal flag mask.
+ * A mask used internally with the status flags.
*
* When set the flag indicates that the Daily Tracing Key has been correctly
* initialised.
#define STATUS_DTK (1 << 1)
/**
- * Inernal flag mask.
+ * A mask used internally with the status flags.
*
* When set the flag indicates that the Rolling Proximity Identifier has been
* correctly initialised.
#define STATUS_RPI (1 << 2)
/**
- * Inernal flag mask.
+ * A mask used internally with the status flags.
*
* When all of these flags are set it indicates that the structure is fully
* initialised.
// Function definitions
/**
- * Create a new instance of the class.
+ * Creates a new instance of the class.
*
* @return The newly created object.
*/
}
/**
- * Delete an instance of the class, freeing up the memory allocated to it.
+ * Deletes an instance of the class, freeing up the memory allocated to it.
*
* @param data The instance to free.
*/
}
/**
- * Generate a random Contact Tracing Key.
+ * Generates 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.
}
/**
- * Set the current day number.
+ * Sets 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
* The day number is calculated as:
* (Number of Seconds since Epoch) / (60 * 60 * 24)
*
- * Which can be caluclated from the current epoch using the
+ * Which can be calculated 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.
+ * @param day_number The day number used to generate the DTK.
* @return true if the operation completed successfully, false otherwise.
*/
bool contrac_set_day_number(Contrac * data, uint32_t day_number) {
}
/**
- * Set the current time interval number.
+ * Sets 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
*
* and must fall in the interval [0, 143].
*
- * It can be caluclated from the current epoch using the
+ * It can be calculated 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
}
/**
- * Get whether the internal state has been fully configured or not.
+ * Gets 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
}
/**
- * Set the Tracing Key for the device in binary format.
+ * Gets the current day number.
+ *
+ * Gets the current day number used to generate the most recent DTK.
+ *
+ * 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.
+ *
+ * @param data The context object to work with.
+ * @return The day number most recently used to generate the DTK.
+ */
+uint32_t contrac_get_day_number(Contrac * data) {
+ return dtk_get_day_number(data->dtk);
+}
+
+/**
+ * Gets the current time interval number.
+ *
+ * Gets the current time interval number used to generate the most recent RPI.
+ *
+ * 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.
+ *
+ * @param data The context object to work with.
+ * @return The time interval number most recently used to generate the RPI.
+ */
+uint8_t contrac_get_time_interval_number(Contrac * data) {
+ return rpi_get_time_interval_number(data->rpi);
+}
+
+/**
+ * Sets 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().
* 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.
+ * data.It doen't have to be null terminated.
*
* @param data The context object to work with.
* @param tracing_key The Tracing Key to set in binary format.
}
/**
- * Get the Tracing Key for the device in binary format.
+ * Gets 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
*
* 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.
+ * necessarily be null terminated. Future operations may cause the data to
+ * change, so the caller should make a copy of the buffer rather than keeping
+ * the pointer to it.
*
* @param data The context object to work with.
* @return The Tracing Key in binary format, not null terminated.
}
/**
- * Get the Tracing Key for the device in base64 format.
+ * Gets 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
}
/**
- * Set the Tracing Key for the device in base64 format.
+ * Sets 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().
}
/**
- * Get the Daily Tracing Key for the device in binary format.
+ * Gets 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
*
* 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.
+ * necessarily be null terminated. Future operations may cause the data to
+ * change, so the caller should make a copy of the buffer rather than keeping
+ * the pointer to it.
*
* @param data The context object to work with.
* @return The Daily Tracing Key in binary format, not null terminated.
}
/**
- * Get the Daily Tracing Key for the device in base64 format.
+ * Gets 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
}
/**
- * Get the Rolling Proximity Identifier for the device in binary format.
+ * Gets 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
*
* 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.
+ * necessarily be null terminated. Future operations may cause the data to
+ * change, so the caller should make a copy of the buffer rather than keeping
+ * the pointer to it.
*
* @param data The context object to work with.
* @return The Rolling Proximity Identifier in binary format, not null
}
/**
- * Get the Rolling Proximity Identifier for the device in base64 format.
+ * Gets 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
}
/**
- * Update the Daily Tracing Key and Random Proxmity Identifer.
+ * Updates the Daily Tracing Key and Random Proxmity Identifer.
*
* The Daily Tracing Key changes every day, the Random Proximity Identifier
* changes every 10 minutes.
* @brief Daily Tracing Key functionality
* @section DESCRIPTION
*
- * This class is used to generate and manage the Daily Tracing Key. It's
+ * This class is used to generate and manage the Daily Tracing Key (DTK). It's
* largely internal. The functionality from \ref Contrac should generally be
- * used instead of these functions.
+ * used in preference to this.
*
*/
// Function definitions
/**
- * Create a new instance of the class.
+ * Creates a new instance of the class.
*
* @return The newly created object.
*/
}
/**
- * Delete an instance of the class, freeing up the memory allocated to it.
+ * Deletes an instance of the class, freeing up the memory allocated to it.
*
* @param data The instance to free.
*/
}
/**
- * Generate a random Daily Tracing Key.
+ * Generates a Daily Tracing Key based on the day number provided.
*
* The operation may fail under certain circumstances, such as if the
* HKDF operation fails for some reason.
* contrac_set_day_number() function instead.
*
* @param data The context object to work with.
+ * @param day_number The day number to use to generate the key.
* @return true if the operation completed successfully, false otherwise.
*/
bool dtk_generate_daily_key(Dtk * data, Contrac const * contrac, uint32_t day_number) {
char encode[sizeof(DTK_INFO_PREFIX) + sizeof(day_number)];
size_t out_length = 0;
EVP_PKEY_CTX *pctx = NULL;
- const unsigned char * tk;
+ unsigned char const * tk;
// dtk_i <- HKDF(tk, NULL, (UTF8("CT-DTK") || D_i), 16)
return (result > 0);
}
-const unsigned char * dtk_get_daily_key(Dtk const * data) {
+/**
+ * Gets the Daily Tracing Key for the device in binary format.
+ *
+ * For internal use. It generally makes more sense to use the
+ * contrac_get_daily_key() function instead.
+ *
+ * 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. Future operations may cause the data to
+ * change, so the caller should make a copy of the buffer rather than keeping
+ * a pointer to it.
+ *
+ * @param data The context object to work with.
+ * @return The Daily Tracing Key in binary format, not null terminated.
+ */
+unsigned char const * dtk_get_daily_key(Dtk const * data) {
return data->dtk;
}
+/**
+ * Gets the day number that applies to the current DTK.
+ *
+ * For internal use. It generally makes more sense to use the
+ * contrac_get_day_number() function instead.
+ *
+ * @param data The context object to work with.
+ * @return The day number stored in the object..
+ */
uint32_t dtk_get_day_number(Dtk const * data) {
return data->day_number;
}
+/**
+ * Populates the data structure.
+ *
+ * Allows the DTK and day number values of the object to be set explicitly.
+ *
+ * For internal use. To set the DTK it generally makes more sense to use one of
+ * eiher contrac_set_day_number() or contrac_update_current_time() instead.
+ *
+ * The dtk_bytes buffer passed in must contain exactly DTK_SIZE (16) bytes of
+ * data. It doen't have to be null terminated.
+ *
+ * @param data The context object to work with.
+ * @param dtk_bytes The DTK value to set, in binary format.
+ * @param day_number The day number to associate with this DTK.
+ */
void dtk_assign(Dtk * data, unsigned char const * dtk_bytes, uint32_t day_number) {
memcpy(data->dtk, dtk_bytes, DTK_SIZE);
data->day_number = day_number;
-/** \ingroup contrac
+/** \ingroup KeyGeneration
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Provides a list of DTKs
* @section DESCRIPTION
*
+ * This class allows the simplified management of lists of Dtk objects. This is
+ * useful when checking DTKs received from a Diagnosis Server with RPIs
+ * captured over Bluetooth. Combined with the \ref RpiList class the two can
+ * be easily stored and passed into the \ref match_list_find_matches() function.
*
- *
+ */
+
+/** \addtogroup Containers
+ * @{
*/
// Includes
// Structures
+/**
+ * @brief A DTK list element
+ *
+ * This is an opaque structure that represents a single item in the list and
+ * contains a Dtk instance.
+ *
+ * The structure typedef is in dtk_list.h
+ */
struct _DtkListItem {
Dtk * dtk;
DtkListItem * next;
};
+/**
+ * @brief The head of a DTK list
+ *
+ * This is an opaque structure that represents the head of a list of Dtk
+ * items.
+ *
+ * This is the object usually passed as the first parameter of every non-static
+ * function.
+ *
+ * The structure typedef is in dtk_list.h
+ */
struct _DtkList {
DtkListItem * first;
DtkListItem * last;
// Function definitions
+/**
+ * Creates a new instance of the class.
+ *
+ * @return The newly created object.
+ */
DtkList * dtk_list_new() {
DtkList * data;
return data;
}
+/**
+ * Deletes an instance of the class, freeing up the memory allocated to it.
+ *
+ * This will also delete all items contained in the list.
+ *
+ * @param data The instance to free.
+ */
void dtk_list_delete(DtkList * data) {
DtkListItem * item;
DtkListItem * next;
}
}
+/**
+ * Adds an item to the list.
+ *
+ * This adds a Dtk item to the list. It's primarily for internal use and when
+ * adding DTKs to the list it's usually more appropriate to use the
+ * \ref dtk_list_add_diagnosis() function.
+ *
+ * @param data The list to append to.
+ * @param dtk The DTK to append.
+ */
void dtk_list_append(DtkList * data, Dtk * dtk) {
DtkListItem * item;
}
}
+/**
+ * Returns the first item in the list.
+ *
+ * Useful for iterating through the items in the list.
+ *
+ * @param data The list to operate on.
+ * @return The first item of the list.
+ */
DtkListItem const * dtk_list_first(DtkList const * data) {
return data->first;
}
+/**
+ * Returns the next item in the list.
+ *
+ * Useful for iterating through the items in the list.
+ *
+ * @param data The current item in the list.
+ * @return The next item in the list following the current item.
+ */
DtkListItem const * dtk_list_next(DtkListItem const * data) {
return data->next;
}
+/**
+ * Returns the Dtk item contained in this list item.
+ *
+ * @param data The current item in the list.
+ * @return The Dtk instance stored in the list element.
+ */
Dtk const * dtk_list_get_dtk(DtkListItem const * data) {
return data->dtk;
}
+/**
+ * Adds Dtk data to the list.
+ *
+ * The dtk_bytes buffer passed in must contain exactly DTK_SIZE (16) bytes of
+ * data. It doen't have to be null terminated.
+ *
+ * @param data The current list to operate on.
+ * @param dtk_bytes The DTK value to add, in binary format.
+ * @param day_number The day number to associate with the DTK.
+ */
void dtk_list_add_diagnosis(DtkList * data, unsigned char const * dtk_bytes, uint32_t day_number) {
Dtk * dtk = dtk_new();
dtk_assign(dtk, dtk_bytes, day_number);
dtk_list_append(data, dtk);
}
+/** @} addtogroup Containers*/
+
// Function prototypes
+/**
+ * Log a string to syslog.
+ *
+ * In generl, the LOG macro should be used instead.
+ *
+ * Constructs a message using the supplied format and parameters and records it
+ * in the system log. The format is the same as for printf.
+ *
+ * The logging levels are the standard syslog levels:
+ *
+ * LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, etc.
+ *
+ * @param priority The log level priority.
+ * @param format The format for the message, the same as for printf.
+ * @param ... parameters to combine with the format to create the message.
+ */
void log_priority(int priority, const char *format, ...) {
va_list args;
int length;
--- /dev/null
+/**
+ * @mainpage
+ *
+ * @version $(VERSION)
+ *
+ * libcontrac is an implementation of the Apple/Google Contact Tracing API.
+ *
+ * See the draft specs: https://www.apple.com/covid19/contacttracing/
+ *
+ * ## Install
+ *
+ * If you have autoconf you can install as follows.
+ *
+ * ```
+ * autoreconf --install
+ * ./configure
+ * make
+ * make check
+ * make install
+ * ```
+ *
+ * ## Usage
+ *
+ * Include header files.
+ * ```
+ * #include "contrac/contrac.h"
+ * #include "contrac/rpi.h"
+ * #include "contrac/dtk.h"
+ * #include "contrac/rpi_list.h"
+ * #include "contrac/rpi_list.h"
+ * #include "contrac/matches.h"
+ * ```
+ *
+ * ### Broadcasting and uploading keys
+ *
+ * Most of the functionality is managed through the opaque `Contrac` structure.
+ *
+ * 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();
+ * // Generates a random Tracing Key if one hasn't yet been set
+ * contrac_update_current_time(data);
+ * ```
+ *
+ * Get the Rolling Proximity Identifier for broadcast in Bluetooth beacons.
+ * ```
+ * // Returns a buffer containing RPI_SIZE bytes of data
+ * 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
+ * unsigned char const * dtk = contrac_get_daily_key(contrac);
+ * ```
+ *
+ * ### Receiving and matching keys
+ *
+ * Add RPIs captured via Bluetooth to an RPI list.
+ * ```
+ * RpiList * rpis = rpi_list_new();
+ * // Add bytes captured at a given time to the list
+ * rpi_list_add_beacon(rpis, captured_bytes, time_interval_number);
+ * ```
+ *
+ * Construct a list of DTKs using data downloaded from a Diagnosis Server.
+ * ```
+ * DtkList * dtks = dtk_list_new();
+ * // Add data downloaded from a Diagnosis Server to the list
+ * dtk_list_add_diagnosis(dtks, dtk_bytes, day_number);
+ * ```
+ *
+ * Having collected these two lists any matches can be tested for as follows.
+ *
+ * ```
+ * MatchList * matches = match_list_new();
+ * match_list_find_matches(matches, rpis, dtks);
+ *
+ * if (match_list_count(matches) > 0) {
+ * printf("Exposure identified, follow medical advice\n");
+ * }
+ * ```
+ *
+ * ### Cleaning up
+ *
+ * Finally, clean up.
+ * ```
+ * match_list_delete(matches);
+ * rpi_list_delete(rpis);
+ * dtk_list_delete(dtks);
+ * contrac_delete(contrac);
+ * ```
+ */
+
+/**
+ * @defgroup KeyGeneration Key Generation
+ * @brief Core Contact Tracing functionality
+ *
+ * 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.
+ *
+ */
+
+/**
+ * @defgroup Utils Utilities
+ * @brief Static utility functions
+ *
+ * Provides various static utitlity functions. In particular:
+ *
+ * base64 encoding and decoding functionality.
+ * Time conversion: from epoch to day numbers and time interval numbers.
+ *
+ */
+
+/**
+ * @defgroup DailyTracingKey Daily Tracing Key
+ * @brief Daily Tracing Key functionality
+ *
+ * This class is used to generate and manage the Daily Tracing Key (DTK). It's
+ * largely internal. The functionality from \ref Contrac should generally be
+ * used in preference to this.
+ *
+ */
+
+/**
+ * @defgroup RandomProximityIdentifier Random Proximity Identifier
+ * @brief Proximity Identifier functionality
+ *
+ * This class is used to generate and manage the Random Proximity Identifier
+ * (RPI). It's largely internal. The functionality from \ref Contrac should
+ * generally be used in preference to this.
+ *
+ */
+
+/**
+ * @defgroup Containers Containers
+ * @brief Provides containers for managing lists of items
+ *
+ * This allows the simplified management of lists of Dtk and Rpi objects. This
+ * is useful when checking DTKs received from a Diagnosis Server with RPIs
+ * captured over Bluetooth. The two can be easily stored and passed into the
+ * \ref match_list_find_matches() function.
+ *
+ */
+
+/**
+ * @defgroup Matching Matching
+ * @brief Provides a way to match collected RPIs with downloaded DTKs.
+ *
+ * This class provides functionality allowing RPIs that have been collected
+ * over Bluetooth to be matched against DTKs downloaded from a Diagnosis
+ * Server.
+ *
+ */
+
+/**
+ * @defgroup Logging Logging
+ * @brief Allows output to be sent to the log
+ *
+ * This is a simple set of functions and macros that allows strings to be
+ * recorded in the syslog.
+ *
+ */
+
+
-/** \ingroup contrac
+/** \ingroup Matching
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Provides a way to match collected RPIs with downloaded DTKs.
* @section DESCRIPTION
*
+ * This class provides functionality allowing RPIs that have been collected
+ * over Bluetooth to be matched against DTKs downloaded from a Diagnosis
+ * Server.
*
+ * The list of RPIs and DTKs can be constructed easily using the
+ * \ref Container functions.
*
*/
+/** \addtogroup Matching
+ * @{
+ */
+
// Includes
#include <stdlib.h>
// Structures
+/**
+ * @brief A match list element
+ *
+ * This is an opaque structure that represents a single item in the list and
+ * captures a match between an RPI and a DTK.
+ *
+ * The structure typedef is in match.h
+ */
struct _MatchListItem {
uint32_t day_number;
uint8_t time_interval_number;
MatchListItem * next;
};
+/**
+ * @brief The head of a match list
+ *
+ * This is an opaque structure that represents the head of the list. Each item
+ * in the list captures a match between an RPI and a DTK.
+ *
+ * This is the object usually passed as the first parameter of every non-static
+ * function.
+ *
+ * The structure typedef is in match.h
+ */
struct _MatchList {
size_t count;
MatchListItem * first;
// Function definitions
+/**
+ * Creates a new instance of the class.
+ *
+ * @return The newly created object.
+ */
MatchList * match_list_new() {
MatchList * data;
return data;
}
+/**
+ * Deletes an instance of the class, freeing up the memory allocated to it.
+ *
+ * This will also delete all items contained in the list.
+ *
+ * @param data The instance to free.
+ */
void match_list_delete(MatchList * data) {
if (data) {
match_list_clear(data);
}
}
+/**
+ * Creates a new instance of the class.
+ *
+ * @return The newly created object.
+ */
MatchListItem * match_list_item_new() {
MatchListItem * data;
return data;
}
+/**
+ * Deletes an instance of the class, freeing up the memory allocated to it.
+ *
+ * @param data The instance to free.
+ */
void match_list_item_delete(MatchListItem * data) {
if (data) {
free(data);
}
}
+/**
+ * Clears all items from the list.
+ *
+ * Removes all items from the list to create an empty list. The memory
+ * associated with the items in the list is freed.
+ *
+ * @param data The list to operate on.
+ */
void match_list_clear(MatchList * data) {
MatchListItem * item;
MatchListItem * next;
data->count = 0;
}
+/**
+ * Returns the number of items in the list.
+ *
+ * Immediately after creation, or after the \ref match_list_clear() function
+ * has been called, this will return zero.
+ *
+ * @param data The list to operate on.
+ */
size_t match_list_count(MatchList * data) {
return data->count;
}
+/**
+ * Returns the first item in the list.
+ *
+ * Useful for iterating through the items in the list.
+ *
+ * @param data The list to operate on.
+ * @return The first item of the list.
+ */
MatchListItem const * match_list_first(MatchList const * data) {
return data->first;
}
+/**
+ * Returns the next item in the list.
+ *
+ * Useful for iterating through the items in the list.
+ *
+ * @param data The current item in the list.
+ * @return The next item in the list following the current item.
+ */
MatchListItem const * match_list_next(MatchListItem const * data) {
return data->next;
}
+/**
+ * Returns the day number of the item in the list.
+ *
+ * This will represent the day number of when an interaction occurred with
+ * someone who has subsequently uploaded their DTK to a diagnosis server due to
+ * testing positive.
+ *
+ * @param data The list to operate on.
+ * @return The day number for this item.
+ */
uint32_t match_list_get_day_number(MatchListItem const * data) {
return data->day_number;
}
+/**
+ * Returns the time interval number of the item in the list.
+ *
+ * This will represent the time interval number of when an interaction occurred
+ * with someone who has subsequently uploaded their DTK to a diagnosis server
+ * due to testing positive.
+ *
+ * @param data The list to operate on.
+ * @return The time interval number for this item.
+ */
uint8_t match_list_get_time_interval_number(MatchListItem const * data) {
return data->time_interval_number;
}
+/**
+ * Adds an item to the list.
+ *
+ * This adds a match to the list. It's primarily for internal use.
+ *
+ * @param data The list to append to.
+ * @param item The match to append.
+ */
void match_list_append(MatchList * data, MatchListItem * item) {
if (data->last == NULL) {
data->first = item;
data->count++;
}
+/**
+ * Returns a list of matches found between the beacons and diagnoses.
+ *
+ * This searches through the list of DTKs and the list of RPIs provided, and
+ * returns a list of matches.
+ *
+ * If the returned list has any elements in, this would suggest that the user
+ * has been in contact with someone who tested positive and uploaded their DTK
+ * to a Diagnosis Server.
+ *
+ * The match list isn't cleared by this call and so any new values will be
+ * appended to it.
+ *
+ * @param data The list that any matches will be appended to.
+ * @param beacons A list of RPIs extracted from overheard BLE beacons.
+ * @param diagnosis_keys A list of DTKs downloaed from a Diagnosis Server.
+ */
void match_list_find_matches(MatchList * data, RpiList * beacons, DtkList * diagnosis_keys) {
// For each diagnosis key, generate the RPIs and compare them against the captured RPI beacons
DtkListItem const * dtk_item;
rpi_delete(generated);
}
+/** @} addtogroup Matching*/
-/** \ingroup contrac
+/** \ingroup RandomProximityIdentifier
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Random Proximity Identifier functionality
* @section DESCRIPTION
*
- *
+ * This class is used to generate and manage the Random Proximity Identifier
+ * (RPI). It's largely internal. The functionality from \ref Contrac should
+ * generally be used in preference to this.
*
*/
+/** \addtogroup RandomProximityIdentifier
+ * @{
+ */
+
// Includes
#include <stdlib.h>
// Defines
+/**
+ * Used internally.
+ *
+ * This is the prefix for the Info parameter provided to the HMAC and used to
+ * generate the RPI.
+ */
#define RPI_INFO_PREFIX "CT-RPI"
// Structures
+/**
+ * @brief The structure used to represent a Rolling Proximity Identifier.
+ *
+ * This is an opaque structure that contains information about the RPI..
+ *
+ * This must be passed as the first parameter of every non-static function.
+ *
+ * The structure typedef is in dtk.h
+ */
struct _Rpi {
// Rolling proximity identifier
unsigned char rpi[RPI_SIZE];
// Function definitions
+/**
+ * Creates a new instance of the class.
+ *
+ * @return The newly created object.
+ */
Rpi * rpi_new() {
Rpi * data;
return data;
}
+/**
+ * Deletes an instance of the class, freeing up the memory allocated to it.
+ *
+ * @param data The instance to free.
+ */
void rpi_delete(Rpi * data) {
if (data) {
// Clear the data for security
}
}
+/**
+ * Generates a Rolling Proximity Identifier based on the time interval number
+ * provided.
+ *
+ * The operation may fail under certain circumstances, such as if the
+ * HMAC operation fails for some reason.
+ *
+ * For internal use. It generally makes more sense to use the
+ * contrac_set_time_interval_number() function instead.
+ *
+ * @param data The context object to work with.
+ * @param time_interval_number The time interval number to use to generate the
+ * key.
+ * @return true if the operation completed successfully, false otherwise.
+ */
bool rpi_generate_proximity_id(Rpi * data, Dtk const * dtk, uint8_t time_interval_number) {
int result = 1;
unsigned char encode[sizeof(RPI_INFO_PREFIX) + sizeof(time_interval_number)];
return (result > 0);
}
-const unsigned char * rpi_get_proximity_id(Rpi const * data) {
+/**
+ * Gets the Rolling Proximity Identifier for the device in binary format.
+ *
+ * For internal use. It generally makes more sense to use the
+ * contrac_get_proximity_id() function instead.
+ *
+ * This allows the Rolling Proximity Identifier to be extracted. The Rolling
+ * Proximity Identifier is public, in the sense that it is usual to broadcast
+ * the value in Bluetooth beacons.
+ *
+ * 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. Future operations may cause the data to
+ * change, so the caller should make a copy of the buffer rather than keeping
+ * a pointer to it.
+ *
+ * @param data The context object to work with.
+ * @return The Rolling Proximity Identifier in binary format, not null
+ * terminated.
+ */
+unsigned char const * rpi_get_proximity_id(Rpi const * data) {
return data->rpi;
}
+/**
+ * Gets the time interval number that applies to the current RPI.
+ *
+ * For internal use. It generally makes more sense to use the
+ * contrac_set_time_interval_number() function instead.
+ *
+ * @param data The context object to work with.
+ * @return The time interval number stored in the object.
+ */
uint8_t rpi_get_time_interval_number(Rpi const * data) {
return data->time_interval_number;
}
-
+/**
+ * Populates the data structure.
+ *
+ * Allows the RPI and time interval number values of the object to be set
+ * explicitly.
+ *
+ * For internal use. To set the RPI it generally makes more sense to use one of
+ * eiher contrac_set_time_interval_number() or contrac_update_current_time()
+ * instead.
+ *
+ * The rpi_bytes buffer passed in must contain exactly RPI_SIZE (16) bytes of
+ * data. It doen't have to be null terminated.
+ *
+ * @param data The context object to work with.
+ * @param rpi_bytes The RPI value to set, in binary format.
+ * @param day_number The time interval number to associate with this RPI.
+ */
void rpi_assign(Rpi * data, unsigned char const * rpi_bytes, uint8_t time_interval_number) {
memcpy(data->rpi, rpi_bytes, RPI_SIZE);
data->time_interval_number = time_interval_number;
}
+/**
+ * Compares two RPI values.
+ *
+ * @param data The RPI to compare with.
+ * @param comparitor The RPI to compare against.
+ * @return true if the two RPIs are the same, false otherwise.
+ */
bool rpi_compare(Rpi const * data, Rpi const * comparitor) {
unsigned char left[RPI_SIZE_BASE64 + 1];
unsigned char right[RPI_SIZE_BASE64 + 1];
return (memcmp(data, comparitor, RPI_SIZE) == 0);
}
+/** @} addtogroup RandomProximityIdentifier */
-/** \ingroup contrac
+/** \ingroup KeyGeneration
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Provides a list of RPIs
* @section DESCRIPTION
*
+ * This class allows the simplified management of lists of Rpi objects. This is
+ * useful when checking DTKs received from a Diagnosis Server with RPIs
+ * captured over Bluetooth. Combined with the \ref DtkList class the two can
+ * be easily stored and passed into the \ref match_list_find_matches() function.
*
- *
+ */
+
+/** \addtogroup Containers
+ * @{
*/
// Includes
// Structures
+/**
+ * @brief An RPI list element
+ *
+ * This is an opaque structure that represents a single item in the list and
+ * contains an Rpi instance.
+ *
+ * The structure typedef is in rpi_list.h
+ */
struct _RpiListItem {
Rpi * rpi;
RpiListItem * next;
};
+/**
+ * @brief The head of an RPI list
+ *
+ * This is an opaque structure that represents the head of a list of Rpi
+ * items.
+ *
+ * This is the object usually passed as the first parameter of every non-static
+ * function.
+ *
+ * The structure typedef is in dtk_list.h
+ */
struct _RpiList {
RpiListItem * first;
RpiListItem * last;
// Function definitions
+/**
+ * Creates a new instance of the class.
+ *
+ * @return The newly created object.
+ */
RpiList * rpi_list_new() {
RpiList * data;
return data;
}
+/**
+ * Deletes an instance of the class, freeing up the memory allocated to it.
+ *
+ * This will also delete all items contained in the list.
+ *
+ * @param data The instance to free.
+ */
void rpi_list_delete(RpiList * data) {
RpiListItem * item;
RpiListItem * next;
}
}
+/**
+ * Adds an item to the list.
+ *
+ * This adds an Rpi item to the list. It's primarily for internal use and when
+ * adding RPIs to the list it's usually more appropriate to use the
+ * \ref rpi_list_add_beacon() function.
+ *
+ * @param data The list to append to.
+ * @param rpi The RPI to append.
+ */
void rpi_list_append(RpiList * data, Rpi * rpi) {
RpiListItem * item;
}
}
+/**
+ * Returns the first item in the list.
+ *
+ * Useful for iterating through the items in the list.
+ *
+ * @param data The list to operate on.
+ * @return The first item of the list.
+ */
RpiListItem const * rpi_list_first(RpiList const * data) {
return data->first;
}
+/**
+ * Returns the next item in the list.
+ *
+ * Useful for iterating through the items in the list.
+ *
+ * @param data The current item in the list.
+ * @return The next item in the list following the current item.
+ */
RpiListItem const * rpi_list_next(RpiListItem const * data) {
return data->next;
}
+/**
+ * Returns the Rpi item contained in this list item.
+ *
+ * @param data The current item in the list.
+ * @return The Rpi instance stored in the list element.
+ */
Rpi const * rpi_list_get_rpi(RpiListItem const * data) {
return data->rpi;
}
+/**
+ * Adds Rpi data to the list.
+ *
+ * The rpi_bytes buffer passed in must contain exactly RPI_SIZE (16) bytes of
+ * data. It doen't have to be null terminated.
+ *
+ * @param data The current list to operate on.
+ * @param rpi_bytes The RPI value to add, in binary format.
+ * @param time_interval_number The time interval number to associate with the
+ * RPI.
+ */
void rpi_list_add_beacon(RpiList * data, unsigned char const * rpi_bytes, uint8_t time_interval_number) {
Rpi * rpi = rpi_new();
rpi_assign(rpi, rpi_bytes, time_interval_number);
rpi_list_append(data, rpi);
}
-
-
+/** @} addtogroup Containers*/
-/** \ingroup contrac
+/** \ingroup Utils
* @file
- * @author David Llewellyn-Jones
+ * @author David Llewellyn-Jones <david@flypig.co.uk>
* @version $(VERSION)
*
* @section LICENSE
*
+ * Copyright David Llewellyn-Jones, 2020
+ * Released under the GPLv2.
*
- *
- * @brief
+ * @brief Static utitlity functions.
* @section DESCRIPTION
*
+ * Provides various static utitlity functions. In particular:
*
+ * base64 encoding and decoding functionality.
+ * Time conversion: from epoch to day numbers and time interval numbers.
*
*/
+/** \addtogroup Utils
+ * @{
+ */
+
// Includes
#include <openssl/evp.h>
// Function definitions
+/**
+ * Returns the amount of space needed to store the base64 equivalent of a binary
+ * input.
+ *
+ * When converting to base64 it's often useful to know how much space will be
+ * needed to store the result, for example so that a buffer of the correct size
+ * can be allocated for it.
+ *
+ * This function returns the size needed for a buffer that will be large enough
+ * to store the result, including a terminating null character. The returned
+ * value may be larger than the size actually needed.
+ *
+ * @param binary_input The length of binary input that would be encoded.
+ * @return The buffer size needed to store the base64 version of the same data.
+ */
size_t base64_encode_size(size_t binary_input) {
return (((size_t)((binary_input + 2) / 3)) * 4) + 1;
}
+/**
+ * Returns the amount of space needed to store the binary equivalent of a base64
+ * string.
+ *
+ * When converting from base64 it's often useful to know how much space will be
+ * needed to store the result, for example so that a buffer of the correct size
+ * can be allocated for it.
+ *
+ * This function returns the size needed for a buffer that will be large enough
+ * to store the result. The returned value may be larger than the size actually
+ * needed.
+ *
+ * @param base64_input The length of a base64 string that would be decoded.
+ * @return The buffer size needed to store the binary version of the same data.
+ */
size_t base64_decode_size(size_t base64_input) {
return (((size_t)((base64_input + 3) / 4)) * 3) + 1;
}
+/**
+ * Encodes binary data to base64 format string.
+ *
+ * Encodes the binary data provided into a base64 string, storing the result
+ * in the output buffer provided. The output buffer must be pre-allocated
+ * with enough space to store the result. The size needed can be found by
+ * calling the \ref base64_encode_size() function.
+ *
+ * If the output buffer is too small (based on the size provided) then the
+ * base64 string may be only partially written.
+ *
+ * @param input The binary data to encode. This doesn't need to be zero
+ * terminated.
+ * @param input_size The size of the input buffer to be converted.
+ * @param output A pre-allocated buffer to store the result.
+ * @param output_size The size of the allocated buffer, which will be updated
+ * to the number of bytes written to the buffer.
+ */
void base64_encode_binary_to_base64(unsigned char const *input, size_t input_size, unsigned char *output, size_t *output_size) {
size_t size_in;
size_t size_out;
EVP_EncodeBlock(output, input, size_in);
}
+/**
+ * Decodes a base64 string into the original binary data it represents.
+ *
+ * Decodes the base64 string provided into binary, storing the result in the
+ * output buffer provided. The output buffer must be pre-allocated with enough
+ * space to store the result. The size needed can be found by calling the
+ * \ref base64_decode_size() function.
+ *
+ * If the output buffer is too small (based on the size provided) then the
+ * binary output may be only partially written.
+ *
+ * @param input The base64 string to encode. This doesn't need to be zero
+ * terminated.
+ * @param input_size The size of the input buffer to be converted.
+ * @param output A pre-allocated buffer to store the result.
+ * @param output_size The size of the allocated buffer, which will be updated
+ * to the number of bytes written to the buffer.
+ */
void base64_decode_base64_to_binary(unsigned char const *input, size_t input_size, unsigned char *output, size_t *output_size) {
size_t size_in;
size_t size_out;
EVP_DecodeBlock(output, input, size_in);
}
+/**
+ * Converts a time in epoch format into a day number.
+ *
+ * Returns the day number for the given epoch time. The epoch time represents
+ * the number of seconds since 00:00:00 UTC on 01/01/1970.
+ *
+ * The day number is calculated as:
+ * (Number of Seconds since Epoch) / (60 * 60 * 24)
+ *
+ * @param epoch The epoch time in seconds.
+ * @return The day number for this epoch time.
+ */
uint32_t epoch_to_day_number(time_t epoch) {
uint32_t day_number;
return day_number;
}
+/**
+ * Converts a time in epoch format into a time interval number.
+ *
+ * Returns the time interval number for the given epoch time. The epoch time
+ * represents the number of seconds since 00:00:00 UTC on 01/01/1970.
+ *
+ * The time interval number is calculated as:
+ * (Seconds Since Start of DayNumber) / (60 * 10)
+ *
+ * and must fall in the interval [0, 143].
+ *
+ * @param epoch The epoch time in seconds.
+ * @return The time interval number for this epoch time.
+ */
uint8_t epoch_to_time_interval_number(time_t epoch) {
uint8_t time_interval_number;
uint32_t day_number;
return time_interval_number;
}
+/** @} addtogroup Utils */