1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * soup-auth-ntlm.c: HTTP NTLM Authentication helper
4 *
5 * Copyright (C) 2007 Red Hat, Inc.
6 */
7
8 #ifdef HAVE_CONFIG_H
9 #include <config.h>
10 #endif
11
12 #include <errno.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16
17 #include <glib.h>
18
19 #include "soup-auth-ntlm.h"
20 #include "soup.h"
21 #include "soup-message-private.h"
22
23 static void soup_ntlm_lanmanager_hash (const char *password,
24 guchar hash[21]);
25 static void soup_ntlm_nt_hash (const char *password,
26 guchar hash[21]);
27 static char *soup_ntlm_request (void);
28 static gboolean soup_ntlm_parse_challenge (const char *challenge,
29 char **nonce,
30 char **default_domain,
31 gboolean *ntlmv2_session,
32 gboolean *negotiate_target,
33 char **target_info,
34 size_t *target_info_sz);
35 static char *soup_ntlm_response (const char *nonce,
36 const char *user,
37 guchar nt_hash[21],
38 guchar lm_hash[21],
39 const char *host,
40 const char *domain,
41 gboolean ntlmv2_session,
42 gboolean negotiate_target,
43 const char *target_info,
44 size_t target_info_sz);
45
46 typedef enum {
47 SOUP_NTLM_NEW,
48 SOUP_NTLM_SSO_FAILED,
49 SOUP_NTLM_SENT_REQUEST,
50 SOUP_NTLM_RECEIVED_CHALLENGE,
51 SOUP_NTLM_SENT_RESPONSE,
52 SOUP_NTLM_FAILED
53 } SoupNTLMState;
54
55 typedef struct {
56 SoupNTLMState state;
57 char *nonce;
58 char *response_header;
59 gboolean ntlmv2_session;
60 gboolean negotiate_target;
61 char *target_info;
62 size_t target_info_sz;
63 } SoupNTLMConnectionState;
64
65 typedef enum {
66 SOUP_NTLM_PASSWORD_NONE,
67 SOUP_NTLM_PASSWORD_PROVIDED,
68 SOUP_NTLM_PASSWORD_ACCEPTED,
69 SOUP_NTLM_PASSWORD_REJECTED
70 } SoupNTLMPasswordState;
71
72 typedef struct {
73 char *username, *domain;
74 guchar nt_hash[21], lm_hash[21];
75 SoupNTLMPasswordState password_state;
76
77 #ifdef USE_NTLM_AUTH
78 /* Use Samba's 'winbind' daemon to support NTLM single-sign-on,
79 * by delegating the NTLM challenge/response protocal to a helper
80 * in ntlm_auth.
81 * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
82 * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
83 * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
84 */
85 gboolean sso_available;
86 int fd_in;
87 int fd_out;
88 #endif
89 } SoupAuthNTLMPrivate;
90
91 #ifdef USE_NTLM_AUTH
92 static gboolean ntlm_auth_available, ntlm_auth_debug;
93 static void sso_ntlm_close (SoupAuthNTLMPrivate *priv);
94 #endif
95
96 /**
97 * SOUP_TYPE_AUTH_NTLM:
98 *
99 * A #GType corresponding to HTTP-based NTLM authentication.
100 * #SoupSessions do not support this type by default; if you want to
101 * enable support for it, call soup_session_add_feature_by_type(),
102 * passing %SOUP_TYPE_AUTH_NTLM.
103 *
104 * Since: 2.34
105 */
106
G_DEFINE_TYPE_WITH_PRIVATE(SoupAuthNTLM,soup_auth_ntlm,SOUP_TYPE_CONNECTION_AUTH)107 G_DEFINE_TYPE_WITH_PRIVATE (SoupAuthNTLM, soup_auth_ntlm, SOUP_TYPE_CONNECTION_AUTH)
108
109 static void
110 soup_auth_ntlm_init (SoupAuthNTLM *ntlm)
111 {
112 #ifdef USE_NTLM_AUTH
113 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (ntlm);
114 const char *username = NULL, *slash;
115
116 priv->sso_available = TRUE;
117 priv->fd_in = -1;
118 priv->fd_out = -1;
119
120 username = getenv ("NTLMUSER");
121 if (!username)
122 username = g_get_user_name ();
123
124 slash = strpbrk (username, "\\/");
125 if (slash) {
126 priv->username = g_strdup (slash + 1);
127 priv->domain = g_strndup (username, slash - username);
128 } else {
129 priv->username = g_strdup (username);
130 priv->domain = NULL;
131 }
132 #endif
133 }
134
135 static void
soup_auth_ntlm_finalize(GObject * object)136 soup_auth_ntlm_finalize (GObject *object)
137 {
138 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (SOUP_AUTH_NTLM (object));
139
140 g_free (priv->username);
141 g_free (priv->domain);
142
143 memset (priv->nt_hash, 0, sizeof (priv->nt_hash));
144 memset (priv->lm_hash, 0, sizeof (priv->lm_hash));
145
146 #ifdef USE_NTLM_AUTH
147 sso_ntlm_close (priv);
148 #endif
149
150 G_OBJECT_CLASS (soup_auth_ntlm_parent_class)->finalize (object);
151 }
152
153 #ifdef USE_NTLM_AUTH
154 static void
sso_ntlm_close(SoupAuthNTLMPrivate * priv)155 sso_ntlm_close (SoupAuthNTLMPrivate *priv)
156 {
157 if (priv->fd_in != -1) {
158 close (priv->fd_in);
159 priv->fd_in = -1;
160 }
161
162 if (priv->fd_out != -1) {
163 close (priv->fd_out);
164 priv->fd_out = -1;
165 }
166 }
167
168 static gboolean
sso_ntlm_initiate(SoupAuthNTLMPrivate * priv)169 sso_ntlm_initiate (SoupAuthNTLMPrivate *priv)
170 {
171 char *argv[9];
172 gboolean ret;
173
174 if (!priv->sso_available)
175 return FALSE;
176
177 if (!ntlm_auth_available && !ntlm_auth_debug) {
178 priv->sso_available = FALSE;
179 return FALSE;
180 }
181
182 /* Return if ntlm_auth execution process exist already */
183 if (priv->fd_in != -1 && priv->fd_out != -1)
184 return TRUE;
185 else {
186 /* Clean all sso data before re-initiate */
187 sso_ntlm_close (priv);
188 }
189
190 if (ntlm_auth_debug) {
191 argv[0] = (char *) g_getenv ("SOUP_NTLM_AUTH_DEBUG");
192 if (!*argv[0]) {
193 priv->sso_available = FALSE;
194 return FALSE;
195 }
196 } else
197 argv[0] = NTLM_AUTH;
198 argv[1] = "--helper-protocol";
199 argv[2] = "ntlmssp-client-1";
200 argv[3] = "--use-cached-creds";
201 argv[4] = "--username";
202 argv[5] = priv->username;
203 argv[6] = priv->domain ? "--domain" : NULL;
204 argv[7] = priv->domain;
205 argv[8] = NULL;
206
207 ret = g_spawn_async_with_pipes (NULL, argv, NULL,
208 G_SPAWN_STDERR_TO_DEV_NULL,
209 NULL, NULL,
210 NULL, &priv->fd_in, &priv->fd_out,
211 NULL, NULL);
212 if (!ret)
213 priv->sso_available = FALSE;
214 return ret;
215 }
216
217 static char *
sso_ntlm_response(SoupAuthNTLMPrivate * priv,const char * input,SoupNTLMState conn_state)218 sso_ntlm_response (SoupAuthNTLMPrivate *priv, const char *input, SoupNTLMState conn_state)
219 {
220 ssize_t size;
221 char buf[1024];
222 char *tmpbuf = buf;
223 size_t len_in = strlen (input), len_out = sizeof (buf);
224
225 while (len_in > 0) {
226 int written = write (priv->fd_in, input, len_in);
227 if (written == -1) {
228 if (errno == EINTR)
229 continue;
230 /* write failed if other errors happen */
231 return NULL;
232 }
233 input += written;
234 len_in -= written;
235 }
236 /* Read one line */
237 while (len_out > 0) {
238 size = read (priv->fd_out, tmpbuf, len_out);
239 if (size == -1) {
240 if (errno == EINTR)
241 continue;
242 return NULL;
243 } else if (size == 0)
244 return NULL;
245 else if (tmpbuf[size - 1] == '\n') {
246 tmpbuf[size - 1] = '\0';
247 goto wrfinish;
248 }
249 tmpbuf += size;
250 len_out -= size;
251 }
252 return NULL;
253
254 wrfinish:
255 if (g_ascii_strcasecmp (buf, "PW") == 0) {
256 /* Samba/winbind installed but not configured */
257 return g_strdup ("PW");
258 }
259 if (conn_state == SOUP_NTLM_NEW &&
260 g_ascii_strncasecmp (buf, "YR ", 3) != 0) {
261 /* invalid response for type 1 message */
262 return NULL;
263 }
264 if (conn_state == SOUP_NTLM_RECEIVED_CHALLENGE &&
265 g_ascii_strncasecmp (buf, "KK ", 3) != 0 &&
266 g_ascii_strncasecmp (buf, "AF ", 3) != 0) {
267 /* invalid response for type 3 message */
268 return NULL;
269 }
270
271 return g_strdup_printf ("NTLM %.*s", (int)(size - 4), buf + 3);
272 }
273 #endif /* USE_NTLM_AUTH */
274
275 static gpointer
soup_auth_ntlm_create_connection_state(SoupConnectionAuth * auth)276 soup_auth_ntlm_create_connection_state (SoupConnectionAuth *auth)
277 {
278 SoupNTLMConnectionState *conn;
279
280 conn = g_slice_new0 (SoupNTLMConnectionState);
281 conn->state = SOUP_NTLM_NEW;
282
283 return conn;
284 }
285
286 static void
soup_auth_ntlm_free_connection_state(SoupConnectionAuth * auth,gpointer state)287 soup_auth_ntlm_free_connection_state (SoupConnectionAuth *auth,
288 gpointer state)
289 {
290 SoupNTLMConnectionState *conn = state;
291
292 g_free (conn->nonce);
293 g_free (conn->response_header);
294 g_free (conn->target_info);
295 g_slice_free (SoupNTLMConnectionState, conn);
296 }
297
298 static gboolean
soup_auth_ntlm_update_connection(SoupConnectionAuth * auth,SoupMessage * msg,const char * auth_header,gpointer state)299 soup_auth_ntlm_update_connection (SoupConnectionAuth *auth, SoupMessage *msg,
300 const char *auth_header, gpointer state)
301 {
302 SoupAuthNTLM *auth_ntlm = SOUP_AUTH_NTLM (auth);
303 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (auth_ntlm);
304 SoupNTLMConnectionState *conn = state;
305 gboolean success = TRUE;
306
307 /* Note that we only return FALSE if some sort of parsing error
308 * occurs. Otherwise, the SoupAuth is still reusable (though it may
309 * no longer be _ready or _authenticated).
310 */
311
312 if (!g_str_has_prefix (auth_header, "NTLM"))
313 return FALSE;
314
315 if (conn->state > SOUP_NTLM_SENT_REQUEST) {
316 if (priv->password_state == SOUP_NTLM_PASSWORD_ACCEPTED) {
317 /* We know our password is correct, so a 401
318 * means "permission denied". The code can't deal
319 * with re-authenticating correctly, so make sure
320 * we don't try.
321 */
322 conn->state = SOUP_NTLM_FAILED;
323 if (soup_message_is_keepalive (msg)) {
324 soup_message_headers_append (msg->response_headers,
325 "Connection", "close");
326 }
327 return TRUE;
328 }
329
330 #ifdef USE_NTLM_AUTH
331 if (priv->sso_available) {
332 conn->state = SOUP_NTLM_SSO_FAILED;
333 priv->password_state = SOUP_NTLM_PASSWORD_NONE;
334 } else {
335 #endif
336 conn->state = SOUP_NTLM_FAILED;
337 priv->password_state = SOUP_NTLM_PASSWORD_REJECTED;
338 #ifdef USE_NTLM_AUTH
339 }
340 #endif
341 return TRUE;
342 }
343
344 if (conn->state == SOUP_NTLM_NEW && !auth_header[4])
345 return TRUE;
346
347 if (!auth_header[4] || !auth_header[5]) {
348 conn->state = SOUP_NTLM_FAILED;
349 return FALSE;
350 }
351
352 if (!soup_ntlm_parse_challenge (auth_header + 5, &conn->nonce,
353 priv->domain ? NULL : &priv->domain,
354 &conn->ntlmv2_session, &conn->negotiate_target,
355 &conn->target_info, &conn->target_info_sz)) {
356 conn->state = SOUP_NTLM_FAILED;
357 return FALSE;
358 }
359
360 #ifdef USE_NTLM_AUTH
361 if (priv->sso_available && conn->state == SOUP_NTLM_SENT_REQUEST) {
362 char *input, *response;
363
364 /* Re-Initiate ntlm_auth process in case it was closed/killed abnormally */
365 if (!sso_ntlm_initiate (priv)) {
366 conn->state = SOUP_NTLM_SSO_FAILED;
367 success = FALSE;
368 goto out;
369 }
370
371 input = g_strdup_printf ("TT %s\n", auth_header + 5);
372 response = sso_ntlm_response (priv, input, conn->state);
373 sso_ntlm_close (priv);
374 g_free (input);
375
376 if (!response) {
377 conn->state = SOUP_NTLM_SSO_FAILED;
378 success = FALSE;
379 } else if (!g_ascii_strcasecmp (response, "PW")) {
380 conn->state = SOUP_NTLM_SSO_FAILED;
381 priv->sso_available = FALSE;
382 g_free (response);
383 } else {
384 conn->response_header = response;
385 if (priv->password_state != SOUP_NTLM_PASSWORD_ACCEPTED)
386 priv->password_state = SOUP_NTLM_PASSWORD_PROVIDED;
387 }
388 }
389 out:
390 #endif
391
392 if (conn->state == SOUP_NTLM_SENT_REQUEST)
393 conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
394
395 g_object_set (G_OBJECT (auth),
396 SOUP_AUTH_REALM, priv->domain,
397 SOUP_AUTH_HOST, soup_message_get_uri (msg)->host,
398 NULL);
399 return success;
400 }
401
402 static GSList *
soup_auth_ntlm_get_protection_space(SoupAuth * auth,SoupURI * source_uri)403 soup_auth_ntlm_get_protection_space (SoupAuth *auth, SoupURI *source_uri)
404 {
405 char *space, *p;
406
407 space = g_strdup (source_uri->path);
408
409 /* Strip filename component */
410 p = strrchr (space, '/');
411 if (p && p != space && p[1])
412 *p = '\0';
413
414 return g_slist_prepend (NULL, space);
415 }
416
417 static void
soup_auth_ntlm_authenticate(SoupAuth * auth,const char * username,const char * password)418 soup_auth_ntlm_authenticate (SoupAuth *auth, const char *username,
419 const char *password)
420 {
421 SoupAuthNTLM *auth_ntlm = SOUP_AUTH_NTLM (auth);
422 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (auth_ntlm);
423 const char *slash;
424
425 g_return_if_fail (username != NULL);
426 g_return_if_fail (password != NULL);
427
428 if (priv->username)
429 g_free (priv->username);
430 if (priv->domain)
431 g_free (priv->domain);
432
433 slash = strpbrk (username, "\\/");
434 if (slash) {
435 priv->domain = g_strndup (username, slash - username);
436 priv->username = g_strdup (slash + 1);
437 } else {
438 priv->domain = g_strdup ("");
439 priv->username = g_strdup (username);
440 }
441
442 soup_ntlm_nt_hash (password, priv->nt_hash);
443 soup_ntlm_lanmanager_hash (password, priv->lm_hash);
444
445 priv->password_state = SOUP_NTLM_PASSWORD_PROVIDED;
446 }
447
448 static gboolean
soup_auth_ntlm_is_authenticated(SoupAuth * auth)449 soup_auth_ntlm_is_authenticated (SoupAuth *auth)
450 {
451 SoupAuthNTLM *auth_ntlm = SOUP_AUTH_NTLM (auth);
452 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (auth_ntlm);
453
454 return (priv->password_state != SOUP_NTLM_PASSWORD_NONE &&
455 priv->password_state != SOUP_NTLM_PASSWORD_REJECTED);
456 }
457
458 static gboolean
soup_auth_ntlm_is_connection_ready(SoupConnectionAuth * auth,SoupMessage * msg,gpointer state)459 soup_auth_ntlm_is_connection_ready (SoupConnectionAuth *auth,
460 SoupMessage *msg,
461 gpointer state)
462 {
463 SoupAuthNTLM *auth_ntlm = SOUP_AUTH_NTLM (auth);
464 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (auth_ntlm);
465 SoupNTLMConnectionState *conn = state;
466
467 if (priv->password_state == SOUP_NTLM_PASSWORD_REJECTED)
468 return FALSE;
469
470 if (priv->password_state == SOUP_NTLM_PASSWORD_PROVIDED)
471 return TRUE;
472
473 return conn->state != SOUP_NTLM_FAILED;
474 }
475
476 static void
got_final_auth_result(SoupMessage * msg,gpointer data)477 got_final_auth_result (SoupMessage *msg, gpointer data)
478 {
479 SoupAuth *auth = data;
480 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (SOUP_AUTH_NTLM (auth));
481
482 g_signal_handlers_disconnect_by_func (msg, G_CALLBACK (got_final_auth_result), auth);
483
484 if (auth != soup_message_get_auth (msg))
485 return;
486
487 if (msg->status_code != SOUP_STATUS_UNAUTHORIZED)
488 priv->password_state = SOUP_NTLM_PASSWORD_ACCEPTED;
489 }
490
491 static char *
soup_auth_ntlm_get_connection_authorization(SoupConnectionAuth * auth,SoupMessage * msg,gpointer state)492 soup_auth_ntlm_get_connection_authorization (SoupConnectionAuth *auth,
493 SoupMessage *msg,
494 gpointer state)
495 {
496 SoupAuthNTLM *auth_ntlm = SOUP_AUTH_NTLM (auth);
497 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (auth_ntlm);
498 SoupNTLMConnectionState *conn = state;
499 char *header = NULL;
500
501 switch (conn->state) {
502 case SOUP_NTLM_NEW:
503 #ifdef USE_NTLM_AUTH
504 if (sso_ntlm_initiate (priv)) {
505 header = sso_ntlm_response (priv, "YR\n", conn->state);
506 if (header) {
507 if (g_ascii_strcasecmp (header, "PW") != 0) {
508 conn->state = SOUP_NTLM_SENT_REQUEST;
509 break;
510 } else {
511 g_free (header);
512 header = NULL;
513 priv->sso_available = FALSE;
514 }
515 } else {
516 g_debug ("NTLM single-sign-on using %s failed", NTLM_AUTH);
517 }
518 }
519 /* If NTLM single-sign-on fails, go back to original
520 * request handling process.
521 */
522 #endif
523 header = soup_ntlm_request ();
524 conn->state = SOUP_NTLM_SENT_REQUEST;
525 break;
526 case SOUP_NTLM_RECEIVED_CHALLENGE:
527 if (conn->response_header) {
528 header = conn->response_header;
529 conn->response_header = NULL;
530 } else {
531 header = soup_ntlm_response (conn->nonce,
532 priv->username,
533 priv->nt_hash,
534 priv->lm_hash,
535 NULL,
536 priv->domain,
537 conn->ntlmv2_session,
538 conn->negotiate_target,
539 conn->target_info,
540 conn->target_info_sz);
541 }
542 g_clear_pointer (&conn->nonce, g_free);
543 conn->state = SOUP_NTLM_SENT_RESPONSE;
544
545 if (priv->password_state != SOUP_NTLM_PASSWORD_ACCEPTED) {
546 /* We need to know if this worked */
547 g_signal_connect (msg, "got-headers",
548 G_CALLBACK (got_final_auth_result),
549 auth);
550 }
551 break;
552 #ifdef USE_NTLM_AUTH
553 case SOUP_NTLM_SSO_FAILED:
554 /* Restart request without SSO */
555 g_debug ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
556 priv->sso_available = FALSE;
557 header = soup_ntlm_request ();
558 conn->state = SOUP_NTLM_SENT_REQUEST;
559 break;
560 #endif
561 default:
562 break;
563 }
564
565 return header;
566 }
567
568 static void
soup_auth_ntlm_class_init(SoupAuthNTLMClass * auth_ntlm_class)569 soup_auth_ntlm_class_init (SoupAuthNTLMClass *auth_ntlm_class)
570 {
571 SoupAuthClass *auth_class = SOUP_AUTH_CLASS (auth_ntlm_class);
572 SoupConnectionAuthClass *connauth_class = SOUP_CONNECTION_AUTH_CLASS (auth_ntlm_class);
573 GObjectClass *object_class = G_OBJECT_CLASS (auth_ntlm_class);
574
575 auth_class->scheme_name = "NTLM";
576 auth_class->strength = 3;
577
578 auth_class->get_protection_space = soup_auth_ntlm_get_protection_space;
579 auth_class->authenticate = soup_auth_ntlm_authenticate;
580 auth_class->is_authenticated = soup_auth_ntlm_is_authenticated;
581
582 connauth_class->create_connection_state = soup_auth_ntlm_create_connection_state;
583 connauth_class->free_connection_state = soup_auth_ntlm_free_connection_state;
584 connauth_class->update_connection = soup_auth_ntlm_update_connection;
585 connauth_class->get_connection_authorization = soup_auth_ntlm_get_connection_authorization;
586 connauth_class->is_connection_ready = soup_auth_ntlm_is_connection_ready;
587
588 object_class->finalize = soup_auth_ntlm_finalize;
589
590 #ifdef USE_NTLM_AUTH
591 ntlm_auth_available = g_file_test (NTLM_AUTH, G_FILE_TEST_IS_EXECUTABLE);
592 ntlm_auth_debug = (g_getenv ("SOUP_NTLM_AUTH_DEBUG") != NULL);
593 #endif
594 }
595
596 static void md4sum (const unsigned char *in,
597 int nbytes,
598 unsigned char digest[16]);
599
600 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
601
602 static void deskey (DES_KS, unsigned char *, int);
603
604 static void des (DES_KS, unsigned char *);
605
606 static void setup_schedule (const guchar *key_56, DES_KS ks);
607
608 static void calc_response (const guchar *key,
609 const guchar *plaintext,
610 guchar *results);
611
612 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
613 "\x4B\x47\x53\x21\x40\x23\x24\x25" \
614 "\x00\x00\x00\x00\x00"
615
616 static void
soup_ntlm_lanmanager_hash(const char * password,guchar hash[21])617 soup_ntlm_lanmanager_hash (const char *password, guchar hash[21])
618 {
619 guchar lm_password [15];
620 DES_KS ks;
621 int i;
622
623 for (i = 0; i < 14 && password [i]; i++)
624 lm_password [i] = g_ascii_toupper ((unsigned char) password [i]);
625
626 for (; i < 15; i++)
627 lm_password [i] = '\0';
628
629 memcpy (hash, LM_PASSWORD_MAGIC, 21);
630
631 setup_schedule (lm_password, ks);
632 des (ks, hash);
633
634 setup_schedule (lm_password + 7, ks);
635 des (ks, hash + 8);
636 }
637
638 static void
soup_ntlm_nt_hash(const char * password,guchar hash[21])639 soup_ntlm_nt_hash (const char *password, guchar hash[21])
640 {
641 unsigned char *buf, *p;
642
643 p = buf = g_malloc (strlen (password) * 2);
644
645 while (*password) {
646 *p++ = *password++;
647 *p++ = '\0';
648 }
649
650 md4sum (buf, p - buf, hash);
651 memset (hash + 16, 0, 5);
652
653 g_free (buf);
654 }
655
656 typedef struct {
657 guint16 length;
658 guint16 length2;
659 guint16 offset;
660 guchar zero_pad[2];
661 } NTLMString;
662
663 #define NTLM_CHALLENGE_NONCE_OFFSET 24
664 #define NTLM_CHALLENGE_NONCE_LENGTH 8
665 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
666 #define NTLM_CHALLENGE_TARGET_INFORMATION_OFFSET 40
667
668 #define NTLM_CHALLENGE_FLAGS_OFFSET 20
669 #define NTLM_FLAGS_NEGOTIATE_NTLMV2 0x00080000
670 #define NTLM_FLAGS_NEGOTIATE_TARGET_INFORMATION 0x00800000
671 #define NTLM_FLAGS_REQUEST_TARGET 0x00000004
672
673 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
674 #define NTLM_RESPONSE_FLAGS 0x8201
675 #define NTLM_RESPONSE_TARGET_INFORMATION_OFFSET 44
676 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000
677
678 #define HMAC_MD5_LENGTH 16
679
680 typedef struct {
681 guchar header[12];
682
683 NTLMString lm_resp;
684 NTLMString nt_resp;
685 NTLMString domain;
686 NTLMString user;
687 NTLMString host;
688 NTLMString session_key;
689
690 guint32 flags;
691 } NTLMResponse;
692
693 static void
ntlm_set_string(NTLMString * string,int * offset,int len)694 ntlm_set_string (NTLMString *string, int *offset, int len)
695 {
696 string->offset = GUINT16_TO_LE (*offset);
697 string->length = string->length2 = GUINT16_TO_LE (len);
698 *offset += len;
699 }
700
701 static char *
soup_ntlm_request(void)702 soup_ntlm_request (void)
703 {
704 return g_strdup ("NTLM TlRMTVNTUAABAAAABYIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
705 }
706
707 static gboolean
soup_ntlm_parse_challenge(const char * challenge,char ** nonce,char ** default_domain,gboolean * ntlmv2_session,gboolean * negotiate_target,char ** target_info,size_t * target_info_sz)708 soup_ntlm_parse_challenge (const char *challenge,
709 char **nonce,
710 char **default_domain,
711 gboolean *ntlmv2_session,
712 gboolean *negotiate_target,
713 char **target_info,
714 size_t *target_info_sz)
715 {
716 gsize clen;
717 NTLMString domain;
718 NTLMString target;
719 guchar *chall;
720 guint32 flags;
721
722 chall = g_base64_decode (challenge, &clen);
723 if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET ||
724 clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) {
725 g_free (chall);
726 return FALSE;
727 }
728
729 memcpy (&flags, chall + NTLM_CHALLENGE_FLAGS_OFFSET, sizeof(flags));
730 flags = GUINT_FROM_LE (flags);
731 *ntlmv2_session = (flags & NTLM_FLAGS_NEGOTIATE_NTLMV2) ? TRUE : FALSE;
732 /* To know if NTLMv2 responses should be calculated */
733 *negotiate_target = (flags & NTLM_FLAGS_NEGOTIATE_TARGET_INFORMATION ) ? TRUE : FALSE;
734 if (*negotiate_target) {
735 if (clen < NTLM_CHALLENGE_TARGET_INFORMATION_OFFSET + sizeof (target)) {
736 g_free (chall);
737 return FALSE;
738 }
739 }
740
741 if (default_domain) {
742 memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
743 domain.length = GUINT16_FROM_LE (domain.length);
744 domain.offset = GUINT16_FROM_LE (domain.offset);
745
746 if (clen < domain.length + domain.offset) {
747 g_free (chall);
748 return FALSE;
749 }
750
751 *default_domain = g_convert ((char *)chall + domain.offset,
752 domain.length, "UTF-8", "UCS-2LE",
753 NULL, NULL, NULL);
754 }
755
756 if (nonce) {
757 *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
758 NTLM_CHALLENGE_NONCE_LENGTH);
759 }
760 /* For NTLMv2 response */
761 if (*negotiate_target && target_info) {
762 memcpy (&target, chall + NTLM_CHALLENGE_TARGET_INFORMATION_OFFSET, sizeof (target));
763 target.length = GUINT16_FROM_LE (target.length);
764 target.offset = GUINT16_FROM_LE (target.offset);
765
766 if (clen < target.length + target.offset) {
767 g_free (chall);
768 return FALSE;
769 }
770 *target_info = g_memdup (chall + target.offset, target.length);
771 *target_info_sz = target.length;
772 }
773
774 g_free (chall);
775 return TRUE;
776 }
777
778 static void
calc_ntlm2_session_response(const char * nonce,guchar nt_hash[21],guchar lm_hash[21],guchar * lm_resp,gsize lm_resp_sz,guchar * nt_resp)779 calc_ntlm2_session_response (const char *nonce,
780 guchar nt_hash[21],
781 guchar lm_hash[21],
782 guchar *lm_resp,
783 gsize lm_resp_sz,
784 guchar *nt_resp)
785 {
786 guint32 client_nonce[2];
787 guchar ntlmv2_hash[16];
788 GChecksum *ntlmv2_cksum;
789 gsize ntlmv2_hash_sz = sizeof (ntlmv2_hash);
790
791 /* FIXME: if GLib ever gets a more secure random number
792 * generator, use it here
793 */
794 client_nonce[0] = g_random_int();
795 client_nonce[1] = g_random_int();
796
797 ntlmv2_cksum = g_checksum_new (G_CHECKSUM_MD5);
798 g_checksum_update (ntlmv2_cksum, (const guchar *) nonce, 8);
799 g_checksum_update (ntlmv2_cksum, (const guchar *) client_nonce, sizeof (client_nonce));
800 g_checksum_get_digest (ntlmv2_cksum, ntlmv2_hash, &ntlmv2_hash_sz);
801 g_checksum_free (ntlmv2_cksum);
802
803 /* Send the padded client nonce as a fake lm_resp */
804 memset (lm_resp, 0, lm_resp_sz);
805 memcpy (lm_resp, client_nonce, sizeof (client_nonce));
806
807 /* Compute nt_hash as usual but with a new nonce */
808 calc_response (nt_hash, ntlmv2_hash, nt_resp);
809 }
810
811 /* Compute HMAC-MD5 with Glib function*/
812 static void
calc_hmac_md5(unsigned char * hmac,const guchar * key,gsize key_sz,const guchar * data,gsize data_sz)813 calc_hmac_md5 (unsigned char *hmac, const guchar *key, gsize key_sz, const guchar *data, gsize data_sz)
814 {
815 char *hmac_hex, *hex_pos;
816 size_t count;
817
818 hmac_hex = g_compute_hmac_for_data(G_CHECKSUM_MD5, key, key_sz, data, data_sz);
819 hex_pos = hmac_hex;
820 for (count = 0; count < HMAC_MD5_LENGTH; count++)
821 {
822 /* The 'hh' sscanf format modifier is C99, so we enable it on
823 * non-Windows or if __USE_MINGW_ANSI_STDIO is enabled or`
824 * if we are building on Visual Studio 2015 or later
825 */
826 #if !defined (G_OS_WIN32) || (__USE_MINGW_ANSI_STDIO == 1) || (_MSC_VER >= 1900)
827 sscanf(hex_pos, "%2hhx", &hmac[count]);
828 #else
829 unsigned int tmp_hmac;
830 sscanf(hex_pos, "%2x", &tmp_hmac);
831 hmac[count] = (guint8)tmp_hmac;
832 #endif
833
834 hex_pos += 2;
835 }
836 g_free(hmac_hex);
837 }
838
839 static void
calc_ntlmv2_response(const char * user,const char * domain,const guchar * nt_hash,const gsize nt_hash_sz,const guchar * nonce,const char * target_info,size_t target_info_sz,guchar * lm_resp,size_t lm_resp_sz,guchar * nt_resp,size_t nt_resp_sz)840 calc_ntlmv2_response (const char *user, const char *domain,
841 const guchar *nt_hash, const gsize nt_hash_sz,
842 const guchar *nonce,
843 const char *target_info, size_t target_info_sz,
844 guchar *lm_resp, size_t lm_resp_sz,
845 guchar *nt_resp, size_t nt_resp_sz)
846 {
847 const unsigned char blob_signature[] = {0x01,0x01,0x00,0x00};
848 const unsigned char blob_reserved[] = {0x00,0x00,0x00,0x00};
849 gint64 blob_timestamp;
850 unsigned char client_nonce[8];
851 const unsigned char blob_unknown[] = {0x00,0x00,0x00,0x00};
852
853 unsigned char ntv2_hash[HMAC_MD5_LENGTH];
854 guchar *nonce_blob, *blob, *p_blob;
855 unsigned char nonce_blob_hash[HMAC_MD5_LENGTH];
856 unsigned char nonce_client_nonce[16], nonce_client_nonce_hash[HMAC_MD5_LENGTH];
857 gchar *user_uppercase, *user_domain, *user_domain_conv;
858 gsize user_domain_conv_sz;
859 size_t blob_sz;
860 int i;
861
862 /* create HMAC-MD5 hash of Unicode uppercase username and Unicode domain */
863 user_uppercase = g_utf8_strup (user, strlen (user));
864 user_domain = g_strconcat (user_uppercase, domain, NULL);
865 user_domain_conv = g_convert (user_domain, -1, "UCS-2LE", "UTF-8", NULL, &user_domain_conv_sz, NULL);
866 calc_hmac_md5 (ntv2_hash, nt_hash, nt_hash_sz, (const guchar *)user_domain_conv, user_domain_conv_sz);
867 g_free (user_uppercase);
868 g_free (user_domain);
869 g_free (user_domain_conv);
870
871 /* create random client nonce */
872 for (i = 0; i < sizeof (client_nonce); i++)
873 {
874 client_nonce[i] = g_random_int();
875 }
876
877 /* create timestamp for blob
878 * LE, 64-bit signed value, number of tenths of a ms since January 1, 1601.*/
879 blob_timestamp = GINT64_TO_LE(((unsigned long)time(NULL) + 11644473600) * 10000000);
880
881 /* create blob */
882 blob_sz = sizeof (blob_signature) + sizeof (blob_reserved) +
883 sizeof (blob_timestamp) + sizeof (client_nonce) +
884 sizeof (blob_unknown) + target_info_sz;
885 p_blob = blob = g_malloc (blob_sz);
886 memset (blob, 0, blob_sz);
887 memcpy (p_blob, blob_signature, sizeof (blob_signature));
888 memcpy (p_blob += sizeof (blob_signature), blob_reserved, sizeof (blob_reserved));
889 memcpy (p_blob += sizeof (blob_reserved), &blob_timestamp, sizeof (blob_timestamp));
890 memcpy (p_blob += sizeof (blob_timestamp), client_nonce, sizeof (client_nonce));
891 memcpy (p_blob += sizeof (client_nonce), blob_unknown, sizeof (blob_unknown));
892 memcpy (p_blob += sizeof (blob_unknown), target_info, target_info_sz);
893
894 /* create HMAC-MD5 hash of concatenated nonce and blob */
895 nonce_blob = g_malloc (NTLM_CHALLENGE_NONCE_LENGTH + blob_sz);
896 memcpy (nonce_blob, nonce, NTLM_CHALLENGE_NONCE_LENGTH);
897 memcpy (nonce_blob + NTLM_CHALLENGE_NONCE_LENGTH, blob, blob_sz);
898 calc_hmac_md5 (nonce_blob_hash, (const guchar *)ntv2_hash, (gsize) sizeof (ntv2_hash), (const guchar *) nonce_blob, (gsize) NTLM_CHALLENGE_NONCE_LENGTH + blob_sz);
899 g_free (nonce_blob);
900
901 /* create NTv2 response */
902 memset (nt_resp, 0, nt_resp_sz);
903 memcpy (nt_resp, nonce_blob_hash, sizeof (nonce_blob_hash));
904 memcpy (nt_resp + sizeof (nonce_blob_hash), blob, blob_sz);
905
906 g_free (blob);
907
908 /* LMv2
909 * create HMAC-MD5 hash of concatenated nonce and client nonce
910 */
911 memcpy (nonce_client_nonce, nonce, NTLM_CHALLENGE_NONCE_LENGTH);
912 memcpy (nonce_client_nonce + NTLM_CHALLENGE_NONCE_LENGTH, client_nonce, sizeof (client_nonce));
913 calc_hmac_md5 (nonce_client_nonce_hash, (const guchar *) ntv2_hash, (gsize) sizeof (ntv2_hash), (const guchar *) nonce_client_nonce, (gsize) NTLM_CHALLENGE_NONCE_LENGTH + sizeof (client_nonce));
914
915 /* create LMv2 response */
916 memset (lm_resp, 0, lm_resp_sz);
917 memcpy (lm_resp, nonce_client_nonce_hash, sizeof (nonce_client_nonce_hash));
918 memcpy (lm_resp + sizeof (nonce_client_nonce_hash), client_nonce, sizeof (client_nonce));
919 }
920
921 static char *
soup_ntlm_response(const char * nonce,const char * user,guchar nt_hash[21],guchar lm_hash[21],const char * host,const char * domain,gboolean ntlmv2_session,gboolean negotiate_target,const char * target_info,size_t target_info_sz)922 soup_ntlm_response (const char *nonce,
923 const char *user,
924 guchar nt_hash[21],
925 guchar lm_hash[21],
926 const char *host,
927 const char *domain,
928 gboolean ntlmv2_session,
929 gboolean negotiate_target,
930 const char *target_info,
931 size_t target_info_sz)
932 {
933
934 int offset;
935 gsize hlen, dlen, ulen, nt_resp_sz;
936 guchar lm_resp[24], *nt_resp;
937 char *user_conv, *host_conv, *domain_conv;
938 NTLMResponse resp;
939 char *out, *p;
940 int state, save;
941
942 if (negotiate_target)
943 {
944 /* nonce_blob_hash 16 + blob_signature 4 + blob_reserved 4 +
945 * blob_timestamp 8 + client_nonce 8 + blob_unknown 4 +
946 * target_info*/
947 nt_resp_sz = NTLM_RESPONSE_TARGET_INFORMATION_OFFSET + target_info_sz;
948 } else {
949 nt_resp_sz = 24;
950 }
951 nt_resp = g_malloc (nt_resp_sz);
952
953 if (ntlmv2_session && !negotiate_target) {
954 calc_ntlm2_session_response (nonce, nt_hash, lm_hash,
955 lm_resp, sizeof(lm_resp), nt_resp);
956 } else if (!negotiate_target){
957 /* Compute a regular NTLMv1 response */
958 calc_response (nt_hash, (guchar *) nonce, nt_resp);
959 calc_response (lm_hash, (guchar *) nonce, lm_resp);
960 } else {
961 calc_ntlmv2_response (user, domain,
962 nt_hash, 21,
963 (guchar *) nonce,
964 target_info, target_info_sz,
965 lm_resp, sizeof (lm_resp),
966 nt_resp, (size_t) nt_resp_sz);
967 }
968
969 memset (&resp, 0, sizeof (resp));
970 memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
971 resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
972 if (ntlmv2_session)
973 resp.flags |= GUINT32_TO_LE (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY);
974 if (negotiate_target)
975 resp.flags |= GUINT32_TO_LE (NTLM_FLAGS_REQUEST_TARGET);
976 offset = sizeof (resp);
977
978 if (!host)
979 host = "UNKNOWN";
980
981 domain_conv = g_convert (domain, -1, "UCS-2LE", "UTF-8", NULL, &dlen, NULL);
982 user_conv = g_convert (user, -1, "UCS-2LE", "UTF-8", NULL, &ulen, NULL);
983 host_conv = g_convert (host, -1, "UCS-2LE", "UTF-8", NULL, &hlen, NULL);
984
985 ntlm_set_string (&resp.domain, &offset, dlen);
986 ntlm_set_string (&resp.user, &offset, ulen);
987 ntlm_set_string (&resp.host, &offset, hlen);
988 ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
989 ntlm_set_string (&resp.nt_resp, &offset, nt_resp_sz);
990
991 out = g_malloc (((offset + 3) * 4) / 3 + 6);
992 memcpy (out, "NTLM ", 5);
993 p = out + 5;
994
995 state = save = 0;
996
997 p += g_base64_encode_step ((const guchar *) &resp, sizeof (resp),
998 FALSE, p, &state, &save);
999 p += g_base64_encode_step ((const guchar *) domain_conv, dlen,
1000 FALSE, p, &state, &save);
1001 p += g_base64_encode_step ((const guchar *) user_conv, ulen,
1002 FALSE, p, &state, &save);
1003 p += g_base64_encode_step ((const guchar *) host_conv, hlen,
1004 FALSE, p, &state, &save);
1005 p += g_base64_encode_step (lm_resp, sizeof (lm_resp),
1006 FALSE, p, &state, &save);
1007 p += g_base64_encode_step (nt_resp, nt_resp_sz,
1008 FALSE, p, &state, &save);
1009 p += g_base64_encode_close (FALSE, p, &state, &save);
1010 *p = '\0';
1011
1012 g_free (domain_conv);
1013 g_free (user_conv);
1014 g_free (host_conv);
1015 g_free (nt_resp);
1016
1017 return out;
1018 }
1019
1020 /* DES utils */
1021 /* Set up a key schedule based on a 56bit key */
1022 static void
setup_schedule(const guchar * key_56,DES_KS ks)1023 setup_schedule (const guchar *key_56, DES_KS ks)
1024 {
1025 guchar key[8];
1026 int i, c, bit;
1027
1028 key[0] = (key_56[0]) ;
1029 key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
1030 key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
1031 key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
1032 key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
1033 key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
1034 key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
1035 key[7] = ((key_56[6] << 1) & 0xFF);
1036
1037 /* Fix parity */
1038 for (i = 0; i < 8; i++) {
1039 for (c = bit = 0; bit < 8; bit++)
1040 if (key[i] & (1 << bit))
1041 c++;
1042 if (!(c & 1))
1043 key[i] ^= 0x01;
1044 }
1045
1046 deskey (ks, key, 0);
1047 }
1048
1049 static void
calc_response(const guchar * key,const guchar * plaintext,guchar * results)1050 calc_response (const guchar *key, const guchar *plaintext, guchar *results)
1051 {
1052 DES_KS ks;
1053
1054 memcpy (results, plaintext, 8);
1055 memcpy (results + 8, plaintext, 8);
1056 memcpy (results + 16, plaintext, 8);
1057
1058 setup_schedule (key, ks);
1059 des (ks, results);
1060
1061 setup_schedule (key + 7, ks);
1062 des (ks, results + 8);
1063
1064 setup_schedule (key + 14, ks);
1065 des (ks, results + 16);
1066 }
1067
1068
1069 /*
1070 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
1071 * this is a reimplementation from spec.) This doesn't need to be
1072 * efficient for our purposes, although it would be nice to fix
1073 * it to not malloc()...
1074 */
1075
1076 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
1077 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
1078 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
1079 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
1080
1081 static void
md4sum(const unsigned char * in,int nbytes,unsigned char digest[16])1082 md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
1083 {
1084 unsigned char *M;
1085 guint32 A, B, C, D, AA, BB, CC, DD, X[16];
1086 int pbytes, nbits = nbytes * 8, i, j;
1087
1088 /* There is *always* padding of at least one bit. */
1089 pbytes = ((119 - (nbytes % 64)) % 64) + 1;
1090 M = alloca (nbytes + pbytes + 8);
1091 memcpy (M, in, nbytes);
1092 memset (M + nbytes, 0, pbytes + 8);
1093 M[nbytes] = 0x80;
1094 M[nbytes + pbytes] = nbits & 0xFF;
1095 M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
1096 M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
1097 M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
1098
1099 A = 0x67452301;
1100 B = 0xEFCDAB89;
1101 C = 0x98BADCFE;
1102 D = 0x10325476;
1103
1104 for (i = 0; i < nbytes + pbytes + 8; i += 64) {
1105 for (j = 0; j < 16; j++) {
1106 X[j] = (M[i + j*4]) |
1107 (M[i + j*4 + 1] << 8) |
1108 (M[i + j*4 + 2] << 16) |
1109 (M[i + j*4 + 3] << 24);
1110 }
1111
1112 AA = A;
1113 BB = B;
1114 CC = C;
1115 DD = D;
1116
1117 A = ROT (A + F(B, C, D) + X[0], 3);
1118 D = ROT (D + F(A, B, C) + X[1], 7);
1119 C = ROT (C + F(D, A, B) + X[2], 11);
1120 B = ROT (B + F(C, D, A) + X[3], 19);
1121 A = ROT (A + F(B, C, D) + X[4], 3);
1122 D = ROT (D + F(A, B, C) + X[5], 7);
1123 C = ROT (C + F(D, A, B) + X[6], 11);
1124 B = ROT (B + F(C, D, A) + X[7], 19);
1125 A = ROT (A + F(B, C, D) + X[8], 3);
1126 D = ROT (D + F(A, B, C) + X[9], 7);
1127 C = ROT (C + F(D, A, B) + X[10], 11);
1128 B = ROT (B + F(C, D, A) + X[11], 19);
1129 A = ROT (A + F(B, C, D) + X[12], 3);
1130 D = ROT (D + F(A, B, C) + X[13], 7);
1131 C = ROT (C + F(D, A, B) + X[14], 11);
1132 B = ROT (B + F(C, D, A) + X[15], 19);
1133
1134 A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
1135 D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
1136 C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
1137 B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
1138 A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
1139 D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
1140 C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
1141 B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
1142 A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
1143 D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
1144 C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
1145 B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
1146 A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
1147 D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
1148 C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
1149 B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
1150
1151 A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
1152 D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
1153 C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
1154 B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
1155 A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
1156 D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
1157 C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
1158 B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
1159 A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
1160 D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
1161 C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
1162 B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
1163 A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
1164 D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
1165 C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
1166 B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
1167
1168 A += AA;
1169 B += BB;
1170 C += CC;
1171 D += DD;
1172 }
1173
1174 digest[0] = A & 0xFF;
1175 digest[1] = (A >> 8) & 0xFF;
1176 digest[2] = (A >> 16) & 0xFF;
1177 digest[3] = (A >> 24) & 0xFF;
1178 digest[4] = B & 0xFF;
1179 digest[5] = (B >> 8) & 0xFF;
1180 digest[6] = (B >> 16) & 0xFF;
1181 digest[7] = (B >> 24) & 0xFF;
1182 digest[8] = C & 0xFF;
1183 digest[9] = (C >> 8) & 0xFF;
1184 digest[10] = (C >> 16) & 0xFF;
1185 digest[11] = (C >> 24) & 0xFF;
1186 digest[12] = D & 0xFF;
1187 digest[13] = (D >> 8) & 0xFF;
1188 digest[14] = (D >> 16) & 0xFF;
1189 digest[15] = (D >> 24) & 0xFF;
1190 }
1191
1192
1193 /* Public domain DES implementation from Phil Karn */
1194 static const guint32 Spbox[8][64] = {
1195 { 0x01010400,0x00000000,0x00010000,0x01010404,
1196 0x01010004,0x00010404,0x00000004,0x00010000,
1197 0x00000400,0x01010400,0x01010404,0x00000400,
1198 0x01000404,0x01010004,0x01000000,0x00000004,
1199 0x00000404,0x01000400,0x01000400,0x00010400,
1200 0x00010400,0x01010000,0x01010000,0x01000404,
1201 0x00010004,0x01000004,0x01000004,0x00010004,
1202 0x00000000,0x00000404,0x00010404,0x01000000,
1203 0x00010000,0x01010404,0x00000004,0x01010000,
1204 0x01010400,0x01000000,0x01000000,0x00000400,
1205 0x01010004,0x00010000,0x00010400,0x01000004,
1206 0x00000400,0x00000004,0x01000404,0x00010404,
1207 0x01010404,0x00010004,0x01010000,0x01000404,
1208 0x01000004,0x00000404,0x00010404,0x01010400,
1209 0x00000404,0x01000400,0x01000400,0x00000000,
1210 0x00010004,0x00010400,0x00000000,0x01010004 },
1211 { 0x80108020,0x80008000,0x00008000,0x00108020,
1212 0x00100000,0x00000020,0x80100020,0x80008020,
1213 0x80000020,0x80108020,0x80108000,0x80000000,
1214 0x80008000,0x00100000,0x00000020,0x80100020,
1215 0x00108000,0x00100020,0x80008020,0x00000000,
1216 0x80000000,0x00008000,0x00108020,0x80100000,
1217 0x00100020,0x80000020,0x00000000,0x00108000,
1218 0x00008020,0x80108000,0x80100000,0x00008020,
1219 0x00000000,0x00108020,0x80100020,0x00100000,
1220 0x80008020,0x80100000,0x80108000,0x00008000,
1221 0x80100000,0x80008000,0x00000020,0x80108020,
1222 0x00108020,0x00000020,0x00008000,0x80000000,
1223 0x00008020,0x80108000,0x00100000,0x80000020,
1224 0x00100020,0x80008020,0x80000020,0x00100020,
1225 0x00108000,0x00000000,0x80008000,0x00008020,
1226 0x80000000,0x80100020,0x80108020,0x00108000 },
1227 { 0x00000208,0x08020200,0x00000000,0x08020008,
1228 0x08000200,0x00000000,0x00020208,0x08000200,
1229 0x00020008,0x08000008,0x08000008,0x00020000,
1230 0x08020208,0x00020008,0x08020000,0x00000208,
1231 0x08000000,0x00000008,0x08020200,0x00000200,
1232 0x00020200,0x08020000,0x08020008,0x00020208,
1233 0x08000208,0x00020200,0x00020000,0x08000208,
1234 0x00000008,0x08020208,0x00000200,0x08000000,
1235 0x08020200,0x08000000,0x00020008,0x00000208,
1236 0x00020000,0x08020200,0x08000200,0x00000000,
1237 0x00000200,0x00020008,0x08020208,0x08000200,
1238 0x08000008,0x00000200,0x00000000,0x08020008,
1239 0x08000208,0x00020000,0x08000000,0x08020208,
1240 0x00000008,0x00020208,0x00020200,0x08000008,
1241 0x08020000,0x08000208,0x00000208,0x08020000,
1242 0x00020208,0x00000008,0x08020008,0x00020200 },
1243 { 0x00802001,0x00002081,0x00002081,0x00000080,
1244 0x00802080,0x00800081,0x00800001,0x00002001,
1245 0x00000000,0x00802000,0x00802000,0x00802081,
1246 0x00000081,0x00000000,0x00800080,0x00800001,
1247 0x00000001,0x00002000,0x00800000,0x00802001,
1248 0x00000080,0x00800000,0x00002001,0x00002080,
1249 0x00800081,0x00000001,0x00002080,0x00800080,
1250 0x00002000,0x00802080,0x00802081,0x00000081,
1251 0x00800080,0x00800001,0x00802000,0x00802081,
1252 0x00000081,0x00000000,0x00000000,0x00802000,
1253 0x00002080,0x00800080,0x00800081,0x00000001,
1254 0x00802001,0x00002081,0x00002081,0x00000080,
1255 0x00802081,0x00000081,0x00000001,0x00002000,
1256 0x00800001,0x00002001,0x00802080,0x00800081,
1257 0x00002001,0x00002080,0x00800000,0x00802001,
1258 0x00000080,0x00800000,0x00002000,0x00802080 },
1259 { 0x00000100,0x02080100,0x02080000,0x42000100,
1260 0x00080000,0x00000100,0x40000000,0x02080000,
1261 0x40080100,0x00080000,0x02000100,0x40080100,
1262 0x42000100,0x42080000,0x00080100,0x40000000,
1263 0x02000000,0x40080000,0x40080000,0x00000000,
1264 0x40000100,0x42080100,0x42080100,0x02000100,
1265 0x42080000,0x40000100,0x00000000,0x42000000,
1266 0x02080100,0x02000000,0x42000000,0x00080100,
1267 0x00080000,0x42000100,0x00000100,0x02000000,
1268 0x40000000,0x02080000,0x42000100,0x40080100,
1269 0x02000100,0x40000000,0x42080000,0x02080100,
1270 0x40080100,0x00000100,0x02000000,0x42080000,
1271 0x42080100,0x00080100,0x42000000,0x42080100,
1272 0x02080000,0x00000000,0x40080000,0x42000000,
1273 0x00080100,0x02000100,0x40000100,0x00080000,
1274 0x00000000,0x40080000,0x02080100,0x40000100 },
1275 { 0x20000010,0x20400000,0x00004000,0x20404010,
1276 0x20400000,0x00000010,0x20404010,0x00400000,
1277 0x20004000,0x00404010,0x00400000,0x20000010,
1278 0x00400010,0x20004000,0x20000000,0x00004010,
1279 0x00000000,0x00400010,0x20004010,0x00004000,
1280 0x00404000,0x20004010,0x00000010,0x20400010,
1281 0x20400010,0x00000000,0x00404010,0x20404000,
1282 0x00004010,0x00404000,0x20404000,0x20000000,
1283 0x20004000,0x00000010,0x20400010,0x00404000,
1284 0x20404010,0x00400000,0x00004010,0x20000010,
1285 0x00400000,0x20004000,0x20000000,0x00004010,
1286 0x20000010,0x20404010,0x00404000,0x20400000,
1287 0x00404010,0x20404000,0x00000000,0x20400010,
1288 0x00000010,0x00004000,0x20400000,0x00404010,
1289 0x00004000,0x00400010,0x20004010,0x00000000,
1290 0x20404000,0x20000000,0x00400010,0x20004010 },
1291 { 0x00200000,0x04200002,0x04000802,0x00000000,
1292 0x00000800,0x04000802,0x00200802,0x04200800,
1293 0x04200802,0x00200000,0x00000000,0x04000002,
1294 0x00000002,0x04000000,0x04200002,0x00000802,
1295 0x04000800,0x00200802,0x00200002,0x04000800,
1296 0x04000002,0x04200000,0x04200800,0x00200002,
1297 0x04200000,0x00000800,0x00000802,0x04200802,
1298 0x00200800,0x00000002,0x04000000,0x00200800,
1299 0x04000000,0x00200800,0x00200000,0x04000802,
1300 0x04000802,0x04200002,0x04200002,0x00000002,
1301 0x00200002,0x04000000,0x04000800,0x00200000,
1302 0x04200800,0x00000802,0x00200802,0x04200800,
1303 0x00000802,0x04000002,0x04200802,0x04200000,
1304 0x00200800,0x00000000,0x00000002,0x04200802,
1305 0x00000000,0x00200802,0x04200000,0x00000800,
1306 0x04000002,0x04000800,0x00000800,0x00200002 },
1307 { 0x10001040,0x00001000,0x00040000,0x10041040,
1308 0x10000000,0x10001040,0x00000040,0x10000000,
1309 0x00040040,0x10040000,0x10041040,0x00041000,
1310 0x10041000,0x00041040,0x00001000,0x00000040,
1311 0x10040000,0x10000040,0x10001000,0x00001040,
1312 0x00041000,0x00040040,0x10040040,0x10041000,
1313 0x00001040,0x00000000,0x00000000,0x10040040,
1314 0x10000040,0x10001000,0x00041040,0x00040000,
1315 0x00041040,0x00040000,0x10041000,0x00001000,
1316 0x00000040,0x10040040,0x00001000,0x00041040,
1317 0x10001000,0x00000040,0x10000040,0x10040000,
1318 0x10040040,0x10000000,0x00040000,0x10001040,
1319 0x00000000,0x10041040,0x00040040,0x10000040,
1320 0x10040000,0x10001000,0x10001040,0x00000000,
1321 0x10041040,0x00041000,0x00041000,0x00001040,
1322 0x00001040,0x00040040,0x10000000,0x10041000 }
1323 };
1324
1325 #undef F
1326 #define F(l,r,key){\
1327 work = ((r >> 4) | (r << 28)) ^ key[0];\
1328 l ^= Spbox[6][work & 0x3f];\
1329 l ^= Spbox[4][(work >> 8) & 0x3f];\
1330 l ^= Spbox[2][(work >> 16) & 0x3f];\
1331 l ^= Spbox[0][(work >> 24) & 0x3f];\
1332 work = r ^ key[1];\
1333 l ^= Spbox[7][work & 0x3f];\
1334 l ^= Spbox[5][(work >> 8) & 0x3f];\
1335 l ^= Spbox[3][(work >> 16) & 0x3f];\
1336 l ^= Spbox[1][(work >> 24) & 0x3f];\
1337 }
1338 /* Encrypt or decrypt a block of data in ECB mode */
1339 static void
des(guint32 ks[16][2],unsigned char block[8])1340 des (guint32 ks[16][2], unsigned char block[8])
1341 {
1342 guint32 left,right,work;
1343
1344 /* Read input block and place in left/right in big-endian order */
1345 left = ((guint32)block[0] << 24)
1346 | ((guint32)block[1] << 16)
1347 | ((guint32)block[2] << 8)
1348 | (guint32)block[3];
1349 right = ((guint32)block[4] << 24)
1350 | ((guint32)block[5] << 16)
1351 | ((guint32)block[6] << 8)
1352 | (guint32)block[7];
1353
1354 /* Hoey's clever initial permutation algorithm, from Outerbridge
1355 * (see Schneier p 478)
1356 *
1357 * The convention here is the same as Outerbridge: rotate each
1358 * register left by 1 bit, i.e., so that "left" contains permuted
1359 * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
1360 * (using origin-1 numbering as in the FIPS). This allows us to avoid
1361 * one of the two rotates that would otherwise be required in each of
1362 * the 16 rounds.
1363 */
1364 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
1365 right ^= work;
1366 left ^= work << 4;
1367 work = ((left >> 16) ^ right) & 0xffff;
1368 right ^= work;
1369 left ^= work << 16;
1370 work = ((right >> 2) ^ left) & 0x33333333;
1371 left ^= work;
1372 right ^= (work << 2);
1373 work = ((right >> 8) ^ left) & 0xff00ff;
1374 left ^= work;
1375 right ^= (work << 8);
1376 right = (right << 1) | (right >> 31);
1377 work = (left ^ right) & 0xaaaaaaaa;
1378 left ^= work;
1379 right ^= work;
1380 left = (left << 1) | (left >> 31);
1381
1382 /* Now do the 16 rounds */
1383 F(left,right,ks[0]);
1384 F(right,left,ks[1]);
1385 F(left,right,ks[2]);
1386 F(right,left,ks[3]);
1387 F(left,right,ks[4]);
1388 F(right,left,ks[5]);
1389 F(left,right,ks[6]);
1390 F(right,left,ks[7]);
1391 F(left,right,ks[8]);
1392 F(right,left,ks[9]);
1393 F(left,right,ks[10]);
1394 F(right,left,ks[11]);
1395 F(left,right,ks[12]);
1396 F(right,left,ks[13]);
1397 F(left,right,ks[14]);
1398 F(right,left,ks[15]);
1399
1400 /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
1401 right = (right << 31) | (right >> 1);
1402 work = (left ^ right) & 0xaaaaaaaa;
1403 left ^= work;
1404 right ^= work;
1405 left = (left >> 1) | (left << 31);
1406 work = ((left >> 8) ^ right) & 0xff00ff;
1407 right ^= work;
1408 left ^= work << 8;
1409 work = ((left >> 2) ^ right) & 0x33333333;
1410 right ^= work;
1411 left ^= work << 2;
1412 work = ((right >> 16) ^ left) & 0xffff;
1413 left ^= work;
1414 right ^= work << 16;
1415 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
1416 left ^= work;
1417 right ^= work << 4;
1418
1419 /* Put the block back into the user's buffer with final swap */
1420 block[0] = right >> 24;
1421 block[1] = right >> 16;
1422 block[2] = right >> 8;
1423 block[3] = right;
1424 block[4] = left >> 24;
1425 block[5] = left >> 16;
1426 block[6] = left >> 8;
1427 block[7] = left;
1428 }
1429
1430 /* Key schedule-related tables from FIPS-46 */
1431
1432 /* permuted choice table (key) */
1433 static const unsigned char pc1[] = {
1434 57, 49, 41, 33, 25, 17, 9,
1435 1, 58, 50, 42, 34, 26, 18,
1436 10, 2, 59, 51, 43, 35, 27,
1437 19, 11, 3, 60, 52, 44, 36,
1438
1439 63, 55, 47, 39, 31, 23, 15,
1440 7, 62, 54, 46, 38, 30, 22,
1441 14, 6, 61, 53, 45, 37, 29,
1442 21, 13, 5, 28, 20, 12, 4
1443 };
1444
1445 /* number left rotations of pc1 */
1446 static const unsigned char totrot[] = {
1447 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
1448 };
1449
1450 /* permuted choice key (table) */
1451 static const unsigned char pc2[] = {
1452 14, 17, 11, 24, 1, 5,
1453 3, 28, 15, 6, 21, 10,
1454 23, 19, 12, 4, 26, 8,
1455 16, 7, 27, 20, 13, 2,
1456 41, 52, 31, 37, 47, 55,
1457 30, 40, 51, 45, 33, 48,
1458 44, 49, 39, 56, 34, 53,
1459 46, 42, 50, 36, 29, 32
1460 };
1461
1462 /* End of DES-defined tables */
1463
1464
1465 /* bit 0 is left-most in byte */
1466 static const int bytebit[] = {
1467 0200,0100,040,020,010,04,02,01
1468 };
1469
1470
1471 /* Generate key schedule for encryption or decryption
1472 * depending on the value of "decrypt"
1473 */
1474 static void
deskey(DES_KS k,unsigned char * key,int decrypt)1475 deskey (DES_KS k, unsigned char *key, int decrypt)
1476 {
1477 unsigned char pc1m[56]; /* place to modify pc1 into */
1478 unsigned char pcr[56]; /* place to rotate pc1 into */
1479 register int i,j,l;
1480 int m;
1481 unsigned char ks[8];
1482
1483 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
1484 l=pc1[j]-1; /* integer bit location */
1485 m = l & 07; /* find bit */
1486 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
1487 bytebit[m]) /* and which bit of that byte */
1488 ? 1 : 0; /* and store 1-bit result */
1489 }
1490 for (i=0; i<16; i++) { /* key chunk for each iteration */
1491 memset(ks,0,sizeof(ks)); /* Clear key schedule */
1492 for (j=0; j<56; j++) /* rotate pc1 the right amount */
1493 pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
1494 /* rotate left and right halves independently */
1495 for (j=0; j<48; j++){ /* select bits individually */
1496 /* check bit that goes to ks[j] */
1497 if (pcr[pc2[j]-1]){
1498 /* mask it in if it's there */
1499 l= j % 6;
1500 ks[j/6] |= bytebit[l] >> 2;
1501 }
1502 }
1503 /* Now convert to packed odd/even interleaved form */
1504 k[i][0] = ((guint32)ks[0] << 24)
1505 | ((guint32)ks[2] << 16)
1506 | ((guint32)ks[4] << 8)
1507 | ((guint32)ks[6]);
1508 k[i][1] = ((guint32)ks[1] << 24)
1509 | ((guint32)ks[3] << 16)
1510 | ((guint32)ks[5] << 8)
1511 | ((guint32)ks[7]);
1512 }
1513 }
1514