]> git.xonotic.org Git - xonotic/darkplaces.git/blob - crypto.c
lock the thread mutex while altering crypto key stuff
[xonotic/darkplaces.git] / crypto.c
1 // TODO key loading, generating, saving
2 #include "quakedef.h"
3 #include "crypto.h"
4 #include "common.h"
5 #include "thread.h"
6
7 #include "hmac.h"
8 #include "libcurl.h"
9
10 cvar_t crypto_developer = {CVAR_SAVE, "crypto_developer", "0", "print extra info about crypto handshake"};
11 cvar_t crypto_servercpupercent = {CVAR_SAVE, "crypto_servercpupercent", "10", "allowed crypto CPU load in percent for server operation (0 = no limit, faster)"};
12 cvar_t crypto_servercpumaxtime = {CVAR_SAVE, "crypto_servercpumaxtime", "0.01", "maximum allowed crypto CPU time per frame (0 = no limit)"};
13 cvar_t crypto_servercpudebug = {CVAR_SAVE, "crypto_servercpudebug", "0", "print statistics about time usage by crypto"};
14 static double crypto_servercpu_accumulator = 0;
15 static double crypto_servercpu_lastrealtime = 0;
16 cvar_t crypto_aeslevel = {CVAR_SAVE, "crypto_aeslevel", "1", "whether to support AES encryption in authenticated connections (0 = no, 1 = supported, 2 = requested, 3 = required)"};
17 int crypto_keyfp_recommended_length;
18 static const char *crypto_idstring = NULL;
19 static char crypto_idstring_buf[512];
20
21 #define PROTOCOL_D0_BLIND_ID FOURCC_D0PK
22 #define PROTOCOL_VLEN (('v' << 0) | ('l' << 8) | ('e' << 16) | ('n' << 24))
23
24 // BEGIN stuff shared with crypto-keygen-standalone
25 #define FOURCC_D0PK (('d' << 0) | ('0' << 8) | ('p' << 16) | ('k' << 24))
26 #define FOURCC_D0SK (('d' << 0) | ('0' << 8) | ('s' << 16) | ('k' << 24))
27 #define FOURCC_D0PI (('d' << 0) | ('0' << 8) | ('p' << 16) | ('i' << 24))
28 #define FOURCC_D0SI (('d' << 0) | ('0' << 8) | ('s' << 16) | ('i' << 24))
29 #define FOURCC_D0IQ (('d' << 0) | ('0' << 8) | ('i' << 16) | ('q' << 24))
30 #define FOURCC_D0IR (('d' << 0) | ('0' << 8) | ('i' << 16) | ('r' << 24))
31 #define FOURCC_D0ER (('d' << 0) | ('0' << 8) | ('e' << 16) | ('r' << 24))
32 #define FOURCC_D0IC (('d' << 0) | ('0' << 8) | ('i' << 16) | ('c' << 24))
33
34 static unsigned long Crypto_LittleLong(const char *data)
35 {
36         return
37                 ((unsigned char) data[0]) |
38                 (((unsigned char) data[1]) << 8) |
39                 (((unsigned char) data[2]) << 16) |
40                 (((unsigned char) data[3]) << 24);
41 }
42
43 static void Crypto_UnLittleLong(char *data, unsigned long l)
44 {
45         data[0] = l & 0xFF;
46         data[1] = (l >> 8) & 0xFF;
47         data[2] = (l >> 16) & 0xFF;
48         data[3] = (l >> 24) & 0xFF;
49 }
50
51 static size_t Crypto_ParsePack(const char *buf, size_t len, unsigned long header, const char **lumps, size_t *lumpsize, size_t nlumps)
52 {
53         size_t i;
54         size_t pos;
55         pos = 0;
56         if(header)
57         {
58                 if(len < 4)
59                         return 0;
60                 if(Crypto_LittleLong(buf) != header)
61                         return 0;
62                 pos += 4;
63         }
64         for(i = 0; i < nlumps; ++i)
65         {
66                 if(pos + 4 > len)
67                         return 0;
68                 lumpsize[i] = Crypto_LittleLong(&buf[pos]);
69                 pos += 4;
70                 if(pos + lumpsize[i] > len)
71                         return 0;
72                 lumps[i] = &buf[pos];
73                 pos += lumpsize[i];
74         }
75         return pos;
76 }
77
78 static size_t Crypto_UnParsePack(char *buf, size_t len, unsigned long header, const char *const *lumps, const size_t *lumpsize, size_t nlumps)
79 {
80         size_t i;
81         size_t pos;
82         pos = 0;
83         if(header)
84         {
85                 if(len < 4)
86                         return 0;
87                 Crypto_UnLittleLong(buf, header);
88                 pos += 4;
89         }
90         for(i = 0; i < nlumps; ++i)
91         {
92                 if(pos + 4 + lumpsize[i] > len)
93                         return 0;
94                 Crypto_UnLittleLong(&buf[pos], lumpsize[i]);
95                 pos += 4;
96                 memcpy(&buf[pos], lumps[i], lumpsize[i]);
97                 pos += lumpsize[i];
98         }
99         return pos;
100 }
101 // END stuff shared with xonotic-keygen
102
103 #define USE_AES
104
105 #ifdef CRYPTO_STATIC
106
107 #include <d0_blind_id/d0_blind_id.h>
108
109 #define d0_blind_id_dll 1
110 #define Crypto_OpenLibrary() true
111 #define Crypto_CloseLibrary()
112
113 #define qd0_blind_id_new d0_blind_id_new
114 #define qd0_blind_id_free d0_blind_id_free
115 //#define qd0_blind_id_clear d0_blind_id_clear
116 #define qd0_blind_id_copy d0_blind_id_copy
117 //#define qd0_blind_id_generate_private_key d0_blind_id_generate_private_key
118 //#define qd0_blind_id_generate_private_key_fastreject d0_blind_id_generate_private_key_fastreject
119 //#define qd0_blind_id_read_private_key d0_blind_id_read_private_key
120 #define qd0_blind_id_read_public_key d0_blind_id_read_public_key
121 //#define qd0_blind_id_write_private_key d0_blind_id_write_private_key
122 //#define qd0_blind_id_write_public_key d0_blind_id_write_public_key
123 #define qd0_blind_id_fingerprint64_public_key d0_blind_id_fingerprint64_public_key
124 //#define qd0_blind_id_generate_private_id_modulus d0_blind_id_generate_private_id_modulus
125 #define qd0_blind_id_read_private_id_modulus d0_blind_id_read_private_id_modulus
126 //#define qd0_blind_id_write_private_id_modulus d0_blind_id_write_private_id_modulus
127 #define qd0_blind_id_generate_private_id_start d0_blind_id_generate_private_id_start
128 #define qd0_blind_id_generate_private_id_request d0_blind_id_generate_private_id_request
129 //#define qd0_blind_id_answer_private_id_request d0_blind_id_answer_private_id_request
130 #define qd0_blind_id_finish_private_id_request d0_blind_id_finish_private_id_request
131 //#define qd0_blind_id_read_private_id_request_camouflage d0_blind_id_read_private_id_request_camouflage
132 //#define qd0_blind_id_write_private_id_request_camouflage d0_blind_id_write_private_id_request_camouflage
133 #define qd0_blind_id_read_private_id d0_blind_id_read_private_id
134 //#define qd0_blind_id_read_public_id d0_blind_id_read_public_id
135 #define qd0_blind_id_write_private_id d0_blind_id_write_private_id
136 //#define qd0_blind_id_write_public_id d0_blind_id_write_public_id
137 #define qd0_blind_id_authenticate_with_private_id_start d0_blind_id_authenticate_with_private_id_start
138 #define qd0_blind_id_authenticate_with_private_id_challenge d0_blind_id_authenticate_with_private_id_challenge
139 #define qd0_blind_id_authenticate_with_private_id_response d0_blind_id_authenticate_with_private_id_response
140 #define qd0_blind_id_authenticate_with_private_id_verify d0_blind_id_authenticate_with_private_id_verify
141 #define qd0_blind_id_fingerprint64_public_id d0_blind_id_fingerprint64_public_id
142 #define qd0_blind_id_sessionkey_public_id d0_blind_id_sessionkey_public_id
143 #define qd0_blind_id_INITIALIZE d0_blind_id_INITIALIZE
144 #define qd0_blind_id_SHUTDOWN d0_blind_id_SHUTDOWN
145 #define qd0_blind_id_util_sha256 d0_blind_id_util_sha256
146 #define qd0_blind_id_sign_with_private_id_sign d0_blind_id_sign_with_private_id_sign
147 #define qd0_blind_id_sign_with_private_id_sign_detached d0_blind_id_sign_with_private_id_sign_detached
148 #define qd0_blind_id_setmallocfuncs d0_blind_id_setmallocfuncs
149 #define qd0_blind_id_setmutexfuncs d0_blind_id_setmutexfuncs
150
151 #else
152
153 // d0_blind_id interface
154 #define D0_EXPORT
155 #ifdef __GNUC__
156 #define D0_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
157 #else
158 #define D0_WARN_UNUSED_RESULT
159 #endif
160 #define D0_BOOL int
161
162 typedef void *(d0_malloc_t)(size_t len);
163 typedef void (d0_free_t)(void *p);
164 typedef void *(d0_createmutex_t)(void);
165 typedef void (d0_destroymutex_t)(void *);
166 typedef int (d0_lockmutex_t)(void *); // zero on success
167 typedef int (d0_unlockmutex_t)(void *); // zero on success
168
169 typedef struct d0_blind_id_s d0_blind_id_t;
170 typedef D0_BOOL (*d0_fastreject_function) (const d0_blind_id_t *ctx, void *pass);
171 static D0_EXPORT D0_WARN_UNUSED_RESULT d0_blind_id_t *(*qd0_blind_id_new) (void);
172 static D0_EXPORT void (*qd0_blind_id_free) (d0_blind_id_t *a);
173 //static D0_EXPORT void (*qd0_blind_id_clear) (d0_blind_id_t *ctx);
174 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_copy) (d0_blind_id_t *ctx, const d0_blind_id_t *src);
175 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_key) (d0_blind_id_t *ctx, int k);
176 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_key_fastreject) (d0_blind_id_t *ctx, int k, d0_fastreject_function reject, void *pass);
177 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_key) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
178 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_public_key) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
179 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_key) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
180 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_public_key) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
181 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_fingerprint64_public_key) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
182 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_modulus) (d0_blind_id_t *ctx);
183 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_id_modulus) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
184 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_id_modulus) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
185 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_start) (d0_blind_id_t *ctx);
186 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_generate_private_id_request) (d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
187 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_answer_private_id_request) (const d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen);
188 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_finish_private_id_request) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
189 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_id_request_camouflage) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
190 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_id_request_camouflage) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
191 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_private_id) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
192 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_read_public_id) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen);
193 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_private_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
194 //static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_write_public_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
195 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_start) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen);
196 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_challenge) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL recv_modulus, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen, D0_BOOL *status);
197 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_response) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *outbuf, size_t *outbuflen);
198 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_authenticate_with_private_id_verify) (d0_blind_id_t *ctx, const char *inbuf, size_t inbuflen, char *msg, size_t *msglen, D0_BOOL *status);
199 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_fingerprint64_public_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen);
200 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sessionkey_public_id) (const d0_blind_id_t *ctx, char *outbuf, size_t *outbuflen); // can only be done after successful key exchange, this performs a modpow; key length is limited by SHA_DIGESTSIZE for now; also ONLY valid after successful d0_blind_id_authenticate_with_private_id_verify/d0_blind_id_fingerprint64_public_id
201 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_INITIALIZE) (void);
202 static D0_EXPORT void (*qd0_blind_id_SHUTDOWN) (void);
203 static D0_EXPORT void (*qd0_blind_id_util_sha256) (char *out, const char *in, size_t n);
204 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sign_with_private_id_sign) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen);
205 static D0_EXPORT D0_WARN_UNUSED_RESULT D0_BOOL (*qd0_blind_id_sign_with_private_id_sign_detached) (d0_blind_id_t *ctx, D0_BOOL is_first, D0_BOOL send_modulus, const char *message, size_t msglen, char *outbuf, size_t *outbuflen);
206 static D0_EXPORT void (*qd0_blind_id_setmallocfuncs)(d0_malloc_t *m, d0_free_t *f);
207 static D0_EXPORT void (*qd0_blind_id_setmutexfuncs)(d0_createmutex_t *c, d0_destroymutex_t *d, d0_lockmutex_t *l, d0_unlockmutex_t *u);
208 static dllfunction_t d0_blind_id_funcs[] =
209 {
210         {"d0_blind_id_new", (void **) &qd0_blind_id_new},
211         {"d0_blind_id_free", (void **) &qd0_blind_id_free},
212         //{"d0_blind_id_clear", (void **) &qd0_blind_id_clear},
213         {"d0_blind_id_copy", (void **) &qd0_blind_id_copy},
214         //{"d0_blind_id_generate_private_key", (void **) &qd0_blind_id_generate_private_key},
215         //{"d0_blind_id_generate_private_key_fastreject", (void **) &qd0_blind_id_generate_private_key_fastreject},
216         //{"d0_blind_id_read_private_key", (void **) &qd0_blind_id_read_private_key},
217         {"d0_blind_id_read_public_key", (void **) &qd0_blind_id_read_public_key},
218         //{"d0_blind_id_write_private_key", (void **) &qd0_blind_id_write_private_key},
219         //{"d0_blind_id_write_public_key", (void **) &qd0_blind_id_write_public_key},
220         {"d0_blind_id_fingerprint64_public_key", (void **) &qd0_blind_id_fingerprint64_public_key},
221         //{"d0_blind_id_generate_private_id_modulus", (void **) &qd0_blind_id_generate_private_id_modulus},
222         {"d0_blind_id_read_private_id_modulus", (void **) &qd0_blind_id_read_private_id_modulus},
223         //{"d0_blind_id_write_private_id_modulus", (void **) &qd0_blind_id_write_private_id_modulus},
224         {"d0_blind_id_generate_private_id_start", (void **) &qd0_blind_id_generate_private_id_start},
225         {"d0_blind_id_generate_private_id_request", (void **) &qd0_blind_id_generate_private_id_request},
226         //{"d0_blind_id_answer_private_id_request", (void **) &qd0_blind_id_answer_private_id_request},
227         {"d0_blind_id_finish_private_id_request", (void **) &qd0_blind_id_finish_private_id_request},
228         //{"d0_blind_id_read_private_id_request_camouflage", (void **) &qd0_blind_id_read_private_id_request_camouflage},
229         //{"d0_blind_id_write_private_id_request_camouflage", (void **) &qd0_blind_id_write_private_id_request_camouflage},
230         {"d0_blind_id_read_private_id", (void **) &qd0_blind_id_read_private_id},
231         //{"d0_blind_id_read_public_id", (void **) &qd0_blind_id_read_public_id},
232         {"d0_blind_id_write_private_id", (void **) &qd0_blind_id_write_private_id},
233         //{"d0_blind_id_write_public_id", (void **) &qd0_blind_id_write_public_id},
234         {"d0_blind_id_authenticate_with_private_id_start", (void **) &qd0_blind_id_authenticate_with_private_id_start},
235         {"d0_blind_id_authenticate_with_private_id_challenge", (void **) &qd0_blind_id_authenticate_with_private_id_challenge},
236         {"d0_blind_id_authenticate_with_private_id_response", (void **) &qd0_blind_id_authenticate_with_private_id_response},
237         {"d0_blind_id_authenticate_with_private_id_verify", (void **) &qd0_blind_id_authenticate_with_private_id_verify},
238         {"d0_blind_id_fingerprint64_public_id", (void **) &qd0_blind_id_fingerprint64_public_id},
239         {"d0_blind_id_sessionkey_public_id", (void **) &qd0_blind_id_sessionkey_public_id},
240         {"d0_blind_id_INITIALIZE", (void **) &qd0_blind_id_INITIALIZE},
241         {"d0_blind_id_SHUTDOWN", (void **) &qd0_blind_id_SHUTDOWN},
242         {"d0_blind_id_util_sha256", (void **) &qd0_blind_id_util_sha256},
243         {"d0_blind_id_sign_with_private_id_sign", (void **) &qd0_blind_id_sign_with_private_id_sign},
244         {"d0_blind_id_sign_with_private_id_sign_detached", (void **) &qd0_blind_id_sign_with_private_id_sign_detached},
245         {"d0_blind_id_setmallocfuncs", (void **) &qd0_blind_id_setmallocfuncs},
246         {"d0_blind_id_setmutexfuncs", (void **) &qd0_blind_id_setmutexfuncs},
247         {NULL, NULL}
248 };
249 // end of d0_blind_id interface
250
251 static dllhandle_t d0_blind_id_dll = NULL;
252 static qboolean Crypto_OpenLibrary (void)
253 {
254         const char* dllnames [] =
255         {
256 #if defined(WIN32)
257                 "libd0_blind_id-0.dll",
258 #elif defined(MACOSX)
259                 "libd0_blind_id.0.dylib",
260 #else
261                 "libd0_blind_id.so.0",
262                 "libd0_blind_id.so", // FreeBSD
263 #endif
264                 NULL
265         };
266
267         // Already loaded?
268         if (d0_blind_id_dll)
269                 return true;
270
271         // Load the DLL
272         return Sys_LoadLibrary (dllnames, &d0_blind_id_dll, d0_blind_id_funcs);
273 }
274
275 static void Crypto_CloseLibrary (void)
276 {
277         Sys_UnloadLibrary (&d0_blind_id_dll);
278 }
279
280 #endif
281
282 #ifdef CRYPTO_RIJNDAEL_STATIC
283
284 #include <d0_blind_id/d0_rijndael.h>
285
286 #define d0_rijndael_dll 1
287 #define Crypto_Rijndael_OpenLibrary() true
288 #define Crypto_Rijndael_CloseLibrary()
289
290 #define qd0_rijndael_setup_encrypt d0_rijndael_setup_encrypt
291 #define qd0_rijndael_setup_decrypt d0_rijndael_setup_decrypt
292 #define qd0_rijndael_encrypt d0_rijndael_encrypt
293 #define qd0_rijndael_decrypt d0_rijndael_decrypt
294
295 #else
296
297 // no need to do the #define dance here, as the upper part declares out macros either way
298
299 D0_EXPORT int (*qd0_rijndael_setup_encrypt) (unsigned long *rk, const unsigned char *key,
300   int keybits);
301 D0_EXPORT int (*qd0_rijndael_setup_decrypt) (unsigned long *rk, const unsigned char *key,
302   int keybits);
303 D0_EXPORT void (*qd0_rijndael_encrypt) (const unsigned long *rk, int nrounds,
304   const unsigned char plaintext[16], unsigned char ciphertext[16]);
305 D0_EXPORT void (*qd0_rijndael_decrypt) (const unsigned long *rk, int nrounds,
306   const unsigned char ciphertext[16], unsigned char plaintext[16]);
307 #define D0_RIJNDAEL_KEYLENGTH(keybits) ((keybits)/8)
308 #define D0_RIJNDAEL_RKLENGTH(keybits)  ((keybits)/8+28)
309 #define D0_RIJNDAEL_NROUNDS(keybits)   ((keybits)/32+6)
310 static dllfunction_t d0_rijndael_funcs[] =
311 {
312         {"d0_rijndael_setup_decrypt", (void **) &qd0_rijndael_setup_decrypt},
313         {"d0_rijndael_setup_encrypt", (void **) &qd0_rijndael_setup_encrypt},
314         {"d0_rijndael_decrypt", (void **) &qd0_rijndael_decrypt},
315         {"d0_rijndael_encrypt", (void **) &qd0_rijndael_encrypt},
316         {NULL, NULL}
317 };
318 // end of d0_blind_id interface
319
320 static dllhandle_t d0_rijndael_dll = NULL;
321 static qboolean Crypto_Rijndael_OpenLibrary (void)
322 {
323         const char* dllnames [] =
324         {
325 #if defined(WIN32)
326                 "libd0_rijndael-0.dll",
327 #elif defined(MACOSX)
328                 "libd0_rijndael.0.dylib",
329 #else
330                 "libd0_rijndael.so.0",
331                 "libd0_rijndael.so", // FreeBSD
332 #endif
333                 NULL
334         };
335
336         // Already loaded?
337         if (d0_rijndael_dll)
338                 return true;
339
340         // Load the DLL
341         return Sys_LoadLibrary (dllnames, &d0_rijndael_dll, d0_rijndael_funcs);
342 }
343
344 static void Crypto_Rijndael_CloseLibrary (void)
345 {
346         Sys_UnloadLibrary (&d0_rijndael_dll);
347 }
348
349 #endif
350
351 // various helpers
352 void sha256(unsigned char *out, const unsigned char *in, int n)
353 {
354         qd0_blind_id_util_sha256((char *) out, (const char *) in, n);
355 }
356
357 static size_t Crypto_LoadFile(const char *path, char *buf, size_t nmax, qboolean inuserdir)
358 {
359         char vabuf[1024];
360         qfile_t *f = NULL;
361         fs_offset_t n;
362         if(inuserdir)
363                 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", *fs_userdir ? fs_userdir : fs_basedir, path), "rb", false);
364         else
365                 f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%s%s", fs_basedir, path), "rb", false);
366         if(!f)
367                 return 0;
368         n = FS_Read(f, buf, nmax);
369         if(n < 0)
370                 n = 0;
371         FS_Close(f);
372         return (size_t) n;
373 }
374
375 static qboolean PutWithNul(char **data, size_t *len, const char *str)
376 {
377         // invariant: data points to insertion point
378         size_t l = strlen(str);
379         if(l >= *len)
380                 return false;
381         memcpy(*data, str, l+1);
382         *data += l+1;
383         *len -= l+1;
384         return true;
385 }
386
387 static const char *GetUntilNul(const char **data, size_t *len)
388 {
389         // invariant: data points to next character to take
390         const char *data_save = *data;
391         size_t n;
392         const char *p;
393
394         if(!*data)
395                 return NULL;
396
397         if(!*len)
398         {
399                 *data = NULL;
400                 return NULL;
401         }
402
403         p = (const char *) memchr(*data, 0, *len);
404         if(!p) // no terminating NUL
405         {
406                 *data = NULL;
407                 *len = 0;
408                 return NULL;
409         }
410         else
411         {
412                 n = (p - *data) + 1;
413                 *len -= n;
414                 *data += n;
415                 if(*len == 0)
416                         *data = NULL;
417                 return (const char *) data_save;
418         }
419         *data = NULL;
420         return NULL;
421 }
422
423 // d0pk reading
424 static d0_blind_id_t *Crypto_ReadPublicKey(char *buf, size_t len)
425 {
426         d0_blind_id_t *pk = NULL;
427         const char *p[2];
428         size_t l[2];
429         if(Crypto_ParsePack(buf, len, FOURCC_D0PK, p, l, 2))
430         {
431                 pk = qd0_blind_id_new();
432                 if(pk)
433                         if(qd0_blind_id_read_public_key(pk, p[0], l[0]))
434                                 if(qd0_blind_id_read_private_id_modulus(pk, p[1], l[1]))
435                                         return pk;
436         }
437         if(pk)
438                 qd0_blind_id_free(pk);
439         return NULL;
440 }
441
442 // d0si reading
443 static qboolean Crypto_AddPrivateKey(d0_blind_id_t *pk, char *buf, size_t len)
444 {
445         const char *p[1];
446         size_t l[1];
447         if(Crypto_ParsePack(buf, len, FOURCC_D0SI, p, l, 1))
448         {
449                 if(qd0_blind_id_read_private_id(pk, p[0], l[0]))
450                         return true;
451         }
452         return false;
453 }
454
455 #define MAX_PUBKEYS 16
456 static d0_blind_id_t *pubkeys[MAX_PUBKEYS];
457 static char pubkeys_fp64[MAX_PUBKEYS][FP64_SIZE+1];
458 static qboolean pubkeys_havepriv[MAX_PUBKEYS];
459 static char pubkeys_priv_fp64[MAX_PUBKEYS][FP64_SIZE+1];
460 static char challenge_append[1400];
461 static size_t challenge_append_length;
462
463 static int keygen_i = -1;
464 static char keygen_buf[8192];
465
466 #define MAX_CRYPTOCONNECTS 16
467 #define CRYPTOCONNECT_NONE 0
468 #define CRYPTOCONNECT_PRECONNECT 1
469 #define CRYPTOCONNECT_CONNECT 2
470 #define CRYPTOCONNECT_RECONNECT 3
471 #define CRYPTOCONNECT_DUPLICATE 4
472 typedef struct server_cryptoconnect_s
473 {
474         double lasttime;
475         lhnetaddress_t address;
476         crypto_t crypto;
477         int next_step;
478 }
479 server_cryptoconnect_t;
480 static server_cryptoconnect_t cryptoconnects[MAX_CRYPTOCONNECTS];
481
482 static int cdata_id = 0;
483 typedef struct
484 {
485         d0_blind_id_t *id;
486         int s, c;
487         int next_step;
488         char challenge[2048];
489         char wantserver_idfp[FP64_SIZE+1];
490         qboolean wantserver_aes;
491         int cdata_id;
492 }
493 crypto_data_t;
494
495 // crypto specific helpers
496 #define CDATA ((crypto_data_t *) crypto->data)
497 #define MAKE_CDATA if(!crypto->data) crypto->data = Z_Malloc(sizeof(crypto_data_t))
498 #define CLEAR_CDATA if(crypto->data) { if(CDATA->id) qd0_blind_id_free(CDATA->id); Z_Free(crypto->data); } crypto->data = NULL
499
500 static crypto_t *Crypto_ServerFindInstance(lhnetaddress_t *peeraddress, qboolean allow_create)
501 {
502         crypto_t *crypto; 
503         int i, best;
504
505         if(!d0_blind_id_dll)
506                 return NULL; // no support
507
508         for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
509                 if(LHNETADDRESS_Compare(peeraddress, &cryptoconnects[i].address))
510                         break;
511         if(i < MAX_CRYPTOCONNECTS && (allow_create || cryptoconnects[i].crypto.data))
512         {
513                 crypto = &cryptoconnects[i].crypto;
514                 cryptoconnects[i].lasttime = realtime;
515                 return crypto;
516         }
517         if(!allow_create)
518                 return NULL;
519         best = 0;
520         for(i = 1; i < MAX_CRYPTOCONNECTS; ++i)
521                 if(cryptoconnects[i].lasttime < cryptoconnects[best].lasttime)
522                         best = i;
523         crypto = &cryptoconnects[best].crypto;
524         cryptoconnects[best].lasttime = realtime;
525         memcpy(&cryptoconnects[best].address, peeraddress, sizeof(cryptoconnects[best].address));
526         CLEAR_CDATA;
527         return crypto;
528 }
529
530 qboolean Crypto_ServerFinishInstance(crypto_t *out, crypto_t *crypto)
531 {
532         // no check needed here (returned pointers are only used in prefilled fields)
533         if(!crypto || !crypto->authenticated)
534         {
535                 Con_Printf("Passed an invalid crypto connect instance\n");
536                 memset(out, 0, sizeof(*out));
537                 return false;
538         }
539         CLEAR_CDATA;
540         memcpy(out, crypto, sizeof(*out));
541         memset(crypto, 0, sizeof(crypto));
542         return true;
543 }
544
545 crypto_t *Crypto_ServerGetInstance(lhnetaddress_t *peeraddress)
546 {
547         // no check needed here (returned pointers are only used in prefilled fields)
548         return Crypto_ServerFindInstance(peeraddress, false);
549 }
550
551 typedef struct crypto_storedhostkey_s
552 {
553         struct crypto_storedhostkey_s *next;
554         lhnetaddress_t addr;
555         int keyid;
556         char idfp[FP64_SIZE+1];
557         int aeslevel;
558 }
559 crypto_storedhostkey_t;
560 static crypto_storedhostkey_t *crypto_storedhostkey_hashtable[CRYPTO_HOSTKEY_HASHSIZE];
561
562 static void Crypto_InitHostKeys(void)
563 {
564         int i;
565         for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
566                 crypto_storedhostkey_hashtable[i] = NULL;
567 }
568
569 static void Crypto_ClearHostKeys(void)
570 {
571         int i;
572         crypto_storedhostkey_t *hk, *hkn;
573         for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
574         {
575                 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hkn)
576                 {
577                         hkn = hk->next;
578                         Z_Free(hk);
579                 }
580                 crypto_storedhostkey_hashtable[i] = NULL;
581         }
582 }
583
584 static qboolean Crypto_ClearHostKey(lhnetaddress_t *peeraddress)
585 {
586         char buf[128];
587         int hashindex;
588         crypto_storedhostkey_t **hkp;
589         qboolean found = false;
590
591         LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
592         hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
593         for(hkp = &crypto_storedhostkey_hashtable[hashindex]; *hkp && LHNETADDRESS_Compare(&((*hkp)->addr), peeraddress); hkp = &((*hkp)->next));
594
595         if(*hkp)
596         {
597                 crypto_storedhostkey_t *hk = *hkp;
598                 *hkp = hk->next;
599                 Z_Free(hk);
600                 found = true;
601         }
602
603         return found;
604 }
605
606 static void Crypto_StoreHostKey(lhnetaddress_t *peeraddress, const char *keystring, qboolean complain)
607 {
608         char buf[128];
609         int hashindex;
610         crypto_storedhostkey_t *hk;
611         int keyid;
612         char idfp[FP64_SIZE+1];
613         int aeslevel;
614
615         if(!d0_blind_id_dll)
616                 return;
617         
618         // syntax of keystring:
619         // aeslevel id@key id@key ...
620
621         if(!*keystring)
622                 return;
623         aeslevel = bound(0, *keystring - '0', 3);
624         while(*keystring && *keystring != ' ')
625                 ++keystring;
626
627         keyid = -1;
628         while(*keystring && keyid < 0)
629         {
630                 // id@key
631                 const char *idstart, *idend, *keystart, *keyend;
632                 ++keystring; // skip the space
633                 idstart = keystring;
634                 while(*keystring && *keystring != ' ' && *keystring != '@')
635                         ++keystring;
636                 idend = keystring;
637                 if(!*keystring)
638                         break;
639                 ++keystring;
640                 keystart = keystring;
641                 while(*keystring && *keystring != ' ')
642                         ++keystring;
643                 keyend = keystring;
644
645                 if(idend - idstart == FP64_SIZE && keyend - keystart == FP64_SIZE)
646                 {
647                         for(keyid = 0; keyid < MAX_PUBKEYS; ++keyid)
648                                 if(pubkeys[keyid])
649                                         if(!memcmp(pubkeys_fp64[keyid], keystart, FP64_SIZE))
650                                         {
651                                                 memcpy(idfp, idstart, FP64_SIZE);
652                                                 idfp[FP64_SIZE] = 0;
653                                                 break;
654                                         }
655                         if(keyid >= MAX_PUBKEYS)
656                                 keyid = -1;
657                 }
658         }
659
660         if(keyid < 0)
661                 return;
662
663         LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
664         hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
665         for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next);
666
667         if(hk)
668         {
669                 if(complain)
670                 {
671                         if(hk->keyid != keyid || memcmp(hk->idfp, idfp, FP64_SIZE+1))
672                                 Con_Printf("Server %s tried to change the host key to a value not in the host cache. Connecting to it will fail. To accept the new host key, do crypto_hostkey_clear %s\n", buf, buf);
673                         if(hk->aeslevel > aeslevel)
674                                 Con_Printf("Server %s tried to reduce encryption status, not accepted. Connecting to it will fail. To accept, do crypto_hostkey_clear %s\n", buf, buf);
675                 }
676                 hk->aeslevel = max(aeslevel, hk->aeslevel);
677                 return;
678         }
679
680         // great, we did NOT have it yet
681         hk = (crypto_storedhostkey_t *) Z_Malloc(sizeof(*hk));
682         memcpy(&hk->addr, peeraddress, sizeof(hk->addr));
683         hk->keyid = keyid;
684         memcpy(hk->idfp, idfp, FP64_SIZE+1);
685         hk->next = crypto_storedhostkey_hashtable[hashindex];
686         hk->aeslevel = aeslevel;
687         crypto_storedhostkey_hashtable[hashindex] = hk;
688 }
689
690 qboolean Crypto_RetrieveHostKey(lhnetaddress_t *peeraddress, int *keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen, int *aeslevel)
691 {
692         char buf[128];
693         int hashindex;
694         crypto_storedhostkey_t *hk;
695
696         if(!d0_blind_id_dll)
697                 return false;
698
699         LHNETADDRESS_ToString(peeraddress, buf, sizeof(buf), 1);
700         hashindex = CRC_Block((const unsigned char *) buf, strlen(buf)) % CRYPTO_HOSTKEY_HASHSIZE;
701         for(hk = crypto_storedhostkey_hashtable[hashindex]; hk && LHNETADDRESS_Compare(&hk->addr, peeraddress); hk = hk->next);
702
703         if(!hk)
704                 return false;
705
706         if(keyid)
707                 *keyid = hk->keyid;
708         if(keyfp)
709                 strlcpy(keyfp, pubkeys_fp64[hk->keyid], keyfplen);
710         if(idfp)
711                 strlcpy(idfp, hk->idfp, idfplen);
712         if(aeslevel)
713                 *aeslevel = hk->aeslevel;
714
715         return true;
716 }
717 int Crypto_RetrieveLocalKey(int keyid, char *keyfp, size_t keyfplen, char *idfp, size_t idfplen) // return value: -1 if more to come, +1 if valid, 0 if end of list
718 {
719         if(keyid < 0 || keyid >= MAX_PUBKEYS)
720                 return 0;
721         if(keyfp)
722                 *keyfp = 0;
723         if(idfp)
724                 *idfp = 0;
725         if(!pubkeys[keyid])
726                 return -1;
727         if(keyfp)
728                 strlcpy(keyfp, pubkeys_fp64[keyid], keyfplen);
729         if(idfp)
730                 if(pubkeys_havepriv[keyid])
731                         strlcpy(idfp, pubkeys_priv_fp64[keyid], keyfplen);
732         return 1;
733 }
734 // end
735
736 // init/shutdown code
737 static void Crypto_BuildChallengeAppend(void)
738 {
739         char *p, *lengthptr, *startptr;
740         size_t n;
741         int i;
742         p = challenge_append;
743         n = sizeof(challenge_append);
744         Crypto_UnLittleLong(p, PROTOCOL_VLEN);
745         p += 4;
746         n -= 4;
747         lengthptr = p;
748         Crypto_UnLittleLong(p, 0);
749         p += 4;
750         n -= 4;
751         Crypto_UnLittleLong(p, PROTOCOL_D0_BLIND_ID);
752         p += 4;
753         n -= 4;
754         startptr = p;
755         for(i = 0; i < MAX_PUBKEYS; ++i)
756                 if(pubkeys_havepriv[i])
757                         PutWithNul(&p, &n, pubkeys_fp64[i]);
758         PutWithNul(&p, &n, "");
759         for(i = 0; i < MAX_PUBKEYS; ++i)
760                 if(!pubkeys_havepriv[i] && pubkeys[i])
761                         PutWithNul(&p, &n, pubkeys_fp64[i]);
762         Crypto_UnLittleLong(lengthptr, p - startptr);
763         challenge_append_length = p - challenge_append;
764 }
765
766 void Crypto_LoadKeys(void)
767 {
768         char buf[8192];
769         size_t len, len2;
770         int i;
771         char vabuf[1024];
772
773         if(!d0_blind_id_dll) // don't if we can't
774                 return;
775
776         if(crypto_idstring) // already loaded? then not
777                 return;
778
779         Host_LockSession(); // we use the session ID here
780
781         SV_LockThreadMutex();
782
783         // load keys
784         // note: we are just a CLIENT
785         // so we load:
786         //   PUBLIC KEYS to accept (including modulus)
787         //   PRIVATE KEY of user
788
789         crypto_idstring = NULL;
790         dpsnprintf(crypto_idstring_buf, sizeof(crypto_idstring_buf), "%d", d0_rijndael_dll ? crypto_aeslevel.integer : 0);
791         for(i = 0; i < MAX_PUBKEYS; ++i)
792         {
793                 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
794                 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
795                 pubkeys_havepriv[i] = false;
796                 len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0pk", i), buf, sizeof(buf), false);
797                 if((pubkeys[i] = Crypto_ReadPublicKey(buf, len)))
798                 {
799                         len2 = FP64_SIZE;
800                         if(qd0_blind_id_fingerprint64_public_key(pubkeys[i], pubkeys_fp64[i], &len2)) // keeps final NUL
801                         {
802                                 Con_Printf("Loaded public key key_%d.d0pk (fingerprint: %s)\n", i, pubkeys_fp64[i]);
803                                 len = Crypto_LoadFile(va(vabuf, sizeof(vabuf), "key_%d.d0si%s", i, sessionid.string), buf, sizeof(buf), true);
804                                 if(len)
805                                 {
806                                         if(Crypto_AddPrivateKey(pubkeys[i], buf, len))
807                                         {
808                                                 len2 = FP64_SIZE;
809                                                 if(qd0_blind_id_fingerprint64_public_id(pubkeys[i], pubkeys_priv_fp64[i], &len2)) // keeps final NUL
810                                                 {
811                                                         Con_Printf("Loaded private ID key_%d.d0si%s for key_%d.d0pk (public key fingerprint: %s)\n", i, sessionid.string, i, pubkeys_priv_fp64[i]);
812                                                         pubkeys_havepriv[i] = true;
813                                                         strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[i], pubkeys_fp64[i]), sizeof(crypto_idstring_buf));
814                                                 }
815                                                 else
816                                                 {
817                                                         // can't really happen
818                                                         // but nothing leaked here
819                                                 }
820                                         }
821                                 }
822                         }
823                         else
824                         {
825                                 // can't really happen
826                                 qd0_blind_id_free(pubkeys[i]);
827                                 pubkeys[i] = NULL;
828                         }
829                 }
830         }
831         crypto_idstring = crypto_idstring_buf;
832
833         keygen_i = -1;
834         Crypto_BuildChallengeAppend();
835
836         // find a good prefix length for all the keys we know (yes, algorithm is not perfect yet, may yield too long prefix length)
837         crypto_keyfp_recommended_length = 0;
838         memset(buf+256, 0, MAX_PUBKEYS + MAX_PUBKEYS);
839         while(crypto_keyfp_recommended_length < FP64_SIZE)
840         {
841                 memset(buf, 0, 256);
842                 for(i = 0; i < MAX_PUBKEYS; ++i)
843                         if(pubkeys[i])
844                         {
845                                 if(!buf[256 + i])
846                                         ++buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]];
847                                 if(pubkeys_havepriv[i])
848                                         if(!buf[256 + MAX_PUBKEYS + i])
849                                                 ++buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]];
850                         }
851                 for(i = 0; i < MAX_PUBKEYS; ++i)
852                         if(pubkeys[i])
853                         {
854                                 if(!buf[256 + i])
855                                         if(buf[(unsigned char) pubkeys_fp64[i][crypto_keyfp_recommended_length]] < 2)
856                                                 buf[256 + i] = 1;
857                                 if(pubkeys_havepriv[i])
858                                         if(!buf[256 + MAX_PUBKEYS + i])
859                                                 if(buf[(unsigned char) pubkeys_priv_fp64[i][crypto_keyfp_recommended_length]] < 2)
860                                                         buf[256 + MAX_PUBKEYS + i] = 1;
861                         }
862                 ++crypto_keyfp_recommended_length;
863                 for(i = 0; i < MAX_PUBKEYS; ++i)
864                         if(pubkeys[i])
865                         {
866                                 if(!buf[256 + i])
867                                         break;
868                                 if(pubkeys_havepriv[i])
869                                         if(!buf[256 + MAX_PUBKEYS + i])
870                                                 break;
871                         }
872                 if(i >= MAX_PUBKEYS)
873                         break;
874         }
875         if(crypto_keyfp_recommended_length < 7)
876                 crypto_keyfp_recommended_length = 7;
877
878         SV_UnlockThreadMutex();
879 }
880
881 static void Crypto_UnloadKeys(void)
882 {
883         int i;
884
885         SV_LockThreadMutex();
886
887         keygen_i = -1;
888         for(i = 0; i < MAX_PUBKEYS; ++i)
889         {
890                 if(pubkeys[i])
891                         qd0_blind_id_free(pubkeys[i]);
892                 pubkeys[i] = NULL;
893                 pubkeys_havepriv[i] = false;
894                 memset(pubkeys_fp64[i], 0, sizeof(pubkeys_fp64[i]));
895                 memset(pubkeys_priv_fp64[i], 0, sizeof(pubkeys_fp64[i]));
896                 challenge_append_length = 0;
897         }
898         crypto_idstring = NULL;
899
900         SV_UnlockThreadMutex();
901 }
902
903 static mempool_t *cryptomempool;
904
905 #ifdef __cplusplus
906 extern "C"
907 {
908 #endif
909 static void *Crypto_d0_malloc(size_t len)
910 {
911         return Mem_Alloc(cryptomempool, len);
912 }
913
914 static void Crypto_d0_free(void *p)
915 {
916         Mem_Free(p);
917 }
918
919 static void *Crypto_d0_createmutex(void)
920 {
921         return Thread_CreateMutex();
922 }
923
924 static void Crypto_d0_destroymutex(void *m)
925 {
926         Thread_DestroyMutex(m);
927 }
928
929 static int Crypto_d0_lockmutex(void *m)
930 {
931         return Thread_LockMutex(m);
932 }
933
934 static int Crypto_d0_unlockmutex(void *m)
935 {
936         return Thread_UnlockMutex(m);
937 }
938 #ifdef __cplusplus
939 }
940 #endif
941
942 void Crypto_Shutdown(void)
943 {
944         crypto_t *crypto;
945         int i;
946
947         Crypto_Rijndael_CloseLibrary();
948
949         if(d0_blind_id_dll)
950         {
951                 // free memory
952                 for(i = 0; i < MAX_CRYPTOCONNECTS; ++i)
953                 {
954                         crypto = &cryptoconnects[i].crypto;
955                         CLEAR_CDATA;
956                 }
957                 memset(cryptoconnects, 0, sizeof(cryptoconnects));
958                 crypto = &cls.crypto;
959                 CLEAR_CDATA;
960
961                 Crypto_UnloadKeys();
962
963                 qd0_blind_id_SHUTDOWN();
964
965                 Crypto_CloseLibrary();
966         }
967
968         Mem_FreePool(&cryptomempool);
969 }
970
971 void Crypto_Init(void)
972 {
973         cryptomempool = Mem_AllocPool("crypto", 0, NULL);
974
975         if(!Crypto_OpenLibrary())
976                 return;
977
978         qd0_blind_id_setmallocfuncs(Crypto_d0_malloc, Crypto_d0_free);
979         if (Thread_HasThreads())
980                 qd0_blind_id_setmutexfuncs(Crypto_d0_createmutex, Crypto_d0_destroymutex, Crypto_d0_lockmutex, Crypto_d0_unlockmutex);
981
982         if(!qd0_blind_id_INITIALIZE())
983         {
984                 Crypto_Rijndael_CloseLibrary();
985                 Crypto_CloseLibrary();
986                 Con_Printf("libd0_blind_id initialization FAILED, cryptography support has been disabled\n");
987                 return;
988         }
989
990         Crypto_Rijndael_OpenLibrary(); // if this fails, it's uncritical
991
992         Crypto_InitHostKeys();
993 }
994 // end
995
996 qboolean Crypto_Available(void)
997 {
998         if(!d0_blind_id_dll)
999                 return false;
1000         return true;
1001 }
1002
1003 // keygen code
1004 static void Crypto_KeyGen_Finished(int code, size_t length_received, unsigned char *buffer, void *cbdata)
1005 {
1006         const char *p[1];
1007         size_t l[1];
1008         static char buf[8192];
1009         static char buf2[8192];
1010         size_t bufsize, buf2size;
1011         qfile_t *f = NULL;
1012         d0_blind_id_t *ctx, *ctx2;
1013         D0_BOOL status;
1014         size_t len2;
1015         char vabuf[1024];
1016
1017         SV_LockThreadMutex();
1018
1019         if(!d0_blind_id_dll)
1020         {
1021                 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1022                 keygen_i = -1;
1023                 SV_UnlockThreadMutex();
1024                 return;
1025         }
1026
1027         if(keygen_i >= MAX_PUBKEYS || !pubkeys[keygen_i])
1028         {
1029                 Con_Printf("overflow of keygen_i\n");
1030                 keygen_i = -1;
1031                 SV_UnlockThreadMutex();
1032                 return;
1033         }
1034         if(keygen_i < 0)
1035         {
1036                 Con_Printf("Unexpected response from keygen server:\n");
1037                 Com_HexDumpToConsole(buffer, length_received);
1038                 SV_UnlockThreadMutex();
1039                 return;
1040         }
1041         if(!Crypto_ParsePack((const char *) buffer, length_received, FOURCC_D0IR, p, l, 1))
1042         {
1043                 if(length_received >= 5 && Crypto_LittleLong((const char *) buffer) == FOURCC_D0ER)
1044                 {
1045                         Con_Printf("Error response from keygen server: %.*s\n", (int)(length_received - 5), buffer + 5);
1046                 }
1047                 else
1048                 {
1049                         Con_Printf("Invalid response from keygen server:\n");
1050                         Com_HexDumpToConsole(buffer, length_received);
1051                 }
1052                 keygen_i = -1;
1053                 SV_UnlockThreadMutex();
1054                 return;
1055         }
1056         if(!qd0_blind_id_finish_private_id_request(pubkeys[keygen_i], p[0], l[0]))
1057         {
1058                 Con_Printf("d0_blind_id_finish_private_id_request failed\n");
1059                 keygen_i = -1;
1060                 SV_UnlockThreadMutex();
1061                 return;
1062         }
1063
1064         // verify the key we just got (just in case)
1065         ctx = qd0_blind_id_new();
1066         if(!ctx)
1067         {
1068                 Con_Printf("d0_blind_id_new failed\n");
1069                 keygen_i = -1;
1070                 SV_UnlockThreadMutex();
1071                 return;
1072         }
1073         ctx2 = qd0_blind_id_new();
1074         if(!ctx2)
1075         {
1076                 Con_Printf("d0_blind_id_new failed\n");
1077                 qd0_blind_id_free(ctx);
1078                 keygen_i = -1;
1079                 SV_UnlockThreadMutex();
1080                 return;
1081         }
1082         if(!qd0_blind_id_copy(ctx, pubkeys[keygen_i]))
1083         {
1084                 Con_Printf("d0_blind_id_copy failed\n");
1085                 qd0_blind_id_free(ctx);
1086                 qd0_blind_id_free(ctx2);
1087                 keygen_i = -1;
1088                 SV_UnlockThreadMutex();
1089                 return;
1090         }
1091         if(!qd0_blind_id_copy(ctx2, pubkeys[keygen_i]))
1092         {
1093                 Con_Printf("d0_blind_id_copy failed\n");
1094                 qd0_blind_id_free(ctx);
1095                 qd0_blind_id_free(ctx2);
1096                 keygen_i = -1;
1097                 SV_UnlockThreadMutex();
1098                 return;
1099         }
1100         bufsize = sizeof(buf);
1101         if(!qd0_blind_id_authenticate_with_private_id_start(ctx, 1, 1, "hello world", 11, buf, &bufsize))
1102         {
1103                 Con_Printf("d0_blind_id_authenticate_with_private_id_start failed\n");
1104                 qd0_blind_id_free(ctx);
1105                 qd0_blind_id_free(ctx2);
1106                 keygen_i = -1;
1107                 SV_UnlockThreadMutex();
1108                 return;
1109         }
1110         buf2size = sizeof(buf2);
1111         if(!qd0_blind_id_authenticate_with_private_id_challenge(ctx2, 1, 1, buf, bufsize, buf2, &buf2size, &status) || !status)
1112         {
1113                 Con_Printf("d0_blind_id_authenticate_with_private_id_challenge failed (server does not have the requested private key)\n");
1114                 qd0_blind_id_free(ctx);
1115                 qd0_blind_id_free(ctx2);
1116                 keygen_i = -1;
1117                 SV_UnlockThreadMutex();
1118                 return;
1119         }
1120         bufsize = sizeof(buf);
1121         if(!qd0_blind_id_authenticate_with_private_id_response(ctx, buf2, buf2size, buf, &bufsize))
1122         {
1123                 Con_Printf("d0_blind_id_authenticate_with_private_id_response failed\n");
1124                 qd0_blind_id_free(ctx);
1125                 qd0_blind_id_free(ctx2);
1126                 keygen_i = -1;
1127                 SV_UnlockThreadMutex();
1128                 return;
1129         }
1130         buf2size = sizeof(buf2);
1131         if(!qd0_blind_id_authenticate_with_private_id_verify(ctx2, buf, bufsize, buf2, &buf2size, &status) || !status)
1132         {
1133                 Con_Printf("d0_blind_id_authenticate_with_private_id_verify failed (server does not have the requested private key)\n");
1134                 qd0_blind_id_free(ctx);
1135                 qd0_blind_id_free(ctx2);
1136                 keygen_i = -1;
1137                 SV_UnlockThreadMutex();
1138                 return;
1139         }
1140         qd0_blind_id_free(ctx);
1141         qd0_blind_id_free(ctx2);
1142
1143         // we have a valid key now!
1144         // make the rest of crypto.c know that
1145         len2 = FP64_SIZE;
1146         if(qd0_blind_id_fingerprint64_public_id(pubkeys[keygen_i], pubkeys_priv_fp64[keygen_i], &len2)) // keeps final NUL
1147         {
1148                 Con_Printf("Received private ID key_%d.d0pk (public key fingerprint: %s)\n", keygen_i, pubkeys_priv_fp64[keygen_i]);
1149                 pubkeys_havepriv[keygen_i] = true;
1150                 strlcat(crypto_idstring_buf, va(vabuf, sizeof(vabuf), " %s@%s", pubkeys_priv_fp64[keygen_i], pubkeys_fp64[keygen_i]), sizeof(crypto_idstring_buf));
1151                 crypto_idstring = crypto_idstring_buf;
1152                 Crypto_BuildChallengeAppend();
1153         }
1154         // write the key to disk
1155         p[0] = buf;
1156         l[0] = sizeof(buf);
1157         if(!qd0_blind_id_write_private_id(pubkeys[keygen_i], buf, &l[0]))
1158         {
1159                 Con_Printf("d0_blind_id_write_private_id failed\n");
1160                 keygen_i = -1;
1161                 SV_UnlockThreadMutex();
1162                 return;
1163         }
1164         if(!(buf2size = Crypto_UnParsePack(buf2, sizeof(buf2), FOURCC_D0SI, p, l, 1)))
1165         {
1166                 Con_Printf("Crypto_UnParsePack failed\n");
1167                 keygen_i = -1;
1168                 SV_UnlockThreadMutex();
1169                 return;
1170         }
1171
1172         FS_CreatePath(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string));
1173         f = FS_SysOpen(va(vabuf, sizeof(vabuf), "%skey_%d.d0si%s", *fs_userdir ? fs_userdir : fs_basedir, keygen_i, sessionid.string), "wb", false);
1174         if(!f)
1175         {
1176                 Con_Printf("Cannot open key_%d.d0si%s\n", keygen_i, sessionid.string);
1177                 keygen_i = -1;
1178                 SV_UnlockThreadMutex();
1179                 return;
1180         }
1181         FS_Write(f, buf2, buf2size);
1182         FS_Close(f);
1183
1184         Con_Printf("Saved to key_%d.d0si%s\n", keygen_i, sessionid.string);
1185         keygen_i = -1;
1186         SV_UnlockThreadMutex();
1187 }
1188
1189 static void Crypto_KeyGen_f(void)
1190 {
1191         int i;
1192         const char *p[1];
1193         size_t l[1];
1194         static char buf[8192];
1195         static char buf2[8192];
1196         size_t buf2l, buf2pos;
1197         if(!d0_blind_id_dll)
1198         {
1199                 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1200                 return;
1201         }
1202         if(Cmd_Argc() != 3)
1203         {
1204                 Con_Printf("usage:\n%s id url\n", Cmd_Argv(0));
1205                 return;
1206         }
1207         SV_LockThreadMutex();
1208         Crypto_LoadKeys();
1209         i = atoi(Cmd_Argv(1));
1210         if(!pubkeys[i])
1211         {
1212                 Con_Printf("there is no public key %d\n", i);
1213                 SV_UnlockThreadMutex();
1214                 return;
1215         }
1216         if(pubkeys_havepriv[i])
1217         {
1218                 Con_Printf("there is already a private key for %d\n", i);
1219                 SV_UnlockThreadMutex();
1220                 return;
1221         }
1222         if(keygen_i >= 0)
1223         {
1224                 Con_Printf("there is already a keygen run on the way\n");
1225                 SV_UnlockThreadMutex();
1226                 return;
1227         }
1228         keygen_i = i;
1229         if(!qd0_blind_id_generate_private_id_start(pubkeys[keygen_i]))
1230         {
1231                 Con_Printf("d0_blind_id_start failed\n");
1232                 keygen_i = -1;
1233                 SV_UnlockThreadMutex();
1234                 return;
1235         }
1236         p[0] = buf;
1237         l[0] = sizeof(buf);
1238         if(!qd0_blind_id_generate_private_id_request(pubkeys[keygen_i], buf, &l[0]))
1239         {
1240                 Con_Printf("d0_blind_id_generate_private_id_request failed\n");
1241                 keygen_i = -1;
1242                 SV_UnlockThreadMutex();
1243                 return;
1244         }
1245         buf2pos = strlen(Cmd_Argv(2));
1246         memcpy(buf2, Cmd_Argv(2), buf2pos);
1247         if(!(buf2l = Crypto_UnParsePack(buf2 + buf2pos, sizeof(buf2) - buf2pos - 1, FOURCC_D0IQ, p, l, 1)))
1248         {
1249                 Con_Printf("Crypto_UnParsePack failed\n");
1250                 keygen_i = -1;
1251                 SV_UnlockThreadMutex();
1252                 return;
1253         }
1254         if(!(buf2l = base64_encode((unsigned char *) (buf2 + buf2pos), buf2l, sizeof(buf2) - buf2pos - 1)))
1255         {
1256                 Con_Printf("base64_encode failed\n");
1257                 keygen_i = -1;
1258                 SV_UnlockThreadMutex();
1259                 return;
1260         }
1261         buf2l += buf2pos;
1262         buf[buf2l] = 0;
1263         if(!Curl_Begin_ToMemory(buf2, 0, (unsigned char *) keygen_buf, sizeof(keygen_buf), Crypto_KeyGen_Finished, NULL))
1264         {
1265                 Con_Printf("curl failed\n");
1266                 keygen_i = -1;
1267                 SV_UnlockThreadMutex();
1268                 return;
1269         }
1270         Con_Printf("key generation in progress\n");
1271         SV_UnlockThreadMutex();
1272 }
1273 // end
1274
1275 // console commands
1276 static void Crypto_Reload_f(void)
1277 {
1278         Crypto_ClearHostKeys();
1279         Crypto_UnloadKeys();
1280         Crypto_LoadKeys();
1281 }
1282
1283 static void Crypto_Keys_f(void)
1284 {
1285         int i;
1286         if(!d0_blind_id_dll)
1287         {
1288                 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1289                 return;
1290         }
1291         for(i = 0; i < MAX_PUBKEYS; ++i)
1292         {
1293                 if(pubkeys[i])
1294                 {
1295                         Con_Printf("%2d: public key key_%d.d0pk (fingerprint: %s)\n", i, i, pubkeys_fp64[i]);
1296                         if(pubkeys_havepriv[i])
1297                                 Con_Printf("    private ID key_%d.d0si%s (public key fingerprint: %s)\n", i, sessionid.string, pubkeys_priv_fp64[i]);
1298                 }
1299         }
1300 }
1301
1302 static void Crypto_HostKeys_f(void)
1303 {
1304         int i;
1305         crypto_storedhostkey_t *hk;
1306         char buf[128];
1307
1308         if(!d0_blind_id_dll)
1309         {
1310                 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1311                 return;
1312         }
1313         for(i = 0; i < CRYPTO_HOSTKEY_HASHSIZE; ++i)
1314         {
1315                 for(hk = crypto_storedhostkey_hashtable[i]; hk; hk = hk->next)
1316                 {
1317                         LHNETADDRESS_ToString(&hk->addr, buf, sizeof(buf), 1);
1318                         Con_Printf("%d %s@%.*s %s\n",
1319                                         hk->aeslevel,
1320                                         hk->idfp,
1321                                         crypto_keyfp_recommended_length, pubkeys_fp64[hk->keyid],
1322                                         buf);
1323                 }
1324         }
1325 }
1326
1327 static void Crypto_HostKey_Clear_f(void)
1328 {
1329         lhnetaddress_t addr;
1330         int i;
1331
1332         if(!d0_blind_id_dll)
1333         {
1334                 Con_Print("libd0_blind_id DLL not found, this command is inactive.\n");
1335                 return;
1336         }
1337
1338         for(i = 1; i < Cmd_Argc(); ++i)
1339         {
1340                 LHNETADDRESS_FromString(&addr, Cmd_Argv(i), 26000);
1341                 if(Crypto_ClearHostKey(&addr))
1342                 {
1343                         Con_Printf("cleared host key for %s\n", Cmd_Argv(i));
1344                 }
1345         }
1346 }
1347
1348 void Crypto_Init_Commands(void)
1349 {
1350         if(d0_blind_id_dll)
1351         {
1352                 Cmd_AddCommand("crypto_reload", Crypto_Reload_f, "reloads cryptographic keys");
1353                 Cmd_AddCommand("crypto_keygen", Crypto_KeyGen_f, "generates and saves a cryptographic key");
1354                 Cmd_AddCommand("crypto_keys", Crypto_Keys_f, "lists the loaded keys");
1355                 Cmd_AddCommand("crypto_hostkeys", Crypto_HostKeys_f, "lists the cached host keys");
1356                 Cmd_AddCommand("crypto_hostkey_clear", Crypto_HostKey_Clear_f, "clears a cached host key");
1357                 Cvar_RegisterVariable(&crypto_developer);
1358                 if(d0_rijndael_dll)
1359                         Cvar_RegisterVariable(&crypto_aeslevel);
1360                 else
1361                         crypto_aeslevel.integer = 0; // make sure
1362                 Cvar_RegisterVariable(&crypto_servercpupercent);
1363                 Cvar_RegisterVariable(&crypto_servercpumaxtime);
1364                 Cvar_RegisterVariable(&crypto_servercpudebug);
1365         }
1366 }
1367 // end
1368
1369 // AES encryption
1370 static void aescpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1371 {
1372         const unsigned char *xorpos = iv;
1373         unsigned char xorbuf[16];
1374         unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1375         size_t i;
1376         qd0_rijndael_setup_encrypt(rk, key, DHKEY_SIZE * 8);
1377         while(len > 16)
1378         {
1379                 for(i = 0; i < 16; ++i)
1380                         xorbuf[i] = src[i] ^ xorpos[i];
1381                 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1382                 xorpos = dst;
1383                 len -= 16;
1384                 src += 16;
1385                 dst += 16;
1386         }
1387         if(len > 0)
1388         {
1389                 for(i = 0; i < len; ++i)
1390                         xorbuf[i] = src[i] ^ xorpos[i];
1391                 for(; i < 16; ++i)
1392                         xorbuf[i] = xorpos[i];
1393                 qd0_rijndael_encrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), xorbuf, dst);
1394         }
1395 }
1396 static void seacpy(unsigned char *key, const unsigned char *iv, unsigned char *dst, const unsigned char *src, size_t len)
1397 {
1398         const unsigned char *xorpos = iv;
1399         unsigned char xorbuf[16];
1400         unsigned long rk[D0_RIJNDAEL_RKLENGTH(DHKEY_SIZE * 8)];
1401         size_t i;
1402         qd0_rijndael_setup_decrypt(rk, key, DHKEY_SIZE * 8);
1403         while(len > 16)
1404         {
1405                 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1406                 for(i = 0; i < 16; ++i)
1407                         dst[i] = xorbuf[i] ^ xorpos[i];
1408                 xorpos = src;
1409                 len -= 16;
1410                 src += 16;
1411                 dst += 16;
1412         }
1413         if(len > 0)
1414         {
1415                 qd0_rijndael_decrypt(rk, D0_RIJNDAEL_NROUNDS(DHKEY_SIZE * 8), src, xorbuf);
1416                 for(i = 0; i < len; ++i)
1417                         dst[i] = xorbuf[i] ^ xorpos[i];
1418         }
1419 }
1420
1421 // NOTE: we MUST avoid the following begins of the packet:
1422 //   1. 0xFF, 0xFF, 0xFF, 0xFF
1423 //   2. 0x80, 0x00, length/256, length%256
1424 // this luckily does NOT affect AES mode, where the first byte always is in the range from 0x00 to 0x0F
1425 const void *Crypto_EncryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len)
1426 {
1427         unsigned char h[32];
1428         int i;
1429         if(crypto->authenticated)
1430         {
1431                 if(crypto->use_aes)
1432                 {
1433                         // AES packet = 1 byte length overhead, 15 bytes from HMAC-SHA-256, data, 0..15 bytes padding
1434                         // 15 bytes HMAC-SHA-256 (112bit) suffice as the attacker can't do more than forge a random-looking packet
1435                         // HMAC is needed to not leak information about packet content
1436                         if(developer_networking.integer)
1437                         {
1438                                 Con_Print("To be encrypted:\n");
1439                                 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1440                         }
1441                         if(len_src + 32 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, len_src, crypto->dhkey, DHKEY_SIZE))
1442                         {
1443                                 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1444                                 return NULL;
1445                         }
1446                         *len_dst = ((len_src + 15) / 16) * 16 + 16; // add 16 for HMAC, then round to 16-size for AES
1447                         ((unsigned char *) data_dst)[0] = *len_dst - len_src;
1448                         memcpy(((unsigned char *) data_dst)+1, h, 15);
1449                         aescpy(crypto->dhkey, (const unsigned char *) data_dst, ((unsigned char *) data_dst) + 16, (const unsigned char *) data_src, len_src);
1450                         //                    IV                                dst                                src                               len
1451                 }
1452                 else
1453                 {
1454                         // HMAC packet = 16 bytes HMAC-SHA-256 (truncated to 128 bits), data
1455                         if(len_src + 16 > len || !HMAC_SHA256_32BYTES(h, (const unsigned char *) data_src, len_src, crypto->dhkey, DHKEY_SIZE))
1456                         {
1457                                 Con_Printf("Crypto_EncryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1458                                 return NULL;
1459                         }
1460                         *len_dst = len_src + 16;
1461                         memcpy(data_dst, h, 16);
1462                         memcpy(((unsigned char *) data_dst) + 16, (unsigned char *) data_src, len_src);
1463
1464                         // handle the "avoid" conditions:
1465                         i = BuffBigLong((unsigned char *) data_dst);
1466                         if(
1467                                 (i == (int)0xFFFFFFFF) // avoid QW control packet
1468                                 ||
1469                                 (i == (int)0x80000000 + (int)*len_dst) // avoid NQ control packet
1470                         )
1471                                 *(unsigned char *)data_dst ^= 0x80; // this will ALWAYS fix it
1472                 }
1473                 return data_dst;
1474         }
1475         else
1476         {
1477                 *len_dst = len_src;
1478                 return data_src;
1479         }
1480 }
1481
1482 const void *Crypto_DecryptPacket(crypto_t *crypto, const void *data_src, size_t len_src, void *data_dst, size_t *len_dst, size_t len)
1483 {
1484         unsigned char h[32];
1485         int i;
1486
1487         // silently handle non-crypto packets
1488         i = BuffBigLong((unsigned char *) data_src);
1489         if(
1490                 (i == (int)0xFFFFFFFF) // avoid QW control packet
1491                 ||
1492                 (i == (int)0x80000000 + (int)len_src) // avoid NQ control packet
1493         )
1494                 return NULL;
1495
1496         if(crypto->authenticated)
1497         {
1498                 if(crypto->use_aes)
1499                 {
1500                         if(len_src < 16 || ((len_src - 16) % 16))
1501                         {
1502                                 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1503                                 return NULL;
1504                         }
1505                         *len_dst = len_src - ((unsigned char *) data_src)[0];
1506                         if(len < *len_dst || *len_dst > len_src - 16)
1507                         {
1508                                 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1509                                 return NULL;
1510                         }
1511                         seacpy(crypto->dhkey, (unsigned char *) data_src, (unsigned char *) data_dst, ((const unsigned char *) data_src) + 16, *len_dst);
1512                         //                    IV                          dst                         src                                      len
1513                         if(!HMAC_SHA256_32BYTES(h, (const unsigned char *) data_dst, *len_dst, crypto->dhkey, DHKEY_SIZE))
1514                         {
1515                                 Con_Printf("HMAC fail\n");
1516                                 return NULL;
1517                         }
1518                         if(memcmp(((const unsigned char *) data_src)+1, h, 15)) // ignore first byte, used for length
1519                         {
1520                                 Con_Printf("HMAC mismatch\n");
1521                                 return NULL;
1522                         }
1523                         if(developer_networking.integer)
1524                         {
1525                                 Con_Print("Decrypted:\n");
1526                                 Com_HexDumpToConsole((const unsigned char *) data_dst, *len_dst);
1527                         }
1528                         return data_dst; // no need to copy
1529                 }
1530                 else
1531                 {
1532                         if(len_src < 16)
1533                         {
1534                                 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d bytes out)\n", (int) len_src, (int) len);
1535                                 return NULL;
1536                         }
1537                         *len_dst = len_src - 16;
1538                         if(len < *len_dst)
1539                         {
1540                                 Con_Printf("Crypto_DecryptPacket failed (not enough space: %d bytes in, %d->%d bytes out)\n", (int) len_src, (int) *len_dst, (int) len);
1541                                 return NULL;
1542                         }
1543                         //memcpy(data_dst, data_src + 16, *len_dst);
1544                         if(!HMAC_SHA256_32BYTES(h, ((const unsigned char *) data_src) + 16, *len_dst, crypto->dhkey, DHKEY_SIZE))
1545                         {
1546                                 Con_Printf("HMAC fail\n");
1547                                 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1548                                 return NULL;
1549                         }
1550
1551                         if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1552                         {
1553                                 // undo the "avoid conditions"
1554                                 if(
1555                                                 (i == (int)0x7FFFFFFF) // avoided QW control packet
1556                                                 ||
1557                                                 (i == (int)0x00000000 + (int)len_src) // avoided NQ control packet
1558                                   )
1559                                 {
1560                                         // do the avoidance on the hash too
1561                                         h[0] ^= 0x80;
1562                                         if(memcmp((const unsigned char *) data_src, h, 16)) // ignore first byte, used for length
1563                                         {
1564                                                 Con_Printf("HMAC mismatch\n");
1565                                                 Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1566                                                 return NULL;
1567                                         }
1568                                 }
1569                                 else
1570                                 {
1571                                         Con_Printf("HMAC mismatch\n");
1572                                         Com_HexDumpToConsole((const unsigned char *) data_src, len_src);
1573                                         return NULL;
1574                                 }
1575                         }
1576                         return ((const unsigned char *) data_src) + 16; // no need to copy, so data_dst is not used
1577                 }
1578         }
1579         else
1580         {
1581                 *len_dst = len_src;
1582                 return data_src;
1583         }
1584 }
1585 // end
1586
1587 const char *Crypto_GetInfoResponseDataString(void)
1588 {
1589         crypto_idstring_buf[0] = '0' + crypto_aeslevel.integer;
1590         return crypto_idstring;
1591 }
1592
1593 // network protocol
1594 qboolean Crypto_ServerAppendToChallenge(const char *data_in, size_t len_in, char *data_out, size_t *len_out, size_t maxlen_out)
1595 {
1596         // cheap op, all is precomputed
1597         if(!d0_blind_id_dll)
1598                 return false; // no support
1599         // append challenge
1600         if(maxlen_out <= *len_out + challenge_append_length)
1601                 return false;
1602         memcpy(data_out + *len_out, challenge_append, challenge_append_length);
1603         *len_out += challenge_append_length;
1604         return false;
1605 }
1606
1607 static int Crypto_ServerError(char *data_out, size_t *len_out, const char *msg, const char *msg_client)
1608 {
1609         if(!msg_client)
1610                 msg_client = msg;
1611         Con_DPrintf("rejecting client: %s\n", msg);
1612         if(*msg_client)
1613                 dpsnprintf(data_out, *len_out, "reject %s", msg_client);
1614         *len_out = strlen(data_out);
1615         return CRYPTO_DISCARD;
1616 }
1617
1618 static int Crypto_SoftServerError(char *data_out, size_t *len_out, const char *msg)
1619 {
1620         *len_out = 0;
1621         Con_DPrintf("%s\n", msg);
1622         return CRYPTO_DISCARD;
1623 }
1624
1625 static int Crypto_ServerParsePacket_Internal(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1626 {
1627         // if "connect": reject if in the middle of crypto handshake
1628         crypto_t *crypto = NULL;
1629         char *data_out_p = data_out;
1630         const char *string = data_in;
1631         int aeslevel;
1632         D0_BOOL aes;
1633         D0_BOOL status;
1634         char infostringvalue[MAX_INPUTLINE];
1635         char vabuf[1024];
1636
1637         if(!d0_blind_id_dll)
1638                 return CRYPTO_NOMATCH; // no support
1639
1640         if (len_in > 8 && !memcmp(string, "connect\\", 8) && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
1641         {
1642                 const char *s;
1643                 int i;
1644                 // sorry, we have to verify the challenge here to not reflect network spam
1645
1646                 if (!(s = InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue))))
1647                         return CRYPTO_NOMATCH; // will be later accepted if encryption was set up
1648                 // validate the challenge
1649                 for (i = 0;i < MAX_CHALLENGES;i++)
1650                         if(challenge[i].time > 0)
1651                                 if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s))
1652                                         break;
1653                 // if the challenge is not recognized, drop the packet
1654                 if (i == MAX_CHALLENGES) // challenge mismatch is silent
1655                         return CRYPTO_DISCARD; // pre-challenge: rather be silent
1656
1657                 crypto = Crypto_ServerFindInstance(peeraddress, false);
1658                 if(!crypto || !crypto->authenticated)
1659                         return Crypto_ServerError(data_out, len_out, "This server requires authentication and encryption to be supported by your client", NULL);
1660         }
1661         else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && ((LHNETADDRESS_GetAddressType(peeraddress) == LHNETADDRESSTYPE_LOOP) || sv_public.integer > -3))
1662         {
1663                 const char *cnt, *s, *p;
1664                 int id;
1665                 int clientid = -1, serverid = -1;
1666                 cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue));
1667                 id = (cnt ? atoi(cnt) : -1);
1668                 cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue));
1669                 if(!cnt)
1670                         return CRYPTO_DISCARD; // pre-challenge: rather be silent
1671                 GetUntilNul(&data_in, &len_in);
1672                 if(!data_in)
1673                         return CRYPTO_DISCARD; // pre-challenge: rather be silent
1674                 if(!strcmp(cnt, "0"))
1675                 {
1676                         int i;
1677                         if (!(s = InfoString_GetValue(string + 4, "challenge", infostringvalue, sizeof(infostringvalue))))
1678                                 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1679                         // validate the challenge
1680                         for (i = 0;i < MAX_CHALLENGES;i++)
1681                                 if(challenge[i].time > 0)
1682                                         if (!LHNETADDRESS_Compare(peeraddress, &challenge[i].address) && !strcmp(challenge[i].string, s))
1683                                                 break;
1684                         // if the challenge is not recognized, drop the packet
1685                         if (i == MAX_CHALLENGES) // challenge mismatch is silent
1686                                 return CRYPTO_DISCARD; // pre-challenge: rather be silent
1687
1688                         if (!(s = InfoString_GetValue(string + 4, "aeslevel", infostringvalue, sizeof(infostringvalue))))
1689                                 aeslevel = 0; // not supported
1690                         else
1691                                 aeslevel = bound(0, atoi(s), 3);
1692                         switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
1693                         {
1694                                 default: // dummy, never happens, but to make gcc happy...
1695                                 case 0:
1696                                         if(aeslevel >= 3)
1697                                                 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL);
1698                                         aes = false;
1699                                         break;
1700                                 case 1:
1701                                         aes = (aeslevel >= 2);
1702                                         break;
1703                                 case 2:
1704                                         aes = (aeslevel >= 1);
1705                                         break;
1706                                 case 3:
1707                                         if(aeslevel <= 0)
1708                                                 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be supported (crypto_aeslevel >= 1, and d0_rijndael library must be present)", NULL);
1709                                         aes = true;
1710                                         break;
1711                         }
1712
1713                         p = GetUntilNul(&data_in, &len_in);
1714                         if(p && *p)
1715                         {
1716                                 for(i = 0; i < MAX_PUBKEYS; ++i)
1717                                 {
1718                                         if(pubkeys[i])
1719                                                 if(!strcmp(p, pubkeys_fp64[i]))
1720                                                         if(pubkeys_havepriv[i])
1721                                                                 if(serverid < 0)
1722                                                                         serverid = i;
1723                                 }
1724                                 if(serverid < 0)
1725                                         return Crypto_ServerError(data_out, len_out, "Invalid server key", NULL);
1726                         }
1727                         p = GetUntilNul(&data_in, &len_in);
1728                         if(p && *p)
1729                         {
1730                                 for(i = 0; i < MAX_PUBKEYS; ++i)
1731                                 {
1732                                         if(pubkeys[i])
1733                                                 if(!strcmp(p, pubkeys_fp64[i]))
1734                                                         if(clientid < 0)
1735                                                                 clientid = i;
1736                                 }
1737                                 if(clientid < 0)
1738                                         return Crypto_ServerError(data_out, len_out, "Invalid client key", NULL);
1739                         }
1740
1741                         crypto = Crypto_ServerFindInstance(peeraddress, true);
1742                         if(!crypto)
1743                                 return Crypto_ServerError(data_out, len_out, "Could not create a crypto connect instance", NULL);
1744                         MAKE_CDATA;
1745                         CDATA->cdata_id = id;
1746                         CDATA->s = serverid;
1747                         CDATA->c = clientid;
1748                         memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
1749                         CDATA->challenge[0] = 0;
1750                         crypto->client_keyfp[0] = 0;
1751                         crypto->client_idfp[0] = 0;
1752                         crypto->server_keyfp[0] = 0;
1753                         crypto->server_idfp[0] = 0;
1754                         crypto->use_aes = aes != 0;
1755
1756                         if(CDATA->s >= 0)
1757                         {
1758                                 // I am the server, and my key is ok... so let's set server_keyfp and server_idfp
1759                                 strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
1760                                 strlcpy(crypto->server_idfp, pubkeys_priv_fp64[CDATA->s], sizeof(crypto->server_idfp));
1761
1762                                 if(!CDATA->id)
1763                                         CDATA->id = qd0_blind_id_new();
1764                                 if(!CDATA->id)
1765                                 {
1766                                         CLEAR_CDATA;
1767                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1768                                 }
1769                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
1770                                 {
1771                                         CLEAR_CDATA;
1772                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1773                                 }
1774                                 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\1\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1775                                 if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op
1776                                 {
1777                                         CLEAR_CDATA;
1778                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed", "Internal error");
1779                                 }
1780                                 CDATA->next_step = 2;
1781                                 data_out_p += *len_out;
1782                                 *len_out = data_out_p - data_out;
1783                                 return CRYPTO_DISCARD;
1784                         }
1785                         else if(CDATA->c >= 0)
1786                         {
1787                                 if(!CDATA->id)
1788                                         CDATA->id = qd0_blind_id_new();
1789                                 if(!CDATA->id)
1790                                 {
1791                                         CLEAR_CDATA;
1792                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_new failed", "Internal error");
1793                                 }
1794                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1795                                 {
1796                                         CLEAR_CDATA;
1797                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1798                                 }
1799                                 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d\\aes\\%d", CDATA->cdata_id, crypto->use_aes));
1800                                 if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1801                                 {
1802                                         CLEAR_CDATA;
1803                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1804                                 }
1805                                 CDATA->next_step = 6;
1806                                 data_out_p += *len_out;
1807                                 *len_out = data_out_p - data_out;
1808                                 return CRYPTO_DISCARD;
1809                         }
1810                         else
1811                         {
1812                                 CLEAR_CDATA;
1813                                 return Crypto_ServerError(data_out, len_out, "Missing client and server key", NULL);
1814                         }
1815                 }
1816                 else if(!strcmp(cnt, "2"))
1817                 {
1818                         size_t fpbuflen;
1819                         crypto = Crypto_ServerFindInstance(peeraddress, false);
1820                         if(!crypto)
1821                                 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1822                         if(id >= 0)
1823                                 if(CDATA->cdata_id != id)
1824                                         return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1825                         if(CDATA->next_step != 2)
1826                                 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1827
1828                         PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\3\\id\\%d", CDATA->cdata_id));
1829                         if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
1830                         {
1831                                 CLEAR_CDATA;
1832                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed", "Internal error");
1833                         }
1834                         fpbuflen = DHKEY_SIZE;
1835                         if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
1836                         {
1837                                 CLEAR_CDATA;
1838                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1839                         }
1840                         if(CDATA->c >= 0)
1841                         {
1842                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
1843                                 {
1844                                         CLEAR_CDATA;
1845                                         return Crypto_ServerError(data_out, len_out, "d0_blind_id_copy failed", "Internal error");
1846                                 }
1847                                 CDATA->next_step = 4;
1848                         }
1849                         else
1850                         {
1851                                 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
1852                                 crypto->authenticated = true;
1853                                 CDATA->next_step = 0;
1854                         }
1855                         data_out_p += *len_out;
1856                         *len_out = data_out_p - data_out;
1857                         return CRYPTO_DISCARD;
1858                 }
1859                 else if(!strcmp(cnt, "4"))
1860                 {
1861                         crypto = Crypto_ServerFindInstance(peeraddress, false);
1862                         if(!crypto)
1863                                 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1864                         if(id >= 0)
1865                                 if(CDATA->cdata_id != id)
1866                                         return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1867                         if(CDATA->next_step != 4)
1868                                 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1869                         PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\5\\id\\%d", CDATA->cdata_id));
1870                         if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
1871                         {
1872                                 CLEAR_CDATA;
1873                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed", "Internal error");
1874                         }
1875                         CDATA->next_step = 6;
1876                         data_out_p += *len_out;
1877                         *len_out = data_out_p - data_out;
1878                         return CRYPTO_DISCARD;
1879                 }
1880                 else if(!strcmp(cnt, "6"))
1881                 {
1882                         static char msgbuf[32];
1883                         size_t msgbuflen = sizeof(msgbuf);
1884                         size_t fpbuflen;
1885                         int i;
1886                         unsigned char dhkey[DHKEY_SIZE];
1887                         crypto = Crypto_ServerFindInstance(peeraddress, false);
1888                         if(!crypto)
1889                                 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1890                         if(id >= 0)
1891                                 if(CDATA->cdata_id != id)
1892                                         return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
1893                         if(CDATA->next_step != 6)
1894                                 return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
1895
1896                         if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
1897                         {
1898                                 CLEAR_CDATA;
1899                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (authentication error)", "Authentication error");
1900                         }
1901                         if(status)
1902                                 strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
1903                         else
1904                                 crypto->client_keyfp[0] = 0;
1905                         memset(crypto->client_idfp, 0, sizeof(crypto->client_idfp));
1906                         fpbuflen = FP64_SIZE;
1907                         if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->client_idfp, &fpbuflen))
1908                         {
1909                                 CLEAR_CDATA;
1910                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed", "Internal error");
1911                         }
1912                         fpbuflen = DHKEY_SIZE;
1913                         if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
1914                         {
1915                                 CLEAR_CDATA;
1916                                 return Crypto_ServerError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed", "Internal error");
1917                         }
1918                         // XOR the two DH keys together to make one
1919                         for(i = 0; i < DHKEY_SIZE; ++i)
1920                                 crypto->dhkey[i] ^= dhkey[i];
1921
1922                         // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
1923                         crypto->authenticated = true;
1924                         CDATA->next_step = 0;
1925                         // send a challenge-less challenge
1926                         PutWithNul(&data_out_p, len_out, "challenge ");
1927                         *len_out = data_out_p - data_out;
1928                         --*len_out; // remove NUL terminator
1929                         return CRYPTO_MATCH;
1930                 }
1931                 return CRYPTO_NOMATCH; // pre-challenge, rather be silent
1932         }
1933         return CRYPTO_NOMATCH;
1934 }
1935
1936 int Crypto_ServerParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
1937 {
1938         int ret;
1939         double t = 0;
1940         static double complain_time = 0;
1941         const char *cnt;
1942         qboolean do_time = false;
1943         qboolean do_reject = false;
1944         char infostringvalue[MAX_INPUTLINE];
1945         if(crypto_servercpupercent.value > 0 || crypto_servercpumaxtime.value > 0)
1946                 if(len_in > 5 && !memcmp(data_in, "d0pk\\", 5))
1947                 {
1948                         do_time = true;
1949                         cnt = InfoString_GetValue(data_in + 4, "cnt", infostringvalue, sizeof(infostringvalue));
1950                         if(cnt)
1951                                 if(!strcmp(cnt, "0"))
1952                                         do_reject = true;
1953                 }
1954         if(do_time)
1955         {
1956                 // check if we may perform crypto...
1957                 if(crypto_servercpupercent.value > 0)
1958                 {
1959                         crypto_servercpu_accumulator += (realtime - crypto_servercpu_lastrealtime) * crypto_servercpupercent.value * 0.01;
1960                         if(crypto_servercpumaxtime.value)
1961                                 if(crypto_servercpu_accumulator > crypto_servercpumaxtime.value)
1962                                         crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
1963                 }
1964                 else
1965                 {
1966                         if(crypto_servercpumaxtime.value > 0)
1967                                 if(realtime != crypto_servercpu_lastrealtime)
1968                                         crypto_servercpu_accumulator = crypto_servercpumaxtime.value;
1969                 }
1970                 crypto_servercpu_lastrealtime = realtime;
1971                 if(do_reject && crypto_servercpu_accumulator < 0)
1972                 {
1973                         if(realtime > complain_time + 5)
1974                                 Con_Printf("crypto: cannot perform requested crypto operations; denial service attack or crypto_servercpupercent/crypto_servercpumaxtime are too low\n");
1975                         *len_out = 0;
1976                         return CRYPTO_DISCARD;
1977                 }
1978                 t = Sys_DirtyTime();
1979         }
1980         ret = Crypto_ServerParsePacket_Internal(data_in, len_in, data_out, len_out, peeraddress);
1981         if(do_time)
1982         {
1983                 t = Sys_DirtyTime() - t;if (t < 0.0) t = 0.0; // dirtytime can step backwards
1984                 if(crypto_servercpudebug.integer)
1985                         Con_Printf("crypto: accumulator was %.1f ms, used %.1f ms for crypto, ", crypto_servercpu_accumulator * 1000, t * 1000);
1986                 crypto_servercpu_accumulator -= t;
1987                 if(crypto_servercpudebug.integer)
1988                         Con_Printf("is %.1f ms\n", crypto_servercpu_accumulator * 1000);
1989         }
1990         return ret;
1991 }
1992
1993 static int Crypto_ClientError(char *data_out, size_t *len_out, const char *msg)
1994 {
1995         dpsnprintf(data_out, *len_out, "reject %s", msg);
1996         *len_out = strlen(data_out);
1997         return CRYPTO_REPLACE;
1998 }
1999
2000 static int Crypto_SoftClientError(char *data_out, size_t *len_out, const char *msg)
2001 {
2002         *len_out = 0;
2003         Con_Printf("%s\n", msg);
2004         return CRYPTO_DISCARD;
2005 }
2006
2007 int Crypto_ClientParsePacket(const char *data_in, size_t len_in, char *data_out, size_t *len_out, lhnetaddress_t *peeraddress)
2008 {
2009         crypto_t *crypto = &cls.crypto;
2010         const char *string = data_in;
2011         const char *s;
2012         D0_BOOL aes;
2013         char *data_out_p = data_out;
2014         D0_BOOL status;
2015         char infostringvalue[MAX_INPUTLINE];
2016         char vabuf[1024];
2017
2018         if(!d0_blind_id_dll)
2019                 return CRYPTO_NOMATCH; // no support
2020
2021         // if "challenge": verify challenge, and discard message, send next crypto protocol message instead
2022         // otherwise, just handle actual protocol messages
2023
2024         if (len_in == 6 && !memcmp(string, "accept", 6) && cls.connect_trying && d0_rijndael_dll)
2025         {
2026                 int wantserverid = -1;
2027                 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
2028                 if(!crypto || !crypto->authenticated)
2029                 {
2030                         if(wantserverid >= 0)
2031                                 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2032                         if(crypto_aeslevel.integer >= 3)
2033                                 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2034                 }
2035                 return CRYPTO_NOMATCH;
2036         }
2037         else if (len_in >= 1 && string[0] == 'j' && cls.connect_trying && d0_rijndael_dll && crypto_aeslevel.integer >= 3)
2038         {
2039                 int wantserverid = -1;
2040                 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, NULL, 0, NULL);
2041                 if(!crypto || !crypto->authenticated)
2042                 {
2043                         if(wantserverid >= 0)
2044                                 return Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present");
2045                         if(crypto_aeslevel.integer >= 3)
2046                                 return Crypto_ClientError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)");
2047                 }
2048                 return CRYPTO_NOMATCH;
2049         }
2050         else if (len_in >= 13 && !memcmp(string, "infoResponse\x0A", 13))
2051         {
2052                 s = InfoString_GetValue(string + 13, "d0_blind_id", infostringvalue, sizeof(infostringvalue));
2053                 if(s)
2054                         Crypto_StoreHostKey(peeraddress, s, true);
2055                 return CRYPTO_NOMATCH;
2056         }
2057         else if (len_in >= 15 && !memcmp(string, "statusResponse\x0A", 15))
2058         {
2059                 char save = 0;
2060                 const char *p;
2061                 p = strchr(string + 15, '\n');
2062                 if(p)
2063                 {
2064                         save = *p;
2065                         * (char *) p = 0; // cut off the string there
2066                 }
2067                 s = InfoString_GetValue(string + 15, "d0_blind_id", infostringvalue, sizeof(infostringvalue));
2068                 if(s)
2069                         Crypto_StoreHostKey(peeraddress, s, true);
2070                 if(p)
2071                 {
2072                         * (char *) p = save;
2073                         // invoking those nasal demons again (do not run this on the DS9k)
2074                 }
2075                 return CRYPTO_NOMATCH;
2076         }
2077         else if(len_in > 10 && !memcmp(string, "challenge ", 10) && cls.connect_trying)
2078         {
2079                 const char *vlen_blind_id_ptr = NULL;
2080                 size_t len_blind_id_ptr = 0;
2081                 unsigned long k, v;
2082                 const char *challenge = data_in + 10;
2083                 const char *p;
2084                 int i;
2085                 int clientid = -1, serverid = -1, wantserverid = -1;
2086                 qboolean server_can_auth = true;
2087                 char wantserver_idfp[FP64_SIZE+1];
2088                 int wantserver_aeslevel;
2089
2090                 // if we have a stored host key for the server, assume serverid to already be selected!
2091                 // (the loop will refuse to overwrite this one then)
2092                 wantserver_idfp[0] = 0;
2093                 Crypto_RetrieveHostKey(&cls.connect_address, &wantserverid, NULL, 0, wantserver_idfp, sizeof(wantserver_idfp), &wantserver_aeslevel);
2094                 // requirement: wantserver_idfp is a full ID if wantserverid set
2095
2096                 // if we leave, we have to consider the connection
2097                 // unauthenticated; NOTE: this may be faked by a clever
2098                 // attacker to force an unauthenticated connection; so we have
2099                 // a safeguard check in place when encryption is required too
2100                 // in place, or when authentication is required by the server
2101                 crypto->authenticated = false;
2102
2103                 GetUntilNul(&data_in, &len_in);
2104                 if(!data_in)
2105                         return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though a host key is present") :
2106                                 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) :
2107                                 CRYPTO_NOMATCH;
2108
2109                 // FTEQW extension protocol
2110                 while(len_in >= 8)
2111                 {
2112                         k = Crypto_LittleLong(data_in);
2113                         v = Crypto_LittleLong(data_in + 4);
2114                         data_in += 8;
2115                         len_in -= 8;
2116                         switch(k)
2117                         {
2118                                 case PROTOCOL_VLEN:
2119                                         if(len_in >= 4 + v)
2120                                         {
2121                                                 k = Crypto_LittleLong(data_in);
2122                                                 data_in += 4;
2123                                                 len_in -= 4;
2124                                                 switch(k)
2125                                                 {
2126                                                         case PROTOCOL_D0_BLIND_ID:
2127                                                                 vlen_blind_id_ptr = data_in;
2128                                                                 len_blind_id_ptr = v;
2129                                                                 break;
2130                                                 }
2131                                                 data_in += v;
2132                                                 len_in -= v;
2133                                         }
2134                                         break;
2135                                 default:
2136                                         break;
2137                         }
2138                 }
2139
2140                 if(!vlen_blind_id_ptr)
2141                         return (wantserverid >= 0) ? Crypto_ClientError(data_out, len_out, "Server tried an unauthenticated connection even though authentication is required") :
2142                                 (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) :
2143                                 CRYPTO_NOMATCH;
2144
2145                 data_in = vlen_blind_id_ptr;
2146                 len_in = len_blind_id_ptr;
2147
2148                 // parse fingerprints
2149                 //   once we found a fingerprint we can auth to (ANY), select it as clientfp
2150                 //   once we found a fingerprint in the first list that we know, select it as serverfp
2151
2152                 for(;;)
2153                 {
2154                         p = GetUntilNul(&data_in, &len_in);
2155                         if(!p)
2156                                 break;
2157                         if(!*p)
2158                         {
2159                                 if(!server_can_auth)
2160                                         break; // other protocol message may follow
2161                                 server_can_auth = false;
2162                                 if(clientid >= 0)
2163                                         break;
2164                                 continue;
2165                         }
2166                         for(i = 0; i < MAX_PUBKEYS; ++i)
2167                         {
2168                                 if(pubkeys[i])
2169                                 if(!strcmp(p, pubkeys_fp64[i]))
2170                                 {
2171                                         if(pubkeys_havepriv[i])
2172                                                 if(clientid < 0)
2173                                                         clientid = i;
2174                                         if(server_can_auth)
2175                                                 if(serverid < 0)
2176                                                         if(wantserverid < 0 || i == wantserverid)
2177                                                                 serverid = i;
2178                                 }
2179                         }
2180                         if(clientid >= 0 && serverid >= 0)
2181                                 break;
2182                 }
2183
2184                 // if stored host key is not found:
2185                 if(wantserverid >= 0 && serverid < 0)
2186                         return Crypto_ClientError(data_out, len_out, "Server CA does not match stored host key, refusing to connect");
2187
2188                 if(serverid >= 0 || clientid >= 0)
2189                 {
2190                         // TODO at this point, fill clientside crypto struct!
2191                         MAKE_CDATA;
2192                         CDATA->cdata_id = ++cdata_id;
2193                         CDATA->s = serverid;
2194                         CDATA->c = clientid;
2195                         memset(crypto->dhkey, 0, sizeof(crypto->dhkey));
2196                         strlcpy(CDATA->challenge, challenge, sizeof(CDATA->challenge));
2197                         crypto->client_keyfp[0] = 0;
2198                         crypto->client_idfp[0] = 0;
2199                         crypto->server_keyfp[0] = 0;
2200                         crypto->server_idfp[0] = 0;
2201                         memcpy(CDATA->wantserver_idfp, wantserver_idfp, sizeof(crypto->server_idfp));
2202
2203                         if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2204                         switch(bound(0, d0_rijndael_dll ? crypto_aeslevel.integer : 0, 3))
2205                         {
2206                                 default: // dummy, never happens, but to make gcc happy...
2207                                 case 0:
2208                                         if(wantserver_aeslevel >= 3)
2209                                                 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL);
2210                                         CDATA->wantserver_aes = false;
2211                                         break;
2212                                 case 1:
2213                                         CDATA->wantserver_aes = (wantserver_aeslevel >= 2);
2214                                         break;
2215                                 case 2:
2216                                         CDATA->wantserver_aes = (wantserver_aeslevel >= 1);
2217                                         break;
2218                                 case 3:
2219                                         if(wantserver_aeslevel <= 0)
2220                                                 return Crypto_ServerError(data_out, len_out, "This server requires encryption to be supported (crypto_aeslevel >= 1, and d0_rijndael library must be present)", NULL);
2221                                         CDATA->wantserver_aes = true;
2222                                         break;
2223                         }
2224
2225                         // build outgoing message
2226                         // append regular stuff
2227                         PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\0\\id\\%d\\aeslevel\\%d\\challenge\\%s", CDATA->cdata_id, d0_rijndael_dll ? crypto_aeslevel.integer : 0, challenge));
2228                         PutWithNul(&data_out_p, len_out, serverid >= 0 ? pubkeys_fp64[serverid] : "");
2229                         PutWithNul(&data_out_p, len_out, clientid >= 0 ? pubkeys_fp64[clientid] : "");
2230
2231                         if(clientid >= 0)
2232                         {
2233                                 // I am the client, and my key is ok... so let's set client_keyfp and client_idfp
2234                                 strlcpy(crypto->client_keyfp, pubkeys_fp64[CDATA->c], sizeof(crypto->client_keyfp));
2235                                 strlcpy(crypto->client_idfp, pubkeys_priv_fp64[CDATA->c], sizeof(crypto->client_idfp));
2236                         }
2237
2238                         if(serverid >= 0)
2239                         {
2240                                 if(!CDATA->id)
2241                                         CDATA->id = qd0_blind_id_new();
2242                                 if(!CDATA->id)
2243                                 {
2244                                         CLEAR_CDATA;
2245                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2246                                 }
2247                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->s]))
2248                                 {
2249                                         CLEAR_CDATA;
2250                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2251                                 }
2252                                 CDATA->next_step = 1;
2253                                 *len_out = data_out_p - data_out;
2254                         }
2255                         else if(clientid >= 0)
2256                         {
2257                                 // skip over server auth, perform client auth only
2258                                 if(!CDATA->id)
2259                                         CDATA->id = qd0_blind_id_new();
2260                                 if(!CDATA->id)
2261                                 {
2262                                         CLEAR_CDATA;
2263                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_new failed");
2264                                 }
2265                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2266                                 {
2267                                         CLEAR_CDATA;
2268                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2269                                 }
2270                                 if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op
2271                                 {
2272                                         CLEAR_CDATA;
2273                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2274                                 }
2275                                 CDATA->next_step = 5;
2276                                 data_out_p += *len_out;
2277                                 *len_out = data_out_p - data_out;
2278                         }
2279                         else
2280                                 *len_out = data_out_p - data_out;
2281
2282                         return CRYPTO_DISCARD;
2283                 }
2284                 else
2285                 {
2286                         if(wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2287                         if(wantserver_aeslevel >= 3)
2288                                 return Crypto_ClientError(data_out, len_out, "Server insists on encryption, but neither can authenticate to the other");
2289                         return (d0_rijndael_dll && crypto_aeslevel.integer >= 3) ? Crypto_ServerError(data_out, len_out, "This server requires encryption to be not required (crypto_aeslevel <= 2)", NULL) :
2290                                 CRYPTO_NOMATCH;
2291                 }
2292         }
2293         else if(len_in > 5 && !memcmp(string, "d0pk\\", 5) && cls.connect_trying)
2294         {
2295                 const char *cnt;
2296                 int id;
2297                 cnt = InfoString_GetValue(string + 4, "id", infostringvalue, sizeof(infostringvalue));
2298                 id = (cnt ? atoi(cnt) : -1);
2299                 cnt = InfoString_GetValue(string + 4, "cnt", infostringvalue, sizeof(infostringvalue));
2300                 if(!cnt)
2301                         return Crypto_ClientError(data_out, len_out, "d0pk\\ message without cnt");
2302                 GetUntilNul(&data_in, &len_in);
2303                 if(!data_in)
2304                         return Crypto_ClientError(data_out, len_out, "d0pk\\ message without attachment");
2305
2306                 if(!strcmp(cnt, "1"))
2307                 {
2308                         if(id >= 0)
2309                                 if(CDATA->cdata_id != id)
2310                                         return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2311                         if(CDATA->next_step != 1)
2312                                 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2313
2314                         cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2315
2316                         if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue))))
2317                                 aes = atoi(s);
2318                         else
2319                                 aes = false;
2320                         // we CANNOT toggle the AES status any more!
2321                         // as the server already decided
2322                         if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2323                         if(!aes && CDATA->wantserver_aes)
2324                         {
2325                                 CLEAR_CDATA;
2326                                 return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2327                         }
2328                         if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2329                         {
2330                                 CLEAR_CDATA;
2331                                 return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2332                         }
2333                         if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2334                         {
2335                                 CLEAR_CDATA;
2336                                 return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2337                         }
2338                         crypto->use_aes = aes != 0;
2339
2340                         PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\2\\id\\%d", CDATA->cdata_id));
2341                         if(!qd0_blind_id_authenticate_with_private_id_challenge(CDATA->id, true, false, data_in, len_in, data_out_p, len_out, &status))
2342                         {
2343                                 CLEAR_CDATA;
2344                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_challenge failed");
2345                         }
2346                         CDATA->next_step = 3;
2347                         data_out_p += *len_out;
2348                         *len_out = data_out_p - data_out;
2349                         return CRYPTO_DISCARD;
2350                 }
2351                 else if(!strcmp(cnt, "3"))
2352                 {
2353                         static char msgbuf[32];
2354                         size_t msgbuflen = sizeof(msgbuf);
2355                         size_t fpbuflen;
2356
2357                         if(id >= 0)
2358                                 if(CDATA->cdata_id != id)
2359                                         return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2360                         if(CDATA->next_step != 3)
2361                                 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2362
2363                         cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2364
2365                         if(!qd0_blind_id_authenticate_with_private_id_verify(CDATA->id, data_in, len_in, msgbuf, &msgbuflen, &status))
2366                         {
2367                                 CLEAR_CDATA;
2368                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_verify failed (server authentication error)");
2369                         }
2370                         if(status)
2371                                 strlcpy(crypto->server_keyfp, pubkeys_fp64[CDATA->s], sizeof(crypto->server_keyfp));
2372                         else
2373                                 crypto->server_keyfp[0] = 0;
2374                         memset(crypto->server_idfp, 0, sizeof(crypto->server_idfp));
2375                         fpbuflen = FP64_SIZE;
2376                         if(!qd0_blind_id_fingerprint64_public_id(CDATA->id, crypto->server_idfp, &fpbuflen))
2377                         {
2378                                 CLEAR_CDATA;
2379                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_fingerprint64_public_id failed");
2380                         }
2381                         if(CDATA->wantserver_idfp[0])
2382                         if(memcmp(CDATA->wantserver_idfp, crypto->server_idfp, sizeof(crypto->server_idfp)))
2383                         {
2384                                 CLEAR_CDATA;
2385                                 return Crypto_ClientError(data_out, len_out, "Server ID does not match stored host key, refusing to connect");
2386                         }
2387                         fpbuflen = DHKEY_SIZE;
2388                         if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) crypto->dhkey, &fpbuflen))
2389                         {
2390                                 CLEAR_CDATA;
2391                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2392                         }
2393
2394                         // cache the server key
2395                         Crypto_StoreHostKey(&cls.connect_address, va(vabuf, sizeof(vabuf), "%d %s@%s", crypto->use_aes ? 1 : 0, crypto->server_idfp, pubkeys_fp64[CDATA->s]), false);
2396
2397                         if(CDATA->c >= 0)
2398                         {
2399                                 // client will auth next
2400                                 PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\4\\id\\%d", CDATA->cdata_id));
2401                                 if(!qd0_blind_id_copy(CDATA->id, pubkeys[CDATA->c]))
2402                                 {
2403                                         CLEAR_CDATA;
2404                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_copy failed");
2405                                 }
2406                                 if(!qd0_blind_id_authenticate_with_private_id_start(CDATA->id, true, false, "XONOTIC", 8, data_out_p, len_out)) // len_out receives used size by this op
2407                                 {
2408                                         CLEAR_CDATA;
2409                                         return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_start failed");
2410                                 }
2411                                 CDATA->next_step = 5;
2412                                 data_out_p += *len_out;
2413                                 *len_out = data_out_p - data_out;
2414                                 return CRYPTO_DISCARD;
2415                         }
2416                         else
2417                         {
2418                                 // session key is FINISHED (no server part is to be expected)! By this, all keys are set up
2419                                 crypto->authenticated = true;
2420                                 CDATA->next_step = 0;
2421                                 // assume we got the empty challenge to finish the protocol
2422                                 PutWithNul(&data_out_p, len_out, "challenge ");
2423                                 *len_out = data_out_p - data_out;
2424                                 --*len_out; // remove NUL terminator
2425                                 return CRYPTO_REPLACE;
2426                         }
2427                 }
2428                 else if(!strcmp(cnt, "5"))
2429                 {
2430                         size_t fpbuflen;
2431                         unsigned char dhkey[DHKEY_SIZE];
2432                         int i;
2433
2434                         if(id >= 0)
2435                                 if(CDATA->cdata_id != id)
2436                                         return Crypto_SoftServerError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\id\\%d when expecting %d", id, CDATA->cdata_id));
2437                         if(CDATA->next_step != 5)
2438                                 return Crypto_SoftClientError(data_out, len_out, va(vabuf, sizeof(vabuf), "Got d0pk\\cnt\\%s when expecting %d", cnt, CDATA->next_step));
2439
2440                         cls.connect_nextsendtime = max(cls.connect_nextsendtime, realtime + 1); // prevent "hammering"
2441
2442                         if(CDATA->s < 0) // only if server didn't auth
2443                         {
2444                                 if((s = InfoString_GetValue(string + 4, "aes", infostringvalue, sizeof(infostringvalue))))
2445                                         aes = atoi(s);
2446                                 else
2447                                         aes = false;
2448                                 if(CDATA->wantserver_idfp[0]) // if we know a host key, honor its encryption setting
2449                                 if(!aes && CDATA->wantserver_aes)
2450                                 {
2451                                         CLEAR_CDATA;
2452                                         return Crypto_ClientError(data_out, len_out, "Stored host key requires encryption, but server did not enable encryption");
2453                                 }
2454                                 if(aes && (!d0_rijndael_dll || crypto_aeslevel.integer <= 0))
2455                                 {
2456                                         CLEAR_CDATA;
2457                                         return Crypto_ClientError(data_out, len_out, "Server insists on encryption too hard");
2458                                 }
2459                                 if(!aes && (d0_rijndael_dll && crypto_aeslevel.integer >= 3))
2460                                 {
2461                                         CLEAR_CDATA;
2462                                         return Crypto_ClientError(data_out, len_out, "Server insists on plaintext too hard");
2463                                 }
2464                                 crypto->use_aes = aes != 0;
2465                         }
2466
2467                         PutWithNul(&data_out_p, len_out, va(vabuf, sizeof(vabuf), "d0pk\\cnt\\6\\id\\%d", CDATA->cdata_id));
2468                         if(!qd0_blind_id_authenticate_with_private_id_response(CDATA->id, data_in, len_in, data_out_p, len_out))
2469                         {
2470                                 CLEAR_CDATA;
2471                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_authenticate_with_private_id_response failed");
2472                         }
2473                         fpbuflen = DHKEY_SIZE;
2474                         if(!qd0_blind_id_sessionkey_public_id(CDATA->id, (char *) dhkey, &fpbuflen))
2475                         {
2476                                 CLEAR_CDATA;
2477                                 return Crypto_ClientError(data_out, len_out, "d0_blind_id_sessionkey_public_id failed");
2478                         }
2479                         // XOR the two DH keys together to make one
2480                         for(i = 0; i < DHKEY_SIZE; ++i)
2481                                 crypto->dhkey[i] ^= dhkey[i];
2482                         // session key is FINISHED! By this, all keys are set up
2483                         crypto->authenticated = true;
2484                         CDATA->next_step = 0;
2485                         data_out_p += *len_out;
2486                         *len_out = data_out_p - data_out;
2487                         return CRYPTO_DISCARD;
2488                 }
2489                 return Crypto_SoftClientError(data_out, len_out, "Got unknown d0_blind_id message from server");
2490         }
2491
2492         return CRYPTO_NOMATCH;
2493 }
2494
2495 size_t Crypto_SignData(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
2496 {
2497         if(keyid < 0 || keyid >= MAX_PUBKEYS)
2498                 return 0;
2499         if(!pubkeys_havepriv[keyid])
2500                 return 0;
2501         if(qd0_blind_id_sign_with_private_id_sign(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))
2502                 return signed_size;
2503         return 0;
2504 }
2505
2506 size_t Crypto_SignDataDetached(const void *data, size_t datasize, int keyid, void *signed_data, size_t signed_size)
2507 {
2508         if(keyid < 0 || keyid >= MAX_PUBKEYS)
2509                 return 0;
2510         if(!pubkeys_havepriv[keyid])
2511                 return 0;
2512         if(qd0_blind_id_sign_with_private_id_sign_detached(pubkeys[keyid], true, false, (const char *)data, datasize, (char *)signed_data, &signed_size))
2513                 return signed_size;
2514         return 0;
2515 }