Add time functions, simplify API
authorDavid Llewellyn-Jones <david@flypig.co.uk>
Mon, 20 Apr 2020 21:09:57 +0000 (00:09 +0300)
committerDavid Llewellyn-Jones <david@flypig.co.uk>
Mon, 20 Apr 2020 21:09:57 +0000 (00:09 +0300)
Add functions for calculating time values, and for configuringthe keys
based on the current time,

Simplifies the match api so Rpi and Dtk structures don't need to be
created separately before being added to a list.

14 files changed:
README.md
include/contrac/contrac.h
include/contrac/contrac_private.h
include/contrac/dtk.h
include/contrac/dtk_list.h
include/contrac/rpi_list.h
include/contrac/utils.h
src/contrac.c
src/dtk.c
src/dtk_list.c
src/rpi.c
src/rpi_list.c
src/utils.c
tests/test_contrac.c

index 9df42ae..51017a0 100644 (file)
--- a/README.md
+++ b/README.md
@@ -37,9 +37,8 @@ should be set appropriately.
 
 ```
 Contrac * contrac = contrac_new();
-contrac_generate_tracing_key(contrac);
-contrac_set_day_number(contrac, 23);
-contrac_set_time_interval_number(contrac, 76);
+// 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.
@@ -60,21 +59,15 @@ const unsigned char * dtk = contrac_get_daily_key(contrac);
 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 * rpi = rpi_new();
-rpi_assign(rpi, captured_bytes, time_interval_number);
-rpi_list_append(rpis, rpi);
+rpi_list_add_beacon(rpis, captured_bytes, time_interval_number);
 ```
 
 Construct a list of DTKs from data downloaded from a Diagnosis Server.
 ```
 DtkList * dtks = dtk_list_new();
-
 // Add data downloaded from the server to the list
-Dtk * dtk = dtk_new();
-dtk_assign(dtk, dtk_bytes, day_number);
-dtk_list_append(dtks, dtk);
+dtk_list_add_diagnosis(dtks, dtk_bytes, day_number);
 ```
 
 Having collected these two lists any matches can be tested for as follows. 
index 9478054..ca29847 100644 (file)
@@ -40,11 +40,15 @@ void contrac_delete(Contrac * data);
 bool contrac_generate_tracing_key(Contrac * data);
 bool contrac_set_day_number(Contrac * data, uint32_t day_number);
 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);
 
 const unsigned char * 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);
 void contrac_get_daily_key_base64(Contrac const * data, char * base64);
 
index 68d5aad..7a72d76 100644 (file)
@@ -29,9 +29,6 @@
 
 // Function prototypes
 
-void contrac_set_tracing_key(Contrac * data, unsigned char const * tracing_key);
-bool contrac_set_tracing_key_base64(Contrac * data, char const * tracing_key);
-
 // Function definitions
 
 #endif // __CONTRAC_PRIVATE_H
index 1525ebb..c263fe2 100644 (file)
@@ -33,7 +33,7 @@ typedef struct _Dtk Dtk;
 Dtk * dtk_new();
 void dtk_delete(Dtk * data);
 
-bool contrac_generate_daily_key(Dtk * data, Contrac const * contrac, uint32_t day_number);
+bool dtk_generate_daily_key(Dtk * data, Contrac const * contrac, uint32_t day_number);
 const unsigned char * 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);
index 2eacb68..a681229 100644 (file)
@@ -35,6 +35,8 @@ DtkList * dtk_list_new();
 void dtk_list_delete(DtkList * data);
 
 void dtk_list_append(DtkList * data, Dtk * dtk);
+void dtk_list_add_diagnosis(DtkList * data, unsigned char const * dtk_bytes, uint32_t day_number);
+
 DtkListItem const * dtk_list_first(DtkList const * data);
 DtkListItem const * dtk_list_next(DtkListItem const * data);
 Dtk const * dtk_list_get_dtk(DtkListItem const * data);
index 7814708..efe2f7c 100644 (file)
@@ -35,6 +35,7 @@ RpiList * rpi_list_new();
 void rpi_list_delete(RpiList * data);
 
 void rpi_list_append(RpiList * data, Rpi * rpi);
