Add initial crypto functionality
[libcontrac.git] / src / dtk.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/kdf.h>
26 #include <openssl/err.h>
27 #include <openssl/evp.h>
28
29 #include "contrac/contrac.h"
30 #include "contrac/utils.h"
31 #include "contrac/log.h"
32
33 #include "contrac/dtk.h"
34
35 // Defines
36
37 #define DTK_INFO_PREFIX "CT-DTK"
38
39 // Structures
40
41 struct _Dtk {
42 // Daily key
43 unsigned char dtk[DTK_SIZE];
44 uint32_t day_number;
45 };
46
47 // Function prototypes
48
49 // Function definitions
50
51 Dtk * dtk_new() {
52 Dtk * data;
53
54 data = calloc(sizeof(Dtk), 1);
55
56 return data;
57 }
58
59 void dtk_delete(Dtk * data) {
60 if (data) {
61 // Clear the data for security
62 memset(data, 0, sizeof(Dtk));
63
64 free(data);
65 }
66 }
67
68 bool contrac_generate_daily_key(Dtk * data, Contrac const * contrac, uint32_t day_number) {
69 int result = 1;
70 char encode[sizeof(DTK_INFO_PREFIX) + sizeof(day_number)];
71 size_t out_length = 0;
72 EVP_PKEY_CTX *pctx = NULL;
73 const unsigned char * tk;
74
75 // dtk_i <- HKDF(tk, NULL, (UTF8("CT-DTK") || D_i), 16)
76
77 if (result > 0) {
78 // Produce Info sequence UTF8("CT-DTK") || D_i)
79 // From the spec it's not clear whether this is string or byte concatenation.
80 // Here we use byte, but it might have to be changed
81 memcpy(encode, DTK_INFO_PREFIX, sizeof(DTK_INFO_PREFIX));
82 ((uint32_t *)(encode + sizeof(DTK_INFO_PREFIX)))[0] = day_number;
83
84 pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
85
86 result = EVP_PKEY_derive_init(pctx);
87 }
88
89 if (result > 0) {
90 result = EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256());
91 }
92
93 if (result > 0) {
94 result = EVP_PKEY_CTX_set1_hkdf_salt(pctx, NULL, 4);
95 }
96
97 if (result > 0) {
98 tk = contrac_get_tracing_key(contrac);
99 result = EVP_PKEY_CTX_set1_hkdf_key(pctx, tk, TK_SIZE);
100 }
101
102 if (result > 0) {
103 result = EVP_PKEY_CTX_add1_hkdf_info(pctx, encode, sizeof(encode));
104 }
105
106 if (result > 0) {
107 out_length = DTK_SIZE;
108 result = EVP_PKEY_derive(pctx, data->dtk, &out_length);
109 }
110
111 if ((result > 0) && (out_length == DTK_SIZE)) {
112 data->day_number = day_number;
113 result = 1;
114 }
115
116 if (result <= 0) {
117 LOG(LOG_ERR, "Error generating daily key: %lu\n", ERR_get_error());
118 }
119
120 // Freeing a NULL value is safe
121 EVP_PKEY_CTX_free(pctx);
122
123 return (result > 0);
124 }
125
126 const unsigned char * dtk_get_daily_key(Dtk const * data) {
127 return data->dtk;
128 }
129
130 uint32_t dtk_get_day_number(Dtk const * data) {
131 return data->day_number;
132 }
133
134 void dtk_assign(Dtk * data, unsigned char const * dtk_bytes, uint32_t day_number) {
135 memcpy(data->dtk, dtk_bytes, DTK_SIZE);
136 data->day_number = day_number;
137 }
138
139