```
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.
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.
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);
// 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
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);
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);
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);
// Includes
+#include <time.h>
+
// Defines
#define MAX(a,b) \
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
#include <stdio.h>
#include <string.h>
#include <stddef.h>
+#include <time.h>
#include <openssl/crypto.h>
#include <openssl/rand.h>
// Rolling proximity identifier
Rpi * rpi;
- uint32_t day_number;
- uint8_t time_interval_number;
-
uint32_t status;
};
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;
}
}
if (result) {
- data->time_interval_number = time_interval_number;
data->status |= STATUS_RPI;
}
}
}
+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;
+}
}
}
-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;
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);
+}
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;
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);
+}
+
+
+
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;
+}
+
// 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) {
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]);
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);
int pos;
const unsigned char * rpi_bytes;
const unsigned char * dtk_bytes;
- Rpi * rpi;
- Dtk * dtk;
MatchList * matches;
MatchListItem const * 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)
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
}
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;
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);