+void rpi_list_add_beacon(RpiList * data, unsigned char const * rpi_bytes, uint8_t time_interval_number);
 
 RpiListItem const * rpi_list_first(RpiList const * data);
 RpiListItem const * rpi_list_next(RpiListItem const * data);
index 38b0c3f..41df6d1 100644 (file)
@@ -20,6 +20,8 @@
 
 // Includes
 
+#include <time.h>
+
 // Defines
 
 #define MAX(a,b) \
@@ -41,6 +43,9 @@ size_t base64_decode_size(size_t base64_input);
 void base64_encode_binary_to_base64(unsigned char const *input, size_t input_size, unsigned char *output, size_t *output_size);
 void base64_decode_base64_to_binary(unsigned char const *input, size_t input_size, unsigned char *output, size_t *output_size);
 
+uint32_t epoch_to_day_number(time_t epoch);
+uint8_t epoch_to_time_interval_number(time_t epoch);
+
 // Function definitions
 
 #endif // __UTILS_H
index 47070d3..ed925cb 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <stddef.h>
+#include <time.h>
 
 #include <openssl/crypto.h>
 #include <openssl/rand.h>
@@ -48,9 +49,6 @@ struct _Contrac {
        // Rolling proximity identifier
        Rpi * rpi;
 
-       uint32_t day_number;
-       uint8_t time_interval_number;
-       
        uint32_t status;
 };
 
@@ -102,11 +100,10 @@ bool contrac_set_day_number(Contrac * data, uint32_t day_number) {
        result = ((data->status & STATUS_TK) != 0);
 
        if (result) {
-               result = contrac_generate_daily_key(data->dtk, data, day_number);
+               result = dtk_generate_daily_key(data->dtk, data, day_number);
        }
 
        if (result) {
-               data->day_number = day_number;
                data->status |= STATUS_DTK;
        }
        
@@ -123,7 +120,6 @@ bool contrac_set_time_interval_number(Contrac * data, uint8_t time_interval_numb
        }
 
        if (result) {
-               data->time_interval_number = time_interval_number;
                data->status |= STATUS_RPI;
        }
        
@@ -209,8 +205,44 @@ void contrac_get_proximity_id_base64(Contrac const * data, char * base64) {
        }
 }
 
+bool contrac_update_current_time(Contrac * data) {
+       bool result;
+       time_t epoch;
+       uint32_t dn_stored;
+       uint32_t dn_now;
+       uint8_t tn_stored;
+       uint8_t tn_now;
+
+       result = true;
+
+       if ((data->status & STATUS_TK) == 0) {
+               // No Tracing Key has been set, so generate a random key
+               result = contrac_generate_tracing_key(data);
+       }
+
+       epoch = time(NULL);
+
+       if (result) {
+               dn_now = epoch_to_day_number(epoch);
+               dn_stored = dtk_get_day_number(data->dtk);
+
+               // Only set again if uninitialised or the time has changed
+               if ((dn_now != dn_stored) || ((data->status & STATUS_DTK) == 0)) {
+                       result = contrac_set_day_number(data, dn_now);
+               }
+       }
 
+       if (result) {
+               tn_now = epoch_to_time_interval_number(epoch);
+               tn_stored= rpi_get_time_interval_number(data->rpi);
 
+               // Only set again if uninitialised or the time has changed
+               if ((tn_now != tn_stored) || (dn_now != dn_stored) || ((data->status & STATUS_RPI) == 0)) {
+                       result = contrac_set_time_interval_number(data, tn_now);
+               }
+       }
 
+       return result;
+}
 
 
index 3febd9f..e0c8eeb 100644 (file)
--- a/src/dtk.c
+++ b/src/dtk.c
@@ -65,7 +65,7 @@ void dtk_delete(Dtk * data) {
        }
 }
 
-bool contrac_generate_daily_key(Dtk * data, Contrac const * contrac, uint32_t day_number) {
+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)];
        size_t out_length = 0;
index 9ef41f7..daa03d0 100644 (file)
@@ -98,4 +98,9 @@ Dtk const * dtk_list_get_dtk(DtkListItem const * data) {
        return data->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);
+}
 
index 7523ba4..abef1bd 100644 (file)
--- a/src/rpi.c
+++ b/src/rpi.c
@@ -66,7 +66,7 @@ void rpi_delete(Rpi * data) {
 
 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(uint16_t)];
