embed a diffie hellmann key exchange
[xonotic/d0_blind_id.git] / d0_blind_id.c
1 /*
2 Blind-ID library for user identification using RSA blind signatures
3 Copyright (C) 2010  Rudolf Polzer
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20 #include "d0_blind_id.h"
21
22 #include <stdio.h>
23 #include <string.h>
24 #include "d0_bignum.h"
25 #include "sha1.h"
26
27 // for zero knowledge, we need multiple instances of schnorr ID scheme... should normally be sequential
28 // parallel schnorr ID is not provably zero knowledge :(
29 //   (evil verifier can know all questions in advance, so sequential is disadvantage for him)
30 // we'll just live with a 1:1048576 chance of cheating, and support reauthenticating
31
32 #define SCHNORR_BITS 20
33 // probability of cheat: 2^(-bits+1)
34
35 #define SCHNORR_HASHSIZE 3
36 // cannot be >= SHA_DIGEST_LENGTH
37 // *8 must be >= SCHNORR_BITS
38
39 #define MSGSIZE 640 // ought to be enough for anyone
40
41 struct d0_blind_id_s
42 {
43         // signing (Xonotic pub and priv key)
44         d0_bignum_t *rsa_n, *rsa_e, *rsa_d;
45
46         // public data (Schnorr ID)
47         d0_bignum_t *schnorr_G;
48
49         // private data (player ID private key)
50         d0_bignum_t *schnorr_s;
51
52         // public data (player ID public key, this is what the server gets to know)
53         d0_bignum_t *schnorr_4_to_s;
54         d0_bignum_t *schnorr_4_to_s_signature; // 0 when signature is invalid
55
56         // temp data
57         d0_bignum_t *rn; // random number blind signature
58         d0_bignum_t *r; // random number for schnorr ID
59         char xnbh[SCHNORR_HASHSIZE]; // init hash
60         d0_bignum_t *e; // challenge
61         char msg[MSGSIZE]; // message
62         size_t msglen; // message length
63         d0_bignum_t *other_4_to_r; // for DH key exchange
64 };
65
66 #define CHECK(x) do { if(!(x)) goto fail; } while(0)
67 #define CHECK_ASSIGN(var, value) do { d0_bignum_t *val; val = value; if(!val) goto fail; var = val; } while(0)
68
69 static d0_bignum_t *zero, *one, *four, *temp0, *temp1, *temp2, *temp3, *temp4;
70
71 void d0_blind_id_INITIALIZE(void)
72 {
73         d0_bignum_INITIALIZE();
74         CHECK_ASSIGN(zero, d0_bignum_int(zero, 0));
75         CHECK_ASSIGN(one, d0_bignum_int(one, 1));
76         CHECK_ASSIGN(four, d0_bignum_int(four, 4));
77         CHECK_ASSIGN(temp0, d0_bignum_int(temp0, 0));
78         CHECK_ASSIGN(temp1, d0_bignum_int(temp1, 0));
79         CHECK_ASSIGN(temp2, d0_bignum_int(temp2, 0));
80         CHECK_ASSIGN(temp3, d0_bignum_int(temp3, 0));
81         CHECK_ASSIGN(temp4, d0_bignum_int(temp4, 0));
82 fail:
83         ;
84 }
85
86 void d0_blind_id_SHUTDOWN(void)
87 {
88         d0_bignum_free(zero);
89         d0_bignum_free(one);
90         d0_bignum_free(four);
91         d0_bignum_free(temp0);
92         d0_bignum_free(temp1);
93         d0_bignum_free(temp2);
94         d0_bignum_free(temp3);
95         d0_bignum_free(temp4);
96         d0_bignum_SHUTDOWN();
97 }
98
99 // (G-1)/2
100 d0_bignum_t *d0_dl_get_order(d0_bignum_t *o, const d0_bignum_t *G)
101 {
102         CHECK_ASSIGN(o, d0_bignum_sub(o, G, one));
103         CHECK(d0_bignum_shl(o, o, -1)); // order o = (G-1)/2
104         return o;
105 fail:
106         return NULL;
107 }
108 // 2o+1
109 d0_bignum_t *d0_dl_get_from_order(d0_bignum_t *G, const d0_bignum_t *o)
110 {
111         CHECK_ASSIGN(G, d0_bignum_shl(G, o, 1));
112         CHECK(d0_bignum_add(G, G, one));
113         return G;
114 fail:
115         return NULL;
116 }
117
118 BOOL d0_dl_generate_key(size_t size, d0_bignum_t *G)
119 {
120         // using: temp0
121         if(size < 16)
122                 size = 16;
123         for(;;)
124         {
125                 CHECK(d0_bignum_rand_bit_exact(temp0, size-1));
126                 if(d0_bignum_isprime(temp0, 0) == 0)
127                         continue;
128                 CHECK(d0_dl_get_from_order(G, temp0));
129                 if(d0_bignum_isprime(G, 10) == 0)
130                         continue;
131                 if(d0_bignum_isprime(temp0, 10) == 0) // finish the previous test
132                         continue;
133                 break;
134         }
135         return 1;
136 fail:
137         return 0;
138 }
139
140 BOOL d0_rsa_generate_key(size_t size, const d0_bignum_t *e, d0_bignum_t *d, d0_bignum_t *n)
141 {
142         // uses temp0 to temp4
143         int fail = 0;
144         int gcdfail = 0;
145         int pb = (size + 1)/2;
146         int qb = size - pb;
147         if(pb < 8)
148                 pb = 8;
149         if(qb < 8)
150                 qb = 8;
151         for (;;)
152         {
153                 CHECK(d0_bignum_rand_bit_exact(temp0, pb));
154                 if(d0_bignum_isprime(temp0, 10) == 0)
155                         continue;
156                 CHECK(d0_bignum_sub(temp2, temp0, one));
157                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp2, e));
158                 if(!d0_bignum_cmp(temp4, one))
159                         break;
160                 if(++gcdfail == 3)
161                         return 0;
162                 ++gcdfail;
163         }
164         gcdfail = 0;
165         for (;;)
166         {
167                 CHECK(d0_bignum_rand_bit_exact(temp1, qb));
168                 if(!d0_bignum_cmp(temp1, temp0))
169                 {
170                         if(++fail == 3)
171                                 return 0;
172                 }
173                 fail = 0;
174                 if(d0_bignum_isprime(temp1, 10) == 0)
175                         continue;
176                 CHECK(d0_bignum_sub(temp3, temp1, one));
177                 CHECK(d0_bignum_gcd(temp4, NULL, NULL, temp3, e));
178                 if(!d0_bignum_cmp(temp4, one))
179                         break;
180                 if(++gcdfail == 3)
181                         return 0;
182                 ++gcdfail;
183         }
184
185         // n = temp0*temp1
186         CHECK(d0_bignum_mul(n, temp0, temp1));
187                 
188         // d = e^-1 mod (temp0-1)(temp1-1)
189         CHECK(d0_bignum_mul(temp0, temp2, temp3));
190         CHECK(d0_bignum_mod_inv(d, e, temp0));
191         return 1;
192 fail:
193         return 0;
194 }
195
196 void d0_blind_id_clear(d0_blind_id_t *ctx)
197 {
198         if(ctx->rsa_n) d0_bignum_free(ctx->rsa_n);
199         if(ctx->rsa_e) d0_bignum_free(ctx->rsa_e);
200         if(ctx->rsa_d) d0_bignum_free(ctx->rsa_d);
201         if(ctx->schnorr_G) d0_bignum_free(ctx->schnorr_G);
202         if(ctx->schnorr_s) d0_bignum_free(ctx->schnorr_s);
203         if(ctx->schnorr_4_to_s) d0_bignum_free(ctx->schnorr_4_to_s);
204         if(ctx->schnorr_4_to_s_signature) d0_bignum_free(ctx->schnorr_4_to_s_signature);
205         if(ctx->rn) d0_bignum_free(ctx->rn);
206         if(ctx->r) d0_bignum_free(ctx->r);
207         if(ctx->e) d0_bignum_free(ctx->e);
208         memset(ctx, 0, sizeof(*ctx));
209 }
210
211 void d0_blind_id_copy(d0_blind_id_t *ctx, const d0_blind_id_t *src)
212 {
213         d0_blind_id_clear(ctx);
214         if(src->rsa_n) ctx->rsa_n = d0_bignum_mov(NULL, src->rsa_n);
215         if(src->rsa_e) ctx->rsa_e = d0_bignum_mov(NULL, src->rsa_e);
216         if(src->rsa_d) ctx->rsa_d = d0_bignum_mov(NULL, src->rsa_d);
217         if(src->schnorr_G) ctx->schnorr_G = d0_bignum_mov(NULL, src->schnorr_G);
218         if(src->schnorr_s) ctx->schnorr_s = d0_bignum_mov(NULL, src->schnorr_s);
219         if(src->schnorr_4_to_s) ctx->schnorr_4_to_s = d0_bignum_mov(NULL, ctx->schnorr_G);
220         if(src->schnorr_4_to_s_signature) ctx->schnorr_4_to_s_signature = d0_bignum_mov(NULL, src->schnorr_4_to_s_signature);
221         if(src->rn) ctx->rn = d0_bignum_mov(NULL, src->rn);
222         if(src->r) ctx->r = d0_bignum_mov(NULL, src->r);
223         if(src->e) ctx->e = d0_bignum_mov(NULL, src->e);
224         if(src->other_4_to_r) ctx->other_4_to_r = d0_bignum_mov(NULL, src->other_4_to_r);
225         // TODO xnbh, msg, msglen?
226 }
227
228 WARN_UNUSED_RESULT BOOL d0_blind_id_generate_private_key(d0_blind_id_t *ctx, int k)
229 {
230         d0_blind_id_clear(ctx);
231         CHECK_ASSIGN(ctx->rsa_e, d0_bignum_int(ctx->rsa_e, 65537));
232         CHECK_ASSIGN(ctx->rsa_d, d0_bignum_zero(ctx->rsa_d));
233         CHECK_ASSIGN(ctx->rsa_n, d0_bignum_zero(ctx->rsa_n));
234         CHECK(d0_rsa_generate_key(k+1, ctx->rsa_e, ctx->rsa_d, ctx->rsa_n)); // must fit G for sure
235         return 1;
236 fail:
237         return 0;
238 }
239
240 WARN_UNUSED_RESULT BOOL d0_blind_id_read_private_key(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
241 {
242         d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen);
243         CHECK_ASSIGN(ctx->rsa_n, d0_iobuf_read_bignum(in, ctx->rsa_n));
244         CHECK_ASSIGN(ctx->rsa_e, d0_iobuf_read_bignum(in, ctx->rsa_e));
245         CHECK_ASSIGN(ctx->rsa_d, d0_iobuf_read_bignum(in, ctx->rsa_d));
246         return d0_iobuf_close(in, NULL);
247
248 fail:
249         d0_iobuf_close(in, NULL);
250         return 0;
251 }
252
253 WARN_UNUSED_RESULT BOOL d0_blind_id_read_public_key(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
254 {
255         d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen);
256         CHECK_ASSIGN(ctx->rsa_n, d0_iobuf_read_bignum(in, ctx->rsa_n));
257         CHECK_ASSIGN(ctx->rsa_e, d0_iobuf_read_bignum(in, ctx->rsa_e));
258         return d0_iobuf_close(in, NULL);
259
260 fail:
261         d0_iobuf_close(in, NULL);
262         return 0;
263 }
264
265 #define USING(x) if(!(ctx->x)) return 0
266 #define REPLACING(x)
267
268 WARN_UNUSED_RESULT BOOL d0_blind_id_write_private_key(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
269 {
270         d0_iobuf_t *out = NULL;
271
272         USING(rsa_n); USING(rsa_e); USING(rsa_d);
273
274         out = d0_iobuf_open_write(outbuf, *outbuflen);
275         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_n));
276         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_e));
277         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_d));
278         return d0_iobuf_close(out, outbuflen);
279
280 fail:
281         d0_iobuf_close(out, outbuflen);
282         return 0;
283 }
284
285 WARN_UNUSED_RESULT BOOL d0_blind_id_write_public_key(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
286 {
287         d0_iobuf_t *out = NULL;
288
289         USING(rsa_n); USING(rsa_e);
290
291         out = d0_iobuf_open_write(outbuf, *outbuflen);
292         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_n));
293         CHECK(d0_iobuf_write_bignum(out, ctx->rsa_e));
294         return d0_iobuf_close(out, outbuflen);
295
296 fail:
297         if(!d0_iobuf_close(out, outbuflen))
298                 return 0;
299         return 0;
300 }
301
302 WARN_UNUSED_RESULT BOOL d0_blind_id_generate_private_id_modulus(d0_blind_id_t *ctx)
303 {
304         USING(rsa_n);
305         REPLACING(schnorr_G);
306
307         CHECK_ASSIGN(ctx->schnorr_G, d0_bignum_zero(ctx->schnorr_G));
308         CHECK(d0_dl_generate_key(d0_bignum_size(ctx->rsa_n)-1, ctx->schnorr_G));
309         return 1;
310 fail:
311         return 0;
312 }
313
314 WARN_UNUSED_RESULT BOOL d0_blind_id_read_private_id_modulus(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
315 {
316         d0_iobuf_t *in = d0_iobuf_open_read(inbuf, inbuflen);
317         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
318         return d0_iobuf_close(in, NULL);
319
320 fail:
321         d0_iobuf_close(in, NULL);
322         return 0;
323 }
324
325 WARN_UNUSED_RESULT BOOL d0_blind_id_write_private_id_modulus(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
326 {
327         d0_iobuf_t *out = NULL;
328
329         USING(schnorr_G);
330
331         out = d0_iobuf_open_write(outbuf, *outbuflen);
332         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
333         return d0_iobuf_close(out, outbuflen);
334
335 fail:
336         d0_iobuf_close(out, outbuflen);
337         return 0;
338 }
339
340 WARN_UNUSED_RESULT BOOL d0_blind_id_generate_private_id_start(d0_blind_id_t *ctx)
341 {
342         // temps: temp0 order
343         USING(schnorr_G);
344         REPLACING(schnorr_s); REPLACING(schnorr_4_to_s);
345
346         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
347         CHECK_ASSIGN(ctx->schnorr_s, d0_bignum_rand_range(ctx->schnorr_s, zero, temp0));
348         CHECK_ASSIGN(ctx->schnorr_4_to_s, d0_bignum_mod_pow(ctx->schnorr_4_to_s, four, ctx->schnorr_s, ctx->schnorr_G));
349         CHECK_ASSIGN(ctx->schnorr_4_to_s_signature, d0_bignum_zero(ctx->schnorr_4_to_s_signature));
350         return 1;
351
352 fail:
353         return 0;
354 }
355
356 WARN_UNUSED_RESULT BOOL d0_blind_id_generate_private_id_request(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
357 {
358         d0_iobuf_t *out = NULL;
359
360         // temps: temp0 temp1
361         USING(rsa_n); USING(rsa_e); USING(schnorr_4_to_s);
362         REPLACING(rn);
363
364         out = d0_iobuf_open_write(outbuf, *outbuflen);
365
366         CHECK_ASSIGN(ctx->rn, d0_bignum_rand_bit_atmost(ctx->rn, d0_bignum_size(ctx->rsa_n)));
367         CHECK(d0_bignum_mod_pow(temp0, ctx->rn, ctx->rsa_e, ctx->rsa_n));
368         CHECK(d0_bignum_mod_mul(temp1, ctx->schnorr_4_to_s, temp0, ctx->rsa_n));
369         CHECK(d0_iobuf_write_bignum(out, temp1));
370         return d0_iobuf_close(out, outbuflen);
371
372 fail:
373         d0_iobuf_close(out, outbuflen);
374         return 0;
375 }
376
377 WARN_UNUSED_RESULT BOOL d0_blind_id_answer_private_id_request(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen)
378 {
379         d0_iobuf_t *in = NULL;
380         d0_iobuf_t *out = NULL;
381
382         // temps: temp0 temp1
383         USING(rsa_d); USING(rsa_n);
384
385         in = d0_iobuf_open_read(inbuf, inbuflen);
386         out = d0_iobuf_open_write(outbuf, *outbuflen);
387
388         CHECK(d0_iobuf_read_bignum(in, temp0));
389         CHECK(d0_bignum_mod_pow(temp1, temp0, ctx->rsa_d, ctx->rsa_n));
390         CHECK(d0_iobuf_write_bignum(out, temp1));
391
392         d0_iobuf_close(in, NULL);
393         return d0_iobuf_close(out, outbuflen);
394
395 fail:
396         d0_iobuf_close(in, NULL);
397         d0_iobuf_close(out, outbuflen);
398         return 0;
399 }
400
401 WARN_UNUSED_RESULT BOOL d0_blind_id_finish_private_id_request(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
402 {
403         d0_iobuf_t *in = NULL;
404
405         // temps: temp0 temp1
406         USING(rn); USING(rsa_n);
407         REPLACING(schnorr_4_to_s_signature);
408
409         in = d0_iobuf_open_read(inbuf, inbuflen);
410
411         CHECK(d0_iobuf_read_bignum(in, temp0));
412         CHECK(d0_bignum_mod_inv(temp1, ctx->rn, ctx->rsa_n));
413         CHECK_ASSIGN(ctx->schnorr_4_to_s_signature, d0_bignum_mod_mul(ctx->schnorr_4_to_s_signature, temp0, temp1, ctx->rsa_n));
414
415         return d0_iobuf_close(in, NULL);
416
417 fail:
418         d0_iobuf_close(in, NULL);
419         return 0;
420 }
421
422 WARN_UNUSED_RESULT BOOL d0_blind_id_read_private_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
423 {
424         d0_iobuf_t *in = NULL;
425
426         REPLACING(schnorr_s); REPLACING(schnorr_4_to_s); REPLACING(schnorr_4_to_s_signature);
427
428         in = d0_iobuf_open_read(inbuf, inbuflen);
429
430         CHECK_ASSIGN(ctx->schnorr_s, d0_iobuf_read_bignum(in, ctx->schnorr_s));
431         CHECK_ASSIGN(ctx->schnorr_4_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s));
432         CHECK_ASSIGN(ctx->schnorr_4_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s_signature));
433
434         return d0_iobuf_close(in, NULL);
435
436 fail:
437         d0_iobuf_close(in, NULL);
438         return 0;
439 }
440
441 WARN_UNUSED_RESULT BOOL d0_blind_id_read_public_id(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen)
442 {
443         d0_iobuf_t *in = NULL;
444
445         REPLACING(schnorr_4_to_s); REPLACING(schnorr_4_to_s_signature);
446
447         in = d0_iobuf_open_read(inbuf, inbuflen);
448
449         CHECK_ASSIGN(ctx->schnorr_4_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s));
450         CHECK_ASSIGN(ctx->schnorr_4_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s_signature));
451
452         return d0_iobuf_close(in, NULL);
453
454 fail:
455         d0_iobuf_close(in, NULL);
456         return 0;
457 }
458
459 WARN_UNUSED_RESULT BOOL d0_blind_id_write_private_id(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
460 {
461         d0_iobuf_t *out = NULL;
462
463         USING(schnorr_s); USING(schnorr_4_to_s); USING(schnorr_4_to_s_signature);
464
465         out = d0_iobuf_open_write(outbuf, *outbuflen);
466
467         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_s));
468         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s));
469         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s_signature));
470
471         return d0_iobuf_close(out, outbuflen);
472
473 fail:
474         d0_iobuf_close(out, outbuflen);
475         return 0;
476 }
477
478 WARN_UNUSED_RESULT BOOL d0_blind_id_write_public_id(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
479 {
480         d0_iobuf_t *out = NULL;
481
482         USING(schnorr_4_to_s); USING(schnorr_4_to_s_signature);
483
484         out = d0_iobuf_open_write(outbuf, *outbuflen);
485
486         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s));
487         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s_signature));
488
489         return d0_iobuf_close(out, outbuflen);
490
491 fail:
492         d0_iobuf_close(out, outbuflen);
493         return 0;
494 }
495
496 WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_start(d0_blind_id_t *ctx, BOOL is_first, BOOL send_modulus, char *msg, size_t msglen, char *outbuf, size_t *outbuflen)
497 // start =
498 //   first run: send 4^s, 4^s signature
499 //   1. get random r, send HASH(4^r)
500 {
501         d0_iobuf_t *out = NULL;
502         static unsigned char convbuf[1024];
503         d0_iobuf_t *conv = NULL;
504         size_t sz;
505
506         if(is_first)
507         {
508                 USING(schnorr_4_to_s); USING(schnorr_4_to_s_signature);
509         }
510         USING(schnorr_G);
511         REPLACING(r);
512
513         out = d0_iobuf_open_write(outbuf, *outbuflen);
514
515         if(is_first)
516         {
517                 // send ID
518                 if(send_modulus)
519                         CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_G));
520                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s));
521                 CHECK(d0_iobuf_write_bignum(out, ctx->schnorr_4_to_s_signature));
522         }
523
524         // start schnorr ID scheme
525         // generate random number r; x = g^r; send hash of x, remember r, forget x
526         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
527         CHECK_ASSIGN(ctx->r, d0_bignum_rand_range(ctx->r, zero, temp0));
528         CHECK(d0_bignum_mod_pow(temp0, four, ctx->r, ctx->schnorr_G));
529
530         // hash it, hash it, everybody hash it
531         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
532         CHECK(d0_iobuf_write_bignum(conv, temp0));
533         CHECK(d0_iobuf_write_packet(conv, msg, msglen));
534         CHECK(d0_iobuf_write_bignum(conv, temp0));
535         d0_iobuf_close(conv, &sz);
536         conv = NULL;
537         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), SCHNORR_HASHSIZE) == SCHNORR_HASHSIZE);
538         CHECK(d0_iobuf_write_packet(out, msg, msglen));
539
540         return d0_iobuf_close(out, outbuflen);
541
542 fail:
543         d0_iobuf_close(out, outbuflen);
544         return 0;
545 }
546
547 WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_challenge(d0_blind_id_t *ctx, BOOL is_first, BOOL recv_modulus, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen, BOOL *status)
548 //   first run: get 4^s, 4^s signature
549 //   1. check sig
550 //   2. save HASH(4^r)
551 //   3. send challenge e of SCHNORR_BITS
552 {
553         d0_iobuf_t *in = NULL;
554         d0_iobuf_t *out = NULL;
555
556         if(is_first)
557         {
558                 REPLACING(schnorr_4_to_s); REPLACING(k); REPLACING(schnorr_4_to_s_signature);
559                 USING(rsa_n);
560                 if(!recv_modulus)
561                         USING(schnorr_G);
562         }
563         else
564         {
565                 USING(schnorr_4_to_s_signature); USING(schnorr_4_to_s);
566                 USING(schnorr_G);
567         }
568         USING(rsa_e); USING(rsa_n);
569         REPLACING(e); REPLACING(msg); REPLACING(msglen);
570
571         in = d0_iobuf_open_read(inbuf, inbuflen);
572         out = d0_iobuf_open_write(outbuf, *outbuflen);
573
574         if(is_first)
575         {
576                 if(recv_modulus)
577                 {
578                         CHECK_ASSIGN(ctx->schnorr_G, d0_iobuf_read_bignum(in, ctx->schnorr_G));
579                         CHECK(d0_bignum_cmp(ctx->schnorr_G, zero) > 0);
580                         CHECK(d0_bignum_cmp(ctx->schnorr_G, ctx->rsa_n) < 0);
581                 }
582                 CHECK_ASSIGN(ctx->schnorr_4_to_s, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s));
583                 CHECK(d0_bignum_cmp(ctx->schnorr_4_to_s, zero) > 0);
584                 CHECK(d0_bignum_cmp(ctx->schnorr_4_to_s, ctx->schnorr_G) < 0);
585                 CHECK_ASSIGN(ctx->schnorr_4_to_s_signature, d0_iobuf_read_bignum(in, ctx->schnorr_4_to_s_signature));
586                 CHECK(d0_bignum_cmp(ctx->schnorr_4_to_s_signature, zero) >= 0);
587                 CHECK(d0_bignum_cmp(ctx->schnorr_4_to_s_signature, ctx->rsa_n) < 0);
588
589                 // check signature of key (t = k^d, so, t^e = k)
590                 CHECK(d0_bignum_mod_pow(temp0, ctx->schnorr_4_to_s_signature, ctx->rsa_e, ctx->rsa_n));
591                 if(d0_bignum_cmp(temp0, ctx->schnorr_4_to_s))
592                 {
593                         // accept the key anyway, but mark as failed signature! will later return 0 in status
594                         CHECK(d0_bignum_zero(ctx->schnorr_4_to_s_signature));
595                 }
596         }
597
598         CHECK(d0_iobuf_read_raw(in, ctx->xnbh, SCHNORR_HASHSIZE));
599         ctx->msglen = MSGSIZE;
600         CHECK(d0_iobuf_read_packet(in, ctx->msg, &ctx->msglen));
601
602         // send challenge
603         CHECK_ASSIGN(ctx->e, d0_bignum_rand_bit_atmost(ctx->e, SCHNORR_BITS));
604
605         CHECK(d0_iobuf_write_bignum(out, ctx->e));
606
607         if(is_first)
608         {
609                 // Diffie Hellmann
610                 CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
611                 CHECK_ASSIGN(ctx->r, d0_bignum_rand_range(ctx->r, zero, temp0));
612                 CHECK(d0_bignum_mod_pow(temp0, four, ctx->r, ctx->schnorr_G));
613                 CHECK(d0_iobuf_write_bignum(out, temp0));
614         }
615
616         if(status)
617                 *status = !!d0_bignum_cmp(ctx->schnorr_4_to_s_signature, zero);
618
619         d0_iobuf_close(in, NULL);
620         return d0_iobuf_close(out, outbuflen);
621
622 fail:
623         d0_iobuf_close(in, NULL);
624         d0_iobuf_close(out, outbuflen);
625         return 0;
626 }
627
628 WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_response(d0_blind_id_t *ctx, BOOL is_first, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen)
629 //   1. read challenge e of SCHNORR_BITS
630 //   2. reply with r + s * e mod order
631 {
632         d0_iobuf_t *in = NULL;
633         d0_iobuf_t *out = NULL;
634
635         // temps: 0 order, 1 prod, 2 y, 3 e
636         USING(schnorr_G); USING(schnorr_s); USING(r);
637
638         in = d0_iobuf_open_read(inbuf, inbuflen);
639         out = d0_iobuf_open_write(outbuf, *outbuflen);
640
641         CHECK(d0_iobuf_read_bignum(in, temp3));
642         CHECK(d0_bignum_cmp(temp3, zero) >= 0);
643         CHECK(d0_bignum_size(temp3) <= SCHNORR_BITS);
644
645         if(is_first)
646         {
647                 // Diffie Hellmann
648                 CHECK_ASSIGN(ctx->other_4_to_r, d0_iobuf_read_bignum(in, ctx->other_4_to_r));
649                 CHECK(d0_bignum_cmp(ctx->other_4_to_r, zero) > 0);
650                 CHECK(d0_bignum_cmp(ctx->other_4_to_r, ctx->schnorr_G) < 0);
651         }
652
653         // send response for schnorr ID scheme
654         // i.e. r + ctx->schnorr_s * temp3
655         CHECK(d0_dl_get_order(temp0, ctx->schnorr_G));
656         CHECK(d0_bignum_mod_mul(temp1, ctx->schnorr_s, temp3, temp0));
657         CHECK(d0_bignum_mod_add(temp2, temp1, ctx->r, temp0));
658         CHECK(d0_iobuf_write_bignum(out, temp2));
659
660         d0_iobuf_close(in, NULL);
661         return d0_iobuf_close(out, outbuflen);
662
663 fail:
664         d0_iobuf_close(in, NULL);
665         d0_iobuf_close(out, outbuflen);
666         return 0;
667 }
668
669 WARN_UNUSED_RESULT BOOL d0_blind_id_authenticate_with_private_id_verify(d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *msg, size_t *msglen, BOOL *status)
670 //   1. read y = r + s * e mod order
671 //   2. verify: g^y (g^s)^-e = g^(r+s*e-s*e) = g^r
672 //      (check using H(g^r) which we know)
673 {
674         d0_iobuf_t *in = NULL;
675         static unsigned char convbuf[1024];
676         d0_iobuf_t *conv = NULL;
677         size_t sz;
678
679         // temps: 0 y 1 order
680         USING(e); USING(schnorr_G);
681
682         in = d0_iobuf_open_read(inbuf, inbuflen);
683
684         CHECK(d0_dl_get_order(temp1, ctx->schnorr_G));
685         CHECK(d0_iobuf_read_bignum(in, temp0));
686         CHECK(d0_bignum_cmp(temp0, zero) >= 0);
687         CHECK(d0_bignum_cmp(temp0, temp1) < 0);
688
689         // verify schnorr ID scheme
690         // we need 4^temp0 (g^s)^-e
691         CHECK(d0_bignum_neg(temp1, ctx->e));
692         CHECK(d0_bignum_mod_pow(temp2, ctx->schnorr_4_to_s, temp1, ctx->schnorr_G));
693         CHECK(d0_bignum_mod_pow(temp1, four, temp0, ctx->schnorr_G));
694         CHECK_ASSIGN(ctx->other_4_to_r, d0_bignum_mod_mul(ctx->other_4_to_r, temp1, temp2, ctx->schnorr_G));
695         // hash must be equal to xnbh
696
697         // hash it, hash it, everybody hash it
698         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
699         CHECK(d0_iobuf_write_bignum(conv, ctx->other_4_to_r));
700         CHECK(d0_iobuf_write_packet(conv, ctx->msg, ctx->msglen));
701         CHECK(d0_iobuf_write_bignum(conv, ctx->other_4_to_r));
702         d0_iobuf_close(conv, &sz);
703         conv = NULL;
704         if(memcmp(sha(convbuf, sz), ctx->xnbh, SCHNORR_HASHSIZE))
705         {
706                 // FAIL (not owned by player)
707                 goto fail;
708         }
709
710         if(status)
711                 *status = !!d0_bignum_cmp(ctx->schnorr_4_to_s_signature, zero);
712
713         if(ctx->msglen <= *msglen)
714                 memcpy(msg, ctx->msg, ctx->msglen);
715         else
716                 memcpy(msg, ctx->msg, *msglen);
717         *msglen = ctx->msglen;
718
719         d0_iobuf_close(in, NULL);
720         return 1;
721
722 fail:
723         d0_iobuf_close(in, NULL);
724         return 0;
725 }
726
727 WARN_UNUSED_RESULT BOOL d0_blind_id_fingerprint64_public_id(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
728 {
729         d0_iobuf_t *out = NULL;
730         static unsigned char convbuf[1024];
731         d0_iobuf_t *conv = NULL;
732         size_t sz, n;
733
734         USING(schnorr_4_to_s);
735
736         out = d0_iobuf_open_write(outbuf, *outbuflen);
737         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
738
739         CHECK(d0_iobuf_write_bignum(conv, ctx->schnorr_4_to_s));
740         CHECK(d0_iobuf_close(conv, &sz));
741         conv = NULL;
742
743         n = (*outbuflen / 4) * 3;
744         if(n > SHA_DIGESTSIZE)
745                 n = SHA_DIGESTSIZE;
746         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), n) == n);
747         CHECK(d0_iobuf_conv_base64_out(out));
748
749         return d0_iobuf_close(out, outbuflen);
750
751 fail:
752         if(conv)
753                 d0_iobuf_close(conv, &sz);
754         d0_iobuf_close(out, outbuflen);
755         return 0;
756 }
757
758 BOOL d0_blind_id_sessionkey_public_id(d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen)
759 {
760         d0_iobuf_t *out = NULL;
761         static unsigned char convbuf[1024];
762         d0_iobuf_t *conv = NULL;
763         size_t n, sz;
764
765         USING(r); USING(other_4_to_r);
766
767         out = d0_iobuf_open_write(outbuf, *outbuflen);
768         conv = d0_iobuf_open_write(convbuf, sizeof(convbuf));
769
770         // temps: temp0 result
771         CHECK(d0_bignum_mod_pow(temp0, ctx->other_4_to_r, ctx->r, ctx->schnorr_G));
772         CHECK(d0_iobuf_write_bignum(conv, temp0));
773         CHECK(d0_iobuf_close(conv, &sz));
774         conv = NULL;
775
776         n = *outbuflen;
777         if(n > SHA_DIGESTSIZE)
778                 n = SHA_DIGESTSIZE;
779         CHECK(d0_iobuf_write_raw(out, sha(convbuf, sz), n) == n);
780
781         return d0_iobuf_close(out, outbuflen);
782
783 fail:
784         if(conv)
785                 d0_iobuf_close(conv, &sz);
786         d0_iobuf_close(out, outbuflen);
787         return 0;
788 }
789
790 d0_blind_id_t *d0_blind_id_new(void)
791 {
792         d0_blind_id_t *b = d0_malloc(sizeof(d0_blind_id_t));
793         memset(b, 0, sizeof(*b));
794         return b;
795 }
796
797 void d0_blind_id_free(d0_blind_id_t *a)
798 {
799         d0_blind_id_clear(a);
800         d0_free(a);
801 }