source: trunk/third/libsoup/libsoup/soup-connection-ntlm.c @ 21519

Revision 21519, 27.4 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21518, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-ntlm-offset: 8 -*- */
2/*
3 * soup-connection-ntlm.c: NTLM-using Connection
4 *
5 * Copyright (C) 2001-2003, Ximian, Inc.
6 */
7
8#ifdef HAVE_CONFIG_H
9#include <config.h>
10#endif
11
12#include <ctype.h>
13#include <string.h>
14
15#include "soup-connection-ntlm.h"
16#include "soup-message.h"
17#include "soup-misc.h"
18#include "soup-uri.h"
19
20void send_request (SoupConnection *conn, SoupMessage *req);
21
22typedef enum {
23        SOUP_CONNECTION_NTLM_NEW,
24        SOUP_CONNECTION_NTLM_SENT_REQUEST,
25        SOUP_CONNECTION_NTLM_RECEIVED_CHALLENGE,
26        SOUP_CONNECTION_NTLM_SENT_RESPONSE,
27        SOUP_CONNECTION_NTLM_FAILED
28} SoupConnectionNTLMState;
29
30struct SoupConnectionNTLMPrivate {
31        char *user;
32        guchar nt_hash[21], lm_hash[21];
33        SoupConnectionNTLMState state;
34};
35
36#define PARENT_TYPE SOUP_TYPE_CONNECTION
37static SoupConnectionClass *parent_class;
38
39static char     *soup_ntlm_request         (void);
40static gboolean  soup_ntlm_parse_challenge (const char  *challenge,
41                                            char       **nonce,
42                                            char       **default_domain);
43static char     *soup_ntlm_response        (const char  *nonce,
44                                            const char  *user,
45                                            const char  *password,
46                                            const char  *host,
47                                            const char  *domain);
48
49static void
50init (GObject *object)
51{
52        SoupConnectionNTLM *ntlm = SOUP_CONNECTION_NTLM (object);
53
54        ntlm->priv = g_new0 (SoupConnectionNTLMPrivate, 1);
55}
56
57static void
58finalize (GObject *object)
59{
60        SoupConnectionNTLM *ntlm = SOUP_CONNECTION_NTLM (object);
61
62        g_free (ntlm->priv->user);
63        memset (ntlm->priv->nt_hash, 0, sizeof (ntlm->priv->nt_hash));
64        memset (ntlm->priv->lm_hash, 0, sizeof (ntlm->priv->lm_hash));
65
66        g_free (ntlm->priv);
67
68        G_OBJECT_CLASS (parent_class)->finalize (object);
69}
70
71static void
72class_init (GObjectClass *object_class)
73{
74        SoupConnectionClass *connection_class =
75                SOUP_CONNECTION_CLASS (object_class);
76
77        parent_class = g_type_class_ref (PARENT_TYPE);
78
79        connection_class->send_request = send_request;
80        object_class->finalize = finalize;
81}
82
83SOUP_MAKE_TYPE (soup_connection_ntlm, SoupConnectionNTLM, class_init, init, PARENT_TYPE)
84
85
86static void
87ntlm_authorize_pre (SoupMessage *msg, gpointer user_data)
88{
89        SoupConnectionNTLM *ntlm = user_data;
90        const GSList *headers;
91        const char *val;
92        char *nonce, *header;
93        char *username, *domain_username = NULL, *password = NULL;
94        char *slash, *domain;
95
96        if (ntlm->priv->state > SOUP_CONNECTION_NTLM_SENT_REQUEST) {
97                /* We already authenticated, but then got another 401.
98                 * That means "permission denied", so don't try to
99                 * authenticate again.
100                 */
101                ntlm->priv->state = SOUP_CONNECTION_NTLM_FAILED;
102                goto done;
103        }
104
105        headers = soup_message_get_header_list (msg->response_headers,
106                                                "WWW-Authenticate");
107        while (headers) {
108                val = headers->data;
109                if (!strncmp (val, "NTLM ", 5))
110                        break;
111                headers = headers->next;
112        }
113        if (!headers) {
114                ntlm->priv->state = SOUP_CONNECTION_NTLM_FAILED;
115                goto done;
116        }
117
118        if (!soup_ntlm_parse_challenge (val, &nonce, &domain)) {
119                ntlm->priv->state = SOUP_CONNECTION_NTLM_FAILED;
120                goto done;
121        }
122
123        soup_connection_authenticate (SOUP_CONNECTION (ntlm), msg,
124                                      "NTLM", domain,
125                                      &domain_username, &password);
126        if (!domain_username) {
127                g_free (nonce);
128                g_free (domain);
129                goto done;
130        }
131
132        slash = strpbrk (domain_username, "\\/");
133        if (slash) {
134                g_free (domain);
135                domain = g_strdup (domain_username);
136                username = slash + 1;
137        } else
138                username = domain_username;
139
140        header = soup_ntlm_response (nonce, username, password, NULL, domain);
141        g_free (domain_username);
142        g_free (password);
143        g_free (domain);
144        g_free (nonce);
145
146        soup_message_remove_header (msg->request_headers, "Authorization");
147        soup_message_add_header (msg->request_headers,
148                                 "Authorization", header);
149        g_free (header);
150        ntlm->priv->state = SOUP_CONNECTION_NTLM_RECEIVED_CHALLENGE;
151
152 done:
153        /* Remove the WWW-Authenticate headers so the session won't try
154         * to do Basic auth too.
155         */
156        soup_message_remove_header (msg->response_headers, "WWW-Authenticate");
157}
158
159static void
160ntlm_authorize_post (SoupMessage *msg, gpointer conn)
161{
162        SoupConnectionNTLM *ntlm = conn;
163
164        if (ntlm->priv->state == SOUP_CONNECTION_NTLM_RECEIVED_CHALLENGE &&
165            soup_message_get_header (msg->request_headers, "Authorization")) {
166                /* We just added the last Auth header, so restart it. */
167                ntlm->priv->state = SOUP_CONNECTION_NTLM_SENT_RESPONSE;
168                soup_message_restarted (msg);
169                soup_connection_send_request (conn, msg);
170        }
171}
172
173static void
174ntlm_cleanup_msg (SoupMessage *msg, gpointer user_data)
175{
176        SoupConnectionNTLM *ntlm = user_data;
177
178        /* Do this when the message is restarted, in case it's
179         * restarted on a different connection.
180         */
181        soup_message_remove_handler (msg, SOUP_HANDLER_PRE_BODY,
182                                     ntlm_authorize_pre, ntlm);
183        soup_message_remove_handler (msg, SOUP_HANDLER_POST_BODY,
184                                     ntlm_authorize_post, ntlm);
185}
186
187void
188send_request (SoupConnection *conn, SoupMessage *req)
189{
190        SoupConnectionNTLM *ntlm = SOUP_CONNECTION_NTLM (conn);
191
192        if (ntlm->priv->state == SOUP_CONNECTION_NTLM_NEW) {
193                char *header = soup_ntlm_request ();
194
195                soup_message_remove_header (req->request_headers,
196                                            "Authorization");
197                soup_message_add_header (req->request_headers,
198                                         "Authorization", header);
199                g_free (header);
200                ntlm->priv->state = SOUP_CONNECTION_NTLM_SENT_REQUEST;
201        }
202
203        soup_message_add_status_code_handler (req, SOUP_STATUS_UNAUTHORIZED,
204                                              SOUP_HANDLER_PRE_BODY,
205                                              ntlm_authorize_pre, conn);
206
207        soup_message_add_status_code_handler (req, SOUP_STATUS_UNAUTHORIZED,
208                                              SOUP_HANDLER_POST_BODY,
209                                              ntlm_authorize_post, conn);
210
211        g_signal_connect (req, "restarted",
212                          G_CALLBACK (ntlm_cleanup_msg), ntlm);
213        g_signal_connect (req, "finished",
214                          G_CALLBACK (ntlm_cleanup_msg), ntlm);
215
216        SOUP_CONNECTION_CLASS (parent_class)->send_request (conn, req);
217}
218
219
220
221/* MD4 */
222static void md4sum                (const unsigned char *in,
223                                   int                  nbytes,
224                                   unsigned char        digest[16]);
225
226/* DES */
227typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
228
229static void deskey                (DES_KS, unsigned char *, int);
230
231static void des                   (DES_KS, unsigned char *);
232
233static void setup_schedule        (const guchar *key_56, DES_KS ks);
234
235static void calc_response         (const guchar        *key,
236                                   const guchar        *plaintext,
237                                   guchar              *results);
238
239#define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
240                          "\x4B\x47\x53\x21\x40\x23\x24\x25" \
241                          "\x00\x00\x00\x00\x00"
242
243static void
244lanmanager_hash (const char *password, guchar hash[21])
245{
246        guchar lm_password [15];
247        DES_KS ks;
248        int i;
249
250        for (i = 0; i < 14 && password [i]; i++)
251                lm_password [i] = toupper ((unsigned char) password [i]);
252
253        for (; i < 15; i++)
254                lm_password [i] = '\0';
255
256        memcpy (hash, LM_PASSWORD_MAGIC, 21);
257
258        setup_schedule (lm_password, ks);
259        des (ks, hash);
260
261        setup_schedule (lm_password + 7, ks);
262        des (ks, hash + 8);
263}
264
265static void
266nt_hash (const char *password, guchar hash[21])
267{
268        unsigned char *buf, *p;
269
270        p = buf = g_malloc (strlen (password) * 2);
271
272        while (*password) {
273                *p++ = *password++;
274                *p++ = '\0';
275        }
276
277        md4sum (buf, p - buf, hash);
278        memset (hash + 16, 0, 5);
279
280        g_free (buf);
281}
282
283typedef struct {
284        guint16 length;
285        guint16 length2;
286        guint16 offset;
287        guchar  zero_pad[2];
288} NTLMString;
289
290#define NTLM_CHALLENGE_NONCE_OFFSET         24
291#define NTLM_CHALLENGE_NONCE_LENGTH          8
292#define NTLM_CHALLENGE_DOMAIN_STRING_OFFSET 12
293
294#define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
295#define NTLM_RESPONSE_FLAGS 0x8202
296
297typedef struct {
298        guchar     header[12];
299
300        NTLMString lm_resp;
301        NTLMString nt_resp;
302        NTLMString domain;
303        NTLMString user;
304        NTLMString host;
305        NTLMString session_key;
306
307        guint32    flags;
308} NTLMResponse;
309
310static void
311ntlm_set_string (NTLMString *string, int *offset, int len)
312{
313        string->offset = GUINT16_TO_LE (*offset);
314        string->length = string->length2 = GUINT16_TO_LE (len);
315        *offset += len;
316}
317
318static char *
319soup_ntlm_request (void)
320{
321        return g_strdup ("NTLM TlRMTVNTUAABAAAABoIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA");
322}
323
324static gboolean
325soup_ntlm_parse_challenge (const char *challenge,
326                           char      **nonce,
327                           char      **default_domain)
328{
329        int clen, decodelen;
330        NTLMString domain;
331        char *chall;
332        int state, save;
333
334        if (strncmp (challenge, "NTLM ", 5) != 0)
335                return FALSE;
336
337        decodelen = strlen (challenge) - 5;
338        chall = g_malloc (decodelen);
339
340        state = save = 0;
341        clen = soup_base64_decode_step ((guchar *) challenge + 5,
342                                        decodelen,
343                                        chall,
344                                        &state,
345                                        &save);
346
347        if (clen < NTLM_CHALLENGE_DOMAIN_STRING_OFFSET ||
348            clen < NTLM_CHALLENGE_NONCE_OFFSET + NTLM_CHALLENGE_NONCE_LENGTH) {
349                g_free (chall);
350                return FALSE;
351        }
352
353        if (default_domain) {
354                memcpy (&domain, chall + NTLM_CHALLENGE_DOMAIN_STRING_OFFSET, sizeof (domain));
355                domain.length = GUINT16_FROM_LE (domain.length);
356                domain.offset = GUINT16_FROM_LE (domain.offset);
357
358                if (clen < domain.length + domain.offset) {
359                        g_free (chall);
360                        return FALSE;
361                }
362
363                *default_domain = g_strndup (chall + domain.offset, domain.length);
364        }
365
366        if (nonce) {
367                *nonce = g_memdup (chall + NTLM_CHALLENGE_NONCE_OFFSET,
368                                   NTLM_CHALLENGE_NONCE_LENGTH);
369        }
370
371        g_free (chall);
372        return TRUE;
373}
374
375static char *
376soup_ntlm_response (const char *nonce,
377                    const char *user,
378                    const char *password,
379                    const char *host,
380                    const char *domain)
381{
382        int hlen, dlen, ulen, offset;
383        guchar hash[21], lm_resp[24], nt_resp[24];
384        NTLMResponse resp;
385        unsigned char *out, *p;
386        int state, save;
387
388        nt_hash (password, hash);
389        calc_response (hash, nonce, nt_resp);
390        lanmanager_hash (password, hash);
391        calc_response (hash, nonce, lm_resp);
392
393        memset (&resp, 0, sizeof (resp));
394        memcpy (resp.header, NTLM_RESPONSE_HEADER, sizeof (resp.header));
395        resp.flags = GUINT32_TO_LE (NTLM_RESPONSE_FLAGS);
396
397        offset = sizeof (resp);
398
399        dlen = strlen (domain);
400        ntlm_set_string (&resp.domain, &offset, dlen);
401        ulen = strlen (user);
402        ntlm_set_string (&resp.user, &offset, ulen);
403        if (!host)
404                host = "UNKNOWN";
405        hlen = strlen (host);
406        ntlm_set_string (&resp.host, &offset, hlen);
407        ntlm_set_string (&resp.lm_resp, &offset, sizeof (lm_resp));
408        ntlm_set_string (&resp.nt_resp, &offset, sizeof (nt_resp));
409
410        out = g_malloc (((offset + 3) * 4) / 3 + 6);
411        strncpy (out, "NTLM ", 5);
412        p = out + 5;
413
414        state = save = 0;
415
416        p += soup_base64_encode_step ((guchar *) &resp,
417                                      sizeof (resp),
418                                      FALSE,
419                                      p,
420                                      &state,
421                                      &save);
422        p += soup_base64_encode_step ((guchar *) domain,
423                                      dlen,
424                                      FALSE,
425                                      p,
426                                      &state,
427                                      &save);
428        p += soup_base64_encode_step ((guchar *) user,
429                                      ulen,
430                                      FALSE,
431                                      p,
432                                      &state,
433                                      &save);
434        p += soup_base64_encode_step ((guchar *) host,
435                                      hlen,
436                                      FALSE,
437                                      p,
438                                      &state,
439                                      &save);
440        p += soup_base64_encode_step (lm_resp,
441                                      sizeof (lm_resp),
442                                      FALSE,
443                                      p,
444                                      &state,
445                                      &save);
446
447        p += soup_base64_encode_close (nt_resp,
448                                       sizeof (nt_resp),
449                                       FALSE,
450                                       p,
451                                       &state,
452                                       &save);
453        *p = '\0';
454
455        return out;
456}
457
458/* DES utils */
459/* Set up a key schedule based on a 56bit key */
460static void
461setup_schedule (const guchar *key_56, DES_KS ks)
462{
463        guchar key[8];
464        int i, c, bit;
465
466        key[0] = (key_56[0])                                 ;
467        key[1] = (key_56[1] >> 1) | ((key_56[0] << 7) & 0xFF);
468        key[2] = (key_56[2] >> 2) | ((key_56[1] << 6) & 0xFF);
469        key[3] = (key_56[3] >> 3) | ((key_56[2] << 5) & 0xFF);
470        key[4] = (key_56[4] >> 4) | ((key_56[3] << 4) & 0xFF);
471        key[5] = (key_56[5] >> 5) | ((key_56[4] << 3) & 0xFF);
472        key[6] = (key_56[6] >> 6) | ((key_56[5] << 2) & 0xFF);
473        key[7] =                    ((key_56[6] << 1) & 0xFF);
474
475        /* Fix parity */
476        for (i = 0; i < 8; i++) {
477                for (c = bit = 0; bit < 8; bit++)
478                        if (key[i] & (1 << bit))
479                                c++;
480                if (!(c & 1))
481                        key[i] ^= 0x01;
482        }
483
484        deskey (ks, key, 0);
485}
486
487static void
488calc_response (const guchar *key, const guchar *plaintext, guchar *results)
489{
490        DES_KS ks;
491
492        memcpy (results, plaintext, 8);
493        memcpy (results + 8, plaintext, 8);
494        memcpy (results + 16, plaintext, 8);
495
496        setup_schedule (key, ks);
497        des (ks, results);
498
499        setup_schedule (key + 7, ks);
500        des (ks, results + 8);
501
502        setup_schedule (key + 14, ks);
503        des (ks, results + 16);
504}
505
506
507/*
508 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
509 * this is a reimplementation from spec.) This doesn't need to be
510 * efficient for our purposes, although it would be nice to fix
511 * it to not malloc()...
512 */
513
514#define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
515#define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
516#define H(X,Y,Z) ( (X)^(Y)^(Z) )
517#define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
518
519static void
520md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
521{
522        unsigned char *M;
523        guint32 A, B, C, D, AA, BB, CC, DD, X[16];
524        int pbytes, nbits = nbytes * 8, i, j;
525
526        pbytes = (120 - (nbytes % 64)) % 64;
527        M = alloca (nbytes + pbytes + 8);
528        memcpy (M, in, nbytes);
529        memset (M + nbytes, 0, pbytes + 8);
530        M[nbytes] = 0x80;
531        M[nbytes + pbytes] = nbits & 0xFF;
532        M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
533        M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
534        M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
535
536        A = 0x67452301;
537        B = 0xEFCDAB89;
538        C = 0x98BADCFE;
539        D = 0x10325476;
540
541        for (i = 0; i < nbytes + pbytes + 8; i += 64) {
542                for (j = 0; j < 16; j++) {
543                        X[j] =  (M[i + j*4]) |
544                                (M[i + j*4 + 1] << 8) |
545                                (M[i + j*4 + 2] << 16) |
546                                (M[i + j*4 + 3] << 24);
547                }
548
549                AA = A;
550                BB = B;
551                CC = C;
552                DD = D;
553
554                A = ROT (A + F(B, C, D) + X[0], 3);
555                D = ROT (D + F(A, B, C) + X[1], 7);
556                C = ROT (C + F(D, A, B) + X[2], 11);
557                B = ROT (B + F(C, D, A) + X[3], 19);
558                A = ROT (A + F(B, C, D) + X[4], 3);
559                D = ROT (D + F(A, B, C) + X[5], 7);
560                C = ROT (C + F(D, A, B) + X[6], 11);
561                B = ROT (B + F(C, D, A) + X[7], 19);
562                A = ROT (A + F(B, C, D) + X[8], 3);
563                D = ROT (D + F(A, B, C) + X[9], 7);
564                C = ROT (C + F(D, A, B) + X[10], 11);
565                B = ROT (B + F(C, D, A) + X[11], 19);
566                A = ROT (A + F(B, C, D) + X[12], 3);
567                D = ROT (D + F(A, B, C) + X[13], 7);
568                C = ROT (C + F(D, A, B) + X[14], 11);
569                B = ROT (B + F(C, D, A) + X[15], 19);
570
571                A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
572                D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
573                C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
574                B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
575                A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
576                D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
577                C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
578                B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
579                A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
580                D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
581                C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
582                B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
583                A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
584                D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
585                C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
586                B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
587
588                A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
589                D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
590                C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
591                B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
592                A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
593                D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
594                C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
595                B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
596                A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
597                D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
598                C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
599                B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
600                A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
601                D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
602                C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
603                B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
604
605                A += AA;
606                B += BB;
607                C += CC;
608                D += DD;
609        }
610
611        digest[0]  =  A        & 0xFF;
612        digest[1]  = (A >>  8) & 0xFF;
613        digest[2]  = (A >> 16) & 0xFF;
614        digest[3]  = (A >> 24) & 0xFF;
615        digest[4]  =  B        & 0xFF;
616        digest[5]  = (B >>  8) & 0xFF;
617        digest[6]  = (B >> 16) & 0xFF;
618        digest[7]  = (B >> 24) & 0xFF;
619        digest[8]  =  C        & 0xFF;
620        digest[9]  = (C >>  8) & 0xFF;
621        digest[10] = (C >> 16) & 0xFF;
622        digest[11] = (C >> 24) & 0xFF;
623        digest[12] =  D        & 0xFF;
624        digest[13] = (D >>  8) & 0xFF;
625        digest[14] = (D >> 16) & 0xFF;
626        digest[15] = (D >> 24) & 0xFF;
627}
628
629
630/* Public domain DES implementation from Phil Karn */
631static guint32 Spbox[8][64] = {
632        { 0x01010400,0x00000000,0x00010000,0x01010404,
633          0x01010004,0x00010404,0x00000004,0x00010000,
634          0x00000400,0x01010400,0x01010404,0x00000400,
635          0x01000404,0x01010004,0x01000000,0x00000004,
636          0x00000404,0x01000400,0x01000400,0x00010400,
637          0x00010400,0x01010000,0x01010000,0x01000404,
638          0x00010004,0x01000004,0x01000004,0x00010004,
639          0x00000000,0x00000404,0x00010404,0x01000000,
640          0x00010000,0x01010404,0x00000004,0x01010000,
641          0x01010400,0x01000000,0x01000000,0x00000400,
642          0x01010004,0x00010000,0x00010400,0x01000004,
643          0x00000400,0x00000004,0x01000404,0x00010404,
644          0x01010404,0x00010004,0x01010000,0x01000404,
645          0x01000004,0x00000404,0x00010404,0x01010400,
646          0x00000404,0x01000400,0x01000400,0x00000000,
647          0x00010004,0x00010400,0x00000000,0x01010004 },
648        { 0x80108020,0x80008000,0x00008000,0x00108020,
649          0x00100000,0x00000020,0x80100020,0x80008020,
650          0x80000020,0x80108020,0x80108000,0x80000000,
651          0x80008000,0x00100000,0x00000020,0x80100020,
652          0x00108000,0x00100020,0x80008020,0x00000000,
653          0x80000000,0x00008000,0x00108020,0x80100000,
654          0x00100020,0x80000020,0x00000000,0x00108000,
655          0x00008020,0x80108000,0x80100000,0x00008020,
656          0x00000000,0x00108020,0x80100020,0x00100000,
657          0x80008020,0x80100000,0x80108000,0x00008000,
658          0x80100000,0x80008000,0x00000020,0x80108020,
659          0x00108020,0x00000020,0x00008000,0x80000000,
660          0x00008020,0x80108000,0x00100000,0x80000020,
661          0x00100020,0x80008020,0x80000020,0x00100020,
662          0x00108000,0x00000000,0x80008000,0x00008020,
663          0x80000000,0x80100020,0x80108020,0x00108000 },
664        { 0x00000208,0x08020200,0x00000000,0x08020008,
665          0x08000200,0x00000000,0x00020208,0x08000200,
666          0x00020008,0x08000008,0x08000008,0x00020000,
667          0x08020208,0x00020008,0x08020000,0x00000208,
668          0x08000000,0x00000008,0x08020200,0x00000200,
669          0x00020200,0x08020000,0x08020008,0x00020208,
670          0x08000208,0x00020200,0x00020000,0x08000208,
671          0x00000008,0x08020208,0x00000200,0x08000000,
672          0x08020200,0x08000000,0x00020008,0x00000208,
673          0x00020000,0x08020200,0x08000200,0x00000000,
674          0x00000200,0x00020008,0x08020208,0x08000200,
675          0x08000008,0x00000200,0x00000000,0x08020008,
676          0x08000208,0x00020000,0x08000000,0x08020208,
677          0x00000008,0x00020208,0x00020200,0x08000008,
678          0x08020000,0x08000208,0x00000208,0x08020000,
679          0x00020208,0x00000008,0x08020008,0x00020200 },
680        { 0x00802001,0x00002081,0x00002081,0x00000080,
681          0x00802080,0x00800081,0x00800001,0x00002001,
682          0x00000000,0x00802000,0x00802000,0x00802081,
683          0x00000081,0x00000000,0x00800080,0x00800001,
684          0x00000001,0x00002000,0x00800000,0x00802001,
685          0x00000080,0x00800000,0x00002001,0x00002080,
686          0x00800081,0x00000001,0x00002080,0x00800080,
687          0x00002000,0x00802080,0x00802081,0x00000081,
688          0x00800080,0x00800001,0x00802000,0x00802081,
689          0x00000081,0x00000000,0x00000000,0x00802000,
690          0x00002080,0x00800080,0x00800081,0x00000001,
691          0x00802001,0x00002081,0x00002081,0x00000080,
692          0x00802081,0x00000081,0x00000001,0x00002000,
693          0x00800001,0x00002001,0x00802080,0x00800081,
694          0x00002001,0x00002080,0x00800000,0x00802001,
695          0x00000080,0x00800000,0x00002000,0x00802080 },
696        { 0x00000100,0x02080100,0x02080000,0x42000100,
697          0x00080000,0x00000100,0x40000000,0x02080000,
698          0x40080100,0x00080000,0x02000100,0x40080100,
699          0x42000100,0x42080000,0x00080100,0x40000000,
700          0x02000000,0x40080000,0x40080000,0x00000000,
701          0x40000100,0x42080100,0x42080100,0x02000100,
702          0x42080000,0x40000100,0x00000000,0x42000000,
703          0x02080100,0x02000000,0x42000000,0x00080100,
704          0x00080000,0x42000100,0x00000100,0x02000000,
705          0x40000000,0x02080000,0x42000100,0x40080100,
706          0x02000100,0x40000000,0x42080000,0x02080100,
707          0x40080100,0x00000100,0x02000000,0x42080000,
708          0x42080100,0x00080100,0x42000000,0x42080100,
709          0x02080000,0x00000000,0x40080000,0x42000000,
710          0x00080100,0x02000100,0x40000100,0x00080000,
711          0x00000000,0x40080000,0x02080100,0x40000100 },
712        { 0x20000010,0x20400000,0x00004000,0x20404010,
713          0x20400000,0x00000010,0x20404010,0x00400000,
714          0x20004000,0x00404010,0x00400000,0x20000010,
715          0x00400010,0x20004000,0x20000000,0x00004010,
716          0x00000000,0x00400010,0x20004010,0x00004000,
717          0x00404000,0x20004010,0x00000010,0x20400010,
718          0x20400010,0x00000000,0x00404010,0x20404000,
719          0x00004010,0x00404000,0x20404000,0x20000000,
720          0x20004000,0x00000010,0x20400010,0x00404000,
721          0x20404010,0x00400000,0x00004010,0x20000010,
722          0x00400000,0x20004000,0x20000000,0x00004010,
723          0x20000010,0x20404010,0x00404000,0x20400000,
724          0x00404010,0x20404000,0x00000000,0x20400010,
725          0x00000010,0x00004000,0x20400000,0x00404010,
726          0x00004000,0x00400010,0x20004010,0x00000000,
727          0x20404000,0x20000000,0x00400010,0x20004010 },
728        { 0x00200000,0x04200002,0x04000802,0x00000000,
729          0x00000800,0x04000802,0x00200802,0x04200800,
730          0x04200802,0x00200000,0x00000000,0x04000002,
731          0x00000002,0x04000000,0x04200002,0x00000802,
732          0x04000800,0x00200802,0x00200002,0x04000800,
733          0x04000002,0x04200000,0x04200800,0x00200002,
734          0x04200000,0x00000800,0x00000802,0x04200802,
735          0x00200800,0x00000002,0x04000000,0x00200800,
736          0x04000000,0x00200800,0x00200000,0x04000802,
737          0x04000802,0x04200002,0x04200002,0x00000002,
738          0x00200002,0x04000000,0x04000800,0x00200000,
739          0x04200800,0x00000802,0x00200802,0x04200800,
740          0x00000802,0x04000002,0x04200802,0x04200000,
741          0x00200800,0x00000000,0x00000002,0x04200802,
742          0x00000000,0x00200802,0x04200000,0x00000800,
743          0x04000002,0x04000800,0x00000800,0x00200002 },
744        { 0x10001040,0x00001000,0x00040000,0x10041040,
745          0x10000000,0x10001040,0x00000040,0x10000000,
746          0x00040040,0x10040000,0x10041040,0x00041000,
747          0x10041000,0x00041040,0x00001000,0x00000040,
748          0x10040000,0x10000040,0x10001000,0x00001040,
749          0x00041000,0x00040040,0x10040040,0x10041000,
750          0x00001040,0x00000000,0x00000000,0x10040040,
751          0x10000040,0x10001000,0x00041040,0x00040000,
752          0x00041040,0x00040000,0x10041000,0x00001000,
753          0x00000040,0x10040040,0x00001000,0x00041040,
754          0x10001000,0x00000040,0x10000040,0x10040000,
755          0x10040040,0x10000000,0x00040000,0x10001040,
756          0x00000000,0x10041040,0x00040040,0x10000040,
757          0x10040000,0x10001000,0x10001040,0x00000000,
758          0x10041040,0x00041000,0x00041000,0x00001040,
759          0x00001040,0x00040040,0x10000000,0x10041000 }
760};
761
762#undef F
763#define F(l,r,key){\
764        work = ((r >> 4) | (r << 28)) ^ key[0];\
765        l ^= Spbox[6][work & 0x3f];\
766        l ^= Spbox[4][(work >> 8) & 0x3f];\
767        l ^= Spbox[2][(work >> 16) & 0x3f];\
768        l ^= Spbox[0][(work >> 24) & 0x3f];\
769        work = r ^ key[1];\
770        l ^= Spbox[7][work & 0x3f];\
771        l ^= Spbox[5][(work >> 8) & 0x3f];\
772        l ^= Spbox[3][(work >> 16) & 0x3f];\
773        l ^= Spbox[1][(work >> 24) & 0x3f];\
774}
775/* Encrypt or decrypt a block of data in ECB mode */
776static void
777des(ks,block)
778guint32 ks[16][2];      /* Key schedule */
779unsigned char block[8];         /* Data block */
780{
781        guint32 left,right,work;
782       
783        /* Read input block and place in left/right in big-endian order */
784        left = ((guint32)block[0] << 24)
785         | ((guint32)block[1] << 16)
786         | ((guint32)block[2] << 8)
787         | (guint32)block[3];
788        right = ((guint32)block[4] << 24)
789         | ((guint32)block[5] << 16)
790         | ((guint32)block[6] << 8)
791         | (guint32)block[7];
792
793        /* Hoey's clever initial permutation algorithm, from Outerbridge
794         * (see Schneier p 478)
795         *
796         * The convention here is the same as Outerbridge: rotate each
797         * register left by 1 bit, i.e., so that "left" contains permuted
798         * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32   
799         * (using origin-1 numbering as in the FIPS). This allows us to avoid
800         * one of the two rotates that would otherwise be required in each of
801         * the 16 rounds.
802         */
803        work = ((left >> 4) ^ right) & 0x0f0f0f0f;
804        right ^= work;
805        left ^= work << 4;
806        work = ((left >> 16) ^ right) & 0xffff;
807        right ^= work;
808        left ^= work << 16;
809        work = ((right >> 2) ^ left) & 0x33333333;
810        left ^= work;
811        right ^= (work << 2);
812        work = ((right >> 8) ^ left) & 0xff00ff;
813        left ^= work;
814        right ^= (work << 8);
815        right = (right << 1) | (right >> 31);
816        work = (left ^ right) & 0xaaaaaaaa;
817        left ^= work;
818        right ^= work;
819        left = (left << 1) | (left >> 31);
820
821        /* Now do the 16 rounds */
822        F(left,right,ks[0]);
823        F(right,left,ks[1]);
824        F(left,right,ks[2]);
825        F(right,left,ks[3]);
826        F(left,right,ks[4]);
827        F(right,left,ks[5]);
828        F(left,right,ks[6]);
829        F(right,left,ks[7]);
830        F(left,right,ks[8]);
831        F(right,left,ks[9]);
832        F(left,right,ks[10]);
833        F(right,left,ks[11]);
834        F(left,right,ks[12]);
835        F(right,left,ks[13]);
836        F(left,right,ks[14]);
837        F(right,left,ks[15]);
838
839        /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
840        right = (right << 31) | (right >> 1);
841        work = (left ^ right) & 0xaaaaaaaa;
842        left ^= work;
843        right ^= work;
844        left = (left >> 1) | (left  << 31);
845        work = ((left >> 8) ^ right) & 0xff00ff;
846        right ^= work;
847        left ^= work << 8;
848        work = ((left >> 2) ^ right) & 0x33333333;
849        right ^= work;
850        left ^= work << 2;
851        work = ((right >> 16) ^ left) & 0xffff;
852        left ^= work;
853        right ^= work << 16;
854        work = ((right >> 4) ^ left) & 0x0f0f0f0f;
855        left ^= work;
856        right ^= work << 4;
857
858        /* Put the block back into the user's buffer with final swap */
859        block[0] = right >> 24;
860        block[1] = right >> 16;
861        block[2] = right >> 8;
862        block[3] = right;
863        block[4] = left >> 24;
864        block[5] = left >> 16;
865        block[6] = left >> 8;
866        block[7] = left;
867}
868
869/* Key schedule-related tables from FIPS-46 */
870
871/* permuted choice table (key) */
872static unsigned char pc1[] = {
873        57, 49, 41, 33, 25, 17,  9,
874         1, 58, 50, 42, 34, 26, 18,
875        10,  2, 59, 51, 43, 35, 27,
876        19, 11,  3, 60, 52, 44, 36,
877
878        63, 55, 47, 39, 31, 23, 15,
879         7, 62, 54, 46, 38, 30, 22,
880        14,  6, 61, 53, 45, 37, 29,
881        21, 13,  5, 28, 20, 12,  4
882};
883
884/* number left rotations of pc1 */
885static unsigned char totrot[] = {
886        1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
887};
888
889/* permuted choice key (table) */
890static unsigned char pc2[] = {
891        14, 17, 11, 24,  1,  5,
892         3, 28, 15,  6, 21, 10,
893        23, 19, 12,  4, 26,  8,
894        16,  7, 27, 20, 13,  2,
895        41, 52, 31, 37, 47, 55,
896        30, 40, 51, 45, 33, 48,
897        44, 49, 39, 56, 34, 53,
898        46, 42, 50, 36, 29, 32
899};
900
901/* End of DES-defined tables */
902
903
904/* bit 0 is left-most in byte */
905static int bytebit[] = {
906        0200,0100,040,020,010,04,02,01
907};
908
909
910/* Generate key schedule for encryption or decryption
911 * depending on the value of "decrypt"
912 */
913static void
914deskey(k,key,decrypt)
915DES_KS k;                       /* Key schedule array */
916unsigned char *key;             /* 64 bits (will use only 56) */
917int decrypt;                    /* 0 = encrypt, 1 = decrypt */
918{
919        unsigned char pc1m[56];         /* place to modify pc1 into */
920        unsigned char pcr[56];          /* place to rotate pc1 into */
921        register int i,j,l;
922        int m;
923        unsigned char ks[8];
924
925        for (j=0; j<56; j++) {          /* convert pc1 to bits of key */
926                l=pc1[j]-1;             /* integer bit location  */
927                m = l & 07;             /* find bit              */
928                pc1m[j]=(key[l>>3] &    /* find which key byte l is in */
929                        bytebit[m])     /* and which bit of that byte */
930                        ? 1 : 0;        /* and store 1-bit result */
931        }
932        for (i=0; i<16; i++) {          /* key chunk for each iteration */
933                memset(ks,0,sizeof(ks));        /* Clear key schedule */
934                for (j=0; j<56; j++)    /* rotate pc1 the right amount */
935                        pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
936                        /* rotate left and right halves independently */
937                for (j=0; j<48; j++){   /* select bits individually */
938                        /* check bit that goes to ks[j] */
939                        if (pcr[pc2[j]-1]){
940                                /* mask it in if it's there */
941                                l= j % 6;
942                                ks[j/6] |= bytebit[l] >> 2;
943                        }
944                }
945                /* Now convert to packed odd/even interleaved form */
946                k[i][0] = ((guint32)ks[0] << 24)
947                 | ((guint32)ks[2] << 16)
948                 | ((guint32)ks[4] << 8)
949                 | ((guint32)ks[6]);
950                k[i][1] = ((guint32)ks[1] << 24)
951                 | ((guint32)ks[3] << 16)
952                 | ((guint32)ks[5] << 8)
953                 | ((guint32)ks[7]);
954        }
955}
Note: See TracBrowser for help on using the repository browser.