soup-auth-manager: add soup_auth_manager_use_auth()
[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 <glib.h>
16
17 #include "soup-auth-ntlm.h"
18 #include "soup.h"
19 #include "soup-message-private.h"
20
21 static void        soup_ntlm_lanmanager_hash   (const char  *password,
22                                                 guchar       hash[21]);
23 static void        soup_ntlm_nt_hash           (const char  *password,
24                                                 guchar       hash[21]);
25 static char       *soup_ntlm_request           (void);
26 static gboolean    soup_ntlm_parse_challenge   (const char  *challenge,
27                                                 char       **nonce,
28                                                 char       **default_domain);
29 static char       *soup_ntlm_response          (const char  *nonce, 
30                                                 const char  *user,
31                                                 guchar       nt_hash[21],
32                                                 guchar       lm_hash[21],
33                                                 const char  *host, 
34                                                 const char  *domain);
35
36 typedef enum {
37         SOUP_NTLM_NEW,
38         SOUP_NTLM_SSO_FAILED,
39         SOUP_NTLM_SENT_REQUEST,
40         SOUP_NTLM_RECEIVED_CHALLENGE,
41         SOUP_NTLM_SENT_RESPONSE,
42         SOUP_NTLM_FAILED
43 } SoupNTLMState;
44
45 typedef struct {
46         SoupNTLMState state;
47         char *nonce;
48         char *response_header;
49 } SoupNTLMConnectionState;
50
51 typedef struct {
52         char *username, *domain;
53         guchar nt_hash[21], lm_hash[21];
54         gboolean authenticated;
55
56 #ifdef USE_NTLM_AUTH
57         /* Use Samba's 'winbind' daemon to support NTLM single-sign-on,
58          * by delegating the NTLM challenge/response protocal to a helper
59          * in ntlm_auth.
60          * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
61          * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
62          * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
63          */
64         gboolean sso_available;
65         int fd_in;
66         int fd_out;
67 #endif
68 } SoupAuthNTLMPrivate;
69 #define SOUP_AUTH_NTLM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH_NTLM, SoupAuthNTLMPrivate))
70
71 #ifdef USE_NTLM_AUTH
72 static gboolean ntlm_auth_available, ntlm_auth_debug;
73 static void sso_ntlm_close (SoupAuthNTLMPrivate *priv);
74 #endif
75
76 /**
77  * SOUP_TYPE_AUTH_NTLM:
78  *
79  * A #GType corresponding to HTTP-based NTLM authentication.
80  * #SoupSessions do not support this type by default; if you want to
81  * enable support for it, call soup_session_add_feature_by_type(),
82  * passing %SOUP_TYPE_AUTH_NTLM.
83  *
84  * Since: 2.34
85  */
86
87 G_DEFINE_TYPE (SoupAuthNTLM, soup_auth_ntlm, SOUP_TYPE_CONNECTION_AUTH)
88
89 static void
90 soup_auth_ntlm_init (SoupAuthNTLM *ntlm)
91 {
92 #ifdef USE_NTLM_AUTH
93         SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (ntlm);
94         const char *username = NULL, *slash;
95
96         priv->sso_available = TRUE;
97         priv->fd_in = -1;
98         priv->fd_out = -1;
99
100         username = getenv ("NTLMUSER");
101         if (!username)
102                 username = g_get_user_name ();
103
104         slash = strpbrk (username, "\\/");
105         if (slash) {
106                 priv->username = g_strdup (slash + 1);
107                 priv->domain = g_strndup (username, slash - username);
108         } else {
109                 priv->username = g_strdup (username);
110                 priv->domain = NULL;
111         }
112 #endif
113 }
114
115 static void
116 soup_auth_ntlm_finalize (GObject *object)
117 {
118         SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (object);
119
120         g_free (priv->username);
121         g_free (priv->domain);
122
123         memset (priv->nt_hash, 0, sizeof (priv->nt_hash));
124         memset (priv->lm_hash, 0, sizeof (priv->lm_hash));
125
126 #ifdef USE_NTLM_AUTH
127         sso_ntlm_close (priv);
128 #endif
129
130         G_OBJECT_CLASS (soup_auth_ntlm_parent_class)->finalize (object);
131 }
132
133 #ifdef USE_NTLM_AUTH
134 static void
135 sso_ntlm_close (SoupAuthNTLMPrivate *priv)
136 {
137         if (priv->fd_in != -1) {
138                 close (priv->fd_in);
139                 priv->fd_in = -1;
140         }
141
142         if (priv->fd_out != -1) {
143                 close (priv->fd_out);
144                 priv->fd_out = -1;
145         }
146 }
147
148 static gboolean
149 sso_ntlm_initiate (SoupAuthNTLMPrivate *priv)
150 {
151         char *argv[9];
152         gboolean ret;
153
154         if (!priv->sso_available)
155                 return FALSE;
156
157         if (!ntlm_auth_available && !ntlm_auth_debug) {
158                 priv->sso_available = FALSE;
159                 return FALSE;
160         }
161
162         /* Return if ntlm_auth execution process exist already */
163         if (priv->fd_in != -1 && priv->fd_out != -1)
164                 return TRUE;
165         else {
166                 /* Clean all sso data before re-initiate */
167                 sso_ntlm_close (priv);
168         }
169
170         if (ntlm_auth_debug) {
171                 argv[0] = (char *) g_getenv ("SOUP_NTLM_AUTH_DEBUG");
172                 if (!*argv[0]) {
173                         priv->sso_available = FALSE;
174                         return FALSE;
175                 }
176         } else
177                 argv[0] = NTLM_AUTH;
178         argv[1] = "--helper-protocol";
179         argv[2] = "ntlmssp-client-1";
180         argv[3] = "--use-cached-creds";
181         argv[4] = "--username";
182         argv[5] = priv->username;
183         argv[6] = priv->domain ? "--domain" : NULL;
184         argv[7] = priv->domain;
185         argv[8] = NULL;
186
187         ret = g_spawn_async_with_pipes (NULL, argv, NULL,
188                                         G_SPAWN_STDERR_TO_DEV_NULL,
189                                         NULL, NULL,
190                                         NULL, &priv->fd_in, &priv->fd_out,
191                                         NULL, NULL);
192         if (!ret)
193                 priv->sso_available = FALSE;
194         return ret;
195 }
196
197 static char *
198 sso_ntlm_response (SoupAuthNTLMPrivate *priv, const char *input, SoupNTLMState conn_state)
199 {
200         ssize_t size;
201         char buf[1024];
202         char *tmpbuf = buf;
203         size_t  len_in = strlen (input), len_out = sizeof (buf);
204
205         while (len_in > 0) {
206                 int written = write (priv->fd_in, input, len_in);
207                 if (written == -1) {
208                         if (errno == EINTR)
209                                 continue;
210                         /* write failed if other errors happen */
211                         return NULL;
212                 }
213                 input += written;
214                 len_in -= written;
215         }
216         /* Read one line */
217         while (len_out > 0) {
218                 size = read (priv->fd_out, tmpbuf, len_out);
219                 if (size == -1) {
220                         if (errno == EINTR)
221                                 continue;
222                         return NULL;
223                 } else if (size == 0)
224                         return NULL;
225                 else if (tmpbuf[size - 1] == '\n') {
226                         tmpbuf[size - 1] = '\0';
227                         goto wrfinish;
228                 }
229                 tmpbuf += size;
230                 len_out -= size;
231         }
232         return NULL;
233
234 wrfinish:
235         if (g_ascii_strcasecmp (buf, "PW") == 0) {
236                 /* Samba/winbind installed but not configured */
237                 return g_strdup ("PW");
238         }
239         if (conn_state == SOUP_NTLM_NEW &&
240             g_ascii_strncasecmp (buf, "YR ", 3) != 0) {
241                 /* invalid response for type 1 message */
242                 return NULL;
243         }
244         if (conn_state == SOUP_NTLM_RECEIVED_CHALLENGE &&
245             g_ascii_strncasecmp (buf, "KK ", 3) != 0 &&
246             g_ascii_strncasecmp (buf, "AF ", 3) != 0) {
247                 /* invalid response for type 3 message */
248                 return NULL;
249         }
250
251         return g_strdup_printf ("NTLM %.*s", (int)(size - 4), buf + 3);
252 }
253 #endif /* USE_NTLM_AUTH */
254
255 static gpointer
256 soup_auth_ntlm_create_connection_state (SoupConnectionAuth *auth)
257 {
258         SoupNTLMConnectionState *conn;
259
260         conn = g_slice_new0 (SoupNTLMConnectionState);
261         conn->state = SOUP_NTLM_NEW;
262
263         return conn;
264 }
265
266 static void
267 soup_auth_ntlm_free_connection_state (SoupConnectionAuth *auth,
268                                       gpointer state)
269 {
270         SoupNTLMConnectionState *conn = state;
271
272         g_free (conn->nonce);
273         g_free (conn->response_header);
274         g_slice_free (SoupNTLMConnectionState, conn);
275 }
276
277 static gboolean
278 soup_auth_ntlm_update_connection (SoupConnectionAuth *auth, SoupMessage *msg,
279                                   const char *auth_header, gpointer state)
280 {
281         SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (auth);
282         SoupNTLMConnectionState *conn = state;
283         gboolean success = TRUE;
284
285         if (conn->state > SOUP_NTLM_SENT_REQUEST) {
286                 /* We already authenticated, but then got another 401.
287                  * That means "permission denied", so don't try to
288                  * authenticate again.
289                  */
290                 conn->state = SOUP_NTLM_FAILED;
291
292                 /* FIXME: we should only do this if the password never worked */
293                 priv->authenticated = FALSE;
294
295                 return FALSE;
296         }
297
298         if (!g_str_has_prefix (auth_header, "NTLM "))
299                 return FALSE;
300
301         if (!soup_ntlm_parse_challenge (auth_header + 5, &conn->nonce, &priv->domain)) {
302                 conn->state = SOUP_NTLM_FAILED;
303                 return FALSE;
304         }
305
306 #ifdef USE_NTLM_AUTH
307         if (priv->sso_available && conn->state == SOUP_NTLM_SENT_REQUEST) {
308                 char *input, *response;
309
310                 /* Re-Initiate ntlm_auth process in case it was closed/killed abnormally */
311                 if (!sso_ntlm_initiate (priv)) {
312                         conn->state = SOUP_NTLM_SSO_FAILED;
313                         success = FALSE;
314                         goto out;
315                 }
316
317                 input = g_strdup_printf ("TT %s\n", auth_header + 5);
318                 response = sso_ntlm_response (priv, input, conn->state);
319                 sso_ntlm_close (priv);
320                 g_free (input);
321
322                 if (!response) {
323                         conn->state = SOUP_NTLM_SSO_FAILED;
324                         success = FALSE;
325                 } else if (!g_ascii_strcasecmp (response, "PW")) {
326                         priv->sso_available = FALSE;
327                         g_free (response);
328                 } else {
329                         conn->response_header = response;
330                         priv->authenticated = TRUE;
331                 }
332         }
333  out:
334 #endif
335
336         if (conn->state == SOUP_NTLM_SENT_REQUEST)
337                 conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
338
339         g_object_set (G_OBJECT (auth),
340                       SOUP_AUTH_REALM, priv->domain,
341                       SOUP_AUTH_HOST, soup_message_get_uri (msg)->host,
342                       NULL);
343         return success;
344 }
345
346 static GSList *
347 soup_auth_ntlm_get_protection_space (SoupAuth *auth, SoupURI *source_uri)
348 {
349         char *space, *p;
350
351         space = g_strdup (source_uri->path);
352
353         /* Strip query and filename component */
354         p = strrchr (space, '/');
355         if (p && p != space && p[1])
356                 *p = '\0';
357
358         return g_slist_prepend (NULL, space);
359 }
360
361 static void
362 soup_auth_ntlm_authenticate (SoupAuth *auth, const char *username,
363                              const char *password)
364 {
365         SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (auth);
366         const char *slash;
367
368         g_return_if_fail (username != NULL);
369         g_return_if_fail (password != NULL);
370
371         if (priv->username)
372                 g_free (priv->username);
373         if (priv->domain)
374                 g_free (priv->domain);
375
376         slash = strpbrk (username, "\\/");
377         if (slash) {
378                 priv->domain = g_strndup (username, slash - username);
379                 priv->username = g_strdup (slash + 1);
380         } else {
381                 priv->domain = g_strdup ("");
382                 priv->username = g_strdup (username);
383         }
384
385         soup_ntlm_nt_hash (password, priv->nt_hash);
386         soup_ntlm_lanmanager_hash (password, priv->lm_hash);
387
388         priv->authenticated = TRUE;
389 }
390
391 static gboolean
392 soup_auth_ntlm_is_authenticated (SoupAuth *auth)
393 {
394         SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (auth);
395
396         return priv->authenticated;
397 }
398
399 static gboolean
400 soup_auth_ntlm_is_connection_ready (SoupConnectionAuth *auth,
401                                     SoupMessage        *msg,
402                                     gpointer            state)
403 {
404         SoupNTLMConnectionState *conn = state;
405
406         return conn->state != SOUP_NTLM_FAILED && conn->state != SOUP_NTLM_SSO_FAILED;
407 }
408
409 static char *
410 soup_auth_ntlm_get_connection_authorization (SoupConnectionAuth *auth,
411                                              SoupMessage        *msg,
412                                              gpointer            state)
413 {
414         SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (auth);
415         SoupNTLMConnectionState *conn = state;
416         char *header = NULL;
417
418         switch (conn->state) {
419         case SOUP_NTLM_NEW:
420 #ifdef USE_NTLM_AUTH
421                 if (sso_ntlm_initiate (priv)) {
422                         header = sso_ntlm_response (priv, "YR\n", conn->state);
423                         if (header) {
424                                 if (g_ascii_strcasecmp (header, "PW") != 0) {
425                                         conn->state = SOUP_NTLM_SENT_REQUEST;
426                                         break;
427                                 } else {
428                                         g_free (header);
429                                         header = NULL;
430                                         priv->sso_available = FALSE;
431                                 }
432                         } else {
433                                 g_warning ("NTLM single-sign-on using %s failed", NTLM_AUTH);
434                         }
435                 }
436                 /* If NTLM single-sign-on fails, go back to original
437                  * request handling process.
438                  */
439 #endif
440                 header = soup_ntlm_request ();
441                 conn->state = SOUP_NTLM_SENT_REQUEST;
442                 break;
443         case SOUP_NTLM_RECEIVED_CHALLENGE:
444                 if (conn->response_header) {
445                         header = conn->response_header;
446                         conn->response_header = NULL;
447                 } else {
448                         header = soup_ntlm_response (conn->nonce,
449                                                      priv->username,
450                                                      priv->nt_hash,
451                                                      priv->lm_hash,
452                                                      NULL,
453                                                      priv->domain);
454                 }
455                 g_clear_pointer (&conn->nonce, g_free);
456                 conn->state = SOUP_NTLM_SENT_RESPONSE;
457                 break;
458 #ifdef USE_NTLM_AUTH
459         case SOUP_NTLM_SSO_FAILED:
460                 /* Restart request without SSO */
461                 g_warning ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
462                 priv->sso_available = FALSE;
463                 header = soup_ntlm_request ();
464                 conn->state = SOUP_NTLM_SENT_REQUEST;
465                 break;
466 #endif
467         default:
468                 break;
469         }
470
471         return header;
472 }
473
474 static void
475 soup_auth_ntlm_class_init (SoupAuthNTLMClass *auth_ntlm_class)
476 {
477         SoupAuthClass *auth_class = SOUP_AUTH_CLASS (auth_ntlm_class);
478         SoupConnectionAuthClass *connauth_class = SOUP_CONNECTION_AUTH_CLASS (auth_ntlm_class);
479         GObjectClass *object_class = G_OBJECT_CLASS (auth_ntlm_class);
480
481         g_type_class_add_private (auth_ntlm_class, sizeof (SoupAuthNTLMPrivate));
482
483         auth_class->scheme_name = "NTLM";
484         auth_class->strength = 3;
485
486         auth_class->get_protection_space = soup_auth_ntlm_get_protection_space;
487         auth_class->authenticate = soup_auth_ntlm_authenticate;
488         auth_class->is_authenticated = soup_auth_ntlm_is_authenticated;
489
490         connauth_class->create_connection_state = soup_auth_ntlm_create_connection_state;
491         connauth_class->free_connection_state = soup_auth_ntlm_free_connection_state;
492         connauth_class->update_connection = soup_auth_ntlm_update_connection;
493         connauth_class->get_connection_authorization = soup_auth_ntlm_get_connection_authorization;
494         connauth_class->is_connection_ready = soup_auth_ntlm_is_connection_ready;
495
496         object_class->finalize = soup_auth_ntlm_finalize;
497
498 #ifdef USE_NTLM_AUTH
499         ntlm_auth_available = g_file_test (NTLM_AUTH, G_FILE_TEST_IS_EXECUTABLE);
500         ntlm_auth_debug = (g_getenv ("SOUP_NTLM_AUTH_DEBUG") != NULL);
501 #endif
502 }
503
504 static void md4sum                (const unsigned char *in, 
505                                    int                  nbytes, 
506                                    unsigned char        digest[16]);
507
508 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
509
510 static void deskey                (DES_KS, unsigned char *, int);
511
512 static void des                   (DES_KS, unsigned char *);
513
514 static void setup_schedule        (const guchar *key_56, DES_KS ks);
515
516 static void calc_response         (const guchar        *key, 
517                                    const guchar        *plaintext,
518                                    guchar              *results);
519
520 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
521                           "\x4B\x47\x53\x21\x40\x23\x24\x25" \
522                           "\x00\x00\x00\x00\x00"
523
524 static void
525 soup_ntlm_lanmanager_hash (const char *password, guchar hash[21])
526 {
527         guchar lm_password [15];
528         DES_KS ks;
529         int i;
530
531         for (i = 0; i < 14 && password [i]; i++)
532                 lm_password [i] = g_ascii_toupper ((unsigned char) password [i]);
533
534         for (; i < 15; i++)
535                 lm_password [i] = '\0';
536
537         memcpy (hash, LM_PASSWORD_MAGIC, 21);
538
539         setup_schedule (lm_password, ks);
540         des (ks, hash);
541
542         setup_schedule (lm_password + 7, ks);
543         des (ks, hash + 8);
544 }
545
546 static void
547 soup_ntlm_nt_hash (const char *password, guchar hash[21])
548 {
549         unsigned char *buf, *p;
550
551         p = buf = g_malloc (strlen (password) * 2);
552
553         while (*password) {
554                 *p++ = *password++;
555                 *p++ = '\0';
556         }
557
558         md4sum (buf, p - buf, hash);
559         memset (hash + 16, 0, 5);
560
561         g_free (buf);
562 }
563
564 typedef struct {
565         guint16 length;
566         guint16 length2;
567         guint16 offset;
568         guchar  zero_pad[2];
569 } NTLMString;
570
571 #define NTLM_CHALLENGE_NONCE_OFFSET         24
572 #define NTLM_CHALLENGE_NONCE_LENGTH          8
573 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
574
575 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
576 #define NTLM_RESPONSE_FLAGS 0x8201
577
578 typedef struct {
579         guchar     header[12];
580
581         NTLMString lm_resp;
582         NTLMString nt_resp;
583         NTLMString domain;
584         NTLMString user;
585         NTLMString host;
586         NTLMString session_key;
587
588         guint32    flags;
589 } NTLMResponse;
590
591 static void
592 ntlm_set_string (NTLMString *string, int *offset, int len)
593 {
594         string->offset = GUINT16_TO_LE (*offset);
595         string->length = string->length2 = GUINT16_TO_LE (len);
596         *offset += len;
597 }
598
599 static char *
600 soup_ntlm_request (void)
601 {
602         return g_strdup ("NTLM TlRMTVNTUAABAAAABYIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
603 }
604
605 static gboolean
606 soup_ntlm_parse_challenge (const char *challenge,
607                            char      **nonce,
608                            char      **default_domain)
609 {
610         gsize clen;
611         NTLMString domain;
612         guchar *chall;
613
614         chall = g_base64_decode (challenge, &clen);
615         if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET ||
616             clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) {
617                 g_free (chall);
618                 return FALSE;
619         }
620
621         if (default_domain) {
622                 memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
623                 domain.length = GUINT16_FROM_LE (domain.length);
624                 domain.offset = GUINT16_FROM_LE (domain.offset);
625
626                 if (clen < domain.length + domain.offset) {
627                         g_free (chall);
628                         return FALSE;
629                 }
630
631                 *default_domain = g_convert ((char *)chall + domain.offset,
632                                              domain.length, "UTF-8", "UCS-2LE",
633                                              NULL, NULL, NULL);
634         }
635
636         if (nonce) {
637                 *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
638                                    NTLM_CHALLENGE_NONCE_LENGTH);
639         }
640
641         g_free (chall);
642         return TRUE;
643 }
644
645 static char *
646 soup_ntlm_response (const char *nonce, 
647                     const char *user,
648                     guchar      nt_hash[21],
649                     guchar      lm_hash[21],
650                     const char *host, 
651                     const char *domain)
652 {
653         int offset;
654         gsize hlen, dlen, ulen;
655         guchar lm_resp[24], nt_resp[24];
656         char *user_conv, *host_conv, *domain_conv;
657         NTLMResponse resp;
658         char *out, *p;
659         int state, save;
660
661         calc_response (nt_hash, (guchar *)nonce, nt_resp);
662         calc_response (lm_hash, (guchar *)nonce, lm_resp);
663
664         memset (&resp, 0, sizeof (resp));
665         memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
666         resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
667
668         offset = sizeof (resp);
669
670         if (!host)
671                 host = "UNKNOWN";
672
673         domain_conv = g_convert (domain, -1, "UCS-2LE", "UTF-8", NULL, &dlen, NULL);
674         user_conv = g_convert (user, -1, "UCS-2LE", "UTF-8", NULL, &ulen, NULL);
675         host_conv = g_convert (host, -1, "UCS-2LE", "UTF-8", NULL, &hlen, NULL);
676
677         ntlm_set_string (&resp.domain, &offset, dlen);
678         ntlm_set_string (&resp.user, &offset, ulen);
679         ntlm_set_string (&resp.host, &offset, hlen);
680         ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
681         ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
682
683         out = g_malloc (((offset + 3) * 4) / 3 + 6);
684         strncpy (out, "NTLM ", 5);
685         p = out + 5;
686
687         state = save = 0;
688
689         p += g_base64_encode_step ((const guchar *) &resp, sizeof (resp), 
690                                    FALSE, p, &state, &save);
691         p += g_base64_encode_step ((const guchar *) domain_conv, dlen, 
692                                    FALSE, p, &state, &save);
693         p += g_base64_encode_step ((const guchar *) user_conv, ulen, 
694                                    FALSE, p, &state, &save);
695         p += g_base64_encode_step ((const guchar *) host_conv, hlen, 
696                                    FALSE, p, &state, &save);
697         p += g_base64_encode_step (lm_resp, sizeof (lm_resp), 
698                                    FALSE, p, &state, &save);
699         p += g_base64_encode_step (nt_resp, sizeof (nt_resp), 
700                                    FALSE, p, &state, &save);
701         p += g_base64_encode_close (FALSE, p, &state, &save);
702         *p = '\0';
703
704         g_free (domain_conv);
705         g_free (user_conv);
706         g_free (host_conv);
707
708         return out;
709 }
710
711 /* DES utils */
712 /* Set up a key schedule based on a 56bit key */
713 static void
714 setup_schedule (const guchar *key_56, DES_KS ks)
715 {
716         guchar key[8];
717         int i, c, bit;
718
719         key[0] = (key_56[0])                                 ;
720         key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
721         key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
722         key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
723         key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
724         key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
725         key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
726         key[7] =                    ((key_56[6] << 1) & 0xFF);
727
728         /* Fix parity */
729         for (i = 0; i < 8; i++) {
730                 for (c = bit = 0; bit < 8; bit++)
731                         if (key[i] & (1 << bit))
732                                 c++;
733                 if (!(c & 1))
734                         key[i] ^= 0x01;
735         }
736
737         deskey (ks, key, 0);
738 }
739
740 static void
741 calc_response (const guchar *key, const guchar *plaintext, guchar *results)
742 {
743         DES_KS ks;
744
745         memcpy (results, plaintext, 8);
746         memcpy (results + 8, plaintext, 8);
747         memcpy (results + 16, plaintext, 8);
748
749         setup_schedule (key, ks);
750         des (ks, results);
751
752         setup_schedule (key + 7, ks);
753         des (ks, results + 8);
754
755         setup_schedule (key + 14, ks);
756         des (ks, results + 16);
757 }
758
759
760 /* 
761  * MD4 encoder. (The one everyone else uses is not GPL-compatible;
762  * this is a reimplementation from spec.) This doesn't need to be
763  * efficient for our purposes, although it would be nice to fix
764  * it to not malloc()...
765  */
766
767 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
768 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
769 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
770 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
771
772 static void
773 md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
774 {
775         unsigned char *M;
776         guint32 A, B, C, D, AA, BB, CC, DD, X[16];
777         int pbytes, nbits = nbytes * 8, i, j;
778
779         pbytes = (120 - (nbytes % 64)) % 64;
780         M = alloca (nbytes + pbytes + 8);
781         memcpy (M, in, nbytes);
782         memset (M + nbytes, 0, pbytes + 8);
783         M[nbytes] = 0x80;
784         M[nbytes + pbytes] = nbits & 0xFF;
785         M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
786         M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
787         M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
788
789         A = 0x67452301;
790         B = 0xEFCDAB89;
791         C = 0x98BADCFE;
792         D = 0x10325476;
793
794         for (i = 0; i < nbytes + pbytes + 8; i += 64) {
795                 for (j = 0; j < 16; j++) {
796                         X[j] =  (M[i + j*4]) |
797                                 (M[i + j*4 + 1] << 8) |
798                                 (M[i + j*4 + 2] << 16) |
799                                 (M[i + j*4 + 3] << 24);
800                 }
801
802                 AA = A;
803                 BB = B;
804                 CC = C;
805                 DD = D;
806
807                 A = ROT (A + F(B, C, D) + X[0], 3);
808                 D = ROT (D + F(A, B, C) + X[1], 7);
809                 C = ROT (C + F(D, A, B) + X[2], 11);
810                 B = ROT (B + F(C, D, A) + X[3], 19);
811                 A = ROT (A + F(B, C, D) + X[4], 3);
812                 D = ROT (D + F(A, B, C) + X[5], 7);
813                 C = ROT (C + F(D, A, B) + X[6], 11);
814                 B = ROT (B + F(C, D, A) + X[7], 19);
815                 A = ROT (A + F(B, C, D) + X[8], 3);
816                 D = ROT (D + F(A, B, C) + X[9], 7);
817                 C = ROT (C + F(D, A, B) + X[10], 11);
818                 B = ROT (B + F(C, D, A) + X[11], 19);
819                 A = ROT (A + F(B, C, D) + X[12], 3);
820                 D = ROT (D + F(A, B, C) + X[13], 7);
821                 C = ROT (C + F(D, A, B) + X[14], 11);
822                 B = ROT (B + F(C, D, A) + X[15], 19);
823
824                 A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
825                 D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
826                 C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
827                 B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
828                 A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
829                 D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
830                 C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
831                 B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
832                 A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
833                 D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
834                 C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
835                 B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
836                 A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
837                 D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
838                 C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
839                 B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
840
841                 A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
842                 D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
843                 C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
844                 B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
845                 A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
846                 D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
847                 C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
848                 B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
849                 A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
850                 D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
851                 C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
852                 B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
853                 A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
854                 D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
855                 C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
856                 B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
857
858                 A += AA;
859                 B += BB;
860                 C += CC;
861                 D += DD;
862         }
863
864         digest[0]  =  A        & 0xFF;
865         digest[1]  = (A >>  8) & 0xFF;
866         digest[2]  = (A >> 16) & 0xFF;
867         digest[3]  = (A >> 24) & 0xFF;
868         digest[4]  =  B        & 0xFF;
869         digest[5]  = (B >>  8) & 0xFF;
870         digest[6]  = (B >> 16) & 0xFF;
871         digest[7]  = (B >> 24) & 0xFF;
872         digest[8]  =  C        & 0xFF;
873         digest[9]  = (C >>  8) & 0xFF;
874         digest[10] = (C >> 16) & 0xFF;
875         digest[11] = (C >> 24) & 0xFF;
876         digest[12] =  D        & 0xFF;
877         digest[13] = (D >>  8) & 0xFF;
878         digest[14] = (D >> 16) & 0xFF;
879         digest[15] = (D >> 24) & 0xFF;
880 }
881
882
883 /* Public domain DES implementation from Phil Karn */
884 static const guint32 Spbox[8][64] = {
885         { 0x01010400,0x00000000,0x00010000,0x01010404,
886           0x01010004,0x00010404,0x00000004,0x00010000,
887           0x00000400,0x01010400,0x01010404,0x00000400,
888           0x01000404,0x01010004,0x01000000,0x00000004,
889           0x00000404,0x01000400,0x01000400,0x00010400,
890           0x00010400,0x01010000,0x01010000,0x01000404,
891           0x00010004,0x01000004,0x01000004,0x00010004,
892           0x00000000,0x00000404,0x00010404,0x01000000,
893           0x00010000,0x01010404,0x00000004,0x01010000,
894           0x01010400,0x01000000,0x01000000,0x00000400,
895           0x01010004,0x00010000,0x00010400,0x01000004,
896           0x00000400,0x00000004,0x01000404,0x00010404,
897           0x01010404,0x00010004,0x01010000,0x01000404,
898           0x01000004,0x00000404,0x00010404,0x01010400,
899           0x00000404,0x01000400,0x01000400,0x00000000,
900           0x00010004,0x00010400,0x00000000,0x01010004 },
901         { 0x80108020,0x80008000,0x00008000,0x00108020,
902           0x00100000,0x00000020,0x80100020,0x80008020,
903           0x80000020,0x80108020,0x80108000,0x80000000,
904           0x80008000,0x00100000,0x00000020,0x80100020,
905           0x00108000,0x00100020,0x80008020,0x00000000,
906           0x80000000,0x00008000,0x00108020,0x80100000,
907           0x00100020,0x80000020,0x00000000,0x00108000,
908           0x00008020,0x80108000,0x80100000,0x00008020,
909           0x00000000,0x00108020,0x80100020,0x00100000,
910           0x80008020,0x80100000,0x80108000,0x00008000,
911           0x80100000,0x80008000,0x00000020,0x80108020,
912           0x00108020,0x00000020,0x00008000,0x80000000,
913           0x00008020,0x80108000,0x00100000,0x80000020,
914           0x00100020,0x80008020,0x80000020,0x00100020,
915           0x00108000,0x00000000,0x80008000,0x00008020,
916           0x80000000,0x80100020,0x80108020,0x00108000 },
917         { 0x00000208,0x08020200,0x00000000,0x08020008,
918           0x08000200,0x00000000,0x00020208,0x08000200,
919           0x00020008,0x08000008,0x08000008,0x00020000,
920           0x08020208,0x00020008,0x08020000,0x00000208,
921           0x08000000,0x00000008,0x08020200,0x00000200,
922           0x00020200,0x08020000,0x08020008,0x00020208,
923           0x08000208,0x00020200,0x00020000,0x08000208,
924           0x00000008,0x08020208,0x00000200,0x08000000,
925           0x08020200,0x08000000,0x00020008,0x00000208,
926           0x00020000,0x08020200,0x08000200,0x00000000,
927           0x00000200,0x00020008,0x08020208,0x08000200,
928           0x08000008,0x00000200,0x00000000,0x08020008,
929           0x08000208,0x00020000,0x08000000,0x08020208,
930           0x00000008,0x00020208,0x00020200,0x08000008,
931           0x08020000,0x08000208,0x00000208,0x08020000,
932           0x00020208,0x00000008,0x08020008,0x00020200 },
933         { 0x00802001,0x00002081,0x00002081,0x00000080,
934           0x00802080,0x00800081,0x00800001,0x00002001,
935           0x00000000,0x00802000,0x00802000,0x00802081,
936           0x00000081,0x00000000,0x00800080,0x00800001,
937           0x00000001,0x00002000,0x00800000,0x00802001,
938           0x00000080,0x00800000,0x00002001,0x00002080,
939           0x00800081,0x00000001,0x00002080,0x00800080,
940           0x00002000,0x00802080,0x00802081,0x00000081,
941           0x00800080,0x00800001,0x00802000,0x00802081,
942           0x00000081,0x00000000,0x00000000,0x00802000,
943           0x00002080,0x00800080,0x00800081,0x00000001,
944           0x00802001,0x00002081,0x00002081,0x00000080,
945           0x00802081,0x00000081,0x00000001,0x00002000,
946           0x00800001,0x00002001,0x00802080,0x00800081,
947           0x00002001,0x00002080,0x00800000,0x00802001,
948           0x00000080,0x00800000,0x00002000,0x00802080 },
949         { 0x00000100,0x02080100,0x02080000,0x42000100,
950           0x00080000,0x00000100,0x40000000,0x02080000,
951           0x40080100,0x00080000,0x02000100,0x40080100,
952           0x42000100,0x42080000,0x00080100,0x40000000,
953           0x02000000,0x40080000,0x40080000,0x00000000,
954           0x40000100,0x42080100,0x42080100,0x02000100,
955           0x42080000,0x40000100,0x00000000,0x42000000,
956           0x02080100,0x02000000,0x42000000,0x00080100,
957           0x00080000,0x42000100,0x00000100,0x02000000,
958           0x40000000,0x02080000,0x42000100,0x40080100,
959           0x02000100,0x40000000,0x42080000,0x02080100,
960           0x40080100,0x00000100,0x02000000,0x42080000,
961           0x42080100,0x00080100,0x42000000,0x42080100,
962           0x02080000,0x00000000,0x40080000,0x42000000,
963           0x00080100,0x02000100,0x40000100,0x00080000,
964           0x00000000,0x40080000,0x02080100,0x40000100 },
965         { 0x20000010,0x20400000,0x00004000,0x20404010,
966           0x20400000,0x00000010,0x20404010,0x00400000,
967           0x20004000,0x00404010,0x00400000,0x20000010,
968           0x00400010,0x20004000,0x20000000,0x00004010,
969           0x00000000,0x00400010,0x20004010,0x00004000,
970           0x00404000,0x20004010,0x00000010,0x20400010,
971           0x20400010,0x00000000,0x00404010,0x20404000,
972           0x00004010,0x00404000,0x20404000,0x20000000,
973           0x20004000,0x00000010,0x20400010,0x00404000,
974           0x20404010,0x00400000,0x00004010,0x20000010,
975           0x00400000,0x20004000,0x20000000,0x00004010,
976           0x20000010,0x20404010,0x00404000,0x20400000,
977           0x00404010,0x20404000,0x00000000,0x20400010,
978           0x00000010,0x00004000,0x20400000,0x00404010,
979           0x00004000,0x00400010,0x20004010,0x00000000,
980           0x20404000,0x20000000,0x00400010,0x20004010 },
981         { 0x00200000,0x04200002,0x04000802,0x00000000,
982           0x00000800,0x04000802,0x00200802,0x04200800,
983           0x04200802,0x00200000,0x00000000,0x04000002,
984           0x00000002,0x04000000,0x04200002,0x00000802,
985           0x04000800,0x00200802,0x00200002,0x04000800,
986           0x04000002,0x04200000,0x04200800,0x00200002,
987           0x04200000,0x00000800,0x00000802,0x04200802,
988           0x00200800,0x00000002,0x04000000,0x00200800,
989           0x04000000,0x00200800,0x00200000,0x04000802,
990           0x04000802,0x04200002,0x04200002,0x00000002,
991           0x00200002,0x04000000,0x04000800,0x00200000,
992           0x04200800,0x00000802,0x00200802,0x04200800,
993           0x00000802,0x04000002,0x04200802,0x04200000,
994           0x00200800,0x00000000,0x00000002,0x04200802,
995           0x00000000,0x00200802,0x04200000,0x00000800,
996           0x04000002,0x04000800,0x00000800,0x00200002 },
997         { 0x10001040,0x00001000,0x00040000,0x10041040,
998           0x10000000,0x10001040,0x00000040,0x10000000,
999           0x00040040,0x10040000,0x10041040,0x00041000,
1000           0x10041000,0x00041040,0x00001000,0x00000040,
1001           0x10040000,0x10000040,0x10001000,0x00001040,
1002           0x00041000,0x00040040,0x10040040,0x10041000,
1003           0x00001040,0x00000000,0x00000000,0x10040040,
1004           0x10000040,0x10001000,0x00041040,0x00040000,
1005           0x00041040,0x00040000,0x10041000,0x00001000,
1006           0x00000040,0x10040040,0x00001000,0x00041040,
1007           0x10001000,0x00000040,0x10000040,0x10040000,
1008           0x10040040,0x10000000,0x00040000,0x10001040,
1009           0x00000000,0x10041040,0x00040040,0x10000040,
1010           0x10040000,0x10001000,0x10001040,0x00000000,
1011           0x10041040,0x00041000,0x00041000,0x00001040,
1012           0x00001040,0x00040040,0x10000000,0x10041000 }
1013 };
1014
1015 #undef F
1016 #define F(l,r,key){\
1017         work = ((r >> 4) | (r << 28)) ^ key[0];\
1018         l ^= Spbox[6][work & 0x3f];\
1019         l ^= Spbox[4][(work >> 8) & 0x3f];\
1020         l ^= Spbox[2][(work >> 16) & 0x3f];\
1021         l ^= Spbox[0][(work >> 24) & 0x3f];\
1022         work = r ^ key[1];\
1023         l ^= Spbox[7][work & 0x3f];\
1024         l ^= Spbox[5][(work >> 8) & 0x3f];\
1025         l ^= Spbox[3][(work >> 16) & 0x3f];\
1026         l ^= Spbox[1][(work >> 24) & 0x3f];\
1027 }
1028 /* Encrypt or decrypt a block of data in ECB mode */
1029 static void
1030 des (guint32 ks[16][2], unsigned char block[8])
1031 {
1032         guint32 left,right,work;
1033         
1034         /* Read input block and place in left/right in big-endian order */
1035         left = ((guint32)block[0] << 24)
1036          | ((guint32)block[1] << 16)
1037          | ((guint32)block[2] << 8)
1038          | (guint32)block[3];
1039         right = ((guint32)block[4] << 24)
1040          | ((guint32)block[5] << 16)
1041          | ((guint32)block[6] << 8)
1042          | (guint32)block[7];
1043
1044         /* Hoey's clever initial permutation algorithm, from Outerbridge
1045          * (see Schneier p 478) 
1046          *
1047          * The convention here is the same as Outerbridge: rotate each
1048          * register left by 1 bit, i.e., so that "left" contains permuted
1049          * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32    
1050          * (using origin-1 numbering as in the FIPS). This allows us to avoid
1051          * one of the two rotates that would otherwise be required in each of
1052          * the 16 rounds.
1053          */
1054         work = ((left >> 4) ^ right) & 0x0f0f0f0f;
1055         right ^= work;
1056         left ^= work << 4;
1057         work = ((left >> 16) ^ right) & 0xffff;
1058         right ^= work;
1059         left ^= work << 16;
1060         work = ((right >> 2) ^ left) & 0x33333333;
1061         left ^= work;
1062         right ^= (work << 2);
1063         work = ((right >> 8) ^ left) & 0xff00ff;
1064         left ^= work;
1065         right ^= (work << 8);
1066         right = (right << 1) | (right >> 31);
1067         work = (left ^ right) & 0xaaaaaaaa;
1068         left ^= work;
1069         right ^= work;
1070         left = (left << 1) | (left >> 31);
1071
1072         /* Now do the 16 rounds */
1073         F(left,right,ks[0]);
1074         F(right,left,ks[1]);
1075         F(left,right,ks[2]);
1076         F(right,left,ks[3]);
1077         F(left,right,ks[4]);
1078         F(right,left,ks[5]);
1079         F(left,right,ks[6]);
1080         F(right,left,ks[7]);
1081         F(left,right,ks[8]);
1082         F(right,left,ks[9]);
1083         F(left,right,ks[10]);
1084         F(right,left,ks[11]);
1085         F(left,right,ks[12]);
1086         F(right,left,ks[13]);
1087         F(left,right,ks[14]);
1088         F(right,left,ks[15]);
1089
1090         /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
1091         right = (right << 31) | (right >> 1);
1092         work = (left ^ right) & 0xaaaaaaaa;
1093         left ^= work;
1094         right ^= work;
1095         left = (left >> 1) | (left  << 31);
1096         work = ((left >> 8) ^ right) & 0xff00ff;
1097         right ^= work;
1098         left ^= work << 8;
1099         work = ((left >> 2) ^ right) & 0x33333333;
1100         right ^= work;
1101         left ^= work << 2;
1102         work = ((right >> 16) ^ left) & 0xffff;
1103         left ^= work;
1104         right ^= work << 16;
1105         work = ((right >> 4) ^ left) & 0x0f0f0f0f;
1106         left ^= work;
1107         right ^= work << 4;
1108
1109         /* Put the block back into the user's buffer with final swap */
1110         block[0] = right >> 24;
1111         block[1] = right >> 16;
1112         block[2] = right >> 8;
1113         block[3] = right;
1114         block[4] = left >> 24;
1115         block[5] = left >> 16;
1116         block[6] = left >> 8;
1117         block[7] = left;
1118 }
1119
1120 /* Key schedule-related tables from FIPS-46 */
1121
1122 /* permuted choice table (key) */
1123 static const unsigned char pc1[] = {
1124         57, 49, 41, 33, 25, 17,  9,
1125          1, 58, 50, 42, 34, 26, 18,
1126         10,  2, 59, 51, 43, 35, 27,
1127         19, 11,  3, 60, 52, 44, 36,
1128
1129         63, 55, 47, 39, 31, 23, 15,
1130          7, 62, 54, 46, 38, 30, 22,
1131         14,  6, 61, 53, 45, 37, 29,
1132         21, 13,  5, 28, 20, 12,  4
1133 };
1134
1135 /* number left rotations of pc1 */
1136 static const unsigned char totrot[] = {
1137         1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
1138 };
1139
1140 /* permuted choice key (table) */
1141 static const unsigned char pc2[] = {
1142         14, 17, 11, 24,  1,  5,
1143          3, 28, 15,  6, 21, 10,
1144         23, 19, 12,  4, 26,  8,
1145         16,  7, 27, 20, 13,  2,
1146         41, 52, 31, 37, 47, 55,
1147         30, 40, 51, 45, 33, 48,
1148         44, 49, 39, 56, 34, 53,
1149         46, 42, 50, 36, 29, 32
1150 };
1151
1152 /* End of DES-defined tables */
1153
1154
1155 /* bit 0 is left-most in byte */
1156 static const int bytebit[] = {
1157         0200,0100,040,020,010,04,02,01
1158 };
1159
1160
1161 /* Generate key schedule for encryption or decryption
1162  * depending on the value of "decrypt"
1163  */
1164 static void
1165 deskey (DES_KS k, unsigned char *key, int decrypt)
1166 {
1167         unsigned char pc1m[56];         /* place to modify pc1 into */
1168         unsigned char pcr[56];          /* place to rotate pc1 into */
1169         register int i,j,l;
1170         int m;
1171         unsigned char ks[8];
1172
1173         for (j=0; j<56; j++) {          /* convert pc1 to bits of key */
1174                 l=pc1[j]-1;             /* integer bit location  */
1175                 m = l & 07;             /* find bit              */
1176                 pc1m[j]=(key[l>>3] &    /* find which key byte l is in */
1177                         bytebit[m])     /* and which bit of that byte */
1178                         ? 1 : 0;        /* and store 1-bit result */
1179         }
1180         for (i=0; i<16; i++) {          /* key chunk for each iteration */
1181                 memset(ks,0,sizeof(ks));        /* Clear key schedule */
1182                 for (j=0; j<56; j++)    /* rotate pc1 the right amount */
1183                         pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
1184                         /* rotate left and right halves independently */
1185                 for (j=0; j<48; j++){   /* select bits individually */
1186                         /* check bit that goes to ks[j] */
1187                         if (pcr[pc2[j]-1]){
1188                                 /* mask it in if it's there */
1189                                 l= j % 6;
1190                                 ks[j/6] |= bytebit[l] >> 2;
1191                         }
1192                 }
1193                 /* Now convert to packed odd/even interleaved form */
1194                 k[i][0] = ((guint32)ks[0] << 24)
1195                  | ((guint32)ks[2] << 16)
1196                  | ((guint32)ks[4] << 8)
1197                  | ((guint32)ks[6]);
1198                 k[i][1] = ((guint32)ks[1] << 24)
1199                  | ((guint32)ks[3] << 16)
1200                  | ((guint32)ks[5] << 8)
1201                  | ((guint32)ks[7]);
1202         }
1203 }