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.
16 #include "soup-auth-manager-ntlm.h"
17 #include "soup-auth-ntlm.h"
18 #include "soup-message.h"
19 #include "soup-message-private.h"
20 #include "soup-misc.h"
21 #include "soup-session.h"
22 #include "soup-session-private.h"
27 SOUP_NTLM_SENT_REQUEST,
28 SOUP_NTLM_RECEIVED_CHALLENGE,
29 SOUP_NTLM_SENT_RESPONSE,
36 char *response_header;
42 struct SoupAuthManagerNTLM {
44 GHashTable *connections_by_msg;
45 GHashTable *connections_by_id;
48 static void ntlm_request_queued (SoupSession *session, SoupMessage *msg,
50 static void ntlm_request_started (SoupSession *session, SoupMessage *msg,
51 SoupSocket *socket, gpointer ntlm);
52 static void ntlm_request_unqueued (SoupSession *session, SoupMessage *msg,
55 static char *soup_ntlm_request (void);
56 static gboolean soup_ntlm_parse_challenge (const char *challenge,
58 char **default_domain);
59 static char *soup_ntlm_response (const char *nonce,
66 soup_auth_manager_ntlm_new (SoupSession *session)
68 SoupAuthManagerNTLM *ntlm;
70 ntlm = g_slice_new (SoupAuthManagerNTLM);
71 ntlm->session = session;
72 ntlm->connections_by_id = g_hash_table_new (NULL, NULL);
73 ntlm->connections_by_msg = g_hash_table_new (NULL, NULL);
74 g_signal_connect (session, "request_queued",
75 G_CALLBACK (ntlm_request_queued), ntlm);
76 g_signal_connect (session, "request_started",
77 G_CALLBACK (ntlm_request_started), ntlm);
78 g_signal_connect (session, "request_unqueued",
79 G_CALLBACK (ntlm_request_unqueued), ntlm);
84 free_ntlm_connection (SoupNTLMConnection *conn)
86 g_free (conn->response_header);
88 g_free (conn->domain);
90 g_object_unref (conn->auth);
91 g_slice_free (SoupNTLMConnection, conn);
95 free_ntlm_connection_foreach (gpointer key, gpointer value, gpointer user_data)
97 free_ntlm_connection (value);
101 soup_auth_manager_ntlm_free (SoupAuthManagerNTLM *ntlm)
103 g_hash_table_foreach (ntlm->connections_by_id,
104 free_ntlm_connection_foreach, NULL);
105 g_hash_table_destroy (ntlm->connections_by_id);
106 g_hash_table_destroy (ntlm->connections_by_msg);
107 g_signal_handlers_disconnect_by_func (ntlm->session,
108 ntlm_request_queued, ntlm);
109 g_signal_handlers_disconnect_by_func (ntlm->session,
110 ntlm_request_started, ntlm);
111 g_signal_handlers_disconnect_by_func (ntlm->session,
112 ntlm_request_unqueued, ntlm);
114 g_slice_free (SoupAuthManagerNTLM, ntlm);
118 delete_conn (SoupSocket *socket, gpointer user_data)
120 SoupAuthManagerNTLM *ntlm = user_data;
121 SoupNTLMConnection *conn;
123 conn = g_hash_table_lookup (ntlm->connections_by_id, socket);
125 free_ntlm_connection (conn);
126 g_hash_table_remove (ntlm->connections_by_id, socket);
127 g_signal_handlers_disconnect_by_func (socket, delete_conn, ntlm);
130 static SoupNTLMConnection *
131 get_connection (SoupAuthManagerNTLM *ntlm, SoupSocket *socket)
133 SoupNTLMConnection *conn;
135 conn = g_hash_table_lookup (ntlm->connections_by_id, socket);
139 conn = g_slice_new0 (SoupNTLMConnection);
140 conn->socket = socket;
141 conn->state = SOUP_NTLM_NEW;
142 g_hash_table_insert (ntlm->connections_by_id, socket, conn);
144 g_signal_connect (socket, "disconnected",
145 G_CALLBACK (delete_conn), ntlm);
150 unset_conn (SoupMessage *msg, gpointer user_data)
152 SoupAuthManagerNTLM *ntlm = user_data;
154 g_hash_table_remove (ntlm->connections_by_msg, msg);
155 g_signal_handlers_disconnect_by_func (msg, unset_conn, ntlm);
158 static SoupNTLMConnection *
159 set_connection_for_msg (SoupAuthManagerNTLM *ntlm, SoupMessage *msg,
160 SoupNTLMConnection *conn)
162 if (!g_hash_table_lookup (ntlm->connections_by_msg, msg)) {
163 g_signal_connect (msg, "finished",
164 G_CALLBACK (unset_conn), ntlm);
165 g_signal_connect (msg, "restarted",
166 G_CALLBACK (unset_conn), ntlm);
168 g_hash_table_insert (ntlm->connections_by_msg, msg, conn);
173 static SoupNTLMConnection *
174 get_connection_for_msg (SoupAuthManagerNTLM *ntlm, SoupMessage *msg)
176 return g_hash_table_lookup (ntlm->connections_by_msg, msg);
180 ntlm_authorize_pre (SoupMessage *msg, gpointer user_data)
182 SoupAuthManagerNTLM *ntlm = user_data;
183 SoupNTLMConnection *conn;
186 conn = get_connection_for_msg (ntlm, msg);
190 if (conn->state > SOUP_NTLM_SENT_REQUEST) {
191 /* We already authenticated, but then got another 401.
192 * That means "permission denied", so don't try to
193 * authenticate again.
195 conn->state = SOUP_NTLM_FAILED;
199 val = soup_message_headers_get (msg->response_headers,
202 val = strstr (val, "NTLM ");
204 conn->state = SOUP_NTLM_FAILED;
208 if (!soup_ntlm_parse_challenge (val, &conn->nonce, &conn->domain)) {
209 conn->state = SOUP_NTLM_FAILED;
213 conn->state = SOUP_NTLM_RECEIVED_CHALLENGE;
214 conn->auth = soup_auth_ntlm_new (conn->domain,
215 soup_message_get_uri (msg)->host);
216 soup_session_emit_authenticate (ntlm->session, msg, conn->auth, FALSE);
219 /* Remove the WWW-Authenticate headers so the session won't try
220 * to do Basic auth too.
222 soup_message_headers_remove (msg->response_headers, "WWW-Authenticate");
226 ntlm_authorize_post (SoupMessage *msg, gpointer user_data)
228 SoupAuthManagerNTLM *ntlm = user_data;
229 SoupNTLMConnection *conn;
230 const char *username = NULL, *password = NULL;
231 char *slash, *domain;
233 conn = get_connection_for_msg (ntlm, msg);
234 if (!conn || !conn->auth)
237 username = soup_auth_ntlm_get_username (conn->auth);
238 password = soup_auth_ntlm_get_password (conn->auth);
239 if (!username || !password)
242 slash = strpbrk (username, "\\/");
244 domain = g_strdup (username);
245 slash = domain + (slash - username);
247 username = slash + 1;
249 domain = conn->domain;
251 conn->response_header = soup_ntlm_response (conn->nonce,
254 soup_session_requeue_message (ntlm->session, msg);
257 if (domain != conn->domain)
259 g_free (conn->domain);
261 g_free (conn->nonce);
263 g_object_unref (conn->auth);
268 ntlm_request_queued (SoupSession *session, SoupMessage *msg, gpointer ntlm)
270 soup_message_add_status_code_handler (msg, "got_headers",
271 SOUP_STATUS_UNAUTHORIZED,
272 G_CALLBACK (ntlm_authorize_pre),
274 soup_message_add_status_code_handler (msg, "got_body",
275 SOUP_STATUS_UNAUTHORIZED,
276 G_CALLBACK (ntlm_authorize_post),
281 ntlm_request_started (SoupSession *session, SoupMessage *msg,
282 SoupSocket *socket, gpointer user_data)
284 SoupAuthManagerNTLM *ntlm = user_data;
285 SoupNTLMConnection *conn;
288 conn = get_connection (ntlm, socket);
289 set_connection_for_msg (ntlm, msg, conn);
291 switch (conn->state) {
293 header = soup_ntlm_request ();
294 conn->state = SOUP_NTLM_SENT_REQUEST;
296 case SOUP_NTLM_RECEIVED_CHALLENGE:
297 header = conn->response_header;
298 conn->response_header = NULL;
299 conn->state = SOUP_NTLM_SENT_RESPONSE;
305 if (header && !soup_message_get_auth (msg)) {
306 soup_message_headers_replace (msg->request_headers,
307 "Authorization", header);
313 ntlm_request_unqueued (SoupSession *session, SoupMessage *msg,
316 g_signal_handlers_disconnect_by_func (msg, ntlm_authorize_pre, ntlm);
317 g_signal_handlers_disconnect_by_func (msg, ntlm_authorize_post, ntlm);
323 static void md4sum (const unsigned char *in,
325 unsigned char digest[16]);
327 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
329 static void deskey (DES_KS, unsigned char *, int);
331 static void des (DES_KS, unsigned char *);
333 static void setup_schedule (const guchar *key_56, DES_KS ks);
335 static void calc_response (const guchar *key,
336 const guchar *plaintext,
339 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
340 "\x4B\x47\x53\x21\x40\x23\x24\x25" \
341 "\x00\x00\x00\x00\x00"
344 lanmanager_hash (const char *password, guchar hash[21])
346 guchar lm_password [15];
350 for (i = 0; i < 14 && password [i]; i++)
351 lm_password [i] = toupper ((unsigned char) password [i]);
354 lm_password [i] = '\0';
356 memcpy (hash, LM_PASSWORD_MAGIC, 21);
358 setup_schedule (lm_password, ks);
361 setup_schedule (lm_password + 7, ks);
366 nt_hash (const char *password, guchar hash[21])
368 unsigned char *buf, *p;
370 p = buf = g_malloc (strlen (password) * 2);
377 md4sum (buf, p - buf, hash);
378 memset (hash + 16, 0, 5);
390 #define NTLM_CHALLENGE_NONCE_OFFSET 24
391 #define NTLM_CHALLENGE_NONCE_LENGTH 8
392 #define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
394 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
395 #define NTLM_RESPONSE_FLAGS 0x8202
405 NTLMString session_key;
411 ntlm_set_string (NTLMString *string, int *offset, int len)
413 string->offset = GUINT16_TO_LE (*offset);
414 string->length = string->length2 = GUINT16_TO_LE (len);
419 soup_ntlm_request (void)
421 return g_strdup ("NTLM TlRMTVNTUAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
425 soup_ntlm_parse_challenge (const char *challenge,
427 char **default_domain)
433 if (strncmp (challenge, "NTLM ", 5) != 0)
436 chall = g_base64_decode (challenge + 5, &clen);
437 if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET ||
438 clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) {
443 if (default_domain) {
444 memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
445 domain.length = GUINT16_FROM_LE (domain.length);
446 domain.offset = GUINT16_FROM_LE (domain.offset);
448 if (clen < domain.length + domain.offset) {
453 *default_domain = g_strndup ((char *)chall + domain.offset, domain.length);
457 *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
458 NTLM_CHALLENGE_NONCE_LENGTH);
466 soup_ntlm_response (const char *nonce,
468 const char *password,
472 int hlen, dlen, ulen, offset;
473 guchar hash[21], lm_resp[24], nt_resp[24];
478 nt_hash (password, hash);
479 calc_response (hash, (guchar *)nonce, nt_resp);
480 lanmanager_hash (password, hash);
481 calc_response (hash, (guchar *)nonce, lm_resp);
483 memset (&resp, 0, sizeof (resp));
484 memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
485 resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
487 offset = sizeof (resp);
489 dlen = strlen (domain);
490 ntlm_set_string (&resp.domain, &offset, dlen);
491 ulen = strlen (user);
492 ntlm_set_string (&resp.user, &offset, ulen);
495 hlen = strlen (host);
496 ntlm_set_string (&resp.host, &offset, hlen);
497 ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
498 ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
500 out = g_malloc (((offset + 3) * 4) / 3 + 6);
501 strncpy (out, "NTLM ", 5);
506 p += g_base64_encode_step ((const guchar *) &resp, sizeof (resp),
507 FALSE, p, &state, &save);
508 p += g_base64_encode_step ((const guchar *) domain, dlen,
509 FALSE, p, &state, &save);
510 p += g_base64_encode_step ((const guchar *) user, ulen,
511 FALSE, p, &state, &save);
512 p += g_base64_encode_step ((const guchar *) host, hlen,
513 FALSE, p, &state, &save);
514 p += g_base64_encode_step (lm_resp, sizeof (lm_resp),
515 FALSE, p, &state, &save);
516 p += g_base64_encode_step (nt_resp, sizeof (nt_resp),
517 FALSE, p, &state, &save);
518 p += g_base64_encode_close (FALSE, p, &state, &save);
525 /* Set up a key schedule based on a 56bit key */
527 setup_schedule (const guchar *key_56, DES_KS ks)
532 key[0] = (key_56[0]) ;
533 key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
534 key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
535 key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
536 key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
537 key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
538 key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
539 key[7] = ((key_56[6] << 1) & 0xFF);
542 for (i = 0; i < 8; i++) {
543 for (c = bit = 0; bit < 8; bit++)
544 if (key[i] & (1 << bit))
554 calc_response (const guchar *key, const guchar *plaintext, guchar *results)
558 memcpy (results, plaintext, 8);
559 memcpy (results + 8, plaintext, 8);
560 memcpy (results + 16, plaintext, 8);
562 setup_schedule (key, ks);
565 setup_schedule (key + 7, ks);
566 des (ks, results + 8);
568 setup_schedule (key + 14, ks);
569 des (ks, results + 16);
574 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
575 * this is a reimplementation from spec.) This doesn't need to be
576 * efficient for our purposes, although it would be nice to fix
577 * it to not malloc()...
580 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
581 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
582 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
583 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
586 md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
589 guint32 A, B, C, D, AA, BB, CC, DD, X[16];
590 int pbytes, nbits = nbytes * 8, i, j;
592 pbytes = (120 - (nbytes % 64)) % 64;
593 M = alloca (nbytes + pbytes + 8);
594 memcpy (M, in, nbytes);
595 memset (M + nbytes, 0, pbytes + 8);
597 M[nbytes + pbytes] = nbits & 0xFF;
598 M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
599 M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
600 M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
607 for (i = 0; i < nbytes + pbytes + 8; i += 64) {
608 for (j = 0; j < 16; j++) {
609 X[j] = (M[i + j*4]) |
610 (M[i + j*4 + 1] << 8) |
611 (M[i + j*4 + 2] << 16) |
612 (M[i + j*4 + 3] << 24);
620 A = ROT (A + F(B, C, D) + X[0], 3);
621 D = ROT (D + F(A, B, C) + X[1], 7);
622 C = ROT (C + F(D, A, B) + X[2], 11);
623 B = ROT (B + F(C, D, A) + X[3], 19);
624 A = ROT (A + F(B, C, D) + X[4], 3);
625 D = ROT (D + F(A, B, C) + X[5], 7);
626 C = ROT (C + F(D, A, B) + X[6], 11);
627 B = ROT (B + F(C, D, A) + X[7], 19);
628 A = ROT (A + F(B, C, D) + X[8], 3);
629 D = ROT (D + F(A, B, C) + X[9], 7);
630 C = ROT (C + F(D, A, B) + X[10], 11);
631 B = ROT (B + F(C, D, A) + X[11], 19);
632 A = ROT (A + F(B, C, D) + X[12], 3);
633 D = ROT (D + F(A, B, C) + X[13], 7);
634 C = ROT (C + F(D, A, B) + X[14], 11);
635 B = ROT (B + F(C, D, A) + X[15], 19);
637 A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
638 D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
639 C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
640 B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
641 A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
642 D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
643 C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
644 B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
645 A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
646 D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
647 C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
648 B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
649 A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
650 D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
651 C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
652 B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
654 A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
655 D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
656 C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
657 B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
658 A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
659 D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
660 C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
661 B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
662 A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
663 D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
664 C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
665 B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
666 A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
667 D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
668 C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
669 B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
677 digest[0] = A & 0xFF;
678 digest[1] = (A >> 8) & 0xFF;
679 digest[2] = (A >> 16) & 0xFF;
680 digest[3] = (A >> 24) & 0xFF;
681 digest[4] = B & 0xFF;
682 digest[5] = (B >> 8) & 0xFF;
683 digest[6] = (B >> 16) & 0xFF;
684 digest[7] = (B >> 24) & 0xFF;
685 digest[8] = C & 0xFF;
686 digest[9] = (C >> 8) & 0xFF;
687 digest[10] = (C >> 16) & 0xFF;
688 digest[11] = (C >> 24) & 0xFF;
689 digest[12] = D & 0xFF;
690 digest[13] = (D >> 8) & 0xFF;
691 digest[14] = (D >> 16) & 0xFF;
692 digest[15] = (D >> 24) & 0xFF;
696 /* Public domain DES implementation from Phil Karn */
697 static const guint32 Spbox[8][64] = {
698 { 0x01010400,0x00000000,0x00010000,0x01010404,
699 0x01010004,0x00010404,0x00000004,0x00010000,
700 0x00000400,0x01010400,0x01010404,0x00000400,
701 0x01000404,0x01010004,0x01000000,0x00000004,
702 0x00000404,0x01000400,0x01000400,0x00010400,
703 0x00010400,0x01010000,0x01010000,0x01000404,
704 0x00010004,0x01000004,0x01000004,0x00010004,
705 0x00000000,0x00000404,0x00010404,0x01000000,
706 0x00010000,0x01010404,0x00000004,0x01010000,
707 0x01010400,0x01000000,0x01000000,0x00000400,
708 0x01010004,0x00010000,0x00010400,0x01000004,
709 0x00000400,0x00000004,0x01000404,0x00010404,
710 0x01010404,0x00010004,0x01010000,0x01000404,
711 0x01000004,0x00000404,0x00010404,0x01010400,
712 0x00000404,0x01000400,0x01000400,0x00000000,
713 0x00010004,0x00010400,0x00000000,0x01010004 },
714 { 0x80108020,0x80008000,0x00008000,0x00108020,
715 0x00100000,0x00000020,0x80100020,0x80008020,
716 0x80000020,0x80108020,0x80108000,0x80000000,
717 0x80008000,0x00100000,0x00000020,0x80100020,
718 0x00108000,0x00100020,0x80008020,0x00000000,
719 0x80000000,0x00008000,0x00108020,0x80100000,
720 0x00100020,0x80000020,0x00000000,0x00108000,
721 0x00008020,0x80108000,0x80100000,0x00008020,
722 0x00000000,0x00108020,0x80100020,0x00100000,
723 0x80008020,0x80100000,0x80108000,0x00008000,
724 0x80100000,0x80008000,0x00000020,0x80108020,
725 0x00108020,0x00000020,0x00008000,0x80000000,
726 0x00008020,0x80108000,0x00100000,0x80000020,
727 0x00100020,0x80008020,0x80000020,0x00100020,
728 0x00108000,0x00000000,0x80008000,0x00008020,
729 0x80000000,0x80100020,0x80108020,0x00108000 },
730 { 0x00000208,0x08020200,0x00000000,0x08020008,
731 0x08000200,0x00000000,0x00020208,0x08000200,
732 0x00020008,0x08000008,0x08000008,0x00020000,
733 0x08020208,0x00020008,0x08020000,0x00000208,
734 0x08000000,0x00000008,0x08020200,0x00000200,
735 0x00020200,0x08020000,0x08020008,0x00020208,
736 0x08000208,0x00020200,0x00020000,0x08000208,
737 0x00000008,0x08020208,0x00000200,0x08000000,
738 0x08020200,0x08000000,0x00020008,0x00000208,
739 0x00020000,0x08020200,0x08000200,0x00000000,
740 0x00000200,0x00020008,0x08020208,0x08000200,
741 0x08000008,0x00000200,0x00000000,0x08020008,
742 0x08000208,0x00020000,0x08000000,0x08020208,
743 0x00000008,0x00020208,0x00020200,0x08000008,
744 0x08020000,0x08000208,0x00000208,0x08020000,
745 0x00020208,0x00000008,0x08020008,0x00020200 },
746 { 0x00802001,0x00002081,0x00002081,0x00000080,
747 0x00802080,0x00800081,0x00800001,0x00002001,
748 0x00000000,0x00802000,0x00802000,0x00802081,
749 0x00000081,0x00000000,0x00800080,0x00800001,
750 0x00000001,0x00002000,0x00800000,0x00802001,
751 0x00000080,0x00800000,0x00002001,0x00002080,
752 0x00800081,0x00000001,0x00002080,0x00800080,
753 0x00002000,0x00802080,0x00802081,0x00000081,
754 0x00800080,0x00800001,0x00802000,0x00802081,
755 0x00000081,0x00000000,0x00000000,0x00802000,
756 0x00002080,0x00800080,0x00800081,0x00000001,
757 0x00802001,0x00002081,0x00002081,0x00000080,
758 0x00802081,0x00000081,0x00000001,0x00002000,
759 0x00800001,0x00002001,0x00802080,0x00800081,
760 0x00002001,0x00002080,0x00800000,0x00802001,
761 0x00000080,0x00800000,0x00002000,0x00802080 },
762 { 0x00000100,0x02080100,0x02080000,0x42000100,
763 0x00080000,0x00000100,0x40000000,0x02080000,
764 0x40080100,0x00080000,0x02000100,0x40080100,
765 0x42000100,0x42080000,0x00080100,0x40000000,
766 0x02000000,0x40080000,0x40080000,0x00000000,
767 0x40000100,0x42080100,0x42080100,0x02000100,
768 0x42080000,0x40000100,0x00000000,0x42000000,
769 0x02080100,0x02000000,0x42000000,0x00080100,
770 0x00080000,0x42000100,0x00000100,0x02000000,
771 0x40000000,0x02080000,0x42000100,0x40080100,
772 0x02000100,0x40000000,0x42080000,0x02080100,
773 0x40080100,0x00000100,0x02000000,0x42080000,
774 0x42080100,0x00080100,0x42000000,0x42080100,
775 0x02080000,0x00000000,0x40080000,0x42000000,
776 0x00080100,0x02000100,0x40000100,0x00080000,
777 0x00000000,0x40080000,0x02080100,0x40000100 },
778 { 0x20000010,0x20400000,0x00004000,0x20404010,
779 0x20400000,0x00000010,0x20404010,0x00400000,
780 0x20004000,0x00404010,0x00400000,0x20000010,
781 0x00400010,0x20004000,0x20000000,0x00004010,
782 0x00000000,0x00400010,0x20004010,0x00004000,
783 0x00404000,0x20004010,0x00000010,0x20400010,
784 0x20400010,0x00000000,0x00404010,0x20404000,
785 0x00004010,0x00404000,0x20404000,0x20000000,
786 0x20004000,0x00000010,0x20400010,0x00404000,
787 0x20404010,0x00400000,0x00004010,0x20000010,
788 0x00400000,0x20004000,0x20000000,0x00004010,
789 0x20000010,0x20404010,0x00404000,0x20400000,
790 0x00404010,0x20404000,0x00000000,0x20400010,
791 0x00000010,0x00004000,0x20400000,0x00404010,
792 0x00004000,0x00400010,0x20004010,0x00000000,
793 0x20404000,0x20000000,0x00400010,0x20004010 },
794 { 0x00200000,0x04200002,0x04000802,0x00000000,
795 0x00000800,0x04000802,0x00200802,0x04200800,
796 0x04200802,0x00200000,0x00000000,0x04000002,
797 0x00000002,0x04000000,0x04200002,0x00000802,
798 0x04000800,0x00200802,0x00200002,0x04000800,
799 0x04000002,0x04200000,0x04200800,0x00200002,
800 0x04200000,0x00000800,0x00000802,0x04200802,
801 0x00200800,0x00000002,0x04000000,0x00200800,
802 0x04000000,0x00200800,0x00200000,0x04000802,
803 0x04000802,0x04200002,0x04200002,0x00000002,
804 0x00200002,0x04000000,0x04000800,0x00200000,
805 0x04200800,0x00000802,0x00200802,0x04200800,
806 0x00000802,0x04000002,0x04200802,0x04200000,
807 0x00200800,0x00000000,0x00000002,0x04200802,
808 0x00000000,0x00200802,0x04200000,0x00000800,
809 0x04000002,0x04000800,0x00000800,0x00200002 },
810 { 0x10001040,0x00001000,0x00040000,0x10041040,
811 0x10000000,0x10001040,0x00000040,0x10000000,
812 0x00040040,0x10040000,0x10041040,0x00041000,
813 0x10041000,0x00041040,0x00001000,0x00000040,
814 0x10040000,0x10000040,0x10001000,0x00001040,
815 0x00041000,0x00040040,0x10040040,0x10041000,
816 0x00001040,0x00000000,0x00000000,0x10040040,
817 0x10000040,0x10001000,0x00041040,0x00040000,
818 0x00041040,0x00040000,0x10041000,0x00001000,
819 0x00000040,0x10040040,0x00001000,0x00041040,
820 0x10001000,0x00000040,0x10000040,0x10040000,
821 0x10040040,0x10000000,0x00040000,0x10001040,
822 0x00000000,0x10041040,0x00040040,0x10000040,
823 0x10040000,0x10001000,0x10001040,0x00000000,
824 0x10041040,0x00041000,0x00041000,0x00001040,
825 0x00001040,0x00040040,0x10000000,0x10041000 }
830 work = ((r >> 4) | (r << 28)) ^ key[0];\
831 l ^= Spbox[6][work & 0x3f];\
832 l ^= Spbox[4][(work >> 8) & 0x3f];\
833 l ^= Spbox[2][(work >> 16) & 0x3f];\
834 l ^= Spbox[0][(work >> 24) & 0x3f];\
836 l ^= Spbox[7][work & 0x3f];\
837 l ^= Spbox[5][(work >> 8) & 0x3f];\
838 l ^= Spbox[3][(work >> 16) & 0x3f];\
839 l ^= Spbox[1][(work >> 24) & 0x3f];\
841 /* Encrypt or decrypt a block of data in ECB mode */
843 des (guint32 ks[16][2], unsigned char block[8])
845 guint32 left,right,work;
847 /* Read input block and place in left/right in big-endian order */
848 left = ((guint32)block[0] << 24)
849 | ((guint32)block[1] << 16)
850 | ((guint32)block[2] << 8)
852 right = ((guint32)block[4] << 24)
853 | ((guint32)block[5] << 16)
854 | ((guint32)block[6] << 8)
857 /* Hoey's clever initial permutation algorithm, from Outerbridge
858 * (see Schneier p 478)
860 * The convention here is the same as Outerbridge: rotate each
861 * register left by 1 bit, i.e., so that "left" contains permuted
862 * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
863 * (using origin-1 numbering as in the FIPS). This allows us to avoid
864 * one of the two rotates that would otherwise be required in each of
867 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
870 work = ((left >> 16) ^ right) & 0xffff;
873 work = ((right >> 2) ^ left) & 0x33333333;
875 right ^= (work << 2);
876 work = ((right >> 8) ^ left) & 0xff00ff;
878 right ^= (work << 8);
879 right = (right << 1) | (right >> 31);
880 work = (left ^ right) & 0xaaaaaaaa;
883 left = (left << 1) | (left >> 31);
885 /* Now do the 16 rounds */
896 F(left,right,ks[10]);
897 F(right,left,ks[11]);
898 F(left,right,ks[12]);
899 F(right,left,ks[13]);
900 F(left,right,ks[14]);
901 F(right,left,ks[15]);
903 /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
904 right = (right << 31) | (right >> 1);
905 work = (left ^ right) & 0xaaaaaaaa;
908 left = (left >> 1) | (left << 31);
909 work = ((left >> 8) ^ right) & 0xff00ff;
912 work = ((left >> 2) ^ right) & 0x33333333;
915 work = ((right >> 16) ^ left) & 0xffff;
918 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
922 /* Put the block back into the user's buffer with final swap */
923 block[0] = right >> 24;
924 block[1] = right >> 16;
925 block[2] = right >> 8;
927 block[4] = left >> 24;
928 block[5] = left >> 16;
929 block[6] = left >> 8;
933 /* Key schedule-related tables from FIPS-46 */
935 /* permuted choice table (key) */
936 static const unsigned char pc1[] = {
937 57, 49, 41, 33, 25, 17, 9,
938 1, 58, 50, 42, 34, 26, 18,
939 10, 2, 59, 51, 43, 35, 27,
940 19, 11, 3, 60, 52, 44, 36,
942 63, 55, 47, 39, 31, 23, 15,
943 7, 62, 54, 46, 38, 30, 22,
944 14, 6, 61, 53, 45, 37, 29,
945 21, 13, 5, 28, 20, 12, 4
948 /* number left rotations of pc1 */
949 static const unsigned char totrot[] = {
950 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
953 /* permuted choice key (table) */
954 static const unsigned char pc2[] = {
955 14, 17, 11, 24, 1, 5,
956 3, 28, 15, 6, 21, 10,
957 23, 19, 12, 4, 26, 8,
958 16, 7, 27, 20, 13, 2,
959 41, 52, 31, 37, 47, 55,
960 30, 40, 51, 45, 33, 48,
961 44, 49, 39, 56, 34, 53,
962 46, 42, 50, 36, 29, 32
965 /* End of DES-defined tables */
968 /* bit 0 is left-most in byte */
969 static const int bytebit[] = {
970 0200,0100,040,020,010,04,02,01
974 /* Generate key schedule for encryption or decryption
975 * depending on the value of "decrypt"
978 deskey (DES_KS k, unsigned char *key, int decrypt)
980 unsigned char pc1m[56]; /* place to modify pc1 into */
981 unsigned char pcr[56]; /* place to rotate pc1 into */
986 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
987 l=pc1[j]-1; /* integer bit location */
988 m = l & 07; /* find bit */
989 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
990 bytebit[m]) /* and which bit of that byte */
991 ? 1 : 0; /* and store 1-bit result */
993 for (i=0; i<16; i++) { /* key chunk for each iteration */
994 memset(ks,0,sizeof(ks)); /* Clear key schedule */
995 for (j=0; j<56; j++) /* rotate pc1 the right amount */
996 pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
997 /* rotate left and right halves independently */
998 for (j=0; j<48; j++){ /* select bits individually */
999 /* check bit that goes to ks[j] */
1001 /* mask it in if it's there */
1003 ks[j/6] |= bytebit[l] >> 2;
1006 /* Now convert to packed odd/even interleaved form */
1007 k[i][0] = ((guint32)ks[0] << 24)
1008 | ((guint32)ks[2] << 16)
1009 | ((guint32)ks[4] << 8)
1011 k[i][1] = ((guint32)ks[1] << 24)
1012 | ((guint32)ks[3] << 16)
1013 | ((guint32)ks[5] << 8)