]> git.siccegge.de Git - software/DIPE.git/blob - src/DIPE.cxx
implement hybrid encryption
[software/DIPE.git] / src / DIPE.cxx
1 #include "DIPE.h"
2
3 #include <string.h>
4 #include <nettle/hkdf.h>
5 #include <nettle/hmac.h>
6 #include <sys/random.h>
7 #include <nettle/gcm.h>
8 #include <nettle/memops.h>
9 #include <arpa/inet.h>
10 #include <algorithm>
11 #include <errno.h>
12
13 using std::min;
14 using std::max;
15
16 struct dipe_param {
17 pairing_t pairing;
18 element_t g1;
19 element_t g2;
20 element_t gt;
21 };
22
23 struct dipe_master_publickey {
24 size_t dimension;
25 element_t a;
26 element_t* k;
27 };
28
29 struct dipe_master_secretkey {
30 size_t dimension;
31 element_t a;
32 element_t* k;
33 };
34
35 struct dipe_secretkey {
36 size_t dimension;
37 element_t d;
38 };
39
40 struct dipe_ctxt {
41 size_t dimension;
42 element_t s;
43 element_t* cx;
44 element_t c;
45 };
46
47
48 namespace {
49 size_t dipe_h_length(element_t elem, size_t dimension) {
50 return 16 /*cid*/ + dimension * element_length_in_bytes(elem);
51 }
52
53 void dipe_generate_h(char* cid, element_t* y, size_t dimension, unsigned char* result) {
54 memcpy(result, cid, 16);
55 unsigned char* next_element = result+16;
56 for (size_t i = 0; i < dimension; ++i) {
57 element_to_bytes(next_element, y[i]);
58 next_element += element_length_in_bytes(y[0]);
59 }
60 }
61
62 void dipe_generate_aeskey(element_t encapkey, uint8_t* aeskey) {
63 struct hmac_sha256_ctx ctx;
64 uint8_t salt[SHA256_DIGEST_SIZE];
65 memset(salt, 0, SHA256_DIGEST_SIZE);
66 size_t elen = element_length_in_bytes(encapkey);
67 uint8_t coded[elen];
68 element_to_bytes(coded, encapkey);
69
70 hmac_sha256_set_key(&ctx, SHA256_DIGEST_SIZE, salt);
71 hkdf_extract(&ctx,
72 (nettle_hash_update_func *)hmac_sha256_update,
73 (nettle_hash_digest_func *)hmac_sha256_digest,
74 SHA256_DIGEST_SIZE,
75 elen, coded,
76 aeskey);
77 }
78
79 /* Data format is iv | enc(4 byte len | ptxt | 0 padding) | tag
80 */
81 int dipe_aes_encrypt(uint8_t* key, size_t ptxt_len, uint8_t* ptxt, size_t ctxt_len, uint8_t* ctxt) {
82 struct gcm_aes128_ctx ctx;
83 uint8_t iv[12];
84 uint8_t block[16];
85 uint32_t coded_ptxtlen;
86
87 ctxt_len -= (12 + 16); /* IV + Tag */
88 if (ctxt_len < ptxt_len) return -1;
89
90 getrandom(iv, 12, 0);
91 memcpy(ctxt, iv, 12);
92 ctxt += 12;
93 memset(block, 0, 16);
94 gcm_aes128_set_key(&ctx, key);
95 gcm_aes128_set_iv(&ctx, 12, iv);
96
97 /* First Block */
98 coded_ptxtlen = htonl(ptxt_len);
99 memcpy(block, &coded_ptxtlen, 4);
100 memcpy(block+4, ptxt, min((size_t)12, ptxt_len));
101 ptxt_len -= min((size_t)12, ptxt_len);
102 ptxt += 12;
103
104 while (ctxt_len >= 16) {
105 gcm_aes128_encrypt(&ctx, 16, ctxt, block);
106 memset(block, 0, 16);
107 ctxt_len -= 16;
108 ctxt += 16;
109
110 if (ptxt_len > 0) {
111 memcpy(block, ptxt, min((size_t)16, ptxt_len));
112 ptxt += 16;
113 ptxt_len -= min((size_t)16, ptxt_len);
114 }
115 }
116
117 if (ctxt_len > 0) {
118 gcm_aes128_encrypt(&ctx, ctxt_len, ctxt, block);
119 ctxt += ctxt_len;
120 }
121
122 gcm_aes128_digest(&ctx, 16, ctxt);
123 return 0;
124 }
125
126 int dipe_aes_decrypt(uint8_t* key, size_t len, uint8_t* ctxt, uint8_t* ptxt) {
127 struct gcm_aes128_ctx ctx;
128 uint8_t block[16];
129
130 gcm_aes128_set_key(&ctx, key);
131 gcm_aes128_set_iv(&ctx, 12, ctxt);
132 ctxt += 12; len -= 12;
133 len -= 16; /* GCM tag */
134
135
136 gcm_aes128_decrypt(&ctx, min((size_t)16, len), block, ctxt);
137 uint32_t ptxtlen = 0;
138 memcpy(&ptxtlen, block, 4);
139 memcpy(ptxt, block+4, min((size_t)12, len-4));
140 ptxtlen = ntohl(ptxtlen);
141 ctxt += min((size_t)16, len); len -= min((size_t)16, len);
142 ptxt += 12;
143
144 if (len > 0) {
145 gcm_aes128_decrypt(&ctx, len, ptxt, ctxt);
146 ctxt += len;
147 }
148 gcm_aes128_digest(&ctx, 16, block);
149
150 /* error case is with return code 0, see manual
151 * https://www.lysator.liu.se/~nisse/nettle/nettle.html#Miscellaneous-functions
152 */
153 if (memeql_sec(ctxt, block, 16) == 0)
154 return 0;
155 else
156 return ptxtlen;
157 }
158 }
159
160 /* Note: we need a curve where membership checking is hard for all
161 * group elements. See also https://ia.cr/2015/247 and followups
162 */
163 void dipe_init(FILE* configfp, dipe_param_t* param) {
164 char buffer[2<<16];
165 (*param) = (dipe_param_t)malloc(sizeof(dipe_param));
166 fread(buffer, 1, 2<<16, configfp);
167
168 pairing_init_set_buf((*param)->pairing, buffer, 2<<16);
169
170 element_init_G1((*param)->g1, (*param)->pairing);
171 element_init_G2((*param)->g2, (*param)->pairing);
172 element_init_GT((*param)->gt, (*param)->pairing);
173
174 element_random((*param)->g1);
175 element_random((*param)->g2);
176 pairing_apply((*param)->gt, (*param)->g1, (*param)->g2, (*param)->pairing);
177 }
178
179 pairing_t* dipe_get_pairing(dipe_param_t param) {
180 return &(param->pairing);
181 }
182
183 void dipe_master_keygen(dipe_param_t param, size_t dimension, dipe_master_publickey_t* pk, dipe_master_secretkey_t* sk) {
184 *pk = (dipe_master_publickey_t)malloc(sizeof(dipe_master_publickey));
185 *sk = (dipe_master_secretkey_t)malloc(sizeof(dipe_master_secretkey));
186
187 (*sk)->dimension = (*pk)->dimension = dimension;
188
189 element_init_Zr((*sk)->a, param->pairing);
190 element_init_GT((*pk)->a, param->pairing);
191 element_random((*sk)->a);
192 element_pow_zn((*pk)->a, param->gt, (*sk)->a);
193
194 (*sk)->k = (element_t*)calloc(dimension, sizeof(element_t));
195 (*pk)->k = (element_t*)calloc(dimension, sizeof(element_t));
196 for (size_t i = 0; i < dimension; ++i) {
197 element_init_Zr((*sk)->k[i], param->pairing);
198 element_init_G1((*pk)->k[i], param->pairing);
199 element_random((*sk)->k[i]);
200 element_pow_zn((*pk)->k[i], param->g1, (*sk)->k[i]);
201 }
202 }
203
204 void dipe_keygen(dipe_param_t param, dipe_master_secretkey_t msk, char* cid, element_t* y, dipe_secretkey_t* sk) {
205 *sk = (dipe_secretkey_t)malloc(sizeof(dipe_secretkey));
206 (*sk)->dimension = msk->dimension;
207 element_init_G2((*sk)->d, param->pairing);
208
209 size_t hash_input_length = dipe_h_length(y[0], msk->dimension);
210 unsigned char hash_input[hash_input_length];
211 element_t h;
212 element_init_G2(h, param->pairing);
213
214 dipe_generate_h(cid, y, msk->dimension, hash_input);
215 element_from_hash(h, hash_input, hash_input_length);
216
217 element_t innerp;
218 element_t tmp;
219
220 element_init_Zr(innerp, param->pairing);
221 element_init_Zr(tmp, param->pairing);
222 element_set0(innerp);
223
224 element_from_hash(h, hash_input, hash_input_length);
225
226 for (size_t i = 0; i < msk->dimension; ++i) {
227 element_mul(tmp, y[i], msk->k[i]);
228 element_add(innerp, innerp, tmp);
229 }
230
231 element_t a2;
232 element_init_G2(a2, param->pairing);
233 element_pow_zn(h, h, innerp);
234 element_pow_zn(a2, param->g2, msk->a);
235 element_mul((*sk)->d, a2, h);
236
237 element_clear(h);
238 element_clear(innerp);
239 element_clear(tmp);
240 element_clear(a2);
241 }
242
243 void dipe_encap(dipe_param_t param, dipe_master_publickey_t mpk, element_t* x, element_t ptxt, dipe_ctxt_t* ctxt) {
244 *ctxt = (dipe_ctxt_t)malloc(sizeof(dipe_ctxt));
245 (*ctxt)->dimension = mpk->dimension;
246
247 element_t r;
248 element_t s;
249 element_init_Zr(r, param->pairing);
250 element_init_Zr(s, param->pairing);
251
252 element_random(r);
253 element_random(s);
254
255 element_init_G1((*ctxt)->s, param->pairing);
256 element_pow_zn((*ctxt)->s, param->g1, s);
257
258 element_t k1;
259 element_t x1;
260 element_init_G1(k1, param->pairing);
261 element_init_G1(x1, param->pairing);
262
263 (*ctxt)->cx = (element_t*)calloc(mpk->dimension, sizeof(element_t));
264 for (size_t i = 0; i < mpk->dimension; ++i){
265 element_pow_zn(x1, param->g1, x[i]);
266 element_pow_zn(x1, x1, r);
267
268 element_pow_zn(k1, mpk->k[i], s);
269
270 element_init_G1((*ctxt)->cx[i], param->pairing);
271 element_mul((*ctxt)->cx[i], k1, x1);
272 }
273
274 element_t at;
275 element_init_GT(at, param->pairing);
276 element_pow_zn(at, mpk->a, s);
277 element_init_GT((*ctxt)->c, param->pairing);
278 element_mul((*ctxt)->c, at, ptxt);
279
280 element_clear(r);
281 element_clear(s);
282 element_clear(k1);
283 element_clear(x1);
284 element_clear(at);
285 }
286
287
288 void dipe_decap(dipe_param_t param, dipe_secretkey_t sk, char* cid, element_t* y, dipe_ctxt_t ctxt, element_t ptxt) {
289 size_t hash_input_length = dipe_h_length(y[0], sk->dimension);
290 unsigned char hash_input[hash_input_length];
291 element_t h;
292 element_init_G2(h, param->pairing);
293
294 dipe_generate_h(cid, y, sk->dimension, hash_input);
295 element_from_hash(h, hash_input, hash_input_length);
296
297 element_t tmp;
298 element_t innerp;
299 element_t hy;
300 element_init_GT(tmp, param->pairing);
301 element_init_GT(innerp, param->pairing);
302 element_init_G2(hy, param->pairing);
303
304 element_set1(innerp);
305 for (size_t i = 0; i < sk->dimension; ++i) {
306 element_pow_zn(hy, h, y[i]);
307 pairing_apply(tmp, ctxt->cx[i], hy, param->pairing);
308 element_mul(innerp, innerp, tmp);
309 }
310
311 pairing_apply(ptxt, ctxt->s, sk->d, param->pairing);
312 element_invert(ptxt, ptxt);
313 element_mul(ptxt, ptxt, ctxt->c);
314 element_mul(ptxt, ptxt, innerp);
315
316 element_clear(h);
317 element_clear(tmp);
318 element_clear(innerp);
319 element_clear(hy);
320 }
321
322 void dipe_encrypt(dipe_param_t param, dipe_master_publickey_t mpk, element_t* x, size_t ptxt_len, char* ptxt, size_t ctxt_len, char* ctxt) {
323 element_t key;
324 uint8_t aes[32];
325 dipe_ctxt_t cap;
326 size_t cap_len;
327
328 element_init_GT(key, param->pairing);
329 element_random(key);
330 dipe_generate_aeskey(key, aes);
331 dipe_encap(param, mpk, x, key, &cap);
332 cap_len = dipe_serialize_ctxt(param, cap, (uint8_t*)ctxt);
333 ctxt += cap_len; ctxt_len -= cap_len;
334
335 dipe_aes_encrypt(aes, ptxt_len, (uint8_t*)ptxt, ctxt_len, (uint8_t*)ctxt);
336
337 dipe_free_ctxt(cap);
338 element_clear(key);
339 }
340
341 size_t dipe_decrypt(dipe_param_t param, dipe_secretkey_t sk, char* cid, element_t* y, size_t ctxt_len, char* ctxt, char* ptxt) {
342 dipe_ctxt_t cap;
343 uint8_t aes[32];
344 element_t key;
345 size_t cap_len;
346
347 element_init_GT(key, param->pairing);
348 cap_len = dipe_deserialize_ctxt(param, sk->dimension, &cap, (uint8_t*)ctxt);
349 ctxt += cap_len;
350 ctxt_len -= cap_len;
351 dipe_decap(param, sk, cid, y, cap, key);
352 dipe_generate_aeskey(key, aes);
353
354 dipe_free_ctxt(cap);
355 element_clear(key);
356
357 return dipe_aes_decrypt(aes, ctxt_len, (uint8_t*)ctxt, (uint8_t*)ptxt);
358 }
359
360 /* Note: we're generating random-looking bytes here. Therefore we
361 * can't encode the dimension of the predicate vector (supposed to be
362 * set as system parameter) or information about the secret sharing
363 * (needs to be retrieved by some sort of trial decryption).
364 */
365 size_t dipe_serialize_ctxt(__attribute__((unused)) dipe_param_t param, dipe_ctxt_t ctxt, uint8_t* buffer) {
366 size_t bytes_written = 0;
367 element_to_bytes_compressed(buffer, ctxt->s);
368 buffer += element_length_in_bytes_compressed(ctxt->s);
369 bytes_written += element_length_in_bytes_compressed(ctxt->s);
370
371 for (size_t i = 0; i < ctxt->dimension; ++i) {
372 element_to_bytes_compressed(buffer, ctxt->cx[i]);
373 buffer += element_length_in_bytes_compressed(ctxt->cx[i]);
374 bytes_written += element_length_in_bytes_compressed(ctxt->cx[i]);
375 }
376
377 element_to_bytes(buffer, ctxt->c);
378 buffer += element_length_in_bytes(ctxt->c);
379 bytes_written += element_length_in_bytes(ctxt->c);
380
381 return bytes_written;
382 }
383
384 size_t dipe_deserialize_ctxt(dipe_param_t param, size_t dimension, dipe_ctxt_t* ctxt, uint8_t* buffer) {
385 size_t bytes_read = 0;
386 *ctxt = (dipe_ctxt_t)malloc(sizeof(dipe_ctxt));
387 (*ctxt)->dimension = dimension;
388
389 element_init_G1((*ctxt)->s, param->pairing);
390 element_from_bytes_compressed((*ctxt)->s, buffer);
391 buffer += element_length_in_bytes_compressed((*ctxt)->s);
392 bytes_read += element_length_in_bytes_compressed((*ctxt)->s);
393
394 (*ctxt)->cx = (element_t*)calloc(dimension, sizeof(element_t));
395 for (size_t i = 0; i < dimension; ++i) {
396 element_init_G1((*ctxt)->cx[i], param->pairing);
397 element_from_bytes_compressed((*ctxt)->cx[i], buffer);
398 buffer += element_length_in_bytes_compressed((*ctxt)->cx[i]);
399 bytes_read += element_length_in_bytes_compressed((*ctxt)->cx[i]);
400 }
401
402 element_init_GT((*ctxt)->c, param->pairing);
403 element_from_bytes((*ctxt)->c, buffer);
404 buffer += element_length_in_bytes((*ctxt)->c);
405 bytes_read += element_length_in_bytes((*ctxt)->c);
406
407 return bytes_read;
408 }
409
410 size_t dipe_ciphertext_overhead(dipe_param_t param, size_t dimension) {
411 size_t overhead = 12 + 16 + 4 /* IV + Tag + Size */;
412 element_t t;
413
414 element_init_G1(t, param->pairing);
415 overhead += element_length_in_bytes_compressed(t);
416 overhead += dimension * element_length_in_bytes_compressed(t);
417 element_clear(t);
418 element_init_GT(t, param->pairing);
419 overhead += element_length_in_bytes(t);
420 element_clear(t);
421
422 return overhead;
423 }
424
425 void dipe_free_param(dipe_param_t param) {
426 element_clear(param->g1);
427 element_clear(param->g2);
428 element_clear(param->gt);
429 pairing_clear(param->pairing);
430 free(param);
431 }
432
433 void dipe_free_master_secretkey(dipe_master_secretkey_t sk) {
434 for (size_t i = 0; i < sk->dimension; ++i) {
435 element_clear(sk->k[i]);
436 }
437 element_clear(sk->a);
438 free(sk->k);
439 free(sk);
440 }
441
442 void dipe_free_master_publickey(dipe_master_publickey_t pk) {
443 for (size_t i = 0; i < pk->dimension; ++i) {
444 element_clear(pk->k[i]);
445 }
446 element_clear(pk->a);
447 free(pk->k);
448 free(pk);
449 }
450
451 void dipe_free_secretkey(dipe_secretkey_t sk) {
452 element_clear(sk->d);
453 free(sk);
454 }
455
456 void dipe_free_ctxt(dipe_ctxt_t ctxt) {
457 for (size_t i = 0; i < ctxt->dimension; ++i) {
458 element_clear(ctxt->cx[i]);
459 }
460 element_clear(ctxt->c);
461 element_clear(ctxt->s);
462 free(ctxt->cx);
463 free(ctxt);
464 }