Add initial crypto functionality
[libcontrac.git] / src / rpi.c
diff --git a/src/rpi.c b/src/rpi.c
new file mode 100644 (file)
index 0000000..7523ba4
--- /dev/null
+++ b/src/rpi.c
@@ -0,0 +1,141 @@
+/** \ingroup contrac
+ * @file
+ * @author     David Llewellyn-Jones
+ * @version    $(VERSION)
+ *
+ * @section LICENSE
+ *
+ *
+ *
+ * @brief
+ * @section DESCRIPTION
+ *
+ *
+ *
+ */
+
+// Includes
+
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <openssl/crypto.h>
+#include <openssl/hmac.h>
+#include <openssl/err.h>
+
+#include "contrac/contrac.h"
+#include "contrac/utils.h"
+#include "contrac/log.h"
+
+#include "contrac/rpi.h"
+
+// Defines
+
+#define RPI_INFO_PREFIX "CT-RPI"
+
+// Structures
+
+struct _Rpi {
+       // Rolling proximity identifier
+       unsigned char rpi[RPI_SIZE];
+       uint8_t time_interval_number;
+};
+
+// Function prototypes
+
+// Function definitions
+
+Rpi * rpi_new() {
+       Rpi * data;
+       
+       data = calloc(sizeof(Rpi), 1);
+
+       return data;
+}
+
+void rpi_delete(Rpi * data) {
+       if (data) {
+               // Clear the data for security
+               memset(data, 0, sizeof(Rpi));
+
+               free(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 output[EVP_MAX_MD_SIZE];
+       unsigned int out_length = 0;
+       unsigned int pos;
+       unsigned int min;
+       unsigned char const * daily_key;
+
+       // RPI_{i, j} <- Truncate(HMAC(dkt_i, (UTF8("CT-RPI") || TIN_j)), 16)
+
+       if (result > 0) {
+               // Produce Info sequence UTF8("CT-DTK") || D_i)
+               // From the spec it's not clear whether this is string or byte concatenation.
+               // Here we use byte, but it might have to be changed
+               memcpy(encode, RPI_INFO_PREFIX, sizeof(RPI_INFO_PREFIX));
+               ((uint8_t *)(encode + sizeof(RPI_INFO_PREFIX)))[0] = time_interval_number;
+               out_length = sizeof(output);
+
+               daily_key = dtk_get_daily_key(dtk);
+               HMAC(EVP_sha256(), daily_key, DTK_SIZE, encode, sizeof(encode), output, &out_length);
+
+               _Static_assert ((EVP_MAX_MD_SIZE >= 16), "HMAC buffer size too small");
+
+               // Truncate and copy the result
+               min = MIN(out_length, 16);
+               for (pos = 0; pos < min; ++pos) {
+                       data->rpi[pos] = output[pos];
+               }
+               // Zero out padding if there is any
+               for (pos = min; pos < 16; ++pos) {
+                       data->rpi[pos] = 0;
+               }
+       }
+       
+       if (result > 0) {
+               data->time_interval_number = time_interval_number;
+       }
+
+       if (result <= 0) {
+               LOG(LOG_ERR, "Error generating rolling proximity id: %lu\n", ERR_get_error());
+       }
+
+       return (result > 0);
+}
+
+const unsigned char * rpi_get_proximity_id(Rpi const * data) {
+       return data->rpi;
+}
+
+uint8_t rpi_get_time_interval_number(Rpi const * data) {
+       return data->time_interval_number;
+}
+
+
+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;
+}
+
+bool rpi_compare(Rpi const * data, Rpi const * comparitor) {
+       unsigned char left[RPI_SIZE_BASE64 + 1];
+       unsigned char right[RPI_SIZE_BASE64 + 1];
+       size_t size;
+
+       size = RPI_SIZE_BASE64 + 1;
+       base64_encode_binary_to_base64(data->rpi, RPI_SIZE, left, &size);
+
+       size = RPI_SIZE_BASE64 + 1;
+       base64_encode_binary_to_base64(comparitor->rpi, RPI_SIZE, right, &size);
+
+       return (memcmp(data, comparitor, RPI_SIZE) == 0);
+}
+
+