Remove extern "C" wrapping other includes
[platform/upstream/libsoup.git] / libsoup / soup-auth-ntlm.c
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
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
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
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
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 *
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
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
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
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 *
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
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
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
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
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 *
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
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
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
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
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 *
702 soup_ntlm_request (void)
703 {
704         return g_strdup ("NTLM TlRMTVNTUAABAAAABYIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
705 }
706
707 static gboolean
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
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
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
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 *
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
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
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
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
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
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 }