1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright 2002 Ximian, Inc. (www.ximian.com)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of version 2 of the GNU Lesser General Public
7 * License as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
29 #include <glib/gi18n-lib.h>
31 #include "camel-sasl-ntlm.h"
33 CamelServiceAuthType camel_sasl_ntlm_authtype = {
36 N_("This option will connect to a Windows-based server using "
37 "NTLM / Secure Password Authentication."),
43 static CamelSaslClass *parent_class = NULL;
45 static GByteArray *ntlm_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex);
48 camel_sasl_ntlm_class_init (CamelSaslNTLMClass *camel_sasl_ntlm_class)
50 CamelSaslClass *camel_sasl_class = CAMEL_SASL_CLASS (camel_sasl_ntlm_class);
52 parent_class = CAMEL_SASL_CLASS (camel_type_get_global_classfuncs (camel_sasl_get_type ()));
54 /* virtual method overload */
55 camel_sasl_class->challenge = ntlm_challenge;
59 camel_sasl_ntlm_get_type (void)
61 static CamelType type = CAMEL_INVALID_TYPE;
63 if (type == CAMEL_INVALID_TYPE) {
64 type = camel_type_register (
65 camel_sasl_get_type (), "CamelSaslNTLM",
66 sizeof (CamelSaslNTLM),
67 sizeof (CamelSaslNTLMClass),
68 (CamelObjectClassInitFunc) camel_sasl_ntlm_class_init,
75 #define NTLM_REQUEST "NTLMSSP\x00\x01\x00\x00\x00\x06\x82\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00\x00\x00\x00\x00\x30\x00\x00\x00"
77 #define NTLM_CHALLENGE_NONCE_OFFSET 24
78 #define NTLM_CHALLENGE_DOMAIN_OFFSET 48
79 #define NTLM_CHALLENGE_DOMAIN_LEN_OFFSET 44
81 #define NTLM_RESPONSE_HEADER "NTLMSSP\x00\x03\x00\x00\x00"
82 #define NTLM_RESPONSE_FLAGS "\x82\x01"
83 #define NTLM_RESPONSE_BASE_SIZE 64
84 #define NTLM_RESPONSE_LM_RESP_OFFSET 12
85 #define NTLM_RESPONSE_NT_RESP_OFFSET 20
86 #define NTLM_RESPONSE_DOMAIN_OFFSET 28
87 #define NTLM_RESPONSE_USER_OFFSET 36
88 #define NTLM_RESPONSE_HOST_OFFSET 44
89 #define NTLM_RESPONSE_FLAGS_OFFSET 60
91 static void ntlm_calc_response (const guchar key[21],
92 const guchar plaintext[8],
94 static void ntlm_lanmanager_hash (const char *password, char hash[21]);
95 static void ntlm_nt_hash (const char *password, char hash[21]);
96 static void ntlm_set_string (GByteArray *ba, int offset,
97 const char *data, int len);
100 ntlm_challenge (CamelSasl *sasl, GByteArray *token, CamelException *ex)
103 guchar nonce[8], hash[21], lm_resp[24], nt_resp[24];
105 ret = g_byte_array_new ();
107 if (!token || !token->len) {
108 g_byte_array_append (ret, NTLM_REQUEST,
109 sizeof (NTLM_REQUEST) - 1);
113 memcpy (nonce, token->data + NTLM_CHALLENGE_NONCE_OFFSET, 8);
114 ntlm_lanmanager_hash (sasl->service->url->passwd, hash);
115 ntlm_calc_response (hash, nonce, lm_resp);
116 ntlm_nt_hash (sasl->service->url->passwd, hash);
117 ntlm_calc_response (hash, nonce, nt_resp);
119 ret = g_byte_array_new ();
120 g_byte_array_set_size (ret, NTLM_RESPONSE_BASE_SIZE);
121 memset (ret->data, 0, NTLM_RESPONSE_BASE_SIZE);
122 memcpy (ret->data, NTLM_RESPONSE_HEADER,
123 sizeof (NTLM_RESPONSE_HEADER) - 1);
124 memcpy (ret->data + NTLM_RESPONSE_FLAGS_OFFSET,
125 NTLM_RESPONSE_FLAGS, sizeof (NTLM_RESPONSE_FLAGS) - 1);
127 ntlm_set_string (ret, NTLM_RESPONSE_DOMAIN_OFFSET,
128 token->data + NTLM_CHALLENGE_DOMAIN_OFFSET,
129 atoi (token->data + NTLM_CHALLENGE_DOMAIN_LEN_OFFSET));
130 ntlm_set_string (ret, NTLM_RESPONSE_USER_OFFSET,
131 sasl->service->url->user,
132 strlen (sasl->service->url->user));
133 ntlm_set_string (ret, NTLM_RESPONSE_HOST_OFFSET,
134 "UNKNOWN", sizeof ("UNKNOWN") - 1);
135 ntlm_set_string (ret, NTLM_RESPONSE_LM_RESP_OFFSET,
136 lm_resp, sizeof (lm_resp));
137 ntlm_set_string (ret, NTLM_RESPONSE_NT_RESP_OFFSET,
138 nt_resp, sizeof (nt_resp));
140 sasl->authenticated = TRUE;
145 static void md4sum (const unsigned char *in,
147 unsigned char digest[16]);
150 typedef guint32 DES_KS[16][2]; /* Single-key DES key schedule */
152 static void deskey (DES_KS, unsigned char *, int);
154 static void des (DES_KS, unsigned char *);
156 static void setup_schedule (const guchar *key_56, DES_KS ks);
160 #define LM_PASSWORD_MAGIC "\x4B\x47\x53\x21\x40\x23\x24\x25" \
161 "\x4B\x47\x53\x21\x40\x23\x24\x25" \
162 "\x00\x00\x00\x00\x00"
165 ntlm_lanmanager_hash (const char *password, char hash[21])
167 guchar lm_password [15];
171 for (i = 0; i < 14 && password [i]; i++)
172 lm_password [i] = toupper ((unsigned char) password [i]);
175 lm_password [i] = '\0';
177 memcpy (hash, LM_PASSWORD_MAGIC, 21);
179 setup_schedule (lm_password, ks);
182 setup_schedule (lm_password + 7, ks);
187 ntlm_nt_hash (const char *password, char hash[21])
189 unsigned char *buf, *p;
191 p = buf = g_malloc (strlen (password) * 2);
198 md4sum (buf, p - buf, hash);
199 memset (hash + 16, 0, 5);
205 ntlm_set_string (GByteArray *ba, int offset, const char *data, int len)
207 ba->data[offset ] = ba->data[offset + 2] = len & 0xFF;
208 ba->data[offset + 1] = ba->data[offset + 3] = (len >> 8) & 0xFF;
209 ba->data[offset + 4] = ba->len & 0xFF;
210 ba->data[offset + 5] = (ba->len >> 8) & 0xFF;
211 g_byte_array_append (ba, data, len);
215 #define KEYBITS(k,s) \
216 (((k[(s)/8] << ((s)%8)) & 0xFF) | (k[(s)/8+1] >> (8-(s)%8)))
219 /* Set up a key schedule based on a 56bit key */
221 setup_schedule (const guchar *key_56, DES_KS ks)
226 for (i = 0; i < 8; i++) {
227 key [i] = KEYBITS (key_56, i * 7);
230 for (c = bit = 0; bit < 8; bit++)
231 if (key [i] & (1 << bit))
241 ntlm_calc_response (const guchar key[21], const guchar plaintext[8],
246 memcpy (results, plaintext, 8);
247 memcpy (results + 8, plaintext, 8);
248 memcpy (results + 16, plaintext, 8);
250 setup_schedule (key, ks);
253 setup_schedule (key + 7, ks);
254 des (ks, results + 8);
256 setup_schedule (key + 14, ks);
257 des (ks, results + 16);
262 * MD4 encoder. (The one everyone else uses is not GPL-compatible;
263 * this is a reimplementation from spec.) This doesn't need to be
264 * efficient for our purposes, although it would be nice to fix
265 * it to not malloc()...
268 #define F(X,Y,Z) ( ((X)&(Y)) | ((~(X))&(Z)) )
269 #define G(X,Y,Z) ( ((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z)) )
270 #define H(X,Y,Z) ( (X)^(Y)^(Z) )
271 #define ROT(val, n) ( ((val) << (n)) | ((val) >> (32 - (n))) )
274 md4sum (const unsigned char *in, int nbytes, unsigned char digest[16])
277 guint32 A, B, C, D, AA, BB, CC, DD, X[16];
278 int pbytes, nbits = nbytes * 8, i, j;
280 pbytes = (120 - (nbytes % 64)) % 64;
281 M = alloca (nbytes + pbytes + 8);
282 memcpy (M, in, nbytes);
283 memset (M + nbytes, 0, pbytes + 8);
285 M[nbytes + pbytes] = nbits & 0xFF;
286 M[nbytes + pbytes + 1] = (nbits >> 8) & 0xFF;
287 M[nbytes + pbytes + 2] = (nbits >> 16) & 0xFF;
288 M[nbytes + pbytes + 3] = (nbits >> 24) & 0xFF;
295 for (i = 0; i < nbytes + pbytes + 8; i += 64) {
296 for (j = 0; j < 16; j++) {
297 X[j] = (M[i + j*4]) |
298 (M[i + j*4 + 1] << 8) |
299 (M[i + j*4 + 2] << 16) |
300 (M[i + j*4 + 3] << 24);
308 A = ROT (A + F(B, C, D) + X[0], 3);
309 D = ROT (D + F(A, B, C) + X[1], 7);
310 C = ROT (C + F(D, A, B) + X[2], 11);
311 B = ROT (B + F(C, D, A) + X[3], 19);
312 A = ROT (A + F(B, C, D) + X[4], 3);
313 D = ROT (D + F(A, B, C) + X[5], 7);
314 C = ROT (C + F(D, A, B) + X[6], 11);
315 B = ROT (B + F(C, D, A) + X[7], 19);
316 A = ROT (A + F(B, C, D) + X[8], 3);
317 D = ROT (D + F(A, B, C) + X[9], 7);
318 C = ROT (C + F(D, A, B) + X[10], 11);
319 B = ROT (B + F(C, D, A) + X[11], 19);
320 A = ROT (A + F(B, C, D) + X[12], 3);
321 D = ROT (D + F(A, B, C) + X[13], 7);
322 C = ROT (C + F(D, A, B) + X[14], 11);
323 B = ROT (B + F(C, D, A) + X[15], 19);
325 A = ROT (A + G(B, C, D) + X[0] + 0x5A827999, 3);
326 D = ROT (D + G(A, B, C) + X[4] + 0x5A827999, 5);
327 C = ROT (C + G(D, A, B) + X[8] + 0x5A827999, 9);
328 B = ROT (B + G(C, D, A) + X[12] + 0x5A827999, 13);
329 A = ROT (A + G(B, C, D) + X[1] + 0x5A827999, 3);
330 D = ROT (D + G(A, B, C) + X[5] + 0x5A827999, 5);
331 C = ROT (C + G(D, A, B) + X[9] + 0x5A827999, 9);
332 B = ROT (B + G(C, D, A) + X[13] + 0x5A827999, 13);
333 A = ROT (A + G(B, C, D) + X[2] + 0x5A827999, 3);
334 D = ROT (D + G(A, B, C) + X[6] + 0x5A827999, 5);
335 C = ROT (C + G(D, A, B) + X[10] + 0x5A827999, 9);
336 B = ROT (B + G(C, D, A) + X[14] + 0x5A827999, 13);
337 A = ROT (A + G(B, C, D) + X[3] + 0x5A827999, 3);
338 D = ROT (D + G(A, B, C) + X[7] + 0x5A827999, 5);
339 C = ROT (C + G(D, A, B) + X[11] + 0x5A827999, 9);
340 B = ROT (B + G(C, D, A) + X[15] + 0x5A827999, 13);
342 A = ROT (A + H(B, C, D) + X[0] + 0x6ED9EBA1, 3);
343 D = ROT (D + H(A, B, C) + X[8] + 0x6ED9EBA1, 9);
344 C = ROT (C + H(D, A, B) + X[4] + 0x6ED9EBA1, 11);
345 B = ROT (B + H(C, D, A) + X[12] + 0x6ED9EBA1, 15);
346 A = ROT (A + H(B, C, D) + X[2] + 0x6ED9EBA1, 3);
347 D = ROT (D + H(A, B, C) + X[10] + 0x6ED9EBA1, 9);
348 C = ROT (C + H(D, A, B) + X[6] + 0x6ED9EBA1, 11);
349 B = ROT (B + H(C, D, A) + X[14] + 0x6ED9EBA1, 15);
350 A = ROT (A + H(B, C, D) + X[1] + 0x6ED9EBA1, 3);
351 D = ROT (D + H(A, B, C) + X[9] + 0x6ED9EBA1, 9);
352 C = ROT (C + H(D, A, B) + X[5] + 0x6ED9EBA1, 11);
353 B = ROT (B + H(C, D, A) + X[13] + 0x6ED9EBA1, 15);
354 A = ROT (A + H(B, C, D) + X[3] + 0x6ED9EBA1, 3);
355 D = ROT (D + H(A, B, C) + X[11] + 0x6ED9EBA1, 9);
356 C = ROT (C + H(D, A, B) + X[7] + 0x6ED9EBA1, 11);
357 B = ROT (B + H(C, D, A) + X[15] + 0x6ED9EBA1, 15);
365 digest[0] = A & 0xFF;
366 digest[1] = (A >> 8) & 0xFF;
367 digest[2] = (A >> 16) & 0xFF;
368 digest[3] = (A >> 24) & 0xFF;
369 digest[4] = B & 0xFF;
370 digest[5] = (B >> 8) & 0xFF;
371 digest[6] = (B >> 16) & 0xFF;
372 digest[7] = (B >> 24) & 0xFF;
373 digest[8] = C & 0xFF;
374 digest[9] = (C >> 8) & 0xFF;
375 digest[10] = (C >> 16) & 0xFF;
376 digest[11] = (C >> 24) & 0xFF;
377 digest[12] = D & 0xFF;
378 digest[13] = (D >> 8) & 0xFF;
379 digest[14] = (D >> 16) & 0xFF;
380 digest[15] = (D >> 24) & 0xFF;
384 /* Public domain DES implementation from Phil Karn */
385 static guint32 Spbox[8][64] = {
386 { 0x01010400, 0x00000000, 0x00010000, 0x01010404,
387 0x01010004, 0x00010404, 0x00000004, 0x00010000,
388 0x00000400, 0x01010400, 0x01010404, 0x00000400,
389 0x01000404, 0x01010004, 0x01000000, 0x00000004,
390 0x00000404, 0x01000400, 0x01000400, 0x00010400,
391 0x00010400, 0x01010000, 0x01010000, 0x01000404,
392 0x00010004, 0x01000004, 0x01000004, 0x00010004,
393 0x00000000, 0x00000404, 0x00010404, 0x01000000,
394 0x00010000, 0x01010404, 0x00000004, 0x01010000,
395 0x01010400, 0x01000000, 0x01000000, 0x00000400,
396 0x01010004, 0x00010000, 0x00010400, 0x01000004,
397 0x00000400, 0x00000004, 0x01000404, 0x00010404,
398 0x01010404, 0x00010004, 0x01010000, 0x01000404,
399 0x01000004, 0x00000404, 0x00010404, 0x01010400,
400 0x00000404, 0x01000400, 0x01000400, 0x00000000,
401 0x00010004, 0x00010400, 0x00000000, 0x01010004 },
402 { 0x80108020, 0x80008000, 0x00008000, 0x00108020,
403 0x00100000, 0x00000020, 0x80100020, 0x80008020,
404 0x80000020, 0x80108020, 0x80108000, 0x80000000,
405 0x80008000, 0x00100000, 0x00000020, 0x80100020,
406 0x00108000, 0x00100020, 0x80008020, 0x00000000,
407 0x80000000, 0x00008000, 0x00108020, 0x80100000,
408 0x00100020, 0x80000020, 0x00000000, 0x00108000,
409 0x00008020, 0x80108000, 0x80100000, 0x00008020,
410 0x00000000, 0x00108020, 0x80100020, 0x00100000,
411 0x80008020, 0x80100000, 0x80108000, 0x00008000,
412 0x80100000, 0x80008000, 0x00000020, 0x80108020,
413 0x00108020, 0x00000020, 0x00008000, 0x80000000,
414 0x00008020, 0x80108000, 0x00100000, 0x80000020,
415 0x00100020, 0x80008020, 0x80000020, 0x00100020,
416 0x00108000, 0x00000000, 0x80008000, 0x00008020,
417 0x80000000, 0x80100020, 0x80108020, 0x00108000 },
418 { 0x00000208, 0x08020200, 0x00000000, 0x08020008,
419 0x08000200, 0x00000000, 0x00020208, 0x08000200,
420 0x00020008, 0x08000008, 0x08000008, 0x00020000,
421 0x08020208, 0x00020008, 0x08020000, 0x00000208,
422 0x08000000, 0x00000008, 0x08020200, 0x00000200,
423 0x00020200, 0x08020000, 0x08020008, 0x00020208,
424 0x08000208, 0x00020200, 0x00020000, 0x08000208,
425 0x00000008, 0x08020208, 0x00000200, 0x08000000,
426 0x08020200, 0x08000000, 0x00020008, 0x00000208,
427 0x00020000, 0x08020200, 0x08000200, 0x00000000,
428 0x00000200, 0x00020008, 0x08020208, 0x08000200,
429 0x08000008, 0x00000200, 0x00000000, 0x08020008,
430 0x08000208, 0x00020000, 0x08000000, 0x08020208,
431 0x00000008, 0x00020208, 0x00020200, 0x08000008,
432 0x08020000, 0x08000208, 0x00000208, 0x08020000,
433 0x00020208, 0x00000008, 0x08020008, 0x00020200 },
434 { 0x00802001, 0x00002081, 0x00002081, 0x00000080,
435 0x00802080, 0x00800081, 0x00800001, 0x00002001,
436 0x00000000, 0x00802000, 0x00802000, 0x00802081,
437 0x00000081, 0x00000000, 0x00800080, 0x00800001,
438 0x00000001, 0x00002000, 0x00800000, 0x00802001,
439 0x00000080, 0x00800000, 0x00002001, 0x00002080,
440 0x00800081, 0x00000001, 0x00002080, 0x00800080,
441 0x00002000, 0x00802080, 0x00802081, 0x00000081,
442 0x00800080, 0x00800001, 0x00802000, 0x00802081,
443 0x00000081, 0x00000000, 0x00000000, 0x00802000,
444 0x00002080, 0x00800080, 0x00800081, 0x00000001,
445 0x00802001, 0x00002081, 0x00002081, 0x00000080,
446 0x00802081, 0x00000081, 0x00000001, 0x00002000,
447 0x00800001, 0x00002001, 0x00802080, 0x00800081,
448 0x00002001, 0x00002080, 0x00800000, 0x00802001,
449 0x00000080, 0x00800000, 0x00002000, 0x00802080 },
450 { 0x00000100, 0x02080100, 0x02080000, 0x42000100,
451 0x00080000, 0x00000100, 0x40000000, 0x02080000,
452 0x40080100, 0x00080000, 0x02000100, 0x40080100,
453 0x42000100, 0x42080000, 0x00080100, 0x40000000,
454 0x02000000, 0x40080000, 0x40080000, 0x00000000,
455 0x40000100, 0x42080100, 0x42080100, 0x02000100,
456 0x42080000, 0x40000100, 0x00000000, 0x42000000,
457 0x02080100, 0x02000000, 0x42000000, 0x00080100,
458 0x00080000, 0x42000100, 0x00000100, 0x02000000,
459 0x40000000, 0x02080000, 0x42000100, 0x40080100,
460 0x02000100, 0x40000000, 0x42080000, 0x02080100,
461 0x40080100, 0x00000100, 0x02000000, 0x42080000,
462 0x42080100, 0x00080100, 0x42000000, 0x42080100,
463 0x02080000, 0x00000000, 0x40080000, 0x42000000,
464 0x00080100, 0x02000100, 0x40000100, 0x00080000,
465 0x00000000, 0x40080000, 0x02080100, 0x40000100 },
466 { 0x20000010, 0x20400000, 0x00004000, 0x20404010,
467 0x20400000, 0x00000010, 0x20404010, 0x00400000,
468 0x20004000, 0x00404010, 0x00400000, 0x20000010,
469 0x00400010, 0x20004000, 0x20000000, 0x00004010,
470 0x00000000, 0x00400010, 0x20004010, 0x00004000,
471 0x00404000, 0x20004010, 0x00000010, 0x20400010,
472 0x20400010, 0x00000000, 0x00404010, 0x20404000,
473 0x00004010, 0x00404000, 0x20404000, 0x20000000,
474 0x20004000, 0x00000010, 0x20400010, 0x00404000,
475 0x20404010, 0x00400000, 0x00004010, 0x20000010,
476 0x00400000, 0x20004000, 0x20000000, 0x00004010,
477 0x20000010, 0x20404010, 0x00404000, 0x20400000,
478 0x00404010, 0x20404000, 0x00000000, 0x20400010,
479 0x00000010, 0x00004000, 0x20400000, 0x00404010,
480 0x00004000, 0x00400010, 0x20004010, 0x00000000,
481 0x20404000, 0x20000000, 0x00400010, 0x20004010 },
482 { 0x00200000, 0x04200002, 0x04000802, 0x00000000,
483 0x00000800, 0x04000802, 0x00200802, 0x04200800,
484 0x04200802, 0x00200000, 0x00000000, 0x04000002,
485 0x00000002, 0x04000000, 0x04200002, 0x00000802,
486 0x04000800, 0x00200802, 0x00200002, 0x04000800,
487 0x04000002, 0x04200000, 0x04200800, 0x00200002,
488 0x04200000, 0x00000800, 0x00000802, 0x04200802,
489 0x00200800, 0x00000002, 0x04000000, 0x00200800,
490 0x04000000, 0x00200800, 0x00200000, 0x04000802,
491 0x04000802, 0x04200002, 0x04200002, 0x00000002,
492 0x00200002, 0x04000000, 0x04000800, 0x00200000,
493 0x04200800, 0x00000802, 0x00200802, 0x04200800,
494 0x00000802, 0x04000002, 0x04200802, 0x04200000,
495 0x00200800, 0x00000000, 0x00000002, 0x04200802,
496 0x00000000, 0x00200802, 0x04200000, 0x00000800,
497 0x04000002, 0x04000800, 0x00000800, 0x00200002 },
498 { 0x10001040, 0x00001000, 0x00040000, 0x10041040,
499 0x10000000, 0x10001040, 0x00000040, 0x10000000,
500 0x00040040, 0x10040000, 0x10041040, 0x00041000,
501 0x10041000, 0x00041040, 0x00001000, 0x00000040,
502 0x10040000, 0x10000040, 0x10001000, 0x00001040,
503 0x00041000, 0x00040040, 0x10040040, 0x10041000,
504 0x00001040, 0x00000000, 0x00000000, 0x10040040,
505 0x10000040, 0x10001000, 0x00041040, 0x00040000,
506 0x00041040, 0x00040000, 0x10041000, 0x00001000,
507 0x00000040, 0x10040040, 0x00001000, 0x00041040,
508 0x10001000, 0x00000040, 0x10000040, 0x10040000,
509 0x10040040, 0x10000000, 0x00040000, 0x10001040,
510 0x00000000, 0x10041040, 0x00040040, 0x10000040,
511 0x10040000, 0x10001000, 0x10001040, 0x00000000,
512 0x10041040, 0x00041000, 0x00041000, 0x00001040,
513 0x00001040, 0x00040040, 0x10000000, 0x10041000 }
518 work = ((r >> 4) | (r << 28)) ^ key[0];\
519 l ^= Spbox[6][work & 0x3f];\
520 l ^= Spbox[4][(work >> 8) & 0x3f];\
521 l ^= Spbox[2][(work >> 16) & 0x3f];\
522 l ^= Spbox[0][(work >> 24) & 0x3f];\
524 l ^= Spbox[7][work & 0x3f];\
525 l ^= Spbox[5][(work >> 8) & 0x3f];\
526 l ^= Spbox[3][(work >> 16) & 0x3f];\
527 l ^= Spbox[1][(work >> 24) & 0x3f];\
530 /* Encrypt or decrypt a block of data in ECB mode */
532 des (guint32 ks[16][2], unsigned char block[8])
534 guint32 left, right, work;
536 /* Read input block and place in left/right in big-endian order */
537 left = ((guint32)block[0] << 24)
538 | ((guint32)block[1] << 16)
539 | ((guint32)block[2] << 8)
541 right = ((guint32)block[4] << 24)
542 | ((guint32)block[5] << 16)
543 | ((guint32)block[6] << 8)
546 /* Hoey's clever initial permutation algorithm, from Outerbridge
547 * (see Schneier p 478)
549 * The convention here is the same as Outerbridge: rotate each
550 * register left by 1 bit, i.e., so that "left" contains permuted
551 * input bits 2, 3, 4, ... 1 and "right" contains 33, 34, 35, ... 32
552 * (using origin-1 numbering as in the FIPS). This allows us to avoid
553 * one of the two rotates that would otherwise be required in each of
556 work = ((left >> 4) ^ right) & 0x0f0f0f0f;
559 work = ((left >> 16) ^ right) & 0xffff;
562 work = ((right >> 2) ^ left) & 0x33333333;
564 right ^= (work << 2);
565 work = ((right >> 8) ^ left) & 0xff00ff;
567 right ^= (work << 8);
568 right = (right << 1) | (right >> 31);
569 work = (left ^ right) & 0xaaaaaaaa;
572 left = (left << 1) | (left >> 31);
574 /* Now do the 16 rounds */
585 F(left,right,ks[10]);
586 F(right,left,ks[11]);
587 F(left,right,ks[12]);
588 F(right,left,ks[13]);
589 F(left,right,ks[14]);
590 F(right,left,ks[15]);
592 /* Inverse permutation, also from Hoey via Outerbridge and Schneier */
593 right = (right << 31) | (right >> 1);
594 work = (left ^ right) & 0xaaaaaaaa;
597 left = (left >> 1) | (left << 31);
598 work = ((left >> 8) ^ right) & 0xff00ff;
601 work = ((left >> 2) ^ right) & 0x33333333;
604 work = ((right >> 16) ^ left) & 0xffff;
607 work = ((right >> 4) ^ left) & 0x0f0f0f0f;
611 /* Put the block back into the user's buffer with final swap */
612 block[0] = right >> 24;
613 block[1] = right >> 16;
614 block[2] = right >> 8;
616 block[4] = left >> 24;
617 block[5] = left >> 16;
618 block[6] = left >> 8;
622 /* Key schedule-related tables from FIPS-46 */
624 /* permuted choice table (key) */
625 static unsigned char pc1[] = {
626 57, 49, 41, 33, 25, 17, 9,
627 1, 58, 50, 42, 34, 26, 18,
628 10, 2, 59, 51, 43, 35, 27,
629 19, 11, 3, 60, 52, 44, 36,
631 63, 55, 47, 39, 31, 23, 15,
632 7, 62, 54, 46, 38, 30, 22,
633 14, 6, 61, 53, 45, 37, 29,
634 21, 13, 5, 28, 20, 12, 4
637 /* number left rotations of pc1 */
638 static unsigned char totrot[] = {
639 1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28
642 /* permuted choice key (table) */
643 static unsigned char pc2[] = {
644 14, 17, 11, 24, 1, 5,
645 3, 28, 15, 6, 21, 10,
646 23, 19, 12, 4, 26, 8,
647 16, 7, 27, 20, 13, 2,
648 41, 52, 31, 37, 47, 55,
649 30, 40, 51, 45, 33, 48,
650 44, 49, 39, 56, 34, 53,
651 46, 42, 50, 36, 29, 32
654 /* End of DES-defined tables */
657 /* bit 0 is left-most in byte */
658 static int bytebit[] = {
659 0200,0100,040,020,010,04,02,01
663 /* Generate key schedule for encryption or decryption
664 * depending on the value of "decrypt"
667 deskey (DES_KS k, unsigned char *key, int decrypt)
669 unsigned char pc1m[56]; /* place to modify pc1 into */
670 unsigned char pcr[56]; /* place to rotate pc1 into */
675 for (j=0; j<56; j++) { /* convert pc1 to bits of key */
676 l=pc1[j]-1; /* integer bit location */
677 m = l & 07; /* find bit */
678 pc1m[j]=(key[l>>3] & /* find which key byte l is in */
679 bytebit[m]) /* and which bit of that byte */
680 ? 1 : 0; /* and store 1-bit result */
682 for (i=0; i<16; i++) { /* key chunk for each iteration */
683 memset(ks,0,sizeof(ks)); /* Clear key schedule */
684 for (j=0; j<56; j++) /* rotate pc1 the right amount */
685 pcr[j] = pc1m[(l=j+totrot[decrypt? 15-i : i])<(j<28? 28 : 56) ? l: l-28];
686 /* rotate left and right halves independently */
687 for (j=0; j<48; j++){ /* select bits individually */
688 /* check bit that goes to ks[j] */
690 /* mask it in if it's there */
692 ks[j/6] |= bytebit[l] >> 2;
695 /* Now convert to packed odd/even interleaved form */
696 k[i][0] = ((guint32)ks[0] << 24)
697 | ((guint32)ks[2] << 16)
698 | ((guint32)ks[4] << 8)
700 k[i][1] = ((guint32)ks[1] << 24)
701 | ((guint32)ks[3] << 16)
702 | ((guint32)ks[5] << 8)