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