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.
17 #include "soup-auth-ntlm.h"
19 #include "soup-message-private.h"
21 static void soup_ntlm_lanmanager_hash (const char *password,
23 static void soup_ntlm_nt_hash (const char *password,
25 static char *soup_ntlm_request (void);
26 static gboolean soup_ntlm_parse_challenge (const char *challenge,
28 char **default_domain);
29 static char *soup_ntlm_response (const char *nonce,
39 SOUP_NTLM_SENT_REQUEST,
40 SOUP_NTLM_RECEIVED_CHALLENGE,
41 SOUP_NTLM_SENT_RESPONSE,
48 char *response_header;
49 } SoupNTLMConnectionState;
52 SOUP_NTLM_PASSWORD_NONE,
53 SOUP_NTLM_PASSWORD_PROVIDED,
54 SOUP_NTLM_PASSWORD_ACCEPTED,
55 SOUP_NTLM_PASSWORD_REJECTED
56 } SoupNTLMPasswordState;
59 char *username, *domain;
60 guchar nt_hash[21], lm_hash[21];
61 SoupNTLMPasswordState password_state;
64 /* Use Samba's 'winbind' daemon to support NTLM single-sign-on,
65 * by delegating the NTLM challenge/response protocal to a helper
67 * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
68 * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
69 * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
71 gboolean sso_available;
75 } SoupAuthNTLMPrivate;
76 #define SOUP_AUTH_NTLM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_AUTH_NTLM, SoupAuthNTLMPrivate))
79 static gboolean ntlm_auth_available, ntlm_auth_debug;
80 static void sso_ntlm_close (SoupAuthNTLMPrivate *priv);
84 * SOUP_TYPE_AUTH_NTLM:
86 * A #GType corresponding to HTTP-based NTLM authentication.
87 * #SoupSessions do not support this type by default; if you want to
88 * enable support for it, call soup_session_add_feature_by_type(),
89 * passing %SOUP_TYPE_AUTH_NTLM.
94 G_DEFINE_TYPE (SoupAuthNTLM, soup_auth_ntlm, SOUP_TYPE_CONNECTION_AUTH)
97 soup_auth_ntlm_init (SoupAuthNTLM *ntlm)
100 SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (ntlm);
101 const char *username = NULL, *slash;
103 priv->sso_available = TRUE;
107 username = getenv ("NTLMUSER");
109 username = g_get_user_name ();
111 slash = strpbrk (username, "\\/");
113 priv->username = g_strdup (slash + 1);
114 priv->domain = g_strndup (username, slash - username);
116 priv->username = g_strdup (username);
123 soup_auth_ntlm_finalize (GObject *object)
125 SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (object);
127 g_free (priv->username);
128 g_free (priv->domain);
130 memset (priv->nt_hash, 0, sizeof (priv->nt_hash));
131 memset (priv->lm_hash, 0, sizeof (priv->lm_hash));
134 sso_ntlm_close (priv);
137 G_OBJECT_CLASS (soup_auth_ntlm_parent_class)->finalize (object);
142 sso_ntlm_close (SoupAuthNTLMPrivate *priv)
144 if (priv->fd_in != -1) {
149 if (priv->fd_out != -1) {
150 close (priv->fd_out);
156 sso_ntlm_initiate (SoupAuthNTLMPrivate *priv)
161 if (!priv->sso_available)
164 if (!ntlm_auth_available && !ntlm_auth_debug) {
165 priv->sso_available = FALSE;
169 /* Return if ntlm_auth execution process exist already */
170 if (priv->fd_in != -1 && priv->fd_out != -1)
173 /* Clean all sso data before re-initiate */
174 sso_ntlm_close (priv);
177 if (ntlm_auth_debug) {
178 argv[0] = (char *) g_getenv ("SOUP_NTLM_AUTH_DEBUG");
180 priv->sso_available = FALSE;
185 argv[1] = "--helper-protocol";
186 argv[2] = "ntlmssp-client-1";
187 argv[3] = "--use-cached-creds";
188 argv[4] = "--username";
189 argv[5] = priv->username;
190 argv[6] = priv->domain ? "--domain" : NULL;
191 argv[7] = priv->domain;
194 ret = g_spawn_async_with_pipes (NULL, argv, NULL,
195 G_SPAWN_STDERR_TO_DEV_NULL,
197 NULL, &priv->fd_in, &priv->fd_out,
200 priv->sso_available = FALSE;
205 sso_ntlm_response (SoupAuthNTLMPrivate *priv, const char *input, SoupNTLMState conn_state)
210 size_t len_in = strlen (input), len_out = sizeof (buf);
213 int written = write (priv->fd_in, input, len_in);
217 /* write failed if other errors happen */
224 while (len_out > 0) {
225 size = read (priv->fd_out, tmpbuf, len_out);
230 } else if (size == 0)
232 else if (tmpbuf[size - 1] == '\n') {
233 tmpbuf[size - 1] = '\0';
242 if (g_ascii_strcasecmp (buf, "PW") == 0) {
243 /* Samba/winbind installed but not configured */
244 return g_strdup ("PW");
246 if (conn_state == SOUP_NTLM_NEW &&
247 g_ascii_strncasecmp (buf, "YR ", 3) != 0) {
248 /* invalid response for type 1 message */
251 if (conn_state == SOUP_NTLM_RECEIVED_CHALLENGE &&
252 g_ascii_strncasecmp (buf, "KK ", 3) != 0 &&
253 g_ascii_strncasecmp (buf, "AF ", 3) != 0) {
254 /* invalid response for type 3 message */
258 return g_strdup_printf ("NTLM %.*s", (int)(size - 4), buf + 3);
260 #endif /* USE_NTLM_AUTH */
263 soup_auth_ntlm_create_connection_state (SoupConnectionAuth *auth)
265 SoupNTLMConnectionState *conn;
267 conn = g_slice_new0 (SoupNTLMConnectionState);
268 conn->state = SOUP_NTLM_NEW;
274 soup_auth_ntlm_free_connection_state (SoupConnectionAuth *auth,
277 SoupNTLMConnectionState *conn = state;
279 g_free (conn->nonce);
280 g_free (conn->response_header);
281 g_slice_free (SoupNTLMConnectionState, conn);
285 soup_auth_ntlm_update_connection (SoupConnectionAuth *auth, SoupMessage *msg,
286 const char *auth_header, gpointer state)
288 SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (auth);
289 SoupNTLMConnectionState *conn = state;
290 gboolean success = TRUE;
292 /* Note that we only return FALSE if some sort of parsing error
293 * occurs. Otherwise, the SoupAuth is still reusable (though it may
294 * no longer be _ready or _authenticated).
297 if (!g_str_has_prefix (auth_header, "NTLM"))
300 if (conn->state > SOUP_NTLM_SENT_REQUEST) {
301 if (priv->password_state == SOUP_NTLM_PASSWORD_ACCEPTED) {
302 /* We know our password is correct, so a 401
303 * means "permission denied". Since the conn
304 * state is now FAILED, the auth is no longer
305 * is_ready() for this message, so this will
306 * cause a "retrying" authenticate signal.
308 conn->state = SOUP_NTLM_FAILED;
313 if (priv->sso_available) {
314 conn->state = SOUP_NTLM_SSO_FAILED;
315 priv->password_state = SOUP_NTLM_PASSWORD_NONE;
318 conn->state = SOUP_NTLM_FAILED;
319 priv->password_state = SOUP_NTLM_PASSWORD_REJECTED;
326 if (conn->state == SOUP_NTLM_NEW && !auth_header[4])
329 if (!soup_ntlm_parse_challenge (auth_header + 5, &conn->nonce,
330 priv->domain ? NULL : &priv->domain)) {
331 conn->state = SOUP_NTLM_FAILED;
336 if (priv->sso_available && conn->state == SOUP_NTLM_SENT_REQUEST) {
337 char *input, *response;
339 /* Re-Initiate ntlm_auth process in case it was closed/killed abnormally */
340 if (!sso_ntlm_initiate (priv)) {
341 conn->state = SOUP_NTLM_SSO_FAILED;
346 input = g_strdup_printf ("TT %s\n", auth_header + 5);
347 response = sso_ntlm_response (priv, input, conn->state);
348 sso_ntlm_close (priv);
352 conn->state = SOUP_NTLM_SSO_FAILED;
354 } else if (!g_ascii_strcasecmp (response, "PW")) {
355 priv->sso_available = FALSE;
358 conn->response_header = response;
359 if (priv->password_state != SOUP_NTLM_PASSWORD_ACCEPTED)
360 priv->password_state = SOUP_NTLM_PASSWORD_PROVIDED;
366 if (conn->state == SOUP_NTLM_SENT_REQUEST)
367 conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
369 g_object_set (G_OBJECT (auth),
370 SOUP_AUTH_REALM, priv->domain,
371 SOUP_AUTH_HOST, soup_message_get_uri (msg)->host,
377 soup_auth_ntlm_get_protection_space (SoupAuth *auth, SoupURI *source_uri)
381 space = g_strdup (source_uri->path);
383 /* Strip filename component */
384 p = strrchr (space, '/');
385 if (p && p != space && p[1])
388 return g_slist_prepend (NULL, space);
392 soup_auth_ntlm_authenticate (SoupAuth *auth, const char *username,
393 const char *password)
395 SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (auth);
398 g_return_if_fail (username != NULL);
399 g_return_if_fail (password != NULL);
402 g_free (priv->username);
404 g_free (priv->domain);
406 slash = strpbrk (username, "\\/");
408 priv->domain = g_strndup (username, slash - username);
409 priv->username = g_strdup (slash + 1);
411 priv->domain = g_strdup ("");
412 priv->username = g_strdup (username);
415 soup_ntlm_nt_hash (password, priv->nt_hash);
416 soup_ntlm_lanmanager_hash (password, priv->lm_hash);
418 priv->password_state = SOUP_NTLM_PASSWORD_PROVIDED;
422 soup_auth_ntlm_is_authenticated (SoupAuth *auth)
424 SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (auth);
426 return (priv->password_state != SOUP_NTLM_PASSWORD_NONE &&
427 priv->password_state != SOUP_NTLM_PASSWORD_REJECTED);
431 soup_auth_ntlm_is_connection_ready (SoupConnectionAuth *auth,
435 SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (auth);
436 SoupNTLMConnectionState *conn = state;
438 if (priv->password_state == SOUP_NTLM_PASSWORD_REJECTED)
441 if (priv->password_state == SOUP_NTLM_PASSWORD_PROVIDED)
444 return conn->state != SOUP_NTLM_FAILED;
448 got_final_auth_result (SoupMessage *msg, gpointer data)
450 SoupAuth *auth = data;
452 g_signal_handlers_disconnect_by_func (msg, G_CALLBACK (got_final_auth_result), auth);
454 if (auth != soup_message_get_auth (msg))
457 if (msg->status_code != SOUP_STATUS_UNAUTHORIZED)
458 SOUP_AUTH_NTLM_GET_PRIVATE (auth)->password_state = SOUP_NTLM_PASSWORD_ACCEPTED;
462 soup_auth_ntlm_get_connection_authorization (SoupConnectionAuth *auth,
466 SoupAuthNTLMPrivate *priv = SOUP_AUTH_NTLM_GET_PRIVATE (auth);
467 SoupNTLMConnectionState *conn = state;
470 switch (conn->state) {
473 if (sso_ntlm_initiate (priv)) {
474 header = sso_ntlm_response (priv, "YR\n", conn->state);
476 if (g_ascii_strcasecmp (header, "PW") != 0) {
477 conn->state = SOUP_NTLM_SENT_REQUEST;
482 priv->sso_available = FALSE;
485 g_warning ("NTLM single-sign-on using %s failed", NTLM_AUTH);
488 /* If NTLM single-sign-on fails, go back to original
489 * request handling process.
492 header = soup_ntlm_request ();
493 conn->state = SOUP_NTLM_SENT_REQUEST;
495 case SOUP_NTLM_RECEIVED_CHALLENGE:
496 if (conn->response_header) {
497 header = conn->response_header;
498 conn->response_header = NULL;
500 header = soup_ntlm_response (conn->nonce,
507 g_clear_pointer (&conn->nonce, g_free);
508 conn->state = SOUP_NTLM_SENT_RESPONSE;
510 if (priv->password_state != SOUP_NTLM_PASSWORD_ACCEPTED) {
511 /* We need to know if this worked */
512 g_signal_connect (msg, "got-headers",
513 G_CALLBACK (got_final_auth_result),
518 case SOUP_NTLM_SSO_FAILED:
519 /* Restart request without SSO */
520 g_warning ("NTLM single-sign-on by using %s failed", NTLM_AUTH);
521 priv->sso_available = FALSE;
522 header = soup_ntlm_request ();
523 conn->state = SOUP_NTLM_SENT_REQUEST;
534 soup_auth_ntlm_class_init (SoupAuthNTLMClass *auth_ntlm_class)
536 SoupAuthClass *auth_class = SOUP_AUTH_CLASS (auth_ntlm_class);
537 SoupConnectionAuthClass *connauth_class = SOUP_CONNECTION_AUTH_CLASS (auth_ntlm_class);
538 GObjectClass *object_class = G_OBJECT_CLASS (auth_ntlm_class);
540 g_type_class_add_private (auth_ntlm_class, sizeof (SoupAuthNTLMPrivate));
542 auth_class->scheme_name = "NTLM";
543 auth_class->strength = 3;
545 auth_class->get_protection_space = soup_auth_ntlm_get_protection_space;
546 auth_class->authenticate = soup_auth_ntlm_authenticate;
547 auth_class->is_authenticated = soup_auth_ntlm_is_authenticated;
549 connauth_class->create_connection_state = soup_auth_ntlm_create_connection_state;
550 connauth_class->free_connection_state = soup_auth_ntlm_free_connection_state;
551 connauth_class->update_connection = soup_auth_ntlm_update_connection;
552 connauth_class->get_connection_authorization = soup_auth_ntlm_get_connection_authorization;
553 connauth_class->is_connection_ready = soup_auth_ntlm_is_connection_ready;
555 object_class->finalize = soup_auth_ntlm_finalize;
558 ntlm_auth_available = g_file_test (NTLM_AUTH, G_FILE_TEST_IS_EXECUTABLE);
559 ntlm_auth_debug = (g_getenv ("SOUP_NTLM_AUTH_DEBUG") != NULL);
563 static void md4sum (const unsigned char *in,
565 unsigned char digest[16]);
567 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
569 static void deskey (DES_KS, unsigned char *, int);
571 static void des (DES_KS, unsigned char *);
573 static void setup_schedule (const guchar *key_56, DES_KS ks);
575 static void calc_response (const guchar *key,
576 const guchar *plaintext,
579 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
580 "\x4B\x47\x53\x21\x40\x23\x24\x25" \
581 "\x00\x00\x00\x00\x00"
584 soup_ntlm_lanmanager_hash (const char *password, guchar hash[21])
586 guchar lm_password [15];
590 for (i = 0; i < 14 && password [i]; i++)
591 lm_password [i] = g_ascii_toupper ((unsigned char) password [i]);
594 lm_password [i] = '\0';
596 memcpy (hash, LM_PASSWORD_MAGIC, 21);
598 setup_schedule (lm_password, ks);
601 setup_schedule (lm_password + 7, ks);
606 soup_ntlm_nt_hash (const char *password, guchar hash[21])
608 unsigned char *buf, *p;
610 p = buf = g_malloc (strlen (password) * 2);
617 md4sum (buf, p - buf, hash);
618 memset (hash + 16, 0, 5);
630 #define NTLM_CHALLENGE_NONCE_OFFSET 24
631 #define NTLM_CHALLENGE_NONCE_LENGTH 8
632 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
634 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
635 #define NTLM_RESPONSE_FLAGS 0x8201
645 NTLMString session_key;
651 ntlm_set_string (NTLMString *string, int *offset, int len)
653 string->offset = GUINT16_TO_LE (*offset);
654 string->length = string->length2 = GUINT16_TO_LE (len);
659 soup_ntlm_request (void)
661 return g_strdup ("NTLM TlRMTVNTUAABAAAABYIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
665 soup_ntlm_parse_challenge (const char *challenge,
667 char **default_domain)
673 chall = g_base64_decode (challenge, &clen);
674 if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET ||
675 clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) {
680 if (default_domain) {
681 memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
682 domain.length = GUINT16_FROM_LE (domain.length);
683 domain.offset = GUINT16_FROM_LE (domain.offset);
685 if (clen < domain.length + domain.offset) {
690 *default_domain = g_convert ((char *)chall + domain.offset,
691 domain.length, "UTF-8", "UCS-2LE",
696 *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
697 NTLM_CHALLENGE_NONCE_LENGTH);
705 soup_ntlm_response (const char *nonce,
713 gsize hlen, dlen, ulen;
714 guchar lm_resp[24], nt_resp[24];
715 char *user_conv, *host_conv, *domain_conv;
720 calc_response (nt_hash, (guchar *)nonce, nt_resp);
721 calc_response (lm_hash, (guchar *)nonce, lm_resp);
723 memset (&resp, 0, sizeof (resp));
724 memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
725 resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
727 offset = sizeof (resp);
732 domain_conv = g_convert (domain, -1, "UCS-2LE", "UTF-8", NULL, &dlen, NULL);
733 user_conv = g_convert (user, -1, "UCS-2LE", "UTF-8", NULL, &ulen, NULL);
734 host_conv = g_convert (host, -1, "UCS-2LE", "UTF-8", NULL, &hlen, NULL);
736 ntlm_set_string (&resp.domain, &offset, dlen);
737 ntlm_set_string (&resp.user, &offset, ulen);
738 ntlm_set_string (&resp.host, &offset, hlen);
739 ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
740 ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
742 out = g_malloc (((offset + 3) * 4) / 3 + 6);
743 strncpy (out, "NTLM ", 5);
748 p += g_base64_encode_step ((const guchar *) &resp, sizeof (resp),
749 FALSE, p, &state, &save);
750 p += g_base64_encode_step ((const guchar *) domain_conv, dlen,
751 FALSE, p, &state, &save);
752 p += g_base64_encode_step ((const guchar *) user_conv, ulen,
753 FALSE, p, &state, &save);
754 p += g_base64_encode_step ((const guchar *) host_conv, hlen,
755 FALSE, p, &state, &save);
756 p += g_base64_encode_step (lm_resp, sizeof (lm_resp),
757 FALSE, p, &state, &save);
758 p += g_base64_encode_step (nt_resp, sizeof (nt_resp),
759 FALSE, p, &state, &save);
760 p += g_base64_encode_close (FALSE, p, &state, &save);
763 g_free (domain_conv);
771 /* Set up a key schedule based on a 56bit key */
773 setup_schedule (const guchar *key_56, DES_KS ks)
778 key[0] = (key_56[0]) ;
779 key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
780 key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
781 key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
782 key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
783 key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
784 key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
785 key[7] = ((key_56[6] << 1) & 0xFF);
788 for (i = 0; i < 8; i++) {
789 for (c = bit = 0; bit < 8; bit++)
790 if (key[i] & (1 << bit))
800 calc_response (const guchar *key, const guchar *plaintext, guchar *results)
804 memcpy (results, plaintext, 8);
805 memcpy (results + 8, plaintext, 8);
806 memcpy (results + 16, plaintext, 8);
808 setup_schedule (key, ks);
811 setup_schedule (key + 7, ks);
812 des (ks, results + 8);
814 setup_schedule (key + 14, ks);
815 des (ks, results + 16);
820 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
821 * this is a reimplementation from spec.) This doesn't need to be
822 * efficient for our purposes, although it would be nice to fix
823 * it to not malloc()...
826 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
827 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
828 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
829 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
832 md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
835 guint32 A, B, C, D, AA, BB, CC, DD, X[16];
836 int pbytes, nbits = nbytes * 8, i, j;
838 pbytes = (120 - (nbytes % 64)) % 64;
839 M = alloca (nbytes + pbytes + 8);
840 memcpy (M, in, nbytes);
841 memset (M + nbytes, 0, pbytes + 8);
843 M[nbytes + pbytes] = nbits & 0xFF;
844 M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
845 M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
846 M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
853 for (i = 0; i < nbytes + pbytes + 8; i += 64) {
854 for (j = 0; j < 16; j++) {
855 X[j] = (M[i + j*4]) |
856 (M[i + j*4 + 1] << 8) |
857 (M[i + j*4 + 2] << 16) |
858 (M[i + j*4 + 3] << 24);
866 A = ROT (A + F(B, C, D) + X[0], 3);
867 D = ROT (D + F(A, B, C) + X[1], 7);
868 C = ROT (C + F(D, A, B) + X[2], 11);
869 B = ROT (B + F(C, D, A) + X[3], 19);
870 A = ROT (A + F(B, C, D) + X[4], 3);
871 D = ROT (D + F(A, B, C) + X[5], 7);
872 C = ROT (C + F(D, A, B) + X[6], 11);
873 B = ROT (B + F(C, D, A) + X[7], 19);
874 A = ROT (A + F(B, C, D) + X[8], 3);
875 D = ROT (D + F(A, B, C) + X[9], 7);
876 C = ROT (C + F(D, A, B) + X[10], 11);
877 B = ROT (B + F(C, D, A) + X[11], 19);
878 A = ROT (A + F(B, C, D) + X[12], 3);
879 D = ROT (D + F(A, B, C) + X[13], 7);
880 C = ROT (C + F(D, A, B) + X[14], 11);
881 B = ROT (B + F(C, D, A) + X[15], 19);
883 A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
884 D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
885 C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
886 B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
887 A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
888 D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
889 C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
890 B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
891 A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
892 D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
893 C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
894 B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
895 A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
896 D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
897 C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
898 B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
900 A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
901 D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
902 C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
903 B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
904 A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
905 D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
906 C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
907 B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
908 A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
909 D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
910 C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
911 B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
912 A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
913 D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
914 C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
915 B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
923 digest[0] = A & 0xFF;
924 digest[1] = (A >> 8) & 0xFF;
925 digest[2] = (A >> 16) & 0xFF;
926 digest[3] = (A >> 24) & 0xFF;
927 digest[4] = B & 0xFF;
928 digest[5] = (B >> 8) & 0xFF;
929 digest[6] = (B >> 16) & 0xFF;
930 digest[7] = (B >> 24) & 0xFF;
931 digest[8] = C & 0xFF;
932 digest[9] = (C >> 8) & 0xFF;
933 digest[10] = (C >> 16) & 0xFF;
934 digest[11] = (C >> 24) & 0xFF;
935 digest[12] = D & 0xFF;
936 digest[13] = (D >> 8) & 0xFF;
937 digest[14] = (D >> 16) & 0xFF;
938 digest[15] = (D >> 24) & 0xFF;
942 /* Public domain DES implementation from Phil Karn */
943 static const guint32 Spbox[8][64] = {
944 { 0x01010400,0x00000000,0x00010000,0x01010404,
945 0x01010004,0x00010404,0x00000004,0x00010000,
946 0x00000400,0x01010400,0x01010404,0x00000400,
947 0x01000404,0x01010004,0x01000000,0x00000004,
948 0x00000404,0x01000400,0x01000400,0x00010400,
949 0x00010400,0x01010000,0x01010000,0x01000404,
950 0x00010004,0x01000004,0x01000004,0x00010004,
951 0x00000000,0x00000404,0x00010404,0x01000000,
952 0x00010000,0x01010404,0x00000004,0x01010000,
953 0x01010400,0x01000000,0x01000000,0x00000400,
954 0x01010004,0x00010000,0x00010400,0x01000004,
955 0x00000400,0x00000004,0x01000404,0x00010404,
956 0x01010404,0x00010004,0x01010000,0x01000404,
957 0x01000004,0x00000404,0x00010404,0x01010400,
958 0x00000404,0x01000400,0x01000400,0x00000000,
959 0x00010004,0x00010400,0x00000000,0x01010004 },
960 { 0x80108020,0x80008000,0x00008000,0x00108020,
961 0x00100000,0x00000020,0x80100020,0x80008020,
962 0x80000020,0x80108020,0x80108000,0x80000000,
963 0x80008000,0x00100000,0x00000020,0x80100020,
964 0x00108000,0x00100020,0x80008020,0x00000000,
965 0x80000000,0x00008000,0x00108020,0x80100000,
966 0x00100020,0x80000020,0x00000000,0x00108000,
967 0x00008020,0x80108000,0x80100000,0x00008020,
968 0x00000000,0x00108020,0x80100020,0x00100000,
969 0x80008020,0x80100000,0x80108000,0x00008000,
970 0x80100000,0x80008000,0x00000020,0x80108020,
971 0x00108020,0x00000020,0x00008000,0x80000000,
972 0x00008020,0x80108000,0x00100000,0x80000020,
973 0x00100020,0x80008020,0x80000020,0x00100020,
974 0x00108000,0x00000000,0x80008000,0x00008020,
975 0x80000000,0x80100020,0x80108020,0x00108000 },
976 { 0x00000208,0x08020200,0x00000000,0x08020008,
977 0x08000200,0x00000000,0x00020208,0x08000200,
978 0x00020008,0x08000008,0x08000008,0x00020000,
979 0x08020208,0x00020008,0x08020000,0x00000208,
980 0x08000000,0x00000008,0x08020200,0x00000200,
981 0x00020200,0x08020000,0x08020008,0x00020208,
982 0x08000208,0x00020200,0x00020000,0x08000208,
983 0x00000008,0x08020208,0x00000200,0x08000000,
984 0x08020200,0x08000000,0x00020008,0x00000208,
985 0x00020000,0x08020200,0x08000200,0x00000000,
986 0x00000200,0x00020008,0x08020208,0x08000200,
987 0x08000008,0x00000200,0x00000000,0x08020008,
988 0x08000208,0x00020000,0x08000000,0x08020208,
989 0x00000008,0x00020208,0x00020200,0x08000008,
990 0x08020000,0x08000208,0x00000208,0x08020000,
991 0x00020208,0x00000008,0x08020008,0x00020200 },
992 { 0x00802001,0x00002081,0x00002081,0x00000080,
993 0x00802080,0x00800081,0x00800001,0x00002001,
994 0x00000000,0x00802000,0x00802000,0x00802081,
995 0x00000081,0x00000000,0x00800080,0x00800001,
996 0x00000001,0x00002000,0x00800000,0x00802001,
997 0x00000080,0x00800000,0x00002001,0x00002080,
998 0x00800081,0x00000001,0x00002080,0x00800080,
999 0x00002000,0x00802080,0x00802081,0x00000081,
1000 0x00800080,0x00800001,0x00802000,0x00802081,
1001 0x00000081,0x00000000,0x00000000,0x00802000,
1002 0x00002080,0x00800080,0x00800081,0x00000001,
1003 0x00802001,0x00002081,0x00002081,0x00000080,
1004 0x00802081,0x00000081,0x00000001,0x00002000,
1005 0x00800001,0x00002001,0x00802080,0x00800081,
1006 0x00002001,0x00002080,0x00800000,0x00802001,
1007 0x00000080,0x00800000,0x00002000,0x00802080 },
1008 { 0x00000100,0x02080100,0x02080000,0x42000100,
1009 0x00080000,0x00000100,0x40000000,0x02080000,
1010 0x40080100,0x00080000,0x02000100,0x40080100,
1011 0x42000100,0x42080000,0x00080100,0x40000000,
1012 0x02000000,0x40080000,0x40080000,0x00000000,
1013 0x40000100,0x42080100,0x42080100,0x02000100,
1014 0x42080000,0x40000100,0x00000000,0x42000000,
1015 0x02080100,0x02000000,0x42000000,0x00080100,
1016 0x00080000,0x42000100,0x00000100,0x02000000,
1017 0x40000000,0x02080000,0x42000100,0x40080100,
1018 0x02000100,0x40000000,0x42080000,0x02080100,
1019 0x40080100,0x00000100,0x02000000,0x42080000,
1020 0x42080100,0x00080100,0x42000000,0x42080100,
1021 0x02080000,0x00000000,0x40080000,0x42000000,
1022 0x00080100,0x02000100,0x40000100,0x00080000,
1023 0x00000000,0x40080000,0x02080100,0x40000100 },
1024 { 0x20000010,0x20400000,0x00004000,0x20404010,
1025 0x20400000,0x00000010,0x20404010,0x00400000,
1026 0x20004000,0x00404010,0x00400000,0x20000010,
1027 0x00400010,0x20004000,0x20000000,0x00004010,
1028 0x00000000,0x00400010,0x20004010,0x00004000,
1029 0x00404000,0x20004010,0x00000010,0x20400010,
1030 0x20400010,0x00000000,0x00404010,0x20404000,
1031 0x00004010,0x00404000,0x20404000,0x20000000,
1032 0x20004000,0x00000010,0x20400010,0x00404000,
1033 0x20404010,0x00400000,0x00004010,0x20000010,
1034 0x00400000,0x20004000,0x20000000,0x00004010,
1035 0x20000010,0x20404010,0x00404000,0x20400000,
1036 0x00404010,0x20404000,0x00000000,0x20400010,
1037 0x00000010,0x00004000,0x20400000,0x00404010,
1038 0x00004000,0x00400010,0x20004010,0x00000000,
1039 0x20404000,0x20000000,0x00400010,0x20004010 },
1040 { 0x00200000,0x04200002,0x04000802,0x00000000,
1041 0x00000800,0x04000802,0x00200802,0x04200800,
1042 0x04200802,0x00200000,0x00000000,0x04000002,
1043 0x00000002,0x04000000,0x04200002,0x00000802,
1044 0x04000800,0x00200802,0x00200002,0x04000800,
1045 0x04000002,0x04200000,0x04200800,0x00200002,
1046 0x04200000,0x00000800,0x00000802,0x04200802,
1047 0x00200800,0x00000002,0x04000000,0x00200800,
1048 0x04000000,0x00200800,0x00200000,0x04000802,
1049 0x04000802,0x04200002,0x04200002,0x00000002,
1050 0x00200002,0x04000000,0x04000800,0x00200000,
1051 0x04200800,0x00000802,0x00200802,0x04200800,
1052 0x00000802,0x04000002,0x04200802,0x04200000,
1053 0x00200800,0x00000000,0x00000002,0x04200802,
1054 0x00000000,0x00200802,0x04200000,0x00000800,
1055 0x04000002,0x04000800,0x00000800,0x00200002 },
1056 { 0x10001040,0x00001000,0x00040000,0x10041040,
1057 0x10000000,0x10001040,0x00000040,0x10000000,
1058 0x00040040,0x10040000,0x10041040,0x00041000,
1059 0x10041000,0x00041040,0x00001000,0x00000040,
1060 0x10040000,0x10000040,0x10001000,0x00001040,
1061 0x00041000,0x00040040,0x10040040,0x10041000,
1062 0x00001040,0x00000000,0x00000000,0x10040040,
1063 0x10000040,0x10001000,0x00041040,0x00040000,
1064 0x00041040,0x00040000,0x10041000,0x00001000,
1065 0x00000040,0x10040040,0x00001000,0x00041040,
1066 0x10001000,0x00000040,0x10000040,0x10040000,
1067 0x10040040,0x10000000,0x00040000,0x10001040,
1068 0x00000000,0x10041040,0x00040040,0x10000040,
1069 0x10040000,0x10001000,0x10001040,0x00000000,
1070 0x10041040,0x00041000,0x00041000,0x00001040,
1071 0x00001040,0x00040040,0x10000000,0x10041000 }
1075 #define F(l,r,key){\
1076 work = ((r >> 4) | (r << 28)) ^ key[0];\
1077 l ^= Spbox[6][work & 0x3f];\
1078 l ^= Spbox[4][(work >> 8) & 0x3f];\
1079 l ^= Spbox[2][(work >> 16) & 0x3f];\
1080 l ^= Spbox[0][(work >> 24) & 0x3f];\
1082 l ^= Spbox[7][work & 0x3f];\
1083 l ^= Spbox[5][(work >> 8) & 0x3f];\
1084 l ^= Spbox[3][(work >> 16) & 0x3f];\
1085 l ^= Spbox[1][(work >> 24) & 0x3f];\
1087 /* Encrypt or decrypt a block of data in ECB mode */
1089 des (guint32 ks[16][2], unsigned char block[8])
1091 guint32 left,right,work;
1093 /* Read input block and place in left/right in big-endian order */
1094 left = ((guint32)block[0] << 24)
1095 | ((guint32)block[1] << 16)
1096 | ((guint32)block[2] << 8)
1097 | (guint32)block[3];
1098 right = ((guint32)block[4] << 24)
1099 | ((guint32)block[5] << 16)
1100 | ((guint32)block[6] << 8)
1101 | (guint32)block[7];
1103 /* Hoey's clever initial permutation algorithm, from Outerbridge
1104 * (see Schneier p 478)
1106 * The convention here is the same as Outerbridge: rotate each
1107 * register left by 1 bit, i.e., so that "left" contains permuted
1108 * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
1109 * (using origin-1 numbering as in the FIPS). This allows us to avoid
1110 * one of the two rotates that would otherwise be required in each of
1113 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
1116 work = ((left >> 16) ^ right) & 0xffff;
1119 work = ((right >> 2) ^ left) & 0x33333333;
1121 right ^= (work << 2);
1122 work = ((right >> 8) ^ left) & 0xff00ff;
1124 right ^= (work << 8);
1125 right = (right << 1) | (right >> 31);
1126 work = (left ^ right) & 0xaaaaaaaa;
1129 left = (left << 1) | (left >> 31);
1131 /* Now do the 16 rounds */
1132 F(left,right,ks[0]);
1133 F(right,left,ks[1]);
1134 F(left,right,ks[2]);
1135 F(right,left,ks[3]);
1136 F(left,right,ks[4]);
1137 F(right,left,ks[5]);
1138 F(left,right,ks[6]);
1139 F(right,left,ks[7]);
1140 F(left,right,ks[8]);
1141 F(right,left,ks[9]);
1142 F(left,right,ks[10]);
1143 F(right,left,ks[11]);
1144 F(left,right,ks[12]);
1145 F(right,left,ks[13]);
1146 F(left,right,ks[14]);
1147 F(right,left,ks[15]);
1149 /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
1150 right = (right << 31) | (right >> 1);
1151 work = (left ^ right) & 0xaaaaaaaa;
1154 left = (left >> 1) | (left << 31);
1155 work = ((left >> 8) ^ right) & 0xff00ff;
1158 work = ((left >> 2) ^ right) & 0x33333333;
1161 work = ((right >> 16) ^ left) & 0xffff;
1163 right ^= work << 16;
1164 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
1168 /* Put the block back into the user's buffer with final swap */
1169 block[0] = right >> 24;
1170 block[1] = right >> 16;
1171 block[2] = right >> 8;
1173 block[4] = left >> 24;
1174 block[5] = left >> 16;
1175 block[6] = left >> 8;
1179 /* Key schedule-related tables from FIPS-46 */
1181 /* permuted choice table (key) */
1182 static const unsigned char pc1[] = {
1183 57, 49, 41, 33, 25, 17, 9,
1184 1, 58, 50, 42, 34, 26, 18,
1185 10, 2, 59, 51, 43, 35, 27,
1186 19, 11, 3, 60, 52, 44, 36,
1188 63, 55, 47, 39, 31, 23, 15,
1189 7, 62, 54, 46, 38, 30, 22,
1190 14, 6, 61, 53, 45, 37, 29,
1191 21, 13, 5, 28, 20, 12, 4
1194 /* number left rotations of pc1 */
1195 static const unsigned char totrot[] = {
1196 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
1199 /* permuted choice key (table) */
1200 static const unsigned char pc2[] = {
1201 14, 17, 11, 24, 1, 5,
1202 3, 28, 15, 6, 21, 10,
1203 23, 19, 12, 4, 26, 8,
1204 16, 7, 27, 20, 13, 2,
1205 41, 52, 31, 37, 47, 55,
1206 30, 40, 51, 45, 33, 48,
1207 44, 49, 39, 56, 34, 53,
1208 46, 42, 50, 36, 29, 32
1211 /* End of DES-defined tables */
1214 /* bit 0 is left-most in byte */
1215 static const int bytebit[] = {
1216 0200,0100,040,020,010,04,02,01
1220 /* Generate key schedule for encryption or decryption
1221 * depending on the value of "decrypt"
1224 deskey (DES_KS k, unsigned char *key, int decrypt)
1226 unsigned char pc1m[56]; /* place to modify pc1 into */
1227 unsigned char pcr[56]; /* place to rotate pc1 into */
1230 unsigned char ks[8];
1232 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
1233 l=pc1[j]-1; /* integer bit location */
1234 m = l & 07; /* find bit */
1235 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
1236 bytebit[m]) /* and which bit of that byte */
1237 ? 1 : 0; /* and store 1-bit result */
1239 for (i=0; i<16; i++) { /* key chunk for each iteration */
1240 memset(ks,0,sizeof(ks)); /* Clear key schedule */
1241 for (j=0; j<56; j++) /* rotate pc1 the right amount */
1242 pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
1243 /* rotate left and right halves independently */
1244 for (j=0; j<48; j++){ /* select bits individually */
1245 /* check bit that goes to ks[j] */
1247 /* mask it in if it's there */
1249 ks[j/6] |= bytebit[l] >> 2;
1252 /* Now convert to packed odd/even interleaved form */
1253 k[i][0] = ((guint32)ks[0] << 24)
1254 | ((guint32)ks[2] << 16)
1255 | ((guint32)ks[4] << 8)
1257 k[i][1] = ((guint32)ks[1] << 24)
1258 | ((guint32)ks[3] << 16)
1259 | ((guint32)ks[5] << 8)