ed925cbb74a54bbe1aade2f076c5c69b28e1db08
[libcontrac.git] / src / contrac.c
1 /** \ingroup contrac
2 * @file
3 * @author David Llewellyn-Jones
4 * @version $(VERSION)
5 *
6 * @section LICENSE
7 *
8 *
9 *
10 * @brief
11 * @section DESCRIPTION
12 *
13 *
14 *
15 */
16
17 // Includes
18
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <stddef.h>
23 #include <time.h>
24
25 #include <openssl/crypto.h>
26 #include <openssl/rand.h>
27 #include <openssl/err.h>
28
29 #include "contrac/log.h"
30 #include "contrac/utils.h"
31 #include "contrac/rpi.h"
32
33 #include "contrac/contrac.h"
34
35 // Defines
36
37 #define STATUS_TK (1 << 0)
38 #define STATUS_DTK (1 << 1)
39 #define STATUS_RPI (1 << 2)
40
41 #define STATUS_INITIALISED (STATUS_TK | STATUS_DTK | STATUS_RPI)
42 // Structures
43
44 struct _Contrac {
45 // Tracing key
46 unsigned char tk[TK_SIZE];
47 // Daily key
48 Dtk * dtk;
49 // Rolling proximity identifier
50 Rpi * rpi;
51
52 uint32_t status;
53 };
54
55 // Function prototypes
56
57 // Function definitions
58
59 Contrac * contrac_new() {
60 Contrac * data;
61
62 data = calloc(sizeof(Contrac), 1);
63 data->dtk = dtk_new();
64 data->rpi = rpi_new();
65
66 return data;
67 }
68
69 void contrac_delete(Contrac * data) {
70 if (data) {
71 dtk_delete(data->dtk);
72 rpi_delete(data->rpi);
73
74 // Clear the data for security
75 memset(data, 0, sizeof(Contrac));
76
77 free(data);
78 }
79 }
80
81 bool contrac_generate_tracing_key(Contrac * data) {
82 int result;
83
84 // tk <- CRNG(32)
85 result = RAND_bytes(data->tk, TK_SIZE);
86
87 if (result == 1) {
88 data->status |= STATUS_TK;
89 }
90 else {
91 LOG(LOG_ERR, "Error generating tracing key: %lu\n", ERR_get_error());
92 }
93
94 return (result == 1);
95 }
96
97 bool contrac_set_day_number(Contrac * data, uint32_t day_number) {
98 bool result;
99
100 result = ((data->status & STATUS_TK) != 0);
101
102 if (result) {
103 result = dtk_generate_daily_key(data->dtk, data, day_number);
104 }
105
106 if (result) {
107 data->status |= STATUS_DTK;
108 }
109
110 return result;
111 }
112
113 bool contrac_set_time_interval_number(Contrac * data, uint8_t time_interval_number) {
114 bool result;
115
116 result = ((data->status & STATUS_DTK) != 0);
117
118 if (result) {
119 result = rpi_generate_proximity_id(data->rpi, data->dtk, time_interval_number);
120 }
121
122 if (result) {
123 data->status |= STATUS_RPI;
124 }
125
126 return result;
127 }
128
129 bool contrac_get_initialised(Contrac const * data) {
130 return ((data->status & STATUS_INITIALISED) == STATUS_INITIALISED);
131 }
132
133 void contrac_set_tracing_key(Contrac * data, unsigned char const * tracing_key) {
134 memcpy(data->tk, tracing_key, TK_SIZE);
135 data->status |= STATUS_TK;
136 }
137
138 const unsigned char * contrac_get_tracing_key(Contrac const * data) {
139 return data->tk;
140 }
141
142 // base64 buffer must be at least 45 bytes (TK_SIZE_BASE64 + 1)
143 void contrac_get_tracing_key_base64(Contrac const * data, char * base64) {
144 size_t size = TK_SIZE_BASE64 + 1;
145 base64_encode_binary_to_base64(data->tk, TK_SIZE, (unsigned char *)base64, &size);
146
147 if (size != (TK_SIZE_BASE64 + 1)) {
148 LOG(LOG_ERR, "Base64 tracing key has incorrect size of %d bytes.\n", size);
149 }
150 }
151
152 // tracing_key input must be 44 bytes long
153 bool contrac_set_tracing_key_base64(Contrac * data, char const * tracing_key) {
154 bool result = true;
155 unsigned char tk[TK_SIZE];
156 size_t size;
157
158 if (strlen(tracing_key) != TK_SIZE_BASE64) {
159 LOG(LOG_ERR, "Base64 tracing key has incorrect size. Should be %d bytes.\n", TK_SIZE_BASE64);
160 result = false;
161 }
162
163 if (result) {
164 size = TK_SIZE;
165 base64_decode_base64_to_binary((unsigned char *)tracing_key, TK_SIZE_BASE64, tk, &size);
166
167 if (size < TK_SIZE) {
168 LOG(LOG_ERR, "Base64 tracking key output is too short %d bytes.\n", size);
169 result = false;
170 }
171 }
172
173 if (result) {
174 contrac_set_tracing_key(data, tk);
175 }
176
177 return result;
178 }
179
180 const unsigned char * contrac_get_daily_key(Contrac const * data) {
181 return dtk_get_daily_key(data->dtk);
182 }
183
184 // base64 buffer must be at least 25 bytes (DTK_SIZE_BASE64 + 1)
185 void contrac_get_daily_key_base64(Contrac const * data, char * base64) {
186 size_t size = DTK_SIZE_BASE64 + 1;
187 base64_encode_binary_to_base64(dtk_get_daily_key(data->dtk), DTK_SIZE, (unsigned char *)base64, &size);
188
189 if (size != (DTK_SIZE_BASE64 + 1)) {
190 LOG(LOG_ERR, "Base64 daily key has incorrect size of %d bytes.\n", size);
191 }
192 }
193
194 const unsigned char * contrac_get_proximity_id(Contrac const * data) {
195 return rpi_get_proximity_id(data->rpi);
196 }
197
198 // base64 buffer must be at least 25 bytes (RPI_SIZE_BASE64 + 1)
199 void contrac_get_proximity_id_base64(Contrac const * data, char * base64) {
200 size_t size = RPI_SIZE_BASE64 + 1;
201 base64_encode_binary_to_base64(rpi_get_proximity_id(data->rpi), RPI_SIZE, (unsigned char *)base64, &size);
202
203 if (size != (RPI_SIZE_BASE64 + 1)) {
204 LOG(LOG_ERR, "Base64 proximity id has incorrect size of %d bytes.\n", size);
205 }
206 }
207
208 bool contrac_update_current_time(Contrac * data) {
209 bool result;
210 time_t epoch;
211 uint32_t dn_stored;
212 uint32_t dn_now;
213 uint8_t tn_stored;
214 uint8_t tn_now;
215
216 result = true;
217
218 if ((data->status & STATUS_TK) == 0) {
219 // No Tracing Key has been set, so generate a random key
220 result = contrac_generate_tracing_key(data);
221 }
222
223 epoch = time(NULL);
224
225 if (result) {
226 dn_now = epoch_to_day_number(epoch);
227 dn_stored = dtk_get_day_number(data->dtk);
228
229 // Only set again if uninitialised or the time has changed
230 if ((dn_now != dn_stored) || ((data->status & STATUS_DTK) == 0)) {
231 result = contrac_set_day_number(data, dn_now);
232 }
233 }
234
235 if (result) {
236 tn_now = epoch_to_time_interval_number(epoch);
237 tn_stored= rpi_get_time_interval_number(data->rpi);
238
239 // Only set again if uninitialised or the time has changed
240 if ((tn_now != tn_stored) || (dn_now != dn_stored) || ((data->status & STATUS_RPI) == 0)) {
241 result = contrac_set_time_interval_number(data, tn_now);
242 }
243 }
244
245 return result;
246 }
247
248