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.
20 #include "soup-auth-manager-ntlm.h"
21 #include "soup-auth-ntlm.h"
22 #include "soup-message.h"
23 #include "soup-message-private.h"
24 #include "soup-misc.h"
25 #include "soup-session.h"
26 #include "soup-session-feature.h"
29 static void soup_auth_manager_ntlm_session_feature_init (SoupSessionFeatureInterface *feature_interface, gpointer interface_data);
30 static SoupSessionFeatureInterface *soup_auth_manager_parent_feature_interface;
32 static void attach (SoupSessionFeature *feature, SoupSession *session);
33 static void request_queued (SoupSessionFeature *feature, SoupSession *session,
35 static void request_started (SoupSessionFeature *feature, SoupSession *session,
36 SoupMessage *msg, SoupSocket *socket);
37 static void request_unqueued (SoupSessionFeature *feature,
38 SoupSession *session, SoupMessage *msg);
39 static gboolean add_feature (SoupSessionFeature *feature, GType type);
40 static gboolean remove_feature (SoupSessionFeature *feature, GType type);
41 static gboolean has_feature (SoupSessionFeature *feature, GType type);
43 G_DEFINE_TYPE_WITH_CODE (SoupAuthManagerNTLM, soup_auth_manager_ntlm, SOUP_TYPE_AUTH_MANAGER,
44 G_IMPLEMENT_INTERFACE (SOUP_TYPE_SESSION_FEATURE,
45 soup_auth_manager_ntlm_session_feature_init))
50 SOUP_NTLM_SENT_SSO_REQUEST,
51 SOUP_NTLM_RECEIVED_SSO_CHALLENGE,
52 SOUP_NTLM_SENT_SSO_RESPONSE,
55 SOUP_NTLM_SENT_REQUEST,
56 SOUP_NTLM_RECEIVED_CHALLENGE,
57 SOUP_NTLM_SENT_RESPONSE,
64 char *response_header;
69 char *challenge_header;
79 GHashTable *connections_by_msg;
80 GHashTable *connections_by_id;
82 gboolean ntlm_auth_accessible;
84 } SoupAuthManagerNTLMPrivate;
85 #define SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH_MANAGER_NTLM, SoupAuthManagerNTLMPrivate))
87 static char *soup_ntlm_request (void);
88 static gboolean soup_ntlm_parse_challenge (const char *challenge,
90 char **default_domain);
91 static char *soup_ntlm_response (const char *nonce,
97 static void sso_ntlm_close (SoupNTLMConnection *conn);
101 soup_auth_manager_ntlm_init (SoupAuthManagerNTLM *ntlm)
103 SoupAuthManagerNTLMPrivate *priv =
104 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
106 priv->connections_by_id = g_hash_table_new (NULL, NULL);
107 priv->connections_by_msg = g_hash_table_new (NULL, NULL);
109 priv->ntlm_auth_accessible = (access (NTLM_AUTH, X_OK) == 0);
114 free_ntlm_connection (SoupNTLMConnection *conn)
116 g_free (conn->response_header);
117 g_free (conn->nonce);
118 g_free (conn->domain);
120 g_object_unref (conn->auth);
122 g_free (conn->challenge_header);
123 sso_ntlm_close (conn);
125 g_slice_free (SoupNTLMConnection, conn);
129 free_ntlm_connection_foreach (gpointer key, gpointer value, gpointer user_data)
131 free_ntlm_connection (value);
135 finalize (GObject *object)
137 SoupAuthManagerNTLMPrivate *priv =
138 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (object);
140 g_hash_table_foreach (priv->connections_by_id,
141 free_ntlm_connection_foreach, NULL);
142 g_hash_table_destroy (priv->connections_by_id);
143 g_hash_table_destroy (priv->connections_by_msg);
145 G_OBJECT_CLASS (soup_auth_manager_ntlm_parent_class)->finalize (object);
149 soup_auth_manager_ntlm_class_init (SoupAuthManagerNTLMClass *auth_manager_ntlm_class)
151 GObjectClass *object_class = G_OBJECT_CLASS (auth_manager_ntlm_class);
153 g_type_class_add_private (auth_manager_ntlm_class, sizeof (SoupAuthManagerNTLMPrivate));
155 object_class->finalize = finalize;
159 soup_auth_manager_ntlm_session_feature_init (SoupSessionFeatureInterface *feature_interface,
160 gpointer interface_data)
162 soup_auth_manager_parent_feature_interface =
163 g_type_interface_peek_parent (feature_interface);
165 feature_interface->attach = attach;
166 feature_interface->request_queued = request_queued;
167 feature_interface->request_started = request_started;
168 feature_interface->request_unqueued = request_unqueued;
169 feature_interface->add_feature = add_feature;
170 feature_interface->remove_feature = remove_feature;
171 feature_interface->has_feature = has_feature;
175 attach (SoupSessionFeature *manager, SoupSession *session)
177 SoupAuthManagerNTLMPrivate *priv =
178 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (manager);
180 /* FIXME: should support multiple sessions */
181 priv->session = session;
183 soup_auth_manager_parent_feature_interface->attach (manager, session);
187 delete_conn (SoupSocket *socket, gpointer user_data)
189 SoupAuthManagerNTLMPrivate *priv = user_data;
190 SoupNTLMConnection *conn;
192 conn = g_hash_table_lookup (priv->connections_by_id, socket);
194 free_ntlm_connection (conn);
195 g_hash_table_remove (priv->connections_by_id, socket);
196 g_signal_handlers_disconnect_by_func (socket, delete_conn, priv);
199 static SoupNTLMConnection *
200 get_connection (SoupAuthManagerNTLMPrivate *priv, SoupSocket *socket)
202 SoupNTLMConnection *conn;
204 conn = g_hash_table_lookup (priv->connections_by_id, socket);
208 conn = g_slice_new0 (SoupNTLMConnection);
209 conn->socket = socket;
210 conn->state = SOUP_NTLM_NEW;
215 g_hash_table_insert (priv->connections_by_id, socket, conn);
217 g_signal_connect (socket, "disconnected",
218 G_CALLBACK (delete_conn), priv);
223 unset_conn (SoupMessage *msg, gpointer user_data)
225 SoupAuthManagerNTLMPrivate *priv = user_data;
227 g_hash_table_remove (priv->connections_by_msg, msg);
228 g_signal_handlers_disconnect_by_func (msg, unset_conn, priv);
231 static SoupNTLMConnection *
232 set_connection_for_msg (SoupAuthManagerNTLMPrivate *priv, SoupMessage *msg,
233 SoupNTLMConnection *conn)
235 if (!g_hash_table_lookup (priv->connections_by_msg, msg)) {
236 g_signal_connect (msg, "finished",
237 G_CALLBACK (unset_conn), priv);
238 g_signal_connect (msg, "restarted",
239 G_CALLBACK (unset_conn), priv);
241 g_hash_table_insert (priv->connections_by_msg, msg, conn);
246 static SoupNTLMConnection *
247 get_connection_for_msg (SoupAuthManagerNTLMPrivate *priv, SoupMessage *msg)
249 return g_hash_table_lookup (priv->connections_by_msg, msg);
254 sso_ntlm_close (SoupNTLMConnection *conn)
256 if (conn->fd_in != -1) {
261 if (conn->fd_out != -1) {
262 close (conn->fd_out);
268 sso_ntlm_initiate (SoupNTLMConnection *conn, SoupAuthManagerNTLMPrivate *priv)
270 char *username = NULL, *slash, *domain = NULL;
274 /* Return if ntlm_auth execution process exist already */
275 if (conn->fd_in != -1 && conn->fd_out != -1)
278 /* Clean all sso data before re-initiate */
279 sso_ntlm_close (conn);
281 if (!priv->ntlm_auth_accessible)
284 username = getenv ("NTLMUSER");
286 username = getenv ("USER");
290 slash = strpbrk (username, "\\/");
292 domain = g_strdup (username);
293 slash = domain + (slash - username);
295 username = slash + 1;
299 argv[1] = "--helper-protocol";
300 argv[2] = "ntlmssp-client-1";
301 argv[3] = "--use-cached-creds";
302 argv[4] = "--username";
304 argv[6] = domain ? "--domain" : NULL;
307 /* Spawn child process */
308 ret = g_spawn_async_with_pipes (NULL, argv, NULL,
309 G_SPAWN_FILE_AND_ARGV_ZERO,
311 NULL, &conn->fd_in, &conn->fd_out,
323 sso_ntlm_response (SoupNTLMConnection *conn, const char *input, SoupNTLMState conn_state)
326 char buf[1024], *response = NULL;
328 size_t len_in = strlen (input), len_out = sizeof (buf);
331 int written = write (conn->fd_in, input, len_in);
333 /* Interrupted by a signal, retry it */
336 /* write failed if other errors happen */
343 while (len_out > 0) {
344 size = read (conn->fd_out, tmpbuf, len_out);
349 } else if (size == 0)
351 else if (tmpbuf[size - 1] == '\n') {
352 tmpbuf[size - 1] = '\0';
360 if (conn_state == SOUP_NTLM_NEW &&
361 g_ascii_strcasecmp (buf, "PW") == 0) {
362 /* Samba/winbind installed but not configured */
363 response = g_strdup ("PW");
366 if (conn_state == SOUP_NTLM_NEW &&
367 g_ascii_strncasecmp (buf, "YR ", 3) != 0)
368 /* invalid response for type 1 message */
370 if (conn_state == SOUP_NTLM_RECEIVED_SSO_CHALLENGE &&
371 g_ascii_strncasecmp (buf, "KK ", 3) != 0 &&
372 g_ascii_strncasecmp (buf, "AF ", 3) != 0)
373 /* invalid response for type 3 message */
376 response = g_strdup_printf ("NTLM %.*s", (int)(size - 4), buf + 3);
381 #endif /* USE_NTLM_AUTH */
384 ntlm_authorize_pre (SoupMessage *msg, gpointer ntlm)
386 SoupAuthManagerNTLMPrivate *priv =
387 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
388 SoupNTLMConnection *conn;
391 conn = get_connection_for_msg (priv, msg);
395 val = soup_message_headers_get_list (msg->response_headers,
398 val = strstr (val, "NTLM ");
402 if (conn->state > SOUP_NTLM_SENT_REQUEST) {
403 /* We already authenticated, but then got another 401.
404 * That means "permission denied", so don't try to
405 * authenticate again.
407 conn->state = SOUP_NTLM_FAILED;
411 if (!soup_ntlm_parse_challenge (val, &conn->nonce, &conn->domain)) {
412 conn->state = SOUP_NTLM_FAILED;
416 conn->auth = soup_auth_ntlm_new (conn->domain,
417 soup_message_get_uri (msg)->host);
419 conn->challenge_header = g_strdup (val + 5);
420 if (conn->state == SOUP_NTLM_SENT_SSO_REQUEST) {
421 conn->state = SOUP_NTLM_RECEIVED_SSO_CHALLENGE;
425 conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
426 soup_auth_manager_emit_authenticate (SOUP_AUTH_MANAGER (ntlm), msg,
430 /* Remove the WWW-Authenticate headers so the session won't try
431 * to do Basic auth too.
433 soup_message_headers_remove (msg->response_headers, "WWW-Authenticate");
437 ntlm_authorize_post (SoupMessage *msg, gpointer ntlm)
439 SoupAuthManagerNTLMPrivate *priv =
440 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
441 SoupNTLMConnection *conn;
442 const char *username = NULL, *password = NULL;
443 char *slash, *domain = NULL;
445 conn = get_connection_for_msg (priv, msg);
446 if (!conn || !conn->auth)
450 if (conn->state == SOUP_NTLM_RECEIVED_SSO_CHALLENGE) {
452 input = g_strdup_printf ("TT %s\n", conn->challenge_header);
453 /* Re-Initiate ntlm_auth process in case it was closed/killed abnormally */
454 if (sso_ntlm_initiate (conn, priv)) {
455 conn->response_header = sso_ntlm_response (conn,
458 /* Close ntlm_auth as it is no longer needed for current connection */
459 sso_ntlm_close (conn);
460 if (!conn->response_header) {
464 soup_session_requeue_message (priv->session, msg);
469 conn->state = SOUP_NTLM_SSO_FAILED;
470 soup_session_requeue_message (priv->session, msg);
474 username = soup_auth_ntlm_get_username (conn->auth);
475 password = soup_auth_ntlm_get_password (conn->auth);
476 if (!username || !password)
479 slash = strpbrk (username, "\\/");
481 domain = g_strdup (username);
482 slash = domain + (slash - username);
484 username = slash + 1;
486 domain = conn->domain;
488 conn->response_header = soup_ntlm_response (conn->nonce,
491 soup_session_requeue_message (priv->session, msg);
494 if (domain != conn->domain)
496 g_free (conn->domain);
498 g_free (conn->nonce);
500 g_object_unref (conn->auth);
505 request_queued (SoupSessionFeature *ntlm, SoupSession *session, SoupMessage *msg)
507 SoupAuthManagerNTLMPrivate *priv =
508 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
510 if (priv->use_ntlm) {
511 soup_message_add_status_code_handler (
512 msg, "got_headers", SOUP_STATUS_UNAUTHORIZED,
513 G_CALLBACK (ntlm_authorize_pre), ntlm);
514 soup_message_add_status_code_handler (
515 msg, "got_body", SOUP_STATUS_UNAUTHORIZED,
516 G_CALLBACK (ntlm_authorize_post), ntlm);
519 soup_auth_manager_parent_feature_interface->request_queued (ntlm, session, msg);
523 request_started (SoupSessionFeature *ntlm, SoupSession *session,
524 SoupMessage *msg, SoupSocket *socket)
526 SoupAuthManagerNTLMPrivate *priv =
527 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (ntlm);
528 SoupNTLMConnection *conn;
534 conn = get_connection (priv, socket);
535 set_connection_for_msg (priv, msg, conn);
537 switch (conn->state) {
540 /* Use Samba's 'winbind' daemon to support NTLM single-sign-on,
541 * by delegating the NTLM challenge/response protocal to a helper
543 * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
544 * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
545 * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
546 * The preprocessor variable 'USE_NTLM_AUTH' indicates whether
547 * this feature is enabled. Another one 'NTLM_AUTH' contains absolute
549 * If NTLM single-sign-on fails, go back to original request handling process.
551 if (sso_ntlm_initiate (conn, priv)) {
552 header = sso_ntlm_response (conn, "YR\n", conn->state);
554 if (g_ascii_strcasecmp (header, "PW") != 0) {
555 conn->state = SOUP_NTLM_SENT_SSO_REQUEST;
563 g_warning ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
569 header = soup_ntlm_request ();
570 conn->state = SOUP_NTLM_SENT_REQUEST;
573 case SOUP_NTLM_RECEIVED_SSO_CHALLENGE:
574 header = conn->response_header;
575 conn->response_header = NULL;
576 conn->state = SOUP_NTLM_SENT_SSO_RESPONSE;
578 case SOUP_NTLM_SSO_FAILED:
579 /* Restart request without SSO */
580 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_CHALLENGE:
586 header = conn->response_header;
587 conn->response_header = NULL;
588 conn->state = SOUP_NTLM_SENT_RESPONSE;
594 if (header && !soup_message_get_auth (msg)) {
595 soup_message_headers_replace (msg->request_headers,
596 "Authorization", header);
601 soup_auth_manager_parent_feature_interface->request_started (ntlm, session, msg, socket);
605 request_unqueued (SoupSessionFeature *ntlm, SoupSession *session,
608 g_signal_handlers_disconnect_by_func (msg, ntlm_authorize_pre, ntlm);
609 g_signal_handlers_disconnect_by_func (msg, ntlm_authorize_post, ntlm);
611 soup_auth_manager_parent_feature_interface->request_unqueued (ntlm, session, msg);
615 add_feature (SoupSessionFeature *feature, GType type)
617 SoupAuthManagerNTLMPrivate *priv =
618 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
620 if (type == SOUP_TYPE_AUTH_NTLM) {
621 priv->use_ntlm = TRUE;
625 return soup_auth_manager_parent_feature_interface->add_feature (feature, type);
629 remove_feature (SoupSessionFeature *feature, GType type)
631 SoupAuthManagerNTLMPrivate *priv =
632 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
634 if (type == SOUP_TYPE_AUTH_NTLM) {
635 priv->use_ntlm = FALSE;
639 return soup_auth_manager_parent_feature_interface->remove_feature (feature, type);
643 has_feature (SoupSessionFeature *feature, GType type)
645 SoupAuthManagerNTLMPrivate *priv =
646 SOUP_AUTH_MANAGER_NTLM_GET_PRIVATE (feature);
648 if (type == SOUP_TYPE_AUTH_NTLM)
649 return priv->use_ntlm;
651 return soup_auth_manager_parent_feature_interface->has_feature (feature, type);
656 static void md4sum (const unsigned char *in,
658 unsigned char digest[16]);
660 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
662 static void deskey (DES_KS, unsigned char *, int);
664 static void des (DES_KS, unsigned char *);
666 static void setup_schedule (const guchar *key_56, DES_KS ks);
668 static void calc_response (const guchar *key,
669 const guchar *plaintext,
672 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
673 "\x4B\x47\x53\x21\x40\x23\x24\x25" \
674 "\x00\x00\x00\x00\x00"
677 lanmanager_hash (const char *password, guchar hash[21])
679 guchar lm_password [15];
683 for (i = 0; i < 14 && password [i]; i++)
684 lm_password [i] = toupper ((unsigned char) password [i]);
687 lm_password [i] = '\0';
689 memcpy (hash, LM_PASSWORD_MAGIC, 21);
691 setup_schedule (lm_password, ks);
694 setup_schedule (lm_password + 7, ks);
699 nt_hash (const char *password, guchar hash[21])
701 unsigned char *buf, *p;
703 p = buf = g_malloc (strlen (password) * 2);
710 md4sum (buf, p - buf, hash);
711 memset (hash + 16, 0, 5);
723 #define NTLM_CHALLENGE_NONCE_OFFSET 24
724 #define NTLM_CHALLENGE_NONCE_LENGTH 8
725 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
727 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
728 #define NTLM_RESPONSE_FLAGS 0x8202
738 NTLMString session_key;
744 ntlm_set_string (NTLMString *string, int *offset, int len)
746 string->offset = GUINT16_TO_LE (*offset);
747 string->length = string->length2 = GUINT16_TO_LE (len);
752 soup_ntlm_request (void)
754 return g_strdup ("NTLM TlRMTVNTUAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
758 soup_ntlm_parse_challenge (const char *challenge,
760 char **default_domain)
766 if (strncmp (challenge, "NTLM ", 5) != 0)
769 chall = g_base64_decode (challenge + 5, &clen);
770 if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET ||
771 clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) {
776 if (default_domain) {
777 memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
778 domain.length = GUINT16_FROM_LE (domain.length);
779 domain.offset = GUINT16_FROM_LE (domain.offset);
781 if (clen < domain.length + domain.offset) {
786 *default_domain = g_strndup ((char *)chall + domain.offset, domain.length);
790 *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
791 NTLM_CHALLENGE_NONCE_LENGTH);
799 soup_ntlm_response (const char *nonce,
801 const char *password,
805 int hlen, dlen, ulen, offset;
806 guchar hash[21], lm_resp[24], nt_resp[24];
811 nt_hash (password, hash);
812 calc_response (hash, (guchar *)nonce, nt_resp);
813 lanmanager_hash (password, hash);
814 calc_response (hash, (guchar *)nonce, lm_resp);
816 memset (&resp, 0, sizeof (resp));
817 memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
818 resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
820 offset = sizeof (resp);
822 dlen = strlen (domain);
823 ntlm_set_string (&resp.domain, &offset, dlen);
824 ulen = strlen (user);
825 ntlm_set_string (&resp.user, &offset, ulen);
828 hlen = strlen (host);
829 ntlm_set_string (&resp.host, &offset, hlen);
830 ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
831 ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
833 out = g_malloc (((offset + 3) * 4) / 3 + 6);
834 strncpy (out, "NTLM ", 5);
839 p += g_base64_encode_step ((const guchar *) &resp, sizeof (resp),
840 FALSE, p, &state, &save);
841 p += g_base64_encode_step ((const guchar *) domain, dlen,
842 FALSE, p, &state, &save);
843 p += g_base64_encode_step ((const guchar *) user, ulen,
844 FALSE, p, &state, &save);
845 p += g_base64_encode_step ((const guchar *) host, hlen,
846 FALSE, p, &state, &save);
847 p += g_base64_encode_step (lm_resp, sizeof (lm_resp),
848 FALSE, p, &state, &save);
849 p += g_base64_encode_step (nt_resp, sizeof (nt_resp),
850 FALSE, p, &state, &save);
851 p += g_base64_encode_close (FALSE, p, &state, &save);
858 /* Set up a key schedule based on a 56bit key */
860 setup_schedule (const guchar *key_56, DES_KS ks)
865 key[0] = (key_56[0]) ;
866 key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
867 key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
868 key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
869 key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
870 key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
871 key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
872 key[7] = ((key_56[6] << 1) & 0xFF);
875 for (i = 0; i < 8; i++) {
876 for (c = bit = 0; bit < 8; bit++)
877 if (key[i] & (1 << bit))
887 calc_response (const guchar *key, const guchar *plaintext, guchar *results)
891 memcpy (results, plaintext, 8);
892 memcpy (results + 8, plaintext, 8);
893 memcpy (results + 16, plaintext, 8);
895 setup_schedule (key, ks);
898 setup_schedule (key + 7, ks);
899 des (ks, results + 8);
901 setup_schedule (key + 14, ks);
902 des (ks, results + 16);
907 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
908 * this is a reimplementation from spec.) This doesn't need to be
909 * efficient for our purposes, although it would be nice to fix
910 * it to not malloc()...
913 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
914 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
915 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
916 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
919 md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
922 guint32 A, B, C, D, AA, BB, CC, DD, X[16];
923 int pbytes, nbits = nbytes * 8, i, j;
925 pbytes = (120 - (nbytes % 64)) % 64;
926 M = alloca (nbytes + pbytes + 8);
927 memcpy (M, in, nbytes);
928 memset (M + nbytes, 0, pbytes + 8);
930 M[nbytes + pbytes] = nbits & 0xFF;
931 M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
932 M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
933 M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
940 for (i = 0; i < nbytes + pbytes + 8; i += 64) {
941 for (j = 0; j < 16; j++) {
942 X[j] = (M[i + j*4]) |
943 (M[i + j*4 + 1] << 8) |
944 (M[i + j*4 + 2] << 16) |
945 (M[i + j*4 + 3] << 24);
953 A = ROT (A + F(B, C, D) + X[0], 3);
954 D = ROT (D + F(A, B, C) + X[1], 7);
955 C = ROT (C + F(D, A, B) + X[2], 11);
956 B = ROT (B + F(C, D, A) + X[3], 19);
957 A = ROT (A + F(B, C, D) + X[4], 3);
958 D = ROT (D + F(A, B, C) + X[5], 7);
959 C = ROT (C + F(D, A, B) + X[6], 11);
960 B = ROT (B + F(C, D, A) + X[7], 19);
961 A = ROT (A + F(B, C, D) + X[8], 3);
962 D = ROT (D + F(A, B, C) + X[9], 7);
963 C = ROT (C + F(D, A, B) + X[10], 11);
964 B = ROT (B + F(C, D, A) + X[11], 19);
965 A = ROT (A + F(B, C, D) + X[12], 3);
966 D = ROT (D + F(A, B, C) + X[13], 7);
967 C = ROT (C + F(D, A, B) + X[14], 11);
968 B = ROT (B + F(C, D, A) + X[15], 19);
970 A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
971 D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
972 C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
973 B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
974 A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
975 D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
976 C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
977 B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
978 A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
979 D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
980 C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
981 B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
982 A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
983 D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
984 C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
985 B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
987 A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
988 D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
989 C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
990 B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
991 A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
992 D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
993 C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
994 B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
995 A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
996 D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
997 C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
998 B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
999 A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
1000 D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
1001 C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
1002 B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
1010 digest[0] = A & 0xFF;
1011 digest[1] = (A >> 8) & 0xFF;
1012 digest[2] = (A >> 16) & 0xFF;
1013 digest[3] = (A >> 24) & 0xFF;
1014 digest[4] = B & 0xFF;
1015 digest[5] = (B >> 8) & 0xFF;
1016 digest[6] = (B >> 16) & 0xFF;
1017 digest[7] = (B >> 24) & 0xFF;
1018 digest[8] = C & 0xFF;
1019 digest[9] = (C >> 8) & 0xFF;
1020 digest[10] = (C >> 16) & 0xFF;
1021 digest[11] = (C >> 24) & 0xFF;
1022 digest[12] = D & 0xFF;
1023 digest[13] = (D >> 8) & 0xFF;
1024 digest[14] = (D >> 16) & 0xFF;
1025 digest[15] = (D >> 24) & 0xFF;
1029 /* Public domain DES implementation from Phil Karn */
1030 static const guint32 Spbox[8][64] = {
1031 { 0x01010400,0x00000000,0x00010000,0x01010404,
1032 0x01010004,0x00010404,0x00000004,0x00010000,
1033 0x00000400,0x01010400,0x01010404,0x00000400,
1034 0x01000404,0x01010004,0x01000000,0x00000004,
1035 0x00000404,0x01000400,0x01000400,0x00010400,
1036 0x00010400,0x01010000,0x01010000,0x01000404,
1037 0x00010004,0x01000004,0x01000004,0x00010004,
1038 0x00000000,0x00000404,0x00010404,0x01000000,
1039 0x00010000,0x01010404,0x00000004,0x01010000,
1040 0x01010400,0x01000000,0x01000000,0x00000400,
1041 0x01010004,0x00010000,0x00010400,0x01000004,
1042 0x00000400,0x00000004,0x01000404,0x00010404,
1043 0x01010404,0x00010004,0x01010000,0x01000404,
1044 0x01000004,0x00000404,0x00010404,0x01010400,
1045 0x00000404,0x01000400,0x01000400,0x00000000,
1046 0x00010004,0x00010400,0x00000000,0x01010004 },
1047 { 0x80108020,0x80008000,0x00008000,0x00108020,
1048 0x00100000,0x00000020,0x80100020,0x80008020,
1049 0x80000020,0x80108020,0x80108000,0x80000000,
1050 0x80008000,0x00100000,0x00000020,0x80100020,
1051 0x00108000,0x00100020,0x80008020,0x00000000,
1052 0x80000000,0x00008000,0x00108020,0x80100000,
1053 0x00100020,0x80000020,0x00000000,0x00108000,
1054 0x00008020,0x80108000,0x80100000,0x00008020,
1055 0x00000000,0x00108020,0x80100020,0x00100000,
1056 0x80008020,0x80100000,0x80108000,0x00008000,
1057 0x80100000,0x80008000,0x00000020,0x80108020,
1058 0x00108020,0x00000020,0x00008000,0x80000000,
1059 0x00008020,0x80108000,0x00100000,0x80000020,
1060 0x00100020,0x80008020,0x80000020,0x00100020,
1061 0x00108000,0x00000000,0x80008000,0x00008020,
1062 0x80000000,0x80100020,0x80108020,0x00108000 },
1063 { 0x00000208,0x08020200,0x00000000,0x08020008,
1064 0x08000200,0x00000000,0x00020208,0x08000200,
1065 0x00020008,0x08000008,0x08000008,0x00020000,
1066 0x08020208,0x00020008,0x08020000,0x00000208,
1067 0x08000000,0x00000008,0x08020200,0x00000200,
1068 0x00020200,0x08020000,0x08020008,0x00020208,
1069 0x08000208,0x00020200,0x00020000,0x08000208,
1070 0x00000008,0x08020208,0x00000200,0x08000000,
1071 0x08020200,0x08000000,0x00020008,0x00000208,
1072 0x00020000,0x08020200,0x08000200,0x00000000,
1073 0x00000200,0x00020008,0x08020208,0x08000200,
1074 0x08000008,0x00000200,0x00000000,0x08020008,
1075 0x08000208,0x00020000,0x08000000,0x08020208,
1076 0x00000008,0x00020208,0x00020200,0x08000008,
1077 0x08020000,0x08000208,0x00000208,0x08020000,
1078 0x00020208,0x00000008,0x08020008,0x00020200 },
1079 { 0x00802001,0x00002081,0x00002081,0x00000080,
1080 0x00802080,0x00800081,0x00800001,0x00002001,
1081 0x00000000,0x00802000,0x00802000,0x00802081,
1082 0x00000081,0x00000000,0x00800080,0x00800001,
1083 0x00000001,0x00002000,0x00800000,0x00802001,
1084 0x00000080,0x00800000,0x00002001,0x00002080,
1085 0x00800081,0x00000001,0x00002080,0x00800080,
1086 0x00002000,0x00802080,0x00802081,0x00000081,
1087 0x00800080,0x00800001,0x00802000,0x00802081,
1088 0x00000081,0x00000000,0x00000000,0x00802000,
1089 0x00002080,0x00800080,0x00800081,0x00000001,
1090 0x00802001,0x00002081,0x00002081,0x00000080,
1091 0x00802081,0x00000081,0x00000001,0x00002000,
1092 0x00800001,0x00002001,0x00802080,0x00800081,
1093 0x00002001,0x00002080,0x00800000,0x00802001,
1094 0x00000080,0x00800000,0x00002000,0x00802080 },
1095 { 0x00000100,0x02080100,0x02080000,0x42000100,
1096 0x00080000,0x00000100,0x40000000,0x02080000,
1097 0x40080100,0x00080000,0x02000100,0x40080100,
1098 0x42000100,0x42080000,0x00080100,0x40000000,
1099 0x02000000,0x40080000,0x40080000,0x00000000,
1100 0x40000100,0x42080100,0x42080100,0x02000100,
1101 0x42080000,0x40000100,0x00000000,0x42000000,
1102 0x02080100,0x02000000,0x42000000,0x00080100,
1103 0x00080000,0x42000100,0x00000100,0x02000000,
1104 0x40000000,0x02080000,0x42000100,0x40080100,
1105 0x02000100,0x40000000,0x42080000,0x02080100,
1106 0x40080100,0x00000100,0x02000000,0x42080000,
1107 0x42080100,0x00080100,0x42000000,0x42080100,
1108 0x02080000,0x00000000,0x40080000,0x42000000,
1109 0x00080100,0x02000100,0x40000100,0x00080000,
1110 0x00000000,0x40080000,0x02080100,0x40000100 },
1111 { 0x20000010,0x20400000,0x00004000,0x20404010,
1112 0x20400000,0x00000010,0x20404010,0x00400000,
1113 0x20004000,0x00404010,0x00400000,0x20000010,
1114 0x00400010,0x20004000,0x20000000,0x00004010,
1115 0x00000000,0x00400010,0x20004010,0x00004000,
1116 0x00404000,0x20004010,0x00000010,0x20400010,
1117 0x20400010,0x00000000,0x00404010,0x20404000,
1118 0x00004010,0x00404000,0x20404000,0x20000000,
1119 0x20004000,0x00000010,0x20400010,0x00404000,
1120 0x20404010,0x00400000,0x00004010,0x20000010,
1121 0x00400000,0x20004000,0x20000000,0x00004010,
1122 0x20000010,0x20404010,0x00404000,0x20400000,
1123 0x00404010,0x20404000,0x00000000,0x20400010,
1124 0x00000010,0x00004000,0x20400000,0x00404010,
1125 0x00004000,0x00400010,0x20004010,0x00000000,
1126 0x20404000,0x20000000,0x00400010,0x20004010 },
1127 { 0x00200000,0x04200002,0x04000802,0x00000000,
1128 0x00000800,0x04000802,0x00200802,0x04200800,
1129 0x04200802,0x00200000,0x00000000,0x04000002,
1130 0x00000002,0x04000000,0x04200002,0x00000802,
1131 0x04000800,0x00200802,0x00200002,0x04000800,
1132 0x04000002,0x04200000,0x04200800,0x00200002,
1133 0x04200000,0x00000800,0x00000802,0x04200802,
1134 0x00200800,0x00000002,0x04000000,0x00200800,
1135 0x04000000,0x00200800,0x00200000,0x04000802,
1136 0x04000802,0x04200002,0x04200002,0x00000002,
1137 0x00200002,0x04000000,0x04000800,0x00200000,
1138 0x04200800,0x00000802,0x00200802,0x04200800,
1139 0x00000802,0x04000002,0x04200802,0x04200000,
1140 0x00200800,0x00000000,0x00000002,0x04200802,
1141 0x00000000,0x00200802,0x04200000,0x00000800,
1142 0x04000002,0x04000800,0x00000800,0x00200002 },
1143 { 0x10001040,0x00001000,0x00040000,0x10041040,
1144 0x10000000,0x10001040,0x00000040,0x10000000,
1145 0x00040040,0x10040000,0x10041040,0x00041000,
1146 0x10041000,0x00041040,0x00001000,0x00000040,
1147 0x10040000,0x10000040,0x10001000,0x00001040,
1148 0x00041000,0x00040040,0x10040040,0x10041000,
1149 0x00001040,0x00000000,0x00000000,0x10040040,
1150 0x10000040,0x10001000,0x00041040,0x00040000,
1151 0x00041040,0x00040000,0x10041000,0x00001000,
1152 0x00000040,0x10040040,0x00001000,0x00041040,
1153 0x10001000,0x00000040,0x10000040,0x10040000,
1154 0x10040040,0x10000000,0x00040000,0x10001040,
1155 0x00000000,0x10041040,0x00040040,0x10000040,
1156 0x10040000,0x10001000,0x10001040,0x00000000,
1157 0x10041040,0x00041000,0x00041000,0x00001040,
1158 0x00001040,0x00040040,0x10000000,0x10041000 }
1162 #define F(l,r,key){\
1163 work = ((r >> 4) | (r << 28)) ^ key[0];\
1164 l ^= Spbox[6][work & 0x3f];\
1165 l ^= Spbox[4][(work >> 8) & 0x3f];\
1166 l ^= Spbox[2][(work >> 16) & 0x3f];\
1167 l ^= Spbox[0][(work >> 24) & 0x3f];\
1169 l ^= Spbox[7][work & 0x3f];\
1170 l ^= Spbox[5][(work >> 8) & 0x3f];\
1171 l ^= Spbox[3][(work >> 16) & 0x3f];\
1172 l ^= Spbox[1][(work >> 24) & 0x3f];\
1174 /* Encrypt or decrypt a block of data in ECB mode */
1176 des (guint32 ks[16][2], unsigned char block[8])
1178 guint32 left,right,work;
1180 /* Read input block and place in left/right in big-endian order */
1181 left = ((guint32)block[0] << 24)
1182 | ((guint32)block[1] << 16)
1183 | ((guint32)block[2] << 8)
1184 | (guint32)block[3];
1185 right = ((guint32)block[4] << 24)
1186 | ((guint32)block[5] << 16)
1187 | ((guint32)block[6] << 8)
1188 | (guint32)block[7];
1190 /* Hoey's clever initial permutation algorithm, from Outerbridge
1191 * (see Schneier p 478)
1193 * The convention here is the same as Outerbridge: rotate each
1194 * register left by 1 bit, i.e., so that "left" contains permuted
1195 * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
1196 * (using origin-1 numbering as in the FIPS). This allows us to avoid
1197 * one of the two rotates that would otherwise be required in each of
1200 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
1203 work = ((left >> 16) ^ right) & 0xffff;
1206 work = ((right >> 2) ^ left) & 0x33333333;
1208 right ^= (work << 2);
1209 work = ((right >> 8) ^ left) & 0xff00ff;
1211 right ^= (work << 8);
1212 right = (right << 1) | (right >> 31);
1213 work = (left ^ right) & 0xaaaaaaaa;
1216 left = (left << 1) | (left >> 31);
1218 /* Now do the 16 rounds */
1219 F(left,right,ks[0]);
1220 F(right,left,ks[1]);
1221 F(left,right,ks[2]);
1222 F(right,left,ks[3]);
1223 F(left,right,ks[4]);
1224 F(right,left,ks[5]);
1225 F(left,right,ks[6]);
1226 F(right,left,ks[7]);
1227 F(left,right,ks[8]);
1228 F(right,left,ks[9]);
1229 F(left,right,ks[10]);
1230 F(right,left,ks[11]);
1231 F(left,right,ks[12]);
1232 F(right,left,ks[13]);
1233 F(left,right,ks[14]);
1234 F(right,left,ks[15]);
1236 /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
1237 right = (right << 31) | (right >> 1);
1238 work = (left ^ right) & 0xaaaaaaaa;
1241 left = (left >> 1) | (left << 31);
1242 work = ((left >> 8) ^ right) & 0xff00ff;
1245 work = ((left >> 2) ^ right) & 0x33333333;
1248 work = ((right >> 16) ^ left) & 0xffff;
1250 right ^= work << 16;
1251 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
1255 /* Put the block back into the user's buffer with final swap */
1256 block[0] = right >> 24;
1257 block[1] = right >> 16;
1258 block[2] = right >> 8;
1260 block[4] = left >> 24;
1261 block[5] = left >> 16;
1262 block[6] = left >> 8;
1266 /* Key schedule-related tables from FIPS-46 */
1268 /* permuted choice table (key) */
1269 static const unsigned char pc1[] = {
1270 57, 49, 41, 33, 25, 17, 9,
1271 1, 58, 50, 42, 34, 26, 18,
1272 10, 2, 59, 51, 43, 35, 27,
1273 19, 11, 3, 60, 52, 44, 36,
1275 63, 55, 47, 39, 31, 23, 15,
1276 7, 62, 54, 46, 38, 30, 22,
1277 14, 6, 61, 53, 45, 37, 29,
1278 21, 13, 5, 28, 20, 12, 4
1281 /* number left rotations of pc1 */
1282 static const unsigned char totrot[] = {
1283 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
1286 /* permuted choice key (table) */
1287 static const unsigned char pc2[] = {
1288 14, 17, 11, 24, 1, 5,
1289 3, 28, 15, 6, 21, 10,
1290 23, 19, 12, 4, 26, 8,
1291 16, 7, 27, 20, 13, 2,
1292 41, 52, 31, 37, 47, 55,
1293 30, 40, 51, 45, 33, 48,
1294 44, 49, 39, 56, 34, 53,
1295 46, 42, 50, 36, 29, 32
1298 /* End of DES-defined tables */
1301 /* bit 0 is left-most in byte */
1302 static const int bytebit[] = {
1303 0200,0100,040,020,010,04,02,01
1307 /* Generate key schedule for encryption or decryption
1308 * depending on the value of "decrypt"
1311 deskey (DES_KS k, unsigned char *key, int decrypt)
1313 unsigned char pc1m[56]; /* place to modify pc1 into */
1314 unsigned char pcr[56]; /* place to rotate pc1 into */
1317 unsigned char ks[8];
1319 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
1320 l=pc1[j]-1; /* integer bit location */
1321 m = l & 07; /* find bit */
1322 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
1323 bytebit[m]) /* and which bit of that byte */
1324 ? 1 : 0; /* and store 1-bit result */
1326 for (i=0; i<16; i++) { /* key chunk for each iteration */
1327 memset(ks,0,sizeof(ks)); /* Clear key schedule */
1328 for (j=0; j<56; j++) /* rotate pc1 the right amount */
1329 pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
1330 /* rotate left and right halves independently */
1331 for (j=0; j<48; j++){ /* select bits individually */
1332 /* check bit that goes to ks[j] */
1334 /* mask it in if it's there */
1336 ks[j/6] |= bytebit[l] >> 2;
1339 /* Now convert to packed odd/even interleaved form */
1340 k[i][0] = ((guint32)ks[0] << 24)
1341 | ((guint32)ks[2] << 16)
1342 | ((guint32)ks[4] << 8)
1344 k[i][1] = ((guint32)ks[1] << 24)
1345 | ((guint32)ks[3] << 16)
1346 | ((guint32)ks[5] << 8)