1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * soup-auth-ntlm.c: HTTP NTLM Authentication helper
5 * Copyright (C) 2007 Red Hat, Inc.
19 #include "soup-auth-ntlm.h"
21 #include "soup-message-private.h"
23 static void soup_ntlm_lanmanager_hash (const char *password,
25 static void soup_ntlm_nt_hash (const char *password,
27 static char *soup_ntlm_request (void);
28 static gboolean soup_ntlm_parse_challenge (const char *challenge,
30 char **default_domain,
31 gboolean *ntlmv2_session,
32 gboolean *negotiate_target,
34 size_t *target_info_sz);
35 static char *soup_ntlm_response (const char *nonce,
41 gboolean ntlmv2_session,
42 gboolean negotiate_target,
43 const char *target_info,
44 size_t target_info_sz);
49 SOUP_NTLM_SENT_REQUEST,
50 SOUP_NTLM_RECEIVED_CHALLENGE,
51 SOUP_NTLM_SENT_RESPONSE,
58 char *response_header;
59 gboolean ntlmv2_session;
60 gboolean negotiate_target;
62 size_t target_info_sz;
63 } SoupNTLMConnectionState;
66 SOUP_NTLM_PASSWORD_NONE,
67 SOUP_NTLM_PASSWORD_PROVIDED,
68 SOUP_NTLM_PASSWORD_ACCEPTED,
69 SOUP_NTLM_PASSWORD_REJECTED
70 } SoupNTLMPasswordState;
73 char *username, *domain;
74 guchar nt_hash[21], lm_hash[21];
75 SoupNTLMPasswordState password_state;
78 /* Use Samba's 'winbind' daemon to support NTLM single-sign-on,
79 * by delegating the NTLM challenge/response protocal to a helper
81 * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
82 * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
83 * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
85 gboolean sso_available;
89 } SoupAuthNTLMPrivate;
92 static gboolean ntlm_auth_available, ntlm_auth_debug;
93 static void sso_ntlm_close (SoupAuthNTLMPrivate *priv);
97 * SOUP_TYPE_AUTH_NTLM:
99 * A #GType corresponding to HTTP-based NTLM authentication.
100 * #SoupSessions do not support this type by default; if you want to
101 * enable support for it, call soup_session_add_feature_by_type(),
102 * passing %SOUP_TYPE_AUTH_NTLM.
107 G_DEFINE_TYPE_WITH_PRIVATE (SoupAuthNTLM, soup_auth_ntlm, SOUP_TYPE_CONNECTION_AUTH)
110 soup_auth_ntlm_init (SoupAuthNTLM *ntlm)
113 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (ntlm);
114 const char *username = NULL, *slash;
116 priv->sso_available = TRUE;
120 username = getenv ("NTLMUSER");
122 username = g_get_user_name ();
124 slash = strpbrk (username, "\\/");
126 priv->username = g_strdup (slash + 1);
127 priv->domain = g_strndup (username, slash - username);
129 priv->username = g_strdup (username);
136 soup_auth_ntlm_finalize (GObject *object)
138 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (SOUP_AUTH_NTLM (object));
140 g_free (priv->username);
141 g_free (priv->domain);
143 memset (priv->nt_hash, 0, sizeof (priv->nt_hash));
144 memset (priv->lm_hash, 0, sizeof (priv->lm_hash));
147 sso_ntlm_close (priv);
150 G_OBJECT_CLASS (soup_auth_ntlm_parent_class)->finalize (object);
155 sso_ntlm_close (SoupAuthNTLMPrivate *priv)
157 if (priv->fd_in != -1) {
162 if (priv->fd_out != -1) {
163 close (priv->fd_out);
169 sso_ntlm_initiate (SoupAuthNTLMPrivate *priv)
174 if (!priv->sso_available)
177 if (!ntlm_auth_available && !ntlm_auth_debug) {
178 priv->sso_available = FALSE;
182 /* Return if ntlm_auth execution process exist already */
183 if (priv->fd_in != -1 && priv->fd_out != -1)
186 /* Clean all sso data before re-initiate */
187 sso_ntlm_close (priv);
190 if (ntlm_auth_debug) {
191 argv[0] = (char *) g_getenv ("SOUP_NTLM_AUTH_DEBUG");
193 priv->sso_available = FALSE;
198 argv[1] = "--helper-protocol";
199 argv[2] = "ntlmssp-client-1";
200 argv[3] = "--use-cached-creds";
201 argv[4] = "--username";
202 argv[5] = priv->username;
203 argv[6] = priv->domain ? "--domain" : NULL;
204 argv[7] = priv->domain;
207 ret = g_spawn_async_with_pipes (NULL, argv, NULL,
208 G_SPAWN_STDERR_TO_DEV_NULL,
210 NULL, &priv->fd_in, &priv->fd_out,
213 priv->sso_available = FALSE;
218 sso_ntlm_response (SoupAuthNTLMPrivate *priv, const char *input, SoupNTLMState conn_state)
223 size_t len_in = strlen (input), len_out = sizeof (buf);
226 int written = write (priv->fd_in, input, len_in);
230 /* write failed if other errors happen */
237 while (len_out > 0) {
238 size = read (priv->fd_out, tmpbuf, len_out);
243 } else if (size == 0)
245 else if (tmpbuf[size - 1] == '\n') {
246 tmpbuf[size - 1] = '\0';
255 if (g_ascii_strcasecmp (buf, "PW") == 0) {
256 /* Samba/winbind installed but not configured */
257 return g_strdup ("PW");
259 if (conn_state == SOUP_NTLM_NEW &&
260 g_ascii_strncasecmp (buf, "YR ", 3) != 0) {
261 /* invalid response for type 1 message */
264 if (conn_state == SOUP_NTLM_RECEIVED_CHALLENGE &&
265 g_ascii_strncasecmp (buf, "KK ", 3) != 0 &&
266 g_ascii_strncasecmp (buf, "AF ", 3) != 0) {
267 /* invalid response for type 3 message */
271 return g_strdup_printf ("NTLM %.*s", (int)(size - 4), buf + 3);
273 #endif /* USE_NTLM_AUTH */
276 soup_auth_ntlm_create_connection_state (SoupConnectionAuth *auth)
278 SoupNTLMConnectionState *conn;
280 conn = g_slice_new0 (SoupNTLMConnectionState);
281 conn->state = SOUP_NTLM_NEW;
287 soup_auth_ntlm_free_connection_state (SoupConnectionAuth *auth,
290 SoupNTLMConnectionState *conn = state;
292 g_free (conn->nonce);
293 g_free (conn->response_header);
294 g_free (conn->target_info);
295 g_slice_free (SoupNTLMConnectionState, conn);
299 soup_auth_ntlm_update_connection (SoupConnectionAuth *auth, SoupMessage *msg,
300 const char *auth_header, gpointer state)
302 SoupAuthNTLM *auth_ntlm = SOUP_AUTH_NTLM (auth);
303 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (auth_ntlm);
304 SoupNTLMConnectionState *conn = state;
305 gboolean success = TRUE;
307 /* Note that we only return FALSE if some sort of parsing error
308 * occurs. Otherwise, the SoupAuth is still reusable (though it may
309 * no longer be _ready or _authenticated).
312 if (!g_str_has_prefix (auth_header, "NTLM"))
315 if (conn->state > SOUP_NTLM_SENT_REQUEST) {
316 if (priv->password_state == SOUP_NTLM_PASSWORD_ACCEPTED) {
317 /* We know our password is correct, so a 401
318 * means "permission denied". The code can't deal
319 * with re-authenticating correctly, so make sure
322 conn->state = SOUP_NTLM_FAILED;
323 if (soup_message_is_keepalive (msg)) {
324 soup_message_headers_append (msg->response_headers,
325 "Connection", "close");
331 if (priv->sso_available) {
332 conn->state = SOUP_NTLM_SSO_FAILED;
333 priv->password_state = SOUP_NTLM_PASSWORD_NONE;
336 conn->state = SOUP_NTLM_FAILED;
337 priv->password_state = SOUP_NTLM_PASSWORD_REJECTED;
344 if (conn->state == SOUP_NTLM_NEW && !auth_header[4])
347 if (!auth_header[4] || !auth_header[5]) {
348 conn->state = SOUP_NTLM_FAILED;
352 if (!soup_ntlm_parse_challenge (auth_header + 5, &conn->nonce,
353 priv->domain ? NULL : &priv->domain,
354 &conn->ntlmv2_session, &conn->negotiate_target,
355 &conn->target_info, &conn->target_info_sz)) {
356 conn->state = SOUP_NTLM_FAILED;
361 if (priv->sso_available && conn->state == SOUP_NTLM_SENT_REQUEST) {
362 char *input, *response;
364 /* Re-Initiate ntlm_auth process in case it was closed/killed abnormally */
365 if (!sso_ntlm_initiate (priv)) {
366 conn->state = SOUP_NTLM_SSO_FAILED;
371 input = g_strdup_printf ("TT %s\n", auth_header + 5);
372 response = sso_ntlm_response (priv, input, conn->state);
373 sso_ntlm_close (priv);
377 conn->state = SOUP_NTLM_SSO_FAILED;
379 } else if (!g_ascii_strcasecmp (response, "PW")) {
380 conn->state = SOUP_NTLM_SSO_FAILED;
381 priv->sso_available = FALSE;
384 conn->response_header = response;
385 if (priv->password_state != SOUP_NTLM_PASSWORD_ACCEPTED)
386 priv->password_state = SOUP_NTLM_PASSWORD_PROVIDED;
392 if (conn->state == SOUP_NTLM_SENT_REQUEST)
393 conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
395 g_object_set (G_OBJECT (auth),
396 SOUP_AUTH_REALM, priv->domain,
397 SOUP_AUTH_HOST, soup_message_get_uri (msg)->host,
403 soup_auth_ntlm_get_protection_space (SoupAuth *auth, SoupURI *source_uri)
407 space = g_strdup (source_uri->path);
409 /* Strip filename component */
410 p = strrchr (space, '/');
411 if (p && p != space && p[1])
414 return g_slist_prepend (NULL, space);
418 soup_auth_ntlm_authenticate (SoupAuth *auth, const char *username,
419 const char *password)
421 SoupAuthNTLM *auth_ntlm = SOUP_AUTH_NTLM (auth);
422 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (auth_ntlm);
425 g_return_if_fail (username != NULL);
426 g_return_if_fail (password != NULL);
429 g_free (priv->username);
431 g_free (priv->domain);
433 slash = strpbrk (username, "\\/");
435 priv->domain = g_strndup (username, slash - username);
436 priv->username = g_strdup (slash + 1);
438 priv->domain = g_strdup ("");
439 priv->username = g_strdup (username);
442 soup_ntlm_nt_hash (password, priv->nt_hash);
443 soup_ntlm_lanmanager_hash (password, priv->lm_hash);
445 priv->password_state = SOUP_NTLM_PASSWORD_PROVIDED;
449 soup_auth_ntlm_is_authenticated (SoupAuth *auth)
451 SoupAuthNTLM *auth_ntlm = SOUP_AUTH_NTLM (auth);
452 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (auth_ntlm);
454 return (priv->password_state != SOUP_NTLM_PASSWORD_NONE &&
455 priv->password_state != SOUP_NTLM_PASSWORD_REJECTED);
459 soup_auth_ntlm_is_connection_ready (SoupConnectionAuth *auth,
463 SoupAuthNTLM *auth_ntlm = SOUP_AUTH_NTLM (auth);
464 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (auth_ntlm);
465 SoupNTLMConnectionState *conn = state;
467 if (priv->password_state == SOUP_NTLM_PASSWORD_REJECTED)
470 if (priv->password_state == SOUP_NTLM_PASSWORD_PROVIDED)
473 return conn->state != SOUP_NTLM_FAILED;
477 got_final_auth_result (SoupMessage *msg, gpointer data)
479 SoupAuth *auth = data;
480 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (SOUP_AUTH_NTLM (auth));
482 g_signal_handlers_disconnect_by_func (msg, G_CALLBACK (got_final_auth_result), auth);
484 if (auth != soup_message_get_auth (msg))
487 if (msg->status_code != SOUP_STATUS_UNAUTHORIZED)
488 priv->password_state = SOUP_NTLM_PASSWORD_ACCEPTED;
492 soup_auth_ntlm_get_connection_authorization (SoupConnectionAuth *auth,
496 SoupAuthNTLM *auth_ntlm = SOUP_AUTH_NTLM (auth);
497 SoupAuthNTLMPrivate *priv = soup_auth_ntlm_get_instance_private (auth_ntlm);
498 SoupNTLMConnectionState *conn = state;
501 switch (conn->state) {
504 if (sso_ntlm_initiate (priv)) {
505 header = sso_ntlm_response (priv, "YR\n", conn->state);
507 if (g_ascii_strcasecmp (header, "PW") != 0) {
508 conn->state = SOUP_NTLM_SENT_REQUEST;
513 priv->sso_available = FALSE;
516 g_debug ("NTLM single-sign-on using %s failed", NTLM_AUTH);
519 /* If NTLM single-sign-on fails, go back to original
520 * request handling process.
523 header = soup_ntlm_request ();
524 conn->state = SOUP_NTLM_SENT_REQUEST;
526 case SOUP_NTLM_RECEIVED_CHALLENGE:
527 if (conn->response_header) {
528 header = conn->response_header;
529 conn->response_header = NULL;
531 header = soup_ntlm_response (conn->nonce,
537 conn->ntlmv2_session,
538 conn->negotiate_target,
540 conn->target_info_sz);
542 g_clear_pointer (&conn->nonce, g_free);
543 conn->state = SOUP_NTLM_SENT_RESPONSE;
545 if (priv->password_state != SOUP_NTLM_PASSWORD_ACCEPTED) {
546 /* We need to know if this worked */
547 g_signal_connect (msg, "got-headers",
548 G_CALLBACK (got_final_auth_result),
553 case SOUP_NTLM_SSO_FAILED:
554 /* Restart request without SSO */
555 g_debug ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
556 priv->sso_available = FALSE;
557 header = soup_ntlm_request ();
558 conn->state = SOUP_NTLM_SENT_REQUEST;
569 soup_auth_ntlm_class_init (SoupAuthNTLMClass *auth_ntlm_class)
571 SoupAuthClass *auth_class = SOUP_AUTH_CLASS (auth_ntlm_class);
572 SoupConnectionAuthClass *connauth_class = SOUP_CONNECTION_AUTH_CLASS (auth_ntlm_class);
573 GObjectClass *object_class = G_OBJECT_CLASS (auth_ntlm_class);
575 auth_class->scheme_name = "NTLM";
576 auth_class->strength = 3;
578 auth_class->get_protection_space = soup_auth_ntlm_get_protection_space;
579 auth_class->authenticate = soup_auth_ntlm_authenticate;
580 auth_class->is_authenticated = soup_auth_ntlm_is_authenticated;
582 connauth_class->create_connection_state = soup_auth_ntlm_create_connection_state;
583 connauth_class->free_connection_state = soup_auth_ntlm_free_connection_state;
584 connauth_class->update_connection = soup_auth_ntlm_update_connection;
585 connauth_class->get_connection_authorization = soup_auth_ntlm_get_connection_authorization;
586 connauth_class->is_connection_ready = soup_auth_ntlm_is_connection_ready;
588 object_class->finalize = soup_auth_ntlm_finalize;
591 ntlm_auth_available = g_file_test (NTLM_AUTH, G_FILE_TEST_IS_EXECUTABLE);
592 ntlm_auth_debug = (g_getenv ("SOUP_NTLM_AUTH_DEBUG") != NULL);
596 static void md4sum (const unsigned char *in,
598 unsigned char digest[16]);
600 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
602 static void deskey (DES_KS, unsigned char *, int);
604 static void des (DES_KS, unsigned char *);
606 static void setup_schedule (const guchar *key_56, DES_KS ks);
608 static void calc_response (const guchar *key,
609 const guchar *plaintext,
612 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
613 "\x4B\x47\x53\x21\x40\x23\x24\x25" \
614 "\x00\x00\x00\x00\x00"
617 soup_ntlm_lanmanager_hash (const char *password, guchar hash[21])
619 guchar lm_password [15];
623 for (i = 0; i < 14 && password [i]; i++)
624 lm_password [i] = g_ascii_toupper ((unsigned char) password [i]);
627 lm_password [i] = '\0';
629 memcpy (hash, LM_PASSWORD_MAGIC, 21);
631 setup_schedule (lm_password, ks);
634 setup_schedule (lm_password + 7, ks);
639 soup_ntlm_nt_hash (const char *password, guchar hash[21])
641 unsigned char *buf, *p;
643 p = buf = g_malloc (strlen (password) * 2);
650 md4sum (buf, p - buf, hash);
651 memset (hash + 16, 0, 5);
663 #define NTLM_CHALLENGE_NONCE_OFFSET 24
664 #define NTLM_CHALLENGE_NONCE_LENGTH 8
665 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
666 #define NTLM_CHALLENGE_TARGET_INFORMATION_OFFSET 40
668 #define NTLM_CHALLENGE_FLAGS_OFFSET 20
669 #define NTLM_FLAGS_NEGOTIATE_NTLMV2 0x00080000
670 #define NTLM_FLAGS_NEGOTIATE_TARGET_INFORMATION 0x00800000
671 #define NTLM_FLAGS_REQUEST_TARGET 0x00000004
673 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
674 #define NTLM_RESPONSE_FLAGS 0x8201
675 #define NTLM_RESPONSE_TARGET_INFORMATION_OFFSET 44
676 #define NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000
678 #define HMAC_MD5_LENGTH 16
688 NTLMString session_key;
694 ntlm_set_string (NTLMString *string, int *offset, int len)
696 string->offset = GUINT16_TO_LE (*offset);
697 string->length = string->length2 = GUINT16_TO_LE (len);
702 soup_ntlm_request (void)
704 return g_strdup ("NTLM TlRMTVNTUAABAAAABYIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
708 soup_ntlm_parse_challenge (const char *challenge,
710 char **default_domain,
711 gboolean *ntlmv2_session,
712 gboolean *negotiate_target,
714 size_t *target_info_sz)
722 chall = g_base64_decode (challenge, &clen);
723 if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET ||
724 clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) {
729 memcpy (&flags, chall + NTLM_CHALLENGE_FLAGS_OFFSET, sizeof(flags));
730 flags = GUINT_FROM_LE (flags);
731 *ntlmv2_session = (flags & NTLM_FLAGS_NEGOTIATE_NTLMV2) ? TRUE : FALSE;
732 /* To know if NTLMv2 responses should be calculated */
733 *negotiate_target = (flags & NTLM_FLAGS_NEGOTIATE_TARGET_INFORMATION ) ? TRUE : FALSE;
734 if (*negotiate_target) {
735 if (clen < NTLM_CHALLENGE_TARGET_INFORMATION_OFFSET + sizeof (target)) {
741 if (default_domain) {
742 memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
743 domain.length = GUINT16_FROM_LE (domain.length);
744 domain.offset = GUINT16_FROM_LE (domain.offset);
746 if (clen < domain.length + domain.offset) {
751 *default_domain = g_convert ((char *)chall + domain.offset,
752 domain.length, "UTF-8", "UCS-2LE",
757 *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
758 NTLM_CHALLENGE_NONCE_LENGTH);
760 /* For NTLMv2 response */
761 if (*negotiate_target && target_info) {
762 memcpy (&target, chall + NTLM_CHALLENGE_TARGET_INFORMATION_OFFSET, sizeof (target));
763 target.length = GUINT16_FROM_LE (target.length);
764 target.offset = GUINT16_FROM_LE (target.offset);
766 if (clen < target.length + target.offset) {
770 *target_info = g_memdup (chall + target.offset, target.length);
771 *target_info_sz = target.length;
779 calc_ntlm2_session_response (const char *nonce,
786 guint32 client_nonce[2];
787 guchar ntlmv2_hash[16];
788 GChecksum *ntlmv2_cksum;
789 gsize ntlmv2_hash_sz = sizeof (ntlmv2_hash);
791 /* FIXME: if GLib ever gets a more secure random number
792 * generator, use it here
794 client_nonce[0] = g_random_int();
795 client_nonce[1] = g_random_int();
797 ntlmv2_cksum = g_checksum_new (G_CHECKSUM_MD5);
798 g_checksum_update (ntlmv2_cksum, (const guchar *) nonce, 8);
799 g_checksum_update (ntlmv2_cksum, (const guchar *) client_nonce, sizeof (client_nonce));
800 g_checksum_get_digest (ntlmv2_cksum, ntlmv2_hash, &ntlmv2_hash_sz);
801 g_checksum_free (ntlmv2_cksum);
803 /* Send the padded client nonce as a fake lm_resp */
804 memset (lm_resp, 0, lm_resp_sz);
805 memcpy (lm_resp, client_nonce, sizeof (client_nonce));
807 /* Compute nt_hash as usual but with a new nonce */
808 calc_response (nt_hash, ntlmv2_hash, nt_resp);
811 /* Compute HMAC-MD5 with Glib function*/
813 calc_hmac_md5 (unsigned char *hmac, const guchar *key, gsize key_sz, const guchar *data, gsize data_sz)
815 char *hmac_hex, *hex_pos;
818 hmac_hex = g_compute_hmac_for_data(G_CHECKSUM_MD5, key, key_sz, data, data_sz);
820 for (count = 0; count < HMAC_MD5_LENGTH; count++)
822 /* The 'hh' sscanf format modifier is C99, so we enable it on
823 * non-Windows or if __USE_MINGW_ANSI_STDIO is enabled or`
824 * if we are building on Visual Studio 2015 or later
826 #if !defined (G_OS_WIN32) || (__USE_MINGW_ANSI_STDIO == 1) || (_MSC_VER >= 1900)
827 sscanf(hex_pos, "%2hhx", &hmac[count]);
829 unsigned int tmp_hmac;
830 sscanf(hex_pos, "%2x", &tmp_hmac);
831 hmac[count] = (guint8)tmp_hmac;
840 calc_ntlmv2_response (const char *user, const char *domain,
841 const guchar *nt_hash, const gsize nt_hash_sz,
843 const char *target_info, size_t target_info_sz,
844 guchar *lm_resp, size_t lm_resp_sz,
845 guchar *nt_resp, size_t nt_resp_sz)
847 const unsigned char blob_signature[] = {0x01,0x01,0x00,0x00};
848 const unsigned char blob_reserved[] = {0x00,0x00,0x00,0x00};
849 gint64 blob_timestamp;
850 unsigned char client_nonce[8];
851 const unsigned char blob_unknown[] = {0x00,0x00,0x00,0x00};
853 unsigned char ntv2_hash[HMAC_MD5_LENGTH];
854 guchar *nonce_blob, *blob, *p_blob;
855 unsigned char nonce_blob_hash[HMAC_MD5_LENGTH];
856 unsigned char nonce_client_nonce[16], nonce_client_nonce_hash[HMAC_MD5_LENGTH];
857 gchar *user_uppercase, *user_domain, *user_domain_conv;
858 gsize user_domain_conv_sz;
862 /* create HMAC-MD5 hash of Unicode uppercase username and Unicode domain */
863 user_uppercase = g_utf8_strup (user, strlen (user));
864 user_domain = g_strconcat (user_uppercase, domain, NULL);
865 user_domain_conv = g_convert (user_domain, -1, "UCS-2LE", "UTF-8", NULL, &user_domain_conv_sz, NULL);
866 calc_hmac_md5 (ntv2_hash, nt_hash, nt_hash_sz, (const guchar *)user_domain_conv, user_domain_conv_sz);
867 g_free (user_uppercase);
868 g_free (user_domain);
869 g_free (user_domain_conv);
871 /* create random client nonce */
872 for (i = 0; i < sizeof (client_nonce); i++)
874 client_nonce[i] = g_random_int();
877 /* create timestamp for blob
878 * LE, 64-bit signed value, number of tenths of a ms since January 1, 1601.*/
879 blob_timestamp = GINT64_TO_LE(((unsigned long)time(NULL) + 11644473600) * 10000000);
882 blob_sz = sizeof (blob_signature) + sizeof (blob_reserved) +
883 sizeof (blob_timestamp) + sizeof (client_nonce) +
884 sizeof (blob_unknown) + target_info_sz;
885 p_blob = blob = g_malloc (blob_sz);
886 memset (blob, 0, blob_sz);
887 memcpy (p_blob, blob_signature, sizeof (blob_signature));
888 memcpy (p_blob += sizeof (blob_signature), blob_reserved, sizeof (blob_reserved));
889 memcpy (p_blob += sizeof (blob_reserved), &blob_timestamp, sizeof (blob_timestamp));
890 memcpy (p_blob += sizeof (blob_timestamp), client_nonce, sizeof (client_nonce));
891 memcpy (p_blob += sizeof (client_nonce), blob_unknown, sizeof (blob_unknown));
892 memcpy (p_blob += sizeof (blob_unknown), target_info, target_info_sz);
894 /* create HMAC-MD5 hash of concatenated nonce and blob */
895 nonce_blob = g_malloc (NTLM_CHALLENGE_NONCE_LENGTH + blob_sz);
896 memcpy (nonce_blob, nonce, NTLM_CHALLENGE_NONCE_LENGTH);
897 memcpy (nonce_blob + NTLM_CHALLENGE_NONCE_LENGTH, blob, blob_sz);
898 calc_hmac_md5 (nonce_blob_hash, (const guchar *)ntv2_hash, (gsize) sizeof (ntv2_hash), (const guchar *) nonce_blob, (gsize) NTLM_CHALLENGE_NONCE_LENGTH + blob_sz);
901 /* create NTv2 response */
902 memset (nt_resp, 0, nt_resp_sz);
903 memcpy (nt_resp, nonce_blob_hash, sizeof (nonce_blob_hash));
904 memcpy (nt_resp + sizeof (nonce_blob_hash), blob, blob_sz);
909 * create HMAC-MD5 hash of concatenated nonce and client nonce
911 memcpy (nonce_client_nonce, nonce, NTLM_CHALLENGE_NONCE_LENGTH);
912 memcpy (nonce_client_nonce + NTLM_CHALLENGE_NONCE_LENGTH, client_nonce, sizeof (client_nonce));
913 calc_hmac_md5 (nonce_client_nonce_hash, (const guchar *) ntv2_hash, (gsize) sizeof (ntv2_hash), (const guchar *) nonce_client_nonce, (gsize) NTLM_CHALLENGE_NONCE_LENGTH + sizeof (client_nonce));
915 /* create LMv2 response */
916 memset (lm_resp, 0, lm_resp_sz);
917 memcpy (lm_resp, nonce_client_nonce_hash, sizeof (nonce_client_nonce_hash));
918 memcpy (lm_resp + sizeof (nonce_client_nonce_hash), client_nonce, sizeof (client_nonce));
922 soup_ntlm_response (const char *nonce,
928 gboolean ntlmv2_session,
929 gboolean negotiate_target,
930 const char *target_info,
931 size_t target_info_sz)
935 gsize hlen, dlen, ulen, nt_resp_sz;
936 guchar lm_resp[24], *nt_resp;
937 char *user_conv, *host_conv, *domain_conv;
942 if (negotiate_target)
944 /* nonce_blob_hash 16 + blob_signature 4 + blob_reserved 4 +
945 * blob_timestamp 8 + client_nonce 8 + blob_unknown 4 +
947 nt_resp_sz = NTLM_RESPONSE_TARGET_INFORMATION_OFFSET + target_info_sz;
951 nt_resp = g_malloc (nt_resp_sz);
953 if (ntlmv2_session && !negotiate_target) {
954 calc_ntlm2_session_response (nonce, nt_hash, lm_hash,
955 lm_resp, sizeof(lm_resp), nt_resp);
956 } else if (!negotiate_target){
957 /* Compute a regular NTLMv1 response */
958 calc_response (nt_hash, (guchar *) nonce, nt_resp);
959 calc_response (lm_hash, (guchar *) nonce, lm_resp);
961 calc_ntlmv2_response (user, domain,
964 target_info, target_info_sz,
965 lm_resp, sizeof (lm_resp),
966 nt_resp, (size_t) nt_resp_sz);
969 memset (&resp, 0, sizeof (resp));
970 memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
971 resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
973 resp.flags |= GUINT32_TO_LE (NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY);
974 if (negotiate_target)
975 resp.flags |= GUINT32_TO_LE (NTLM_FLAGS_REQUEST_TARGET);
976 offset = sizeof (resp);
981 domain_conv = g_convert (domain, -1, "UCS-2LE", "UTF-8", NULL, &dlen, NULL);
982 user_conv = g_convert (user, -1, "UCS-2LE", "UTF-8", NULL, &ulen, NULL);
983 host_conv = g_convert (host, -1, "UCS-2LE", "UTF-8", NULL, &hlen, NULL);
985 ntlm_set_string (&resp.domain, &offset, dlen);
986 ntlm_set_string (&resp.user, &offset, ulen);
987 ntlm_set_string (&resp.host, &offset, hlen);
988 ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
989 ntlm_set_string (&resp.nt_resp, &offset, nt_resp_sz);
991 out = g_malloc (((offset + 3) * 4) / 3 + 6);
992 memcpy (out, "NTLM ", 5);
997 p += g_base64_encode_step ((const guchar *) &resp, sizeof (resp),
998 FALSE, p, &state, &save);
999 p += g_base64_encode_step ((const guchar *) domain_conv, dlen,
1000 FALSE, p, &state, &save);
1001 p += g_base64_encode_step ((const guchar *) user_conv, ulen,
1002 FALSE, p, &state, &save);
1003 p += g_base64_encode_step ((const guchar *) host_conv, hlen,
1004 FALSE, p, &state, &save);
1005 p += g_base64_encode_step (lm_resp, sizeof (lm_resp),
1006 FALSE, p, &state, &save);
1007 p += g_base64_encode_step (nt_resp, nt_resp_sz,
1008 FALSE, p, &state, &save);
1009 p += g_base64_encode_close (FALSE, p, &state, &save);
1012 g_free (domain_conv);
1021 /* Set up a key schedule based on a 56bit key */
1023 setup_schedule (const guchar *key_56, DES_KS ks)
1028 key[0] = (key_56[0]) ;
1029 key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
1030 key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
1031 key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
1032 key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
1033 key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
1034 key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
1035 key[7] = ((key_56[6] << 1) & 0xFF);
1038 for (i = 0; i < 8; i++) {
1039 for (c = bit = 0; bit < 8; bit++)
1040 if (key[i] & (1 << bit))
1046 deskey (ks, key, 0);
1050 calc_response (const guchar *key, const guchar *plaintext, guchar *results)
1054 memcpy (results, plaintext, 8);
1055 memcpy (results + 8, plaintext, 8);
1056 memcpy (results + 16, plaintext, 8);
1058 setup_schedule (key, ks);
1061 setup_schedule (key + 7, ks);
1062 des (ks, results + 8);
1064 setup_schedule (key + 14, ks);
1065 des (ks, results + 16);
1070 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
1071 * this is a reimplementation from spec.) This doesn't need to be
1072 * efficient for our purposes, although it would be nice to fix
1073 * it to not malloc()...
1076 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
1077 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
1078 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
1079 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
1082 md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
1085 guint32 A, B, C, D, AA, BB, CC, DD, X[16];
1086 int pbytes, nbits = nbytes * 8, i, j;
1088 /* There is *always* padding of at least one bit. */
1089 pbytes = ((119 - (nbytes % 64)) % 64) + 1;
1090 M = alloca (nbytes + pbytes + 8);
1091 memcpy (M, in, nbytes);
1092 memset (M + nbytes, 0, pbytes + 8);
1094 M[nbytes + pbytes] = nbits & 0xFF;
1095 M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
1096 M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
1097 M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
1104 for (i = 0; i < nbytes + pbytes + 8; i += 64) {
1105 for (j = 0; j < 16; j++) {
1106 X[j] = (M[i + j*4]) |
1107 (M[i + j*4 + 1] << 8) |
1108 (M[i + j*4 + 2] << 16) |
1109 (M[i + j*4 + 3] << 24);
1117 A = ROT (A + F(B, C, D) + X[0], 3);
1118 D = ROT (D + F(A, B, C) + X[1], 7);
1119 C = ROT (C + F(D, A, B) + X[2], 11);
1120 B = ROT (B + F(C, D, A) + X[3], 19);
1121 A = ROT (A + F(B, C, D) + X[4], 3);
1122 D = ROT (D + F(A, B, C) + X[5], 7);
1123 C = ROT (C + F(D, A, B) + X[6], 11);
1124 B = ROT (B + F(C, D, A) + X[7], 19);
1125 A = ROT (A + F(B, C, D) + X[8], 3);
1126 D = ROT (D + F(A, B, C) + X[9], 7);
1127 C = ROT (C + F(D, A, B) + X[10], 11);
1128 B = ROT (B + F(C, D, A) + X[11], 19);
1129 A = ROT (A + F(B, C, D) + X[12], 3);
1130 D = ROT (D + F(A, B, C) + X[13], 7);
1131 C = ROT (C + F(D, A, B) + X[14], 11);
1132 B = ROT (B + F(C, D, A) + X[15], 19);
1134 A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
1135 D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
1136 C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
1137 B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
1138 A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
1139 D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
1140 C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
1141 B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
1142 A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
1143 D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
1144 C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
1145 B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
1146 A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
1147 D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
1148 C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
1149 B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
1151 A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
1152 D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
1153 C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
1154 B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
1155 A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
1156 D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
1157 C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
1158 B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
1159 A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
1160 D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
1161 C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
1162 B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
1163 A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
1164 D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
1165 C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
1166 B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
1174 digest[0] = A & 0xFF;
1175 digest[1] = (A >> 8) & 0xFF;
1176 digest[2] = (A >> 16) & 0xFF;
1177 digest[3] = (A >> 24) & 0xFF;
1178 digest[4] = B & 0xFF;
1179 digest[5] = (B >> 8) & 0xFF;
1180 digest[6] = (B >> 16) & 0xFF;
1181 digest[7] = (B >> 24) & 0xFF;
1182 digest[8] = C & 0xFF;
1183 digest[9] = (C >> 8) & 0xFF;
1184 digest[10] = (C >> 16) & 0xFF;
1185 digest[11] = (C >> 24) & 0xFF;
1186 digest[12] = D & 0xFF;
1187 digest[13] = (D >> 8) & 0xFF;
1188 digest[14] = (D >> 16) & 0xFF;
1189 digest[15] = (D >> 24) & 0xFF;
1193 /* Public domain DES implementation from Phil Karn */
1194 static const guint32 Spbox[8][64] = {
1195 { 0x01010400,0x00000000,0x00010000,0x01010404,
1196 0x01010004,0x00010404,0x00000004,0x00010000,
1197 0x00000400,0x01010400,0x01010404,0x00000400,
1198 0x01000404,0x01010004,0x01000000,0x00000004,
1199 0x00000404,0x01000400,0x01000400,0x00010400,
1200 0x00010400,0x01010000,0x01010000,0x01000404,
1201 0x00010004,0x01000004,0x01000004,0x00010004,
1202 0x00000000,0x00000404,0x00010404,0x01000000,
1203 0x00010000,0x01010404,0x00000004,0x01010000,
1204 0x01010400,0x01000000,0x01000000,0x00000400,
1205 0x01010004,0x00010000,0x00010400,0x01000004,
1206 0x00000400,0x00000004,0x01000404,0x00010404,
1207 0x01010404,0x00010004,0x01010000,0x01000404,
1208 0x01000004,0x00000404,0x00010404,0x01010400,
1209 0x00000404,0x01000400,0x01000400,0x00000000,
1210 0x00010004,0x00010400,0x00000000,0x01010004 },
1211 { 0x80108020,0x80008000,0x00008000,0x00108020,
1212 0x00100000,0x00000020,0x80100020,0x80008020,
1213 0x80000020,0x80108020,0x80108000,0x80000000,
1214 0x80008000,0x00100000,0x00000020,0x80100020,
1215 0x00108000,0x00100020,0x80008020,0x00000000,
1216 0x80000000,0x00008000,0x00108020,0x80100000,
1217 0x00100020,0x80000020,0x00000000,0x00108000,
1218 0x00008020,0x80108000,0x80100000,0x00008020,
1219 0x00000000,0x00108020,0x80100020,0x00100000,
1220 0x80008020,0x80100000,0x80108000,0x00008000,
1221 0x80100000,0x80008000,0x00000020,0x80108020,
1222 0x00108020,0x00000020,0x00008000,0x80000000,
1223 0x00008020,0x80108000,0x00100000,0x80000020,
1224 0x00100020,0x80008020,0x80000020,0x00100020,
1225 0x00108000,0x00000000,0x80008000,0x00008020,
1226 0x80000000,0x80100020,0x80108020,0x00108000 },
1227 { 0x00000208,0x08020200,0x00000000,0x08020008,
1228 0x08000200,0x00000000,0x00020208,0x08000200,
1229 0x00020008,0x08000008,0x08000008,0x00020000,
1230 0x08020208,0x00020008,0x08020000,0x00000208,
1231 0x08000000,0x00000008,0x08020200,0x00000200,
1232 0x00020200,0x08020000,0x08020008,0x00020208,
1233 0x08000208,0x00020200,0x00020000,0x08000208,
1234 0x00000008,0x08020208,0x00000200,0x08000000,
1235 0x08020200,0x08000000,0x00020008,0x00000208,
1236 0x00020000,0x08020200,0x08000200,0x00000000,
1237 0x00000200,0x00020008,0x08020208,0x08000200,
1238 0x08000008,0x00000200,0x00000000,0x08020008,
1239 0x08000208,0x00020000,0x08000000,0x08020208,
1240 0x00000008,0x00020208,0x00020200,0x08000008,
1241 0x08020000,0x08000208,0x00000208,0x08020000,
1242 0x00020208,0x00000008,0x08020008,0x00020200 },
1243 { 0x00802001,0x00002081,0x00002081,0x00000080,
1244 0x00802080,0x00800081,0x00800001,0x00002001,
1245 0x00000000,0x00802000,0x00802000,0x00802081,
1246 0x00000081,0x00000000,0x00800080,0x00800001,
1247 0x00000001,0x00002000,0x00800000,0x00802001,
1248 0x00000080,0x00800000,0x00002001,0x00002080,
1249 0x00800081,0x00000001,0x00002080,0x00800080,
1250 0x00002000,0x00802080,0x00802081,0x00000081,
1251 0x00800080,0x00800001,0x00802000,0x00802081,
1252 0x00000081,0x00000000,0x00000000,0x00802000,
1253 0x00002080,0x00800080,0x00800081,0x00000001,
1254 0x00802001,0x00002081,0x00002081,0x00000080,
1255 0x00802081,0x00000081,0x00000001,0x00002000,
1256 0x00800001,0x00002001,0x00802080,0x00800081,
1257 0x00002001,0x00002080,0x00800000,0x00802001,
1258 0x00000080,0x00800000,0x00002000,0x00802080 },
1259 { 0x00000100,0x02080100,0x02080000,0x42000100,
1260 0x00080000,0x00000100,0x40000000,0x02080000,
1261 0x40080100,0x00080000,0x02000100,0x40080100,
1262 0x42000100,0x42080000,0x00080100,0x40000000,
1263 0x02000000,0x40080000,0x40080000,0x00000000,
1264 0x40000100,0x42080100,0x42080100,0x02000100,
1265 0x42080000,0x40000100,0x00000000,0x42000000,
1266 0x02080100,0x02000000,0x42000000,0x00080100,
1267 0x00080000,0x42000100,0x00000100,0x02000000,
1268 0x40000000,0x02080000,0x42000100,0x40080100,
1269 0x02000100,0x40000000,0x42080000,0x02080100,
1270 0x40080100,0x00000100,0x02000000,0x42080000,
1271 0x42080100,0x00080100,0x42000000,0x42080100,
1272 0x02080000,0x00000000,0x40080000,0x42000000,
1273 0x00080100,0x02000100,0x40000100,0x00080000,
1274 0x00000000,0x40080000,0x02080100,0x40000100 },
1275 { 0x20000010,0x20400000,0x00004000,0x20404010,
1276 0x20400000,0x00000010,0x20404010,0x00400000,
1277 0x20004000,0x00404010,0x00400000,0x20000010,
1278 0x00400010,0x20004000,0x20000000,0x00004010,
1279 0x00000000,0x00400010,0x20004010,0x00004000,
1280 0x00404000,0x20004010,0x00000010,0x20400010,
1281 0x20400010,0x00000000,0x00404010,0x20404000,
1282 0x00004010,0x00404000,0x20404000,0x20000000,
1283 0x20004000,0x00000010,0x20400010,0x00404000,
1284 0x20404010,0x00400000,0x00004010,0x20000010,
1285 0x00400000,0x20004000,0x20000000,0x00004010,
1286 0x20000010,0x20404010,0x00404000,0x20400000,
1287 0x00404010,0x20404000,0x00000000,0x20400010,
1288 0x00000010,0x00004000,0x20400000,0x00404010,
1289 0x00004000,0x00400010,0x20004010,0x00000000,
1290 0x20404000,0x20000000,0x00400010,0x20004010 },
1291 { 0x00200000,0x04200002,0x04000802,0x00000000,
1292 0x00000800,0x04000802,0x00200802,0x04200800,
1293 0x04200802,0x00200000,0x00000000,0x04000002,
1294 0x00000002,0x04000000,0x04200002,0x00000802,
1295 0x04000800,0x00200802,0x00200002,0x04000800,
1296 0x04000002,0x04200000,0x04200800,0x00200002,
1297 0x04200000,0x00000800,0x00000802,0x04200802,
1298 0x00200800,0x00000002,0x04000000,0x00200800,
1299 0x04000000,0x00200800,0x00200000,0x04000802,
1300 0x04000802,0x04200002,0x04200002,0x00000002,
1301 0x00200002,0x04000000,0x04000800,0x00200000,
1302 0x04200800,0x00000802,0x00200802,0x04200800,
1303 0x00000802,0x04000002,0x04200802,0x04200000,
1304 0x00200800,0x00000000,0x00000002,0x04200802,
1305 0x00000000,0x00200802,0x04200000,0x00000800,
1306 0x04000002,0x04000800,0x00000800,0x00200002 },
1307 { 0x10001040,0x00001000,0x00040000,0x10041040,
1308 0x10000000,0x10001040,0x00000040,0x10000000,
1309 0x00040040,0x10040000,0x10041040,0x00041000,
1310 0x10041000,0x00041040,0x00001000,0x00000040,
1311 0x10040000,0x10000040,0x10001000,0x00001040,
1312 0x00041000,0x00040040,0x10040040,0x10041000,
1313 0x00001040,0x00000000,0x00000000,0x10040040,
1314 0x10000040,0x10001000,0x00041040,0x00040000,
1315 0x00041040,0x00040000,0x10041000,0x00001000,
1316 0x00000040,0x10040040,0x00001000,0x00041040,
1317 0x10001000,0x00000040,0x10000040,0x10040000,
1318 0x10040040,0x10000000,0x00040000,0x10001040,
1319 0x00000000,0x10041040,0x00040040,0x10000040,
1320 0x10040000,0x10001000,0x10001040,0x00000000,
1321 0x10041040,0x00041000,0x00041000,0x00001040,
1322 0x00001040,0x00040040,0x10000000,0x10041000 }
1326 #define F(l,r,key){\
1327 work = ((r >> 4) | (r << 28)) ^ key[0];\
1328 l ^= Spbox[6][work & 0x3f];\
1329 l ^= Spbox[4][(work >> 8) & 0x3f];\
1330 l ^= Spbox[2][(work >> 16) & 0x3f];\
1331 l ^= Spbox[0][(work >> 24) & 0x3f];\
1333 l ^= Spbox[7][work & 0x3f];\
1334 l ^= Spbox[5][(work >> 8) & 0x3f];\
1335 l ^= Spbox[3][(work >> 16) & 0x3f];\
1336 l ^= Spbox[1][(work >> 24) & 0x3f];\
1338 /* Encrypt or decrypt a block of data in ECB mode */
1340 des (guint32 ks[16][2], unsigned char block[8])
1342 guint32 left,right,work;
1344 /* Read input block and place in left/right in big-endian order */
1345 left = ((guint32)block[0] << 24)
1346 | ((guint32)block[1] << 16)
1347 | ((guint32)block[2] << 8)
1348 | (guint32)block[3];
1349 right = ((guint32)block[4] << 24)
1350 | ((guint32)block[5] << 16)
1351 | ((guint32)block[6] << 8)
1352 | (guint32)block[7];
1354 /* Hoey's clever initial permutation algorithm, from Outerbridge
1355 * (see Schneier p 478)
1357 * The convention here is the same as Outerbridge: rotate each
1358 * register left by 1 bit, i.e., so that "left" contains permuted
1359 * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
1360 * (using origin-1 numbering as in the FIPS). This allows us to avoid
1361 * one of the two rotates that would otherwise be required in each of
1364 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
1367 work = ((left >> 16) ^ right) & 0xffff;
1370 work = ((right >> 2) ^ left) & 0x33333333;
1372 right ^= (work << 2);
1373 work = ((right >> 8) ^ left) & 0xff00ff;
1375 right ^= (work << 8);
1376 right = (right << 1) | (right >> 31);
1377 work = (left ^ right) & 0xaaaaaaaa;
1380 left = (left << 1) | (left >> 31);
1382 /* Now do the 16 rounds */
1383 F(left,right,ks[0]);
1384 F(right,left,ks[1]);
1385 F(left,right,ks[2]);
1386 F(right,left,ks[3]);
1387 F(left,right,ks[4]);
1388 F(right,left,ks[5]);
1389 F(left,right,ks[6]);
1390 F(right,left,ks[7]);
1391 F(left,right,ks[8]);
1392 F(right,left,ks[9]);
1393 F(left,right,ks[10]);
1394 F(right,left,ks[11]);
1395 F(left,right,ks[12]);
1396 F(right,left,ks[13]);
1397 F(left,right,ks[14]);
1398 F(right,left,ks[15]);
1400 /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
1401 right = (right << 31) | (right >> 1);
1402 work = (left ^ right) & 0xaaaaaaaa;
1405 left = (left >> 1) | (left << 31);
1406 work = ((left >> 8) ^ right) & 0xff00ff;
1409 work = ((left >> 2) ^ right) & 0x33333333;
1412 work = ((right >> 16) ^ left) & 0xffff;
1414 right ^= work << 16;
1415 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
1419 /* Put the block back into the user's buffer with final swap */
1420 block[0] = right >> 24;
1421 block[1] = right >> 16;
1422 block[2] = right >> 8;
1424 block[4] = left >> 24;
1425 block[5] = left >> 16;
1426 block[6] = left >> 8;
1430 /* Key schedule-related tables from FIPS-46 */
1432 /* permuted choice table (key) */
1433 static const unsigned char pc1[] = {
1434 57, 49, 41, 33, 25, 17, 9,
1435 1, 58, 50, 42, 34, 26, 18,
1436 10, 2, 59, 51, 43, 35, 27,
1437 19, 11, 3, 60, 52, 44, 36,
1439 63, 55, 47, 39, 31, 23, 15,
1440 7, 62, 54, 46, 38, 30, 22,
1441 14, 6, 61, 53, 45, 37, 29,
1442 21, 13, 5, 28, 20, 12, 4
1445 /* number left rotations of pc1 */
1446 static const unsigned char totrot[] = {
1447 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
1450 /* permuted choice key (table) */
1451 static const unsigned char pc2[] = {
1452 14, 17, 11, 24, 1, 5,
1453 3, 28, 15, 6, 21, 10,
1454 23, 19, 12, 4, 26, 8,
1455 16, 7, 27, 20, 13, 2,
1456 41, 52, 31, 37, 47, 55,
1457 30, 40, 51, 45, 33, 48,
1458 44, 49, 39, 56, 34, 53,
1459 46, 42, 50, 36, 29, 32
1462 /* End of DES-defined tables */
1465 /* bit 0 is left-most in byte */
1466 static const int bytebit[] = {
1467 0200,0100,040,020,010,04,02,01
1471 /* Generate key schedule for encryption or decryption
1472 * depending on the value of "decrypt"
1475 deskey (DES_KS k, unsigned char *key, int decrypt)
1477 unsigned char pc1m[56]; /* place to modify pc1 into */
1478 unsigned char pcr[56]; /* place to rotate pc1 into */
1481 unsigned char ks[8];
1483 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
1484 l=pc1[j]-1; /* integer bit location */
1485 m = l & 07; /* find bit */
1486 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
1487 bytebit[m]) /* and which bit of that byte */
1488 ? 1 : 0; /* and store 1-bit result */
1490 for (i=0; i<16; i++) { /* key chunk for each iteration */
1491 memset(ks,0,sizeof(ks)); /* Clear key schedule */
1492 for (j=0; j<56; j++) /* rotate pc1 the right amount */
1493 pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
1494 /* rotate left and right halves independently */
1495 for (j=0; j<48; j++){ /* select bits individually */
1496 /* check bit that goes to ks[j] */
1498 /* mask it in if it's there */
1500 ks[j/6] |= bytebit[l] >> 2;
1503 /* Now convert to packed odd/even interleaved form */
1504 k[i][0] = ((guint32)ks[0] << 24)
1505 | ((guint32)ks[2] << 16)
1506 | ((guint32)ks[4] << 8)
1508 k[i][1] = ((guint32)ks[1] << 24)
1509 | ((guint32)ks[3] << 16)
1510 | ((guint32)ks[5] << 8)