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;
391 char *challenge = NULL;
394 conn = get_connection_for_msg (priv, msg);
398 val = soup_message_headers_get_list (msg->response_headers,
402 challenge = soup_auth_manager_extract_challenge (val, "NTLM");
406 if (conn->state > SOUP_NTLM_SENT_REQUEST) {
407 /* We already authenticated, but then got another 401.
408 * That means "permission denied", so don't try to
409 * authenticate again.
411 conn->state = SOUP_NTLM_FAILED;
415 if (!soup_ntlm_parse_challenge (challenge, &conn->nonce, &conn->domain)) {
416 conn->state = SOUP_NTLM_FAILED;
420 conn->auth = soup_auth_ntlm_new (conn->domain,
421 soup_message_get_uri (msg)->host);
423 conn->challenge_header = g_strdup (challenge + 5);
424 if (conn->state == SOUP_NTLM_SENT_SSO_REQUEST) {
425 conn->state = SOUP_NTLM_RECEIVED_SSO_CHALLENGE;
429 conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
431 uri = soup_message_get_uri (msg);
433 soup_auth_authenticate (conn->auth, uri->user, uri->password);
435 soup_auth_manager_emit_authenticate (SOUP_AUTH_MANAGER (ntlm),
436 msg, conn->auth, FALSE);
442 /* Remove the WWW-Authenticate headers so the session won't try
443 * to do Basic auth too.
445 soup_message_headers_remove (msg->response_headers, "WWW-Authenticate");
449 ntlm_authorize_post (SoupMessage *msg, gpointer ntlm)
451 SoupAuthManagerNTLMPrivate *priv =
452 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
453 SoupNTLMConnection *conn;
454 const char *username = NULL, *password = NULL;
455 char *slash, *domain = NULL;
456 SoupMessageFlags flags;
458 conn = get_connection_for_msg (priv, msg);
459 if (!conn || !conn->auth)
463 if (conn->state == SOUP_NTLM_RECEIVED_SSO_CHALLENGE) {
465 input = g_strdup_printf ("TT %s\n", conn->challenge_header);
466 /* Re-Initiate ntlm_auth process in case it was closed/killed abnormally */
467 if (sso_ntlm_initiate (conn, priv)) {
468 conn->response_header = sso_ntlm_response (conn,
471 /* Close ntlm_auth as it is no longer needed for current connection */
472 sso_ntlm_close (conn);
473 if (!conn->response_header) {
477 soup_session_requeue_message (priv->session, msg);
482 conn->state = SOUP_NTLM_SSO_FAILED;
483 soup_session_requeue_message (priv->session, msg);
487 username = soup_auth_ntlm_get_username (conn->auth);
488 password = soup_auth_ntlm_get_password (conn->auth);
489 if (!username || !password)
492 slash = strpbrk (username, "\\/");
494 domain = g_strdup (username);
495 slash = domain + (slash - username);
497 username = slash + 1;
499 domain = conn->domain;
501 conn->response_header = soup_ntlm_response (conn->nonce,
505 flags = soup_message_get_flags (msg);
506 soup_message_set_flags (msg, flags & ~SOUP_MESSAGE_NEW_CONNECTION);
507 soup_session_requeue_message (priv->session, msg);
510 if (domain != conn->domain)
512 g_free (conn->domain);
514 g_free (conn->nonce);
516 g_object_unref (conn->auth);
521 request_queued (SoupSessionFeature *ntlm, SoupSession *session, SoupMessage *msg)
523 SoupAuthManagerNTLMPrivate *priv =
524 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
526 if (priv->use_ntlm) {
527 soup_message_add_status_code_handler (
528 msg, "got_headers", SOUP_STATUS_UNAUTHORIZED,
529 G_CALLBACK (ntlm_authorize_pre), ntlm);
530 soup_message_add_status_code_handler (
531 msg, "got_body", SOUP_STATUS_UNAUTHORIZED,
532 G_CALLBACK (ntlm_authorize_post), ntlm);
535 soup_auth_manager_parent_feature_interface->request_queued (ntlm, session, msg);
539 request_started (SoupSessionFeature *ntlm, SoupSession *session,
540 SoupMessage *msg, SoupSocket *socket)
542 SoupAuthManagerNTLMPrivate *priv =
543 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
544 SoupNTLMConnection *conn;
550 conn = get_connection (priv, socket);
551 set_connection_for_msg (priv, msg, conn);
553 switch (conn->state) {
556 /* Use Samba's 'winbind' daemon to support NTLM single-sign-on,
557 * by delegating the NTLM challenge/response protocal to a helper
559 * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
560 * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
561 * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
562 * The preprocessor variable 'USE_NTLM_AUTH' indicates whether
563 * this feature is enabled. Another one 'NTLM_AUTH' contains absolute
565 * If NTLM single-sign-on fails, go back to original request handling process.
567 if (sso_ntlm_initiate (conn, priv)) {
568 header = sso_ntlm_response (conn, "YR\n", conn->state);
570 if (g_ascii_strcasecmp (header, "PW") != 0) {
571 conn->state = SOUP_NTLM_SENT_SSO_REQUEST;
579 g_warning ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
585 header = soup_ntlm_request ();
586 conn->state = SOUP_NTLM_SENT_REQUEST;
589 case SOUP_NTLM_RECEIVED_SSO_CHALLENGE:
590 header = conn->response_header;
591 conn->response_header = NULL;
592 conn->state = SOUP_NTLM_SENT_SSO_RESPONSE;
594 case SOUP_NTLM_SSO_FAILED:
595 /* Restart request without SSO */
596 g_warning ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
597 header = soup_ntlm_request ();
598 conn->state = SOUP_NTLM_SENT_REQUEST;
601 case SOUP_NTLM_RECEIVED_CHALLENGE:
602 header = conn->response_header;
603 conn->response_header = NULL;
604 conn->state = SOUP_NTLM_SENT_RESPONSE;
610 if (header && !soup_message_get_auth (msg)) {
611 soup_message_headers_replace (msg->request_headers,
612 "Authorization", header);
617 soup_auth_manager_parent_feature_interface->request_started (ntlm, session, msg, socket);
621 request_unqueued (SoupSessionFeature *ntlm, SoupSession *session,
624 g_signal_handlers_disconnect_by_func (msg, ntlm_authorize_pre, ntlm);
625 g_signal_handlers_disconnect_by_func (msg, ntlm_authorize_post, ntlm);
627 soup_auth_manager_parent_feature_interface->request_unqueued (ntlm, session, msg);
631 add_feature (SoupSessionFeature *feature, GType type)
633 SoupAuthManagerNTLMPrivate *priv =
634 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
636 if (type == SOUP_TYPE_AUTH_NTLM) {
637 priv->use_ntlm = TRUE;
641 return soup_auth_manager_parent_feature_interface->add_feature (feature, type);
645 remove_feature (SoupSessionFeature *feature, GType type)
647 SoupAuthManagerNTLMPrivate *priv =
648 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
650 if (type == SOUP_TYPE_AUTH_NTLM) {
651 priv->use_ntlm = FALSE;
655 return soup_auth_manager_parent_feature_interface->remove_feature (feature, type);
659 has_feature (SoupSessionFeature *feature, GType type)
661 SoupAuthManagerNTLMPrivate *priv =
662 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
664 if (type == SOUP_TYPE_AUTH_NTLM)
665 return priv->use_ntlm;
667 return soup_auth_manager_parent_feature_interface->has_feature (feature, type);
672 static void md4sum (const unsigned char *in,
674 unsigned char digest[16]);
676 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
678 static void deskey (DES_KS, unsigned char *, int);
680 static void des (DES_KS, unsigned char *);
682 static void setup_schedule (const guchar *key_56, DES_KS ks);
684 static void calc_response (const guchar *key,
685 const guchar *plaintext,
688 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
689 "\x4B\x47\x53\x21\x40\x23\x24\x25" \
690 "\x00\x00\x00\x00\x00"
693 lanmanager_hash (const char *password, guchar hash[21])
695 guchar lm_password [15];
699 for (i = 0; i < 14 && password [i]; i++)
700 lm_password [i] = toupper ((unsigned char) password [i]);
703 lm_password [i] = '\0';
705 memcpy (hash, LM_PASSWORD_MAGIC, 21);
707 setup_schedule (lm_password, ks);
710 setup_schedule (lm_password + 7, ks);
715 nt_hash (const char *password, guchar hash[21])
717 unsigned char *buf, *p;
719 p = buf = g_malloc (strlen (password) * 2);
726 md4sum (buf, p - buf, hash);
727 memset (hash + 16, 0, 5);
739 #define NTLM_CHALLENGE_NONCE_OFFSET 24
740 #define NTLM_CHALLENGE_NONCE_LENGTH 8
741 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
743 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
744 #define NTLM_RESPONSE_FLAGS 0x8201
754 NTLMString session_key;
760 ntlm_set_string (NTLMString *string, int *offset, int len)
762 string->offset = GUINT16_TO_LE (*offset);
763 string->length = string->length2 = GUINT16_TO_LE (len);
768 soup_ntlm_request (void)
770 return g_strdup ("NTLM TlRMTVNTUAABAAAABYIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
774 soup_ntlm_parse_challenge (const char *challenge,
776 char **default_domain)
782 if (strncmp (challenge, "NTLM ", 5) != 0)
785 chall = g_base64_decode (challenge + 5, &clen);
786 if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET ||
787 clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) {
792 if (default_domain) {
793 memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
794 domain.length = GUINT16_FROM_LE (domain.length);
795 domain.offset = GUINT16_FROM_LE (domain.offset);
797 if (clen < domain.length + domain.offset) {
802 *default_domain = g_convert ((char *)chall + domain.offset,
803 domain.length, "UTF-8", "UCS-2LE",
808 *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
809 NTLM_CHALLENGE_NONCE_LENGTH);
817 soup_ntlm_response (const char *nonce,
819 const char *password,
824 gsize hlen, dlen, ulen;
825 guchar hash[21], lm_resp[24], nt_resp[24];
826 char *user_conv, *host_conv, *domain_conv;
831 nt_hash (password, hash);
832 calc_response (hash, (guchar *)nonce, nt_resp);
833 lanmanager_hash (password, hash);
834 calc_response (hash, (guchar *)nonce, lm_resp);
836 memset (&resp, 0, sizeof (resp));
837 memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
838 resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
840 offset = sizeof (resp);
845 domain_conv = g_convert (domain, -1, "UCS-2LE", "UTF-8", NULL, &dlen, NULL);
846 user_conv = g_convert (user, -1, "UCS-2LE", "UTF-8", NULL, &ulen, NULL);
847 host_conv = g_convert (host, -1, "UCS-2LE", "UTF-8", NULL, &hlen, NULL);
849 ntlm_set_string (&resp.domain, &offset, dlen);
850 ntlm_set_string (&resp.user, &offset, ulen);
851 ntlm_set_string (&resp.host, &offset, hlen);
852 ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
853 ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
855 out = g_malloc (((offset + 3) * 4) / 3 + 6);
856 strncpy (out, "NTLM ", 5);
861 p += g_base64_encode_step ((const guchar *) &resp, sizeof (resp),
862 FALSE, p, &state, &save);
863 p += g_base64_encode_step ((const guchar *) domain_conv, dlen,
864 FALSE, p, &state, &save);
865 p += g_base64_encode_step ((const guchar *) user_conv, ulen,
866 FALSE, p, &state, &save);
867 p += g_base64_encode_step ((const guchar *) host_conv, hlen,
868 FALSE, p, &state, &save);
869 p += g_base64_encode_step (lm_resp, sizeof (lm_resp),
870 FALSE, p, &state, &save);
871 p += g_base64_encode_step (nt_resp, sizeof (nt_resp),
872 FALSE, p, &state, &save);
873 p += g_base64_encode_close (FALSE, p, &state, &save);
876 g_free (domain_conv);
884 /* Set up a key schedule based on a 56bit key */
886 setup_schedule (const guchar *key_56, DES_KS ks)
891 key[0] = (key_56[0]) ;
892 key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
893 key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
894 key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
895 key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
896 key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
897 key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
898 key[7] = ((key_56[6] << 1) & 0xFF);
901 for (i = 0; i < 8; i++) {
902 for (c = bit = 0; bit < 8; bit++)
903 if (key[i] & (1 << bit))
913 calc_response (const guchar *key, const guchar *plaintext, guchar *results)
917 memcpy (results, plaintext, 8);
918 memcpy (results + 8, plaintext, 8);
919 memcpy (results + 16, plaintext, 8);
921 setup_schedule (key, ks);
924 setup_schedule (key + 7, ks);
925 des (ks, results + 8);
927 setup_schedule (key + 14, ks);
928 des (ks, results + 16);
933 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
934 * this is a reimplementation from spec.) This doesn't need to be
935 * efficient for our purposes, although it would be nice to fix
936 * it to not malloc()...
939 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
940 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
941 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
942 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
945 md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
948 guint32 A, B, C, D, AA, BB, CC, DD, X[16];
949 int pbytes, nbits = nbytes * 8, i, j;
951 pbytes = (120 - (nbytes % 64)) % 64;
952 M = alloca (nbytes + pbytes + 8);
953 memcpy (M, in, nbytes);
954 memset (M + nbytes, 0, pbytes + 8);
956 M[nbytes + pbytes] = nbits & 0xFF;
957 M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
958 M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
959 M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
966 for (i = 0; i < nbytes + pbytes + 8; i += 64) {
967 for (j = 0; j < 16; j++) {
968 X[j] = (M[i + j*4]) |
969 (M[i + j*4 + 1] << 8) |
970 (M[i + j*4 + 2] << 16) |
971 (M[i + j*4 + 3] << 24);
979 A = ROT (A + F(B, C, D) + X[0], 3);
980 D = ROT (D + F(A, B, C) + X[1], 7);
981 C = ROT (C + F(D, A, B) + X[2], 11);
982 B = ROT (B + F(C, D, A) + X[3], 19);
983 A = ROT (A + F(B, C, D) + X[4], 3);
984 D = ROT (D + F(A, B, C) + X[5], 7);
985 C = ROT (C + F(D, A, B) + X[6], 11);
986 B = ROT (B + F(C, D, A) + X[7], 19);
987 A = ROT (A + F(B, C, D) + X[8], 3);
988 D = ROT (D + F(A, B, C) + X[9], 7);
989 C = ROT (C + F(D, A, B) + X[10], 11);
990 B = ROT (B + F(C, D, A) + X[11], 19);
991 A = ROT (A + F(B, C, D) + X[12], 3);
992 D = ROT (D + F(A, B, C) + X[13], 7);
993 C = ROT (C + F(D, A, B) + X[14], 11);
994 B = ROT (B + F(C, D, A) + X[15], 19);
996 A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
997 D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
998 C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
999 B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
1000 A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
1001 D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
1002 C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
1003 B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
1004 A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
1005 D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
1006 C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
1007 B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
1008 A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
1009 D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
1010 C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
1011 B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
1013 A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
1014 D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
1015 C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
1016 B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
1017 A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
1018 D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
1019 C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
1020 B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
1021 A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
1022 D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
1023 C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
1024 B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
1025 A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
1026 D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
1027 C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
1028 B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
1036 digest[0] = A & 0xFF;
1037 digest[1] = (A >> 8) & 0xFF;
1038 digest[2] = (A >> 16) & 0xFF;
1039 digest[3] = (A >> 24) & 0xFF;
1040 digest[4] = B & 0xFF;
1041 digest[5] = (B >> 8) & 0xFF;
1042 digest[6] = (B >> 16) & 0xFF;
1043 digest[7] = (B >> 24) & 0xFF;
1044 digest[8] = C & 0xFF;
1045 digest[9] = (C >> 8) & 0xFF;
1046 digest[10] = (C >> 16) & 0xFF;
1047 digest[11] = (C >> 24) & 0xFF;
1048 digest[12] = D & 0xFF;
1049 digest[13] = (D >> 8) & 0xFF;
1050 digest[14] = (D >> 16) & 0xFF;
1051 digest[15] = (D >> 24) & 0xFF;
1055 /* Public domain DES implementation from Phil Karn */
1056 static const guint32 Spbox[8][64] = {
1057 { 0x01010400,0x00000000,0x00010000,0x01010404,
1058 0x01010004,0x00010404,0x00000004,0x00010000,
1059 0x00000400,0x01010400,0x01010404,0x00000400,
1060 0x01000404,0x01010004,0x01000000,0x00000004,
1061 0x00000404,0x01000400,0x01000400,0x00010400,
1062 0x00010400,0x01010000,0x01010000,0x01000404,
1063 0x00010004,0x01000004,0x01000004,0x00010004,
1064 0x00000000,0x00000404,0x00010404,0x01000000,
1065 0x00010000,0x01010404,0x00000004,0x01010000,
1066 0x01010400,0x01000000,0x01000000,0x00000400,
1067 0x01010004,0x00010000,0x00010400,0x01000004,
1068 0x00000400,0x00000004,0x01000404,0x00010404,
1069 0x01010404,0x00010004,0x01010000,0x01000404,
1070 0x01000004,0x00000404,0x00010404,0x01010400,
1071 0x00000404,0x01000400,0x01000400,0x00000000,
1072 0x00010004,0x00010400,0x00000000,0x01010004 },
1073 { 0x80108020,0x80008000,0x00008000,0x00108020,
1074 0x00100000,0x00000020,0x80100020,0x80008020,
1075 0x80000020,0x80108020,0x80108000,0x80000000,
1076 0x80008000,0x00100000,0x00000020,0x80100020,
1077 0x00108000,0x00100020,0x80008020,0x00000000,
1078 0x80000000,0x00008000,0x00108020,0x80100000,
1079 0x00100020,0x80000020,0x00000000,0x00108000,
1080 0x00008020,0x80108000,0x80100000,0x00008020,
1081 0x00000000,0x00108020,0x80100020,0x00100000,
1082 0x80008020,0x80100000,0x80108000,0x00008000,
1083 0x80100000,0x80008000,0x00000020,0x80108020,
1084 0x00108020,0x00000020,0x00008000,0x80000000,
1085 0x00008020,0x80108000,0x00100000,0x80000020,
1086 0x00100020,0x80008020,0x80000020,0x00100020,
1087 0x00108000,0x00000000,0x80008000,0x00008020,
1088 0x80000000,0x80100020,0x80108020,0x00108000 },
1089 { 0x00000208,0x08020200,0x00000000,0x08020008,
1090 0x08000200,0x00000000,0x00020208,0x08000200,
1091 0x00020008,0x08000008,0x08000008,0x00020000,
1092 0x08020208,0x00020008,0x08020000,0x00000208,
1093 0x08000000,0x00000008,0x08020200,0x00000200,
1094 0x00020200,0x08020000,0x08020008,0x00020208,
1095 0x08000208,0x00020200,0x00020000,0x08000208,
1096 0x00000008,0x08020208,0x00000200,0x08000000,
1097 0x08020200,0x08000000,0x00020008,0x00000208,
1098 0x00020000,0x08020200,0x08000200,0x00000000,
1099 0x00000200,0x00020008,0x08020208,0x08000200,
1100 0x08000008,0x00000200,0x00000000,0x08020008,
1101 0x08000208,0x00020000,0x08000000,0x08020208,
1102 0x00000008,0x00020208,0x00020200,0x08000008,
1103 0x08020000,0x08000208,0x00000208,0x08020000,
1104 0x00020208,0x00000008,0x08020008,0x00020200 },
1105 { 0x00802001,0x00002081,0x00002081,0x00000080,
1106 0x00802080,0x00800081,0x00800001,0x00002001,
1107 0x00000000,0x00802000,0x00802000,0x00802081,
1108 0x00000081,0x00000000,0x00800080,0x00800001,
1109 0x00000001,0x00002000,0x00800000,0x00802001,
1110 0x00000080,0x00800000,0x00002001,0x00002080,
1111 0x00800081,0x00000001,0x00002080,0x00800080,
1112 0x00002000,0x00802080,0x00802081,0x00000081,
1113 0x00800080,0x00800001,0x00802000,0x00802081,
1114 0x00000081,0x00000000,0x00000000,0x00802000,
1115 0x00002080,0x00800080,0x00800081,0x00000001,
1116 0x00802001,0x00002081,0x00002081,0x00000080,
1117 0x00802081,0x00000081,0x00000001,0x00002000,
1118 0x00800001,0x00002001,0x00802080,0x00800081,
1119 0x00002001,0x00002080,0x00800000,0x00802001,
1120 0x00000080,0x00800000,0x00002000,0x00802080 },
1121 { 0x00000100,0x02080100,0x02080000,0x42000100,
1122 0x00080000,0x00000100,0x40000000,0x02080000,
1123 0x40080100,0x00080000,0x02000100,0x40080100,
1124 0x42000100,0x42080000,0x00080100,0x40000000,
1125 0x02000000,0x40080000,0x40080000,0x00000000,
1126 0x40000100,0x42080100,0x42080100,0x02000100,
1127 0x42080000,0x40000100,0x00000000,0x42000000,
1128 0x02080100,0x02000000,0x42000000,0x00080100,
1129 0x00080000,0x42000100,0x00000100,0x02000000,
1130 0x40000000,0x02080000,0x42000100,0x40080100,
1131 0x02000100,0x40000000,0x42080000,0x02080100,
1132 0x40080100,0x00000100,0x02000000,0x42080000,
1133 0x42080100,0x00080100,0x42000000,0x42080100,
1134 0x02080000,0x00000000,0x40080000,0x42000000,
1135 0x00080100,0x02000100,0x40000100,0x00080000,
1136 0x00000000,0x40080000,0x02080100,0x40000100 },
1137 { 0x20000010,0x20400000,0x00004000,0x20404010,
1138 0x20400000,0x00000010,0x20404010,0x00400000,
1139 0x20004000,0x00404010,0x00400000,0x20000010,
1140 0x00400010,0x20004000,0x20000000,0x00004010,
1141 0x00000000,0x00400010,0x20004010,0x00004000,
1142 0x00404000,0x20004010,0x00000010,0x20400010,
1143 0x20400010,0x00000000,0x00404010,0x20404000,
1144 0x00004010,0x00404000,0x20404000,0x20000000,
1145 0x20004000,0x00000010,0x20400010,0x00404000,
1146 0x20404010,0x00400000,0x00004010,0x20000010,
1147 0x00400000,0x20004000,0x20000000,0x00004010,
1148 0x20000010,0x20404010,0x00404000,0x20400000,
1149 0x00404010,0x20404000,0x00000000,0x20400010,
1150 0x00000010,0x00004000,0x20400000,0x00404010,
1151 0x00004000,0x00400010,0x20004010,0x00000000,
1152 0x20404000,0x20000000,0x00400010,0x20004010 },
1153 { 0x00200000,0x04200002,0x04000802,0x00000000,
1154 0x00000800,0x04000802,0x00200802,0x04200800,
1155 0x04200802,0x00200000,0x00000000,0x04000002,
1156 0x00000002,0x04000000,0x04200002,0x00000802,
1157 0x04000800,0x00200802,0x00200002,0x04000800,
1158 0x04000002,0x04200000,0x04200800,0x00200002,
1159 0x04200000,0x00000800,0x00000802,0x04200802,
1160 0x00200800,0x00000002,0x04000000,0x00200800,
1161 0x04000000,0x00200800,0x00200000,0x04000802,
1162 0x04000802,0x04200002,0x04200002,0x00000002,
1163 0x00200002,0x04000000,0x04000800,0x00200000,
1164 0x04200800,0x00000802,0x00200802,0x04200800,
1165 0x00000802,0x04000002,0x04200802,0x04200000,
1166 0x00200800,0x00000000,0x00000002,0x04200802,
1167 0x00000000,0x00200802,0x04200000,0x00000800,
1168 0x04000002,0x04000800,0x00000800,0x00200002 },
1169 { 0x10001040,0x00001000,0x00040000,0x10041040,
1170 0x10000000,0x10001040,0x00000040,0x10000000,
1171 0x00040040,0x10040000,0x10041040,0x00041000,
1172 0x10041000,0x00041040,0x00001000,0x00000040,
1173 0x10040000,0x10000040,0x10001000,0x00001040,
1174 0x00041000,0x00040040,0x10040040,0x10041000,
1175 0x00001040,0x00000000,0x00000000,0x10040040,
1176 0x10000040,0x10001000,0x00041040,0x00040000,
1177 0x00041040,0x00040000,0x10041000,0x00001000,
1178 0x00000040,0x10040040,0x00001000,0x00041040,
1179 0x10001000,0x00000040,0x10000040,0x10040000,
1180 0x10040040,0x10000000,0x00040000,0x10001040,
1181 0x00000000,0x10041040,0x00040040,0x10000040,
1182 0x10040000,0x10001000,0x10001040,0x00000000,
1183 0x10041040,0x00041000,0x00041000,0x00001040,
1184 0x00001040,0x00040040,0x10000000,0x10041000 }
1188 #define F(l,r,key){\
1189 work = ((r >> 4) | (r << 28)) ^ key[0];\
1190 l ^= Spbox[6][work & 0x3f];\
1191 l ^= Spbox[4][(work >> 8) & 0x3f];\
1192 l ^= Spbox[2][(work >> 16) & 0x3f];\
1193 l ^= Spbox[0][(work >> 24) & 0x3f];\
1195 l ^= Spbox[7][work & 0x3f];\
1196 l ^= Spbox[5][(work >> 8) & 0x3f];\
1197 l ^= Spbox[3][(work >> 16) & 0x3f];\
1198 l ^= Spbox[1][(work >> 24) & 0x3f];\
1200 /* Encrypt or decrypt a block of data in ECB mode */
1202 des (guint32 ks[16][2], unsigned char block[8])
1204 guint32 left,right,work;
1206 /* Read input block and place in left/right in big-endian order */
1207 left = ((guint32)block[0] << 24)
1208 | ((guint32)block[1] << 16)
1209 | ((guint32)block[2] << 8)
1210 | (guint32)block[3];
1211 right = ((guint32)block[4] << 24)
1212 | ((guint32)block[5] << 16)
1213 | ((guint32)block[6] << 8)
1214 | (guint32)block[7];
1216 /* Hoey's clever initial permutation algorithm, from Outerbridge
1217 * (see Schneier p 478)
1219 * The convention here is the same as Outerbridge: rotate each
1220 * register left by 1 bit, i.e., so that "left" contains permuted
1221 * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
1222 * (using origin-1 numbering as in the FIPS). This allows us to avoid
1223 * one of the two rotates that would otherwise be required in each of
1226 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
1229 work = ((left >> 16) ^ right) & 0xffff;
1232 work = ((right >> 2) ^ left) & 0x33333333;
1234 right ^= (work << 2);
1235 work = ((right >> 8) ^ left) & 0xff00ff;
1237 right ^= (work << 8);
1238 right = (right << 1) | (right >> 31);
1239 work = (left ^ right) & 0xaaaaaaaa;
1242 left = (left << 1) | (left >> 31);
1244 /* Now do the 16 rounds */
1245 F(left,right,ks[0]);
1246 F(right,left,ks[1]);
1247 F(left,right,ks[2]);
1248 F(right,left,ks[3]);
1249 F(left,right,ks[4]);
1250 F(right,left,ks[5]);
1251 F(left,right,ks[6]);
1252 F(right,left,ks[7]);
1253 F(left,right,ks[8]);
1254 F(right,left,ks[9]);
1255 F(left,right,ks[10]);
1256 F(right,left,ks[11]);
1257 F(left,right,ks[12]);
1258 F(right,left,ks[13]);
1259 F(left,right,ks[14]);
1260 F(right,left,ks[15]);
1262 /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
1263 right = (right << 31) | (right >> 1);
1264 work = (left ^ right) & 0xaaaaaaaa;
1267 left = (left >> 1) | (left << 31);
1268 work = ((left >> 8) ^ right) & 0xff00ff;
1271 work = ((left >> 2) ^ right) & 0x33333333;
1274 work = ((right >> 16) ^ left) & 0xffff;
1276 right ^= work << 16;
1277 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
1281 /* Put the block back into the user's buffer with final swap */
1282 block[0] = right >> 24;
1283 block[1] = right >> 16;
1284 block[2] = right >> 8;
1286 block[4] = left >> 24;
1287 block[5] = left >> 16;
1288 block[6] = left >> 8;
1292 /* Key schedule-related tables from FIPS-46 */
1294 /* permuted choice table (key) */
1295 static const unsigned char pc1[] = {
1296 57, 49, 41, 33, 25, 17, 9,
1297 1, 58, 50, 42, 34, 26, 18,
1298 10, 2, 59, 51, 43, 35, 27,
1299 19, 11, 3, 60, 52, 44, 36,
1301 63, 55, 47, 39, 31, 23, 15,
1302 7, 62, 54, 46, 38, 30, 22,
1303 14, 6, 61, 53, 45, 37, 29,
1304 21, 13, 5, 28, 20, 12, 4
1307 /* number left rotations of pc1 */
1308 static const unsigned char totrot[] = {
1309 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
1312 /* permuted choice key (table) */
1313 static const unsigned char pc2[] = {
1314 14, 17, 11, 24, 1, 5,
1315 3, 28, 15, 6, 21, 10,
1316 23, 19, 12, 4, 26, 8,
1317 16, 7, 27, 20, 13, 2,
1318 41, 52, 31, 37, 47, 55,
1319 30, 40, 51, 45, 33, 48,
1320 44, 49, 39, 56, 34, 53,
1321 46, 42, 50, 36, 29, 32
1324 /* End of DES-defined tables */
1327 /* bit 0 is left-most in byte */
1328 static const int bytebit[] = {
1329 0200,0100,040,020,010,04,02,01
1333 /* Generate key schedule for encryption or decryption
1334 * depending on the value of "decrypt"
1337 deskey (DES_KS k, unsigned char *key, int decrypt)
1339 unsigned char pc1m[56]; /* place to modify pc1 into */
1340 unsigned char pcr[56]; /* place to rotate pc1 into */
1343 unsigned char ks[8];
1345 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
1346 l=pc1[j]-1; /* integer bit location */
1347 m = l & 07; /* find bit */
1348 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
1349 bytebit[m]) /* and which bit of that byte */
1350 ? 1 : 0; /* and store 1-bit result */
1352 for (i=0; i<16; i++) { /* key chunk for each iteration */
1353 memset(ks,0,sizeof(ks)); /* Clear key schedule */
1354 for (j=0; j<56; j++) /* rotate pc1 the right amount */
1355 pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
1356 /* rotate left and right halves independently */
1357 for (j=0; j<48; j++){ /* select bits individually */
1358 /* check bit that goes to ks[j] */
1360 /* mask it in if it's there */
1362 ks[j/6] |= bytebit[l] >> 2;
1365 /* Now convert to packed odd/even interleaved form */
1366 k[i][0] = ((guint32)ks[0] << 24)
1367 | ((guint32)ks[2] << 16)
1368 | ((guint32)ks[4] << 8)
1370 k[i][1] = ((guint32)ks[1] << 24)
1371 | ((guint32)ks[3] << 16)
1372 | ((guint32)ks[5] << 8)