Add initial crypto functionality
[libcontrac.git] / src / rpi.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 <string.h>
21 #include <stddef.h>
22 #include <stdint.h>
23
24 #include <openssl/crypto.h>
25 #include <openssl/hmac.h>
26 #include <openssl/err.h>
27
28 #include "contrac/contrac.h"
29 #include "contrac/utils.h"
30 #include "contrac/log.h"
31
32 #include "contrac/rpi.h"
33
34 // Defines
35
36 #define RPI_INFO_PREFIX "CT-RPI"
37
38 // Structures
39
40 struct _Rpi {
41 // Rolling proximity identifier
42 unsigned char rpi[RPI_SIZE];
43 uint8_t time_interval_number;
44 };
45
46 // Function prototypes
47
48 // Function definitions
49
50 Rpi * rpi_new() {
51 Rpi * data;
52
53 data = calloc(sizeof(Rpi), 1);
54
55 return data;
56 }
57
58 void rpi_delete(Rpi * data) {
59 if (data) {
60 // Clear the data for security
61 memset(data, 0, sizeof(Rpi));
62
63 free(data);
64 }
65 }
66
67 bool rpi_generate_proximity_id(Rpi * data, Dtk const * dtk, uint8_t time_interval_number) {
68 int result = 1;
69 unsigned char encode[sizeof(RPI_INFO_PREFIX) + sizeof(uint16_t)];
70 unsigned char output[EVP_MAX_MD_SIZE];
71 unsigned int out_length = 0;
72 unsigned int pos;
73 unsigned int min;
74 unsigned char const * daily_key;
75
76 // RPI_{i, j} <- Truncate(HMAC(dkt_i, (UTF8("CT-RPI") || TIN_j)), 16)
77
78 if (result > 0) {
79 // Produce Info sequence UTF8("CT-DTK") || D_i)
80 // From the spec it's not clear whether this is string or byte concatenation.
81 // Here we use byte, but it might have to be changed
82 memcpy(encode, RPI_INFO_PREFIX, sizeof(RPI_INFO_PREFIX));
83 ((uint8_t *)(encode + sizeof(RPI_INFO_PREFIX)))[0] = time_interval_number;
84 out_length = sizeof(output);
85
86 daily_key = dtk_get_daily_key(dtk);
87 HMAC(EVP_sha256(), daily_key, DTK_SIZE, encode, sizeof(encode), output, &out_length);
88
89 _Static_assert ((EVP_MAX_MD_SIZE >= 16), "HMAC buffer size too small");
90
91 // Truncate and copy the result
92 min = MIN(out_length, 16);
93 for (pos = 0; pos < min; ++pos) {
94 data->rpi[pos] = output[pos];
95 }
96 // Zero out padding if there is any
97 for (pos = min; pos < 16; ++pos) {
98 data->rpi[pos] = 0;
99 }
100 }
101
102 if (result > 0) {
103 data->time_interval_number = time_interval_number;
104 }
105
106 if (result <= 0) {
107 LOG(LOG_ERR, "Error generating rolling proximity id: %lu\n", ERR_get_error());
108 }
109
110 return (result > 0);
111 }
112
113 const unsigned char * rpi_get_proximity_id(Rpi const * data) {
114 return data->rpi;
115 }
116
117 uint8_t rpi_get_time_interval_number(Rpi const * data) {
118 return data->time_interval_number;
119 }
120
121
122 void rpi_assign(Rpi * data, unsigned char const * rpi_bytes, uint8_t time_interval_number) {
123 memcpy(data->rpi, rpi_bytes, RPI_SIZE);
124 data->time_interval_number = time_interval_number;
125 }
126
127 bool rpi_compare(Rpi const * data, Rpi const * comparitor) {
128 unsigned char left[RPI_SIZE_BASE64 + 1];
129 unsigned char right[RPI_SIZE_BASE64 + 1];
130 size_t size;
131
132 size = RPI_SIZE_BASE64 + 1;
133 base64_encode_binary_to_base64(data->rpi, RPI_SIZE, left, &size);
134
135 size = RPI_SIZE_BASE64 + 1;
136 base64_encode_binary_to_base64(comparitor->rpi, RPI_SIZE, right, &size);
137
138 return (memcmp(data, comparitor, RPI_SIZE) == 0);
139 }
140
141