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