1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-auth-manager-ntlm.c: NTLM auth manager
5 * Copyright (C) 2001-2007 Novell, Inc.
6 * Copyright (C) 2008 Red Hat, Inc.
21 #include "soup-auth-manager-ntlm.h"
22 #include "soup-auth-ntlm.h"
23 #include "soup-message.h"
24 #include "soup-message-private.h"
25 #include "soup-misc.h"
26 #include "soup-session.h"
27 #include "soup-session-feature.h"
30 static void soup_auth_manager_ntlm_session_feature_init (SoupSessionFeatureInterface *feature_interface, gpointer interface_data);
31 static SoupSessionFeatureInterface *soup_auth_manager_parent_feature_interface;
33 static void attach (SoupSessionFeature *feature, SoupSession *session);
34 static void request_queued (SoupSessionFeature *feature, SoupSession *session,
36 static void request_started (SoupSessionFeature *feature, SoupSession *session,
37 SoupMessage *msg, SoupSocket *socket);
38 static void request_unqueued (SoupSessionFeature *feature,
39 SoupSession *session, SoupMessage *msg);
40 static gboolean add_feature (SoupSessionFeature *feature, GType type);
41 static gboolean remove_feature (SoupSessionFeature *feature, GType type);
42 static gboolean has_feature (SoupSessionFeature *feature, GType type);
44 G_DEFINE_TYPE_WITH_CODE (SoupAuthManagerNTLM, soup_auth_manager_ntlm, SOUP_TYPE_AUTH_MANAGER,
45 G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
46 soup_auth_manager_ntlm_session_feature_init))
51 SOUP_NTLM_SENT_SSO_REQUEST,
52 SOUP_NTLM_RECEIVED_SSO_CHALLENGE,
53 SOUP_NTLM_SENT_SSO_RESPONSE,
56 SOUP_NTLM_SENT_REQUEST,
57 SOUP_NTLM_RECEIVED_CHALLENGE,
58 SOUP_NTLM_SENT_RESPONSE,
65 char *response_header;
70 char *challenge_header;
80 GHashTable *connections_by_msg;
81 GHashTable *connections_by_id;
83 gboolean ntlm_auth_accessible;
85 } SoupAuthManagerNTLMPrivate;
86 #define SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH_MANAGER_NTLM, SoupAuthManagerNTLMPrivate))
88 static char *soup_ntlm_request (void);
89 static gboolean soup_ntlm_parse_challenge (const char *challenge,
91 char **default_domain);
92 static char *soup_ntlm_response (const char *nonce,
98 static void sso_ntlm_close (SoupNTLMConnection *conn);
102 soup_auth_manager_ntlm_init (SoupAuthManagerNTLM *ntlm)
104 SoupAuthManagerNTLMPrivate *priv =
105 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
107 priv->connections_by_id = g_hash_table_new (NULL, NULL);
108 priv->connections_by_msg = g_hash_table_new (NULL, NULL);
110 priv->ntlm_auth_accessible = (access (NTLM_AUTH, X_OK) == 0);
115 free_ntlm_connection (SoupNTLMConnection *conn)
117 g_free (conn->response_header);
118 g_free (conn->nonce);
119 g_free (conn->domain);
121 g_object_unref (conn->auth);
123 g_free (conn->challenge_header);
124 sso_ntlm_close (conn);
126 g_slice_free (SoupNTLMConnection, conn);
130 free_ntlm_connection_foreach (gpointer key, gpointer value, gpointer user_data)
132 free_ntlm_connection (value);
136 finalize (GObject *object)
138 SoupAuthManagerNTLMPrivate *priv =
139 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (object);
141 g_hash_table_foreach (priv->connections_by_id,
142 free_ntlm_connection_foreach, NULL);
143 g_hash_table_destroy (priv->connections_by_id);
144 g_hash_table_destroy (priv->connections_by_msg);
146 G_OBJECT_CLASS (soup_auth_manager_ntlm_parent_class)->finalize (object);
150 soup_auth_manager_ntlm_class_init (SoupAuthManagerNTLMClass *auth_manager_ntlm_class)
152 GObjectClass *object_class = G_OBJECT_CLASS (auth_manager_ntlm_class);
154 g_type_class_add_private (auth_manager_ntlm_class, sizeof (SoupAuthManagerNTLMPrivate));
156 object_class->finalize = finalize;
160 soup_auth_manager_ntlm_session_feature_init (SoupSessionFeatureInterface *feature_interface,
161 gpointer interface_data)
163 soup_auth_manager_parent_feature_interface =
164 g_type_interface_peek_parent (feature_interface);
166 feature_interface->attach = attach;
167 feature_interface->request_queued = request_queued;
168 feature_interface->request_started = request_started;
169 feature_interface->request_unqueued = request_unqueued;
170 feature_interface->add_feature = add_feature;
171 feature_interface->remove_feature = remove_feature;
172 feature_interface->has_feature = has_feature;
176 attach (SoupSessionFeature *manager, SoupSession *session)
178 SoupAuthManagerNTLMPrivate *priv =
179 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (manager);
181 /* FIXME: should support multiple sessions */
182 priv->session = session;
184 soup_auth_manager_parent_feature_interface->attach (manager, session);
188 delete_conn (SoupSocket *socket, gpointer user_data)
190 SoupAuthManagerNTLMPrivate *priv = user_data;
191 SoupNTLMConnection *conn;
193 conn = g_hash_table_lookup (priv->connections_by_id, socket);
195 free_ntlm_connection (conn);
196 g_hash_table_remove (priv->connections_by_id, socket);
197 g_signal_handlers_disconnect_by_func (socket, delete_conn, priv);
200 static SoupNTLMConnection *
201 get_connection (SoupAuthManagerNTLMPrivate *priv, SoupSocket *socket)
203 SoupNTLMConnection *conn;
205 conn = g_hash_table_lookup (priv->connections_by_id, socket);
209 conn = g_slice_new0 (SoupNTLMConnection);
210 conn->socket = socket;
211 conn->state = SOUP_NTLM_NEW;
216 g_hash_table_insert (priv->connections_by_id, socket, conn);
218 g_signal_connect (socket, "disconnected",
219 G_CALLBACK (delete_conn), priv);
224 unset_conn (SoupMessage *msg, gpointer user_data)
226 SoupAuthManagerNTLMPrivate *priv = user_data;
228 g_hash_table_remove (priv->connections_by_msg, msg);
229 g_signal_handlers_disconnect_by_func (msg, unset_conn, priv);
232 static SoupNTLMConnection *
233 set_connection_for_msg (SoupAuthManagerNTLMPrivate *priv, SoupMessage *msg,
234 SoupNTLMConnection *conn)
236 if (!g_hash_table_lookup (priv->connections_by_msg, msg)) {
237 g_signal_connect (msg, "finished",
238 G_CALLBACK (unset_conn), priv);
239 g_signal_connect (msg, "restarted",
240 G_CALLBACK (unset_conn), priv);
242 g_hash_table_insert (priv->connections_by_msg, msg, conn);
247 static SoupNTLMConnection *
248 get_connection_for_msg (SoupAuthManagerNTLMPrivate *priv, SoupMessage *msg)
250 return g_hash_table_lookup (priv->connections_by_msg, msg);
255 sso_ntlm_close (SoupNTLMConnection *conn)
257 if (conn->fd_in != -1) {
262 if (conn->fd_out != -1) {
263 close (conn->fd_out);
269 sso_ntlm_initiate (SoupNTLMConnection *conn, SoupAuthManagerNTLMPrivate *priv)
271 char *username = NULL, *slash, *domain = NULL;
275 /* Return if ntlm_auth execution process exist already */
276 if (conn->fd_in != -1 && conn->fd_out != -1)
279 /* Clean all sso data before re-initiate */
280 sso_ntlm_close (conn);
282 if (!priv->ntlm_auth_accessible)
285 username = getenv ("NTLMUSER");
287 username = getenv ("USER");
291 slash = strpbrk (username, "\\/");
293 domain = g_strdup (username);
294 slash = domain + (slash - username);
296 username = slash + 1;
300 argv[1] = "--helper-protocol";
301 argv[2] = "ntlmssp-client-1";
302 argv[3] = "--use-cached-creds";
303 argv[4] = "--username";
305 argv[6] = domain ? "--domain" : NULL;
308 /* Spawn child process */
309 ret = g_spawn_async_with_pipes (NULL, argv, NULL,
310 G_SPAWN_FILE_AND_ARGV_ZERO,
312 NULL, &conn->fd_in, &conn->fd_out,
324 sso_ntlm_response (SoupNTLMConnection *conn, const char *input, SoupNTLMState conn_state)
327 char buf[1024], *response = NULL;
329 size_t len_in = strlen (input), len_out = sizeof (buf);
332 int written = write (conn->fd_in, input, len_in);
334 /* Interrupted by a signal, retry it */
337 /* write failed if other errors happen */
344 while (len_out > 0) {
345 size = read (conn->fd_out, tmpbuf, len_out);
350 } else if (size == 0)
352 else if (tmpbuf[size - 1] == '\n') {
353 tmpbuf[size - 1] = '\0';
361 if (conn_state == SOUP_NTLM_NEW &&
362 g_ascii_strcasecmp (buf, "PW") == 0) {
363 /* Samba/winbind installed but not configured */
364 response = g_strdup ("PW");
367 if (conn_state == SOUP_NTLM_NEW &&
368 g_ascii_strncasecmp (buf, "YR ", 3) != 0)
369 /* invalid response for type 1 message */
371 if (conn_state == SOUP_NTLM_RECEIVED_SSO_CHALLENGE &&
372 g_ascii_strncasecmp (buf, "KK ", 3) != 0 &&
373 g_ascii_strncasecmp (buf, "AF ", 3) != 0)
374 /* invalid response for type 3 message */
377 response = g_strdup_printf ("NTLM %.*s", (int)(size - 4), buf + 3);
382 #endif /* USE_NTLM_AUTH */
385 ntlm_authorize_pre (SoupMessage *msg, gpointer ntlm)
387 SoupAuthManagerNTLMPrivate *priv =
388 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
389 SoupNTLMConnection *conn;
393 conn = get_connection_for_msg (priv, msg);
397 val = soup_message_headers_get_list (msg->response_headers,
400 val = strstr (val, "NTLM ");
404 if (conn->state > SOUP_NTLM_SENT_REQUEST) {
405 /* We already authenticated, but then got another 401.
406 * That means "permission denied", so don't try to
407 * authenticate again.
409 conn->state = SOUP_NTLM_FAILED;
413 if (!soup_ntlm_parse_challenge (val, &conn->nonce, &conn->domain)) {
414 conn->state = SOUP_NTLM_FAILED;
418 conn->auth = soup_auth_ntlm_new (conn->domain,
419 soup_message_get_uri (msg)->host);
421 conn->challenge_header = g_strdup (val + 5);
422 if (conn->state == SOUP_NTLM_SENT_SSO_REQUEST) {
423 conn->state = SOUP_NTLM_RECEIVED_SSO_CHALLENGE;
427 conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
429 uri = soup_message_get_uri (msg);
431 soup_auth_authenticate (conn->auth, uri->user, uri->password);
433 soup_auth_manager_emit_authenticate (SOUP_AUTH_MANAGER (ntlm),
434 msg, conn->auth, FALSE);
438 /* Remove the WWW-Authenticate headers so the session won't try
439 * to do Basic auth too.
441 soup_message_headers_remove (msg->response_headers, "WWW-Authenticate");
445 ntlm_authorize_post (SoupMessage *msg, gpointer ntlm)
447 SoupAuthManagerNTLMPrivate *priv =
448 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
449 SoupNTLMConnection *conn;
450 const char *username = NULL, *password = NULL;
451 char *slash, *domain = NULL;
452 SoupMessageFlags flags;
454 conn = get_connection_for_msg (priv, msg);
455 if (!conn || !conn->auth)
459 if (conn->state == SOUP_NTLM_RECEIVED_SSO_CHALLENGE) {
461 input = g_strdup_printf ("TT %s\n", conn->challenge_header);
462 /* Re-Initiate ntlm_auth process in case it was closed/killed abnormally */
463 if (sso_ntlm_initiate (conn, priv)) {
464 conn->response_header = sso_ntlm_response (conn,
467 /* Close ntlm_auth as it is no longer needed for current connection */
468 sso_ntlm_close (conn);
469 if (!conn->response_header) {
473 soup_session_requeue_message (priv->session, msg);
478 conn->state = SOUP_NTLM_SSO_FAILED;
479 soup_session_requeue_message (priv->session, msg);
483 username = soup_auth_ntlm_get_username (conn->auth);
484 password = soup_auth_ntlm_get_password (conn->auth);
485 if (!username || !password)
488 slash = strpbrk (username, "\\/");
490 domain = g_strdup (username);
491 slash = domain + (slash - username);
493 username = slash + 1;
495 domain = conn->domain;
497 conn->response_header = soup_ntlm_response (conn->nonce,
501 flags = soup_message_get_flags (msg);
502 soup_message_set_flags (msg, flags & ~SOUP_MESSAGE_NEW_CONNECTION);
503 soup_session_requeue_message (priv->session, msg);
506 if (domain != conn->domain)
508 g_free (conn->domain);
510 g_free (conn->nonce);
512 g_object_unref (conn->auth);
517 request_queued (SoupSessionFeature *ntlm, SoupSession *session, SoupMessage *msg)
519 SoupAuthManagerNTLMPrivate *priv =
520 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
522 if (priv->use_ntlm) {
523 soup_message_add_status_code_handler (
524 msg, "got_headers", SOUP_STATUS_UNAUTHORIZED,
525 G_CALLBACK (ntlm_authorize_pre), ntlm);
526 soup_message_add_status_code_handler (
527 msg, "got_body", SOUP_STATUS_UNAUTHORIZED,
528 G_CALLBACK (ntlm_authorize_post), ntlm);
531 soup_auth_manager_parent_feature_interface->request_queued (ntlm, session, msg);
535 request_started (SoupSessionFeature *ntlm, SoupSession *session,
536 SoupMessage *msg, SoupSocket *socket)
538 SoupAuthManagerNTLMPrivate *priv =
539 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
540 SoupNTLMConnection *conn;
546 conn = get_connection (priv, socket);
547 set_connection_for_msg (priv, msg, conn);
549 switch (conn->state) {
552 /* Use Samba's 'winbind' daemon to support NTLM single-sign-on,
553 * by delegating the NTLM challenge/response protocal to a helper
555 * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
556 * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
557 * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
558 * The preprocessor variable 'USE_NTLM_AUTH' indicates whether
559 * this feature is enabled. Another one 'NTLM_AUTH' contains absolute
561 * If NTLM single-sign-on fails, go back to original request handling process.
563 if (sso_ntlm_initiate (conn, priv)) {
564 header = sso_ntlm_response (conn, "YR\n", conn->state);
566 if (g_ascii_strcasecmp (header, "PW") != 0) {
567 conn->state = SOUP_NTLM_SENT_SSO_REQUEST;
575 g_warning ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
581 header = soup_ntlm_request ();
582 conn->state = SOUP_NTLM_SENT_REQUEST;
585 case SOUP_NTLM_RECEIVED_SSO_CHALLENGE:
586 header = conn->response_header;
587 conn->response_header = NULL;
588 conn->state = SOUP_NTLM_SENT_SSO_RESPONSE;
590 case SOUP_NTLM_SSO_FAILED:
591 /* Restart request without SSO */
592 g_warning ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
593 header = soup_ntlm_request ();
594 conn->state = SOUP_NTLM_SENT_REQUEST;
597 case SOUP_NTLM_RECEIVED_CHALLENGE:
598 header = conn->response_header;
599 conn->response_header = NULL;
600 conn->state = SOUP_NTLM_SENT_RESPONSE;
606 if (header && !soup_message_get_auth (msg)) {
607 soup_message_headers_replace (msg->request_headers,
608 "Authorization", header);
613 soup_auth_manager_parent_feature_interface->request_started (ntlm, session, msg, socket);
617 request_unqueued (SoupSessionFeature *ntlm, SoupSession *session,
620 g_signal_handlers_disconnect_by_func (msg, ntlm_authorize_pre, ntlm);
621 g_signal_handlers_disconnect_by_func (msg, ntlm_authorize_post, ntlm);
623 soup_auth_manager_parent_feature_interface->request_unqueued (ntlm, session, msg);
627 add_feature (SoupSessionFeature *feature, GType type)
629 SoupAuthManagerNTLMPrivate *priv =
630 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
632 if (type == SOUP_TYPE_AUTH_NTLM) {
633 priv->use_ntlm = TRUE;
637 return soup_auth_manager_parent_feature_interface->add_feature (feature, type);
641 remove_feature (SoupSessionFeature *feature, GType type)
643 SoupAuthManagerNTLMPrivate *priv =
644 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
646 if (type == SOUP_TYPE_AUTH_NTLM) {
647 priv->use_ntlm = FALSE;
651 return soup_auth_manager_parent_feature_interface->remove_feature (feature, type);
655 has_feature (SoupSessionFeature *feature, GType type)
657 SoupAuthManagerNTLMPrivate *priv =
658 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
660 if (type == SOUP_TYPE_AUTH_NTLM)
661 return priv->use_ntlm;
663 return soup_auth_manager_parent_feature_interface->has_feature (feature, type);
668 static void md4sum (const unsigned char *in,
670 unsigned char digest[16]);
672 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
674 static void deskey (DES_KS, unsigned char *, int);
676 static void des (DES_KS, unsigned char *);
678 static void setup_schedule (const guchar *key_56, DES_KS ks);
680 static void calc_response (const guchar *key,
681 const guchar *plaintext,
684 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
685 "\x4B\x47\x53\x21\x40\x23\x24\x25" \
686 "\x00\x00\x00\x00\x00"
689 lanmanager_hash (const char *password, guchar hash[21])
691 guchar lm_password [15];
695 for (i = 0; i < 14 && password [i]; i++)
696 lm_password [i] = toupper ((unsigned char) password [i]);
699 lm_password [i] = '\0';
701 memcpy (hash, LM_PASSWORD_MAGIC, 21);
703 setup_schedule (lm_password, ks);
706 setup_schedule (lm_password + 7, ks);
711 nt_hash (const char *password, guchar hash[21])
713 unsigned char *buf, *p;
715 p = buf = g_malloc (strlen (password) * 2);
722 md4sum (buf, p - buf, hash);
723 memset (hash + 16, 0, 5);
735 #define NTLM_CHALLENGE_NONCE_OFFSET 24
736 #define NTLM_CHALLENGE_NONCE_LENGTH 8
737 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
739 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
740 #define NTLM_RESPONSE_FLAGS 0x8201
750 NTLMString session_key;
756 ntlm_set_string (NTLMString *string, int *offset, int len)
758 string->offset = GUINT16_TO_LE (*offset);
759 string->length = string->length2 = GUINT16_TO_LE (len);
764 soup_ntlm_request (void)
766 return g_strdup ("NTLM TlRMTVNTUAABAAAABYIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
770 soup_ntlm_parse_challenge (const char *challenge,
772 char **default_domain)
778 if (strncmp (challenge, "NTLM ", 5) != 0)
781 chall = g_base64_decode (challenge + 5, &clen);
782 if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET ||
783 clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) {
788 if (default_domain) {
789 memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
790 domain.length = GUINT16_FROM_LE (domain.length);
791 domain.offset = GUINT16_FROM_LE (domain.offset);
793 if (clen < domain.length + domain.offset) {
798 *default_domain = g_convert ((char *)chall + domain.offset,
799 domain.length, "UTF-8", "UCS-2LE",
804 *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
805 NTLM_CHALLENGE_NONCE_LENGTH);
813 soup_ntlm_response (const char *nonce,
815 const char *password,
820 gsize hlen, dlen, ulen;
821 guchar hash[21], lm_resp[24], nt_resp[24];
822 char *user_conv, *host_conv, *domain_conv;
827 nt_hash (password, hash);
828 calc_response (hash, (guchar *)nonce, nt_resp);
829 lanmanager_hash (password, hash);
830 calc_response (hash, (guchar *)nonce, lm_resp);
832 memset (&resp, 0, sizeof (resp));
833 memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
834 resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
836 offset = sizeof (resp);
841 domain_conv = g_convert (domain, -1, "UCS-2LE", "UTF-8", NULL, &dlen, NULL);
842 user_conv = g_convert (user, -1, "UCS-2LE", "UTF-8", NULL, &ulen, NULL);
843 host_conv = g_convert (host, -1, "UCS-2LE", "UTF-8", NULL, &hlen, NULL);
845 ntlm_set_string (&resp.domain, &offset, dlen);
846 ntlm_set_string (&resp.user, &offset, ulen);
847 ntlm_set_string (&resp.host, &offset, hlen);
848 ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
849 ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
851 out = g_malloc (((offset + 3) * 4) / 3 + 6);
852 strncpy (out, "NTLM ", 5);
857 p += g_base64_encode_step ((const guchar *) &resp, sizeof (resp),
858 FALSE, p, &state, &save);
859 p += g_base64_encode_step ((const guchar *) domain_conv, dlen,
860 FALSE, p, &state, &save);
861 p += g_base64_encode_step ((const guchar *) user_conv, ulen,
862 FALSE, p, &state, &save);
863 p += g_base64_encode_step ((const guchar *) host_conv, hlen,
864 FALSE, p, &state, &save);
865 p += g_base64_encode_step (lm_resp, sizeof (lm_resp),
866 FALSE, p, &state, &save);
867 p += g_base64_encode_step (nt_resp, sizeof (nt_resp),
868 FALSE, p, &state, &save);
869 p += g_base64_encode_close (FALSE, p, &state, &save);
872 g_free (domain_conv);
880 /* Set up a key schedule based on a 56bit key */
882 setup_schedule (const guchar *key_56, DES_KS ks)
887 key[0] = (key_56[0]) ;
888 key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
889 key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
890 key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
891 key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
892 key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
893 key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
894 key[7] = ((key_56[6] << 1) & 0xFF);
897 for (i = 0; i < 8; i++) {
898 for (c = bit = 0; bit < 8; bit++)
899 if (key[i] & (1 << bit))
909 calc_response (const guchar *key, const guchar *plaintext, guchar *results)
913 memcpy (results, plaintext, 8);
914 memcpy (results + 8, plaintext, 8);
915 memcpy (results + 16, plaintext, 8);
917 setup_schedule (key, ks);
920 setup_schedule (key + 7, ks);
921 des (ks, results + 8);
923 setup_schedule (key + 14, ks);
924 des (ks, results + 16);
929 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
930 * this is a reimplementation from spec.) This doesn't need to be
931 * efficient for our purposes, although it would be nice to fix
932 * it to not malloc()...
935 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
936 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
937 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
938 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
941 md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
944 guint32 A, B, C, D, AA, BB, CC, DD, X[16];
945 int pbytes, nbits = nbytes * 8, i, j;
947 pbytes = (120 - (nbytes % 64)) % 64;
948 M = alloca (nbytes + pbytes + 8);
949 memcpy (M, in, nbytes);
950 memset (M + nbytes, 0, pbytes + 8);
952 M[nbytes + pbytes] = nbits & 0xFF;
953 M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
954 M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
955 M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
962 for (i = 0; i < nbytes + pbytes + 8; i += 64) {
963 for (j = 0; j < 16; j++) {
964 X[j] = (M[i + j*4]) |
965 (M[i + j*4 + 1] << 8) |
966 (M[i + j*4 + 2] << 16) |
967 (M[i + j*4 + 3] << 24);
975 A = ROT (A + F(B, C, D) + X[0], 3);
976 D = ROT (D + F(A, B, C) + X[1], 7);
977 C = ROT (C + F(D, A, B) + X[2], 11);
978 B = ROT (B + F(C, D, A) + X[3], 19);
979 A = ROT (A + F(B, C, D) + X[4], 3);
980 D = ROT (D + F(A, B, C) + X[5], 7);
981 C = ROT (C + F(D, A, B) + X[6], 11);
982 B = ROT (B + F(C, D, A) + X[7], 19);
983 A = ROT (A + F(B, C, D) + X[8], 3);
984 D = ROT (D + F(A, B, C) + X[9], 7);
985 C = ROT (C + F(D, A, B) + X[10], 11);
986 B = ROT (B + F(C, D, A) + X[11], 19);
987 A = ROT (A + F(B, C, D) + X[12], 3);
988 D = ROT (D + F(A, B, C) + X[13], 7);
989 C = ROT (C + F(D, A, B) + X[14], 11);
990 B = ROT (B + F(C, D, A) + X[15], 19);
992 A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
993 D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
994 C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
995 B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
996 A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
997 D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
998 C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
999 B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
1000 A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
1001 D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
1002 C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
1003 B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
1004 A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
1005 D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
1006 C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
1007 B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
1009 A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
1010 D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
1011 C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
1012 B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
1013 A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
1014 D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
1015 C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
1016 B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
1017 A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
1018 D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
1019 C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
1020 B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
1021 A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
1022 D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
1023 C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
1024 B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
1032 digest[0] = A & 0xFF;
1033 digest[1] = (A >> 8) & 0xFF;
1034 digest[2] = (A >> 16) & 0xFF;
1035 digest[3] = (A >> 24) & 0xFF;
1036 digest[4] = B & 0xFF;
1037 digest[5] = (B >> 8) & 0xFF;
1038 digest[6] = (B >> 16) & 0xFF;
1039 digest[7] = (B >> 24) & 0xFF;
1040 digest[8] = C & 0xFF;
1041 digest[9] = (C >> 8) & 0xFF;
1042 digest[10] = (C >> 16) & 0xFF;
1043 digest[11] = (C >> 24) & 0xFF;
1044 digest[12] = D & 0xFF;
1045 digest[13] = (D >> 8) & 0xFF;
1046 digest[14] = (D >> 16) & 0xFF;
1047 digest[15] = (D >> 24) & 0xFF;
1051 /* Public domain DES implementation from Phil Karn */
1052 static const guint32 Spbox[8][64] = {
1053 { 0x01010400,0x00000000,0x00010000,0x01010404,
1054 0x01010004,0x00010404,0x00000004,0x00010000,
1055 0x00000400,0x01010400,0x01010404,0x00000400,
1056 0x01000404,0x01010004,0x01000000,0x00000004,
1057 0x00000404,0x01000400,0x01000400,0x00010400,
1058 0x00010400,0x01010000,0x01010000,0x01000404,
1059 0x00010004,0x01000004,0x01000004,0x00010004,
1060 0x00000000,0x00000404,0x00010404,0x01000000,
1061 0x00010000,0x01010404,0x00000004,0x01010000,
1062 0x01010400,0x01000000,0x01000000,0x00000400,
1063 0x01010004,0x00010000,0x00010400,0x01000004,
1064 0x00000400,0x00000004,0x01000404,0x00010404,
1065 0x01010404,0x00010004,0x01010000,0x01000404,
1066 0x01000004,0x00000404,0x00010404,0x01010400,
1067 0x00000404,0x01000400,0x01000400,0x00000000,
1068 0x00010004,0x00010400,0x00000000,0x01010004 },
1069 { 0x80108020,0x80008000,0x00008000,0x00108020,
1070 0x00100000,0x00000020,0x80100020,0x80008020,
1071 0x80000020,0x80108020,0x80108000,0x80000000,
1072 0x80008000,0x00100000,0x00000020,0x80100020,
1073 0x00108000,0x00100020,0x80008020,0x00000000,
1074 0x80000000,0x00008000,0x00108020,0x80100000,
1075 0x00100020,0x80000020,0x00000000,0x00108000,
1076 0x00008020,0x80108000,0x80100000,0x00008020,
1077 0x00000000,0x00108020,0x80100020,0x00100000,
1078 0x80008020,0x80100000,0x80108000,0x00008000,
1079 0x80100000,0x80008000,0x00000020,0x80108020,
1080 0x00108020,0x00000020,0x00008000,0x80000000,
1081 0x00008020,0x80108000,0x00100000,0x80000020,
1082 0x00100020,0x80008020,0x80000020,0x00100020,
1083 0x00108000,0x00000000,0x80008000,0x00008020,
1084 0x80000000,0x80100020,0x80108020,0x00108000 },
1085 { 0x00000208,0x08020200,0x00000000,0x08020008,
1086 0x08000200,0x00000000,0x00020208,0x08000200,
1087 0x00020008,0x08000008,0x08000008,0x00020000,
1088 0x08020208,0x00020008,0x08020000,0x00000208,
1089 0x08000000,0x00000008,0x08020200,0x00000200,
1090 0x00020200,0x08020000,0x08020008,0x00020208,
1091 0x08000208,0x00020200,0x00020000,0x08000208,
1092 0x00000008,0x08020208,0x00000200,0x08000000,
1093 0x08020200,0x08000000,0x00020008,0x00000208,
1094 0x00020000,0x08020200,0x08000200,0x00000000,
1095 0x00000200,0x00020008,0x08020208,0x08000200,
1096 0x08000008,0x00000200,0x00000000,0x08020008,
1097 0x08000208,0x00020000,0x08000000,0x08020208,
1098 0x00000008,0x00020208,0x00020200,0x08000008,
1099 0x08020000,0x08000208,0x00000208,0x08020000,
1100 0x00020208,0x00000008,0x08020008,0x00020200 },
1101 { 0x00802001,0x00002081,0x00002081,0x00000080,
1102 0x00802080,0x00800081,0x00800001,0x00002001,
1103 0x00000000,0x00802000,0x00802000,0x00802081,
1104 0x00000081,0x00000000,0x00800080,0x00800001,
1105 0x00000001,0x00002000,0x00800000,0x00802001,
1106 0x00000080,0x00800000,0x00002001,0x00002080,
1107 0x00800081,0x00000001,0x00002080,0x00800080,
1108 0x00002000,0x00802080,0x00802081,0x00000081,
1109 0x00800080,0x00800001,0x00802000,0x00802081,
1110 0x00000081,0x00000000,0x00000000,0x00802000,
1111 0x00002080,0x00800080,0x00800081,0x00000001,
1112 0x00802001,0x00002081,0x00002081,0x00000080,
1113 0x00802081,0x00000081,0x00000001,0x00002000,
1114 0x00800001,0x00002001,0x00802080,0x00800081,
1115 0x00002001,0x00002080,0x00800000,0x00802001,
1116 0x00000080,0x00800000,0x00002000,0x00802080 },
1117 { 0x00000100,0x02080100,0x02080000,0x42000100,
1118 0x00080000,0x00000100,0x40000000,0x02080000,
1119 0x40080100,0x00080000,0x02000100,0x40080100,
1120 0x42000100,0x42080000,0x00080100,0x40000000,
1121 0x02000000,0x40080000,0x40080000,0x00000000,
1122 0x40000100,0x42080100,0x42080100,0x02000100,
1123 0x42080000,0x40000100,0x00000000,0x42000000,
1124 0x02080100,0x02000000,0x42000000,0x00080100,
1125 0x00080000,0x42000100,0x00000100,0x02000000,
1126 0x40000000,0x02080000,0x42000100,0x40080100,
1127 0x02000100,0x40000000,0x42080000,0x02080100,
1128 0x40080100,0x00000100,0x02000000,0x42080000,
1129 0x42080100,0x00080100,0x42000000,0x42080100,
1130 0x02080000,0x00000000,0x40080000,0x42000000,
1131 0x00080100,0x02000100,0x40000100,0x00080000,
1132 0x00000000,0x40080000,0x02080100,0x40000100 },
1133 { 0x20000010,0x20400000,0x00004000,0x20404010,
1134 0x20400000,0x00000010,0x20404010,0x00400000,
1135 0x20004000,0x00404010,0x00400000,0x20000010,
1136 0x00400010,0x20004000,0x20000000,0x00004010,
1137 0x00000000,0x00400010,0x20004010,0x00004000,
1138 0x00404000,0x20004010,0x00000010,0x20400010,
1139 0x20400010,0x00000000,0x00404010,0x20404000,
1140 0x00004010,0x00404000,0x20404000,0x20000000,
1141 0x20004000,0x00000010,0x20400010,0x00404000,
1142 0x20404010,0x00400000,0x00004010,0x20000010,
1143 0x00400000,0x20004000,0x20000000,0x00004010,
1144 0x20000010,0x20404010,0x00404000,0x20400000,
1145 0x00404010,0x20404000,0x00000000,0x20400010,
1146 0x00000010,0x00004000,0x20400000,0x00404010,
1147 0x00004000,0x00400010,0x20004010,0x00000000,
1148 0x20404000,0x20000000,0x00400010,0x20004010 },
1149 { 0x00200000,0x04200002,0x04000802,0x00000000,
1150 0x00000800,0x04000802,0x00200802,0x04200800,
1151 0x04200802,0x00200000,0x00000000,0x04000002,
1152 0x00000002,0x04000000,0x04200002,0x00000802,
1153 0x04000800,0x00200802,0x00200002,0x04000800,
1154 0x04000002,0x04200000,0x04200800,0x00200002,
1155 0x04200000,0x00000800,0x00000802,0x04200802,
1156 0x00200800,0x00000002,0x04000000,0x00200800,
1157 0x04000000,0x00200800,0x00200000,0x04000802,
1158 0x04000802,0x04200002,0x04200002,0x00000002,
1159 0x00200002,0x04000000,0x04000800,0x00200000,
1160 0x04200800,0x00000802,0x00200802,0x04200800,
1161 0x00000802,0x04000002,0x04200802,0x04200000,
1162 0x00200800,0x00000000,0x00000002,0x04200802,
1163 0x00000000,0x00200802,0x04200000,0x00000800,
1164 0x04000002,0x04000800,0x00000800,0x00200002 },
1165 { 0x10001040,0x00001000,0x00040000,0x10041040,
1166 0x10000000,0x10001040,0x00000040,0x10000000,
1167 0x00040040,0x10040000,0x10041040,0x00041000,
1168 0x10041000,0x00041040,0x00001000,0x00000040,
1169 0x10040000,0x10000040,0x10001000,0x00001040,
1170 0x00041000,0x00040040,0x10040040,0x10041000,
1171 0x00001040,0x00000000,0x00000000,0x10040040,
1172 0x10000040,0x10001000,0x00041040,0x00040000,
1173 0x00041040,0x00040000,0x10041000,0x00001000,
1174 0x00000040,0x10040040,0x00001000,0x00041040,
1175 0x10001000,0x00000040,0x10000040,0x10040000,
1176 0x10040040,0x10000000,0x00040000,0x10001040,
1177 0x00000000,0x10041040,0x00040040,0x10000040,
1178 0x10040000,0x10001000,0x10001040,0x00000000,
1179 0x10041040,0x00041000,0x00041000,0x00001040,
1180 0x00001040,0x00040040,0x10000000,0x10041000 }
1184 #define F(l,r,key){\
1185 work = ((r >> 4) | (r << 28)) ^ key[0];\
1186 l ^= Spbox[6][work & 0x3f];\
1187 l ^= Spbox[4][(work >> 8) & 0x3f];\
1188 l ^= Spbox[2][(work >> 16) & 0x3f];\
1189 l ^= Spbox[0][(work >> 24) & 0x3f];\
1191 l ^= Spbox[7][work & 0x3f];\
1192 l ^= Spbox[5][(work >> 8) & 0x3f];\
1193 l ^= Spbox[3][(work >> 16) & 0x3f];\
1194 l ^= Spbox[1][(work >> 24) & 0x3f];\
1196 /* Encrypt or decrypt a block of data in ECB mode */
1198 des (guint32 ks[16][2], unsigned char block[8])
1200 guint32 left,right,work;
1202 /* Read input block and place in left/right in big-endian order */
1203 left = ((guint32)block[0] << 24)
1204 | ((guint32)block[1] << 16)
1205 | ((guint32)block[2] << 8)
1206 | (guint32)block[3];
1207 right = ((guint32)block[4] << 24)
1208 | ((guint32)block[5] << 16)
1209 | ((guint32)block[6] << 8)
1210 | (guint32)block[7];
1212 /* Hoey's clever initial permutation algorithm, from Outerbridge
1213 * (see Schneier p 478)
1215 * The convention here is the same as Outerbridge: rotate each
1216 * register left by 1 bit, i.e., so that "left" contains permuted
1217 * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
1218 * (using origin-1 numbering as in the FIPS). This allows us to avoid
1219 * one of the two rotates that would otherwise be required in each of
1222 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
1225 work = ((left >> 16) ^ right) & 0xffff;
1228 work = ((right >> 2) ^ left) & 0x33333333;
1230 right ^= (work << 2);
1231 work = ((right >> 8) ^ left) & 0xff00ff;
1233 right ^= (work << 8);
1234 right = (right << 1) | (right >> 31);
1235 work = (left ^ right) & 0xaaaaaaaa;
1238 left = (left << 1) | (left >> 31);
1240 /* Now do the 16 rounds */
1241 F(left,right,ks[0]);
1242 F(right,left,ks[1]);
1243 F(left,right,ks[2]);
1244 F(right,left,ks[3]);
1245 F(left,right,ks[4]);
1246 F(right,left,ks[5]);
1247 F(left,right,ks[6]);
1248 F(right,left,ks[7]);
1249 F(left,right,ks[8]);
1250 F(right,left,ks[9]);
1251 F(left,right,ks[10]);
1252 F(right,left,ks[11]);
1253 F(left,right,ks[12]);
1254 F(right,left,ks[13]);
1255 F(left,right,ks[14]);
1256 F(right,left,ks[15]);
1258 /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
1259 right = (right << 31) | (right >> 1);
1260 work = (left ^ right) & 0xaaaaaaaa;
1263 left = (left >> 1) | (left << 31);
1264 work = ((left >> 8) ^ right) & 0xff00ff;
1267 work = ((left >> 2) ^ right) & 0x33333333;
1270 work = ((right >> 16) ^ left) & 0xffff;
1272 right ^= work << 16;
1273 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
1277 /* Put the block back into the user's buffer with final swap */
1278 block[0] = right >> 24;
1279 block[1] = right >> 16;
1280 block[2] = right >> 8;
1282 block[4] = left >> 24;
1283 block[5] = left >> 16;
1284 block[6] = left >> 8;
1288 /* Key schedule-related tables from FIPS-46 */
1290 /* permuted choice table (key) */
1291 static const unsigned char pc1[] = {
1292 57, 49, 41, 33, 25, 17, 9,
1293 1, 58, 50, 42, 34, 26, 18,
1294 10, 2, 59, 51, 43, 35, 27,
1295 19, 11, 3, 60, 52, 44, 36,
1297 63, 55, 47, 39, 31, 23, 15,
1298 7, 62, 54, 46, 38, 30, 22,
1299 14, 6, 61, 53, 45, 37, 29,
1300 21, 13, 5, 28, 20, 12, 4
1303 /* number left rotations of pc1 */
1304 static const unsigned char totrot[] = {
1305 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
1308 /* permuted choice key (table) */
1309 static const unsigned char pc2[] = {
1310 14, 17, 11, 24, 1, 5,
1311 3, 28, 15, 6, 21, 10,
1312 23, 19, 12, 4, 26, 8,
1313 16, 7, 27, 20, 13, 2,
1314 41, 52, 31, 37, 47, 55,
1315 30, 40, 51, 45, 33, 48,
1316 44, 49, 39, 56, 34, 53,
1317 46, 42, 50, 36, 29, 32
1320 /* End of DES-defined tables */
1323 /* bit 0 is left-most in byte */
1324 static const int bytebit[] = {
1325 0200,0100,040,020,010,04,02,01
1329 /* Generate key schedule for encryption or decryption
1330 * depending on the value of "decrypt"
1333 deskey (DES_KS k, unsigned char *key, int decrypt)
1335 unsigned char pc1m[56]; /* place to modify pc1 into */
1336 unsigned char pcr[56]; /* place to rotate pc1 into */
1339 unsigned char ks[8];
1341 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
1342 l=pc1[j]-1; /* integer bit location */
1343 m = l & 07; /* find bit */
1344 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
1345 bytebit[m]) /* and which bit of that byte */
1346 ? 1 : 0; /* and store 1-bit result */
1348 for (i=0; i<16; i++) { /* key chunk for each iteration */
1349 memset(ks,0,sizeof(ks)); /* Clear key schedule */
1350 for (j=0; j<56; j++) /* rotate pc1 the right amount */
1351 pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
1352 /* rotate left and right halves independently */
1353 for (j=0; j<48; j++){ /* select bits individually */
1354 /* check bit that goes to ks[j] */
1356 /* mask it in if it's there */
1358 ks[j/6] |= bytebit[l] >> 2;
1361 /* Now convert to packed odd/even interleaved form */
1362 k[i][0] = ((guint32)ks[0] << 24)
1363 | ((guint32)ks[2] << 16)
1364 | ((guint32)ks[4] << 8)
1366 k[i][1] = ((guint32)ks[1] << 24)
1367 | ((guint32)ks[3] << 16)
1368 | ((guint32)ks[5] << 8)