+       unsigned char encode[sizeof(RPI_INFO_PREFIX) + sizeof(time_interval_number)];
        unsigned char output[EVP_MAX_MD_SIZE];
        unsigned int out_length = 0;
        unsigned int pos;
index fb482ba..a21b0da 100644 (file)
@@ -99,4 +99,12 @@ Rpi const * rpi_list_get_rpi(RpiListItem const * data) {
        return data->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);
+}
+
+
+
 
index 1fbb716..443f2a2 100644 (file)
@@ -66,4 +66,32 @@ void base64_decode_base64_to_binary(unsigned char const *input, size_t input_siz
        EVP_DecodeBlock(output, input, size_in);
 }
 
+uint32_t epoch_to_day_number(time_t epoch) {
+       uint32_t day_number;
+
+       // DayNumber <- (Number of Seconds since Epoch) / 60 × 60 × 24
+       day_number = epoch / (60 * 60 * 24);
+
+       return day_number;
+}
+
+uint8_t epoch_to_time_interval_number(time_t epoch) {
+       uint8_t time_interval_number;
+       uint32_t day_number;
+       uint32_t seconds;
+
+       // TimeNumberInterval <- (Seconds Since Start of DayNumber) / 60 × 10
+       day_number = epoch_to_day_number(epoch);
+       seconds = epoch - (day_number * (60 * 60 * 24));
+
+       time_interval_number = seconds / (60 * 10);
+
+       // Falls in interval [0,143]
+       if (time_interval_number > 143) {
+               time_interval_number = 143;
+       }
+
+       return time_interval_number;
+}
+
 
index b697a94..65bcc4f 100644 (file)
 
 // Function prototypes
 
+// Override time function
+static time_t fake_time = 0;
+time_t time(time_t *__timer) {
+       return fake_time;
+}
+
 // Function definitions
 
 START_TEST (check_base64) {
@@ -210,19 +216,19 @@ START_TEST (check_rpi) {
        ck_assert(result);
        contrac_get_proximity_id_base64(contrac, rpi_base64);
        ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
-       ck_assert_str_eq(rpi_base64, "++ucH9hoIkGwCzM+J09faQ==");
+       ck_assert_str_eq(rpi_base64, "yStiu899O+6xvdLiUdrpsA==");
 
        result = contrac_set_time_interval_number(contrac, 82);
        ck_assert(result);
        contrac_get_proximity_id_base64(contrac, rpi_base64);
        ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
-       ck_assert_str_eq(rpi_base64, "GrqeroryZQ+Uvhx10zfKWw==");
+       ck_assert_str_eq(rpi_base64, "aFTYIeEUGYKELi8TUUql+Q==");
 
        result = contrac_set_time_interval_number(contrac, 143);
        ck_assert(result);
        contrac_get_proximity_id_base64(contrac, rpi_base64);
        ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
-       ck_assert_str_eq(rpi_base64, "+9eL1UlYZ9buUCFF5qRDUA==");
+       ck_assert_str_eq(rpi_base64, "MK9mDdgTsgsh6Vxp0XhasA==");
 
        contrac_set_tracing_key_base64(contrac, tracing_key_base64[1]);
 
@@ -233,19 +239,19 @@ START_TEST (check_rpi) {
        ck_assert(result);
        contrac_get_proximity_id_base64(contrac, rpi_base64);
        ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
-       ck_assert_str_eq(rpi_base64, "XmePWi0HlgHyBcVUb0KhjQ==");
+       ck_assert_str_eq(rpi_base64, "layNswS/rQxovfYnBhjXJg==");
 
        result = contrac_set_time_interval_number(contrac, 27);
        ck_assert(result);
        contrac_get_proximity_id_base64(contrac, rpi_base64);
        ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
-       ck_assert_str_eq(rpi_base64, "LlPznz6D044ZKYsY3sHJew==");
+       ck_assert_str_eq(rpi_base64, "BJyzAC3hyVfcWOhQ9paEFA==");
 
        result = contrac_set_time_interval_number(contrac, 143);
        ck_assert(result);
        contrac_get_proximity_id_base64(contrac, rpi_base64);
        ck_assert_int_eq(strlen(rpi_base64), RPI_SIZE_BASE64);
-       ck_assert_str_eq(rpi_base64, "QDG50cy9NTXZ3zDAUGkePQ==");
+       ck_assert_str_eq(rpi_base64, "ItETUQc372fOzJKHvF8z6w==");
 
        // Clean up
        contrac_delete(contrac);
@@ -268,8 +274,6 @@ START_TEST (check_match) {
        int pos;
        const unsigned char * rpi_bytes;
        const unsigned char * dtk_bytes;
-       Rpi * rpi;
-       Dtk * dtk;
        MatchList * matches;
        MatchListItem const * match;
 
@@ -293,10 +297,7 @@ START_TEST (check_match) {
                ck_assert(result);
 
                rpi_bytes = contrac_get_proximity_id(contrac);
-               rpi = rpi_new();
-               rpi_assign(rpi, rpi_bytes, beacon_times[pos]);
-
-               rpi_list_append(beacon_list, rpi);
+               rpi_list_add_beacon(beacon_list, rpi_bytes, beacon_times[pos]);
        }
 
        // Generate some diagnosis data (as if provided by a diagnosis server)
@@ -307,10 +308,7 @@ START_TEST (check_match) {
                ck_assert(result);
 
                dtk_bytes = contrac_get_daily_key(contrac);
-               dtk = dtk_new();
-               dtk_assign(dtk, dtk_bytes, diagnosis_days[pos]);
-
-               dtk_list_append(diagnosis_list, dtk);
+               dtk_list_add_diagnosis(diagnosis_list, dtk_bytes, diagnosis_days[pos]);
        }
 
        // Check that the matching algorithm identifies the beacons that match
@@ -342,6 +340,60 @@ START_TEST (check_match) {
 }
 END_TEST
 
+START_TEST (check_time) {
+       bool result;
+       char const *tracing_key_base64 = "3UmKrtcQ2tfLE8UPSXHb4PtgRfE0E2xdSs+PGVIS8cc=";
+       uint32_t dn;
+       uint8_t tn;
+       time_t base = 1587415596;
+       time_t check;
+       Contrac * contrac;
+       char dtk_base64[DTK_SIZE_BASE64 + 1];
+       char rpi_base64[RPI_SIZE_BASE64 + 1];
+
+       check = base;
+       dn = epoch_to_day_number(check);
+       ck_assert_int_eq(dn, 18372);
+       tn = epoch_to_time_interval_number(check);
+       ck_assert_int_eq(tn, 124);
+
+       check = base + (24 * 60 * 60);
+       dn = epoch_to_day_number(check);
+       ck_assert_int_eq(dn, 18372 + 1);
+       tn = epoch_to_time_interval_number(check);
+       ck_assert_int_eq(tn, 124);
+
+       check = base - 675 * (24 * 60 * 60);
+       dn = epoch_to_day_number(check);
+       ck_assert_int_eq(dn, 18372 - 675);
+       tn = epoch_to_time_interval_number(check);
+       ck_assert_int_eq(tn, 124);
+
+       check = base + 15 * (10 * 60);
+       dn = epoch_to_day_number(check);
+       ck_assert_int_eq(dn, 18372);
+       tn = epoch_to_time_interval_number(check);
+       ck_assert_int_eq(tn, 124 + 15);
+
+       fake_time = 1587415596;
+
+       contrac = contrac_new();
+       contrac_set_tracing_key_base64(contrac, tracing_key_base64);
+
+       contrac_update_current_time(contrac);
+       result = contrac_get_initialised(contrac);
+       ck_assert(result);
+
+       contrac_get_daily_key_base64(contrac, dtk_base64);
+       ck_assert_str_eq(dtk_base64, "6GMXmeDAR5XU0AEtZQJ+tA==");
+
+       contrac_get_proximity_id_base64(contrac, rpi_base64);
+       ck_assert_str_eq(rpi_base64, "ysbjVuF7xf9eDH2y2T8VpQ==");
+
+       contrac_delete(contrac);
+}
+END_TEST
+
 int main(void) {
        int failed;
        Suite * s;
@@ -356,6 +408,7 @@ int main(void) {
        tcase_add_test(tc, check_dtk);
        tcase_add_test(tc, check_rpi);
        tcase_add_test(tc, check_match);
+       tcase_add_test(tc, check_time);
        suite_add_tcase(s, tc);
        sr = srunner_create(s);