summaryrefslogtreecommitdiffstats
path: root/kio/misc/kntlm
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitce4a32fe52ef09d8f5ff1dd22c001110902b60a2 (patch)
tree5ac38a06f3dde268dc7927dc155896926aaf7012 /kio/misc/kntlm
downloadtdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.tar.gz
tdelibs-ce4a32fe52ef09d8f5ff1dd22c001110902b60a2.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kio/misc/kntlm')
-rw-r--r--kio/misc/kntlm/Makefile.am12
-rw-r--r--kio/misc/kntlm/des.cpp513
-rw-r--r--kio/misc/kntlm/des.h19
-rw-r--r--kio/misc/kntlm/kntlm.cpp389
-rw-r--r--kio/misc/kntlm/kntlm.h233
-rw-r--r--kio/misc/kntlm/kswap.h428
6 files changed, 1594 insertions, 0 deletions
diff --git a/kio/misc/kntlm/Makefile.am b/kio/misc/kntlm/Makefile.am
new file mode 100644
index 000000000..192ddc0af
--- /dev/null
+++ b/kio/misc/kntlm/Makefile.am
@@ -0,0 +1,12 @@
+INCLUDES=$(all_includes)
+
+lib_LTLIBRARIES = libkntlm.la
+METASOURCES = AUTO
+
+kntlmincludedir = $(includedir)/kio
+kntlminclude_HEADERS = kntlm.h
+
+libkntlm_la_SOURCES = kntlm.cpp des.cpp
+libkntlm_la_LDFLAGS = $(all_libraries) -version-info 0:0:0 -no-undefined
+libkntlm_la_LIBADD = $(LIB_KDECORE)
+
diff --git a/kio/misc/kntlm/des.cpp b/kio/misc/kntlm/des.cpp
new file mode 100644
index 000000000..b6683ac34
--- /dev/null
+++ b/kio/misc/kntlm/des.cpp
@@ -0,0 +1,513 @@
+
+/* Sofware DES functions
+ * written 12 Dec 1986 by Phil Karn, KA9Q; large sections adapted from
+ * the 1977 public-domain program by Jim Gillogly
+ * Modified for additional speed - 6 December 1988 Phil Karn
+ * Modified for parameterized key schedules - Jan 1991 Phil Karn
+ * Callers now allocate a key schedule as follows:
+ * kn = (char (*)[8])malloc(sizeof(char) * 8 * 16);
+ * or
+ * char kn[16][8];
+ */
+
+/* modified in order to use the libmcrypt API by Nikos Mavroyanopoulos
+ * All modifications are placed under the license of libmcrypt.
+ */
+
+/* $Id$ */
+
+#include <string.h>
+#include <kswap.h>
+#include "des.h"
+
+static void permute_ip (unsigned char *inblock, DES_KEY * key, unsigned char *outblock);
+static void permute_fp (unsigned char *inblock, DES_KEY * key, unsigned char *outblock);
+static void perminit_ip (DES_KEY * key);
+static void spinit (DES_KEY * key);
+static void perminit_fp (DES_KEY * key);
+static Q_UINT32 f (DES_KEY * key, Q_UINT32 r, char *subkey);
+
+
+/* Tables defined in the Data Encryption Standard documents */
+
+/* initial permutation IP */
+static const char ip[] = {
+ 58, 50, 42, 34, 26, 18, 10, 2,
+ 60, 52, 44, 36, 28, 20, 12, 4,
+ 62, 54, 46, 38, 30, 22, 14, 6,
+ 64, 56, 48, 40, 32, 24, 16, 8,
+ 57, 49, 41, 33, 25, 17, 9, 1,
+ 59, 51, 43, 35, 27, 19, 11, 3,
+ 61, 53, 45, 37, 29, 21, 13, 5,
+ 63, 55, 47, 39, 31, 23, 15, 7
+};
+
+/* final permutation IP^-1 */
+static const char fp[] = {
+ 40, 8, 48, 16, 56, 24, 64, 32,
+ 39, 7, 47, 15, 55, 23, 63, 31,
+ 38, 6, 46, 14, 54, 22, 62, 30,
+ 37, 5, 45, 13, 53, 21, 61, 29,
+ 36, 4, 44, 12, 52, 20, 60, 28,
+ 35, 3, 43, 11, 51, 19, 59, 27,
+ 34, 2, 42, 10, 50, 18, 58, 26,
+ 33, 1, 41, 9, 49, 17, 57, 25
+};
+
+/* expansion operation matrix
+ * This is for reference only; it is unused in the code
+ * as the f() function performs it implicitly for speed
+ */
+#ifdef notdef
+static const char ei[] = {
+ 32, 1, 2, 3, 4, 5,
+ 4, 5, 6, 7, 8, 9,
+ 8, 9, 10, 11, 12, 13,
+ 12, 13, 14, 15, 16, 17,
+ 16, 17, 18, 19, 20, 21,
+ 20, 21, 22, 23, 24, 25,
+ 24, 25, 26, 27, 28, 29,
+ 28, 29, 30, 31, 32, 1
+};
+#endif
+
+/* permuted choice table (key) */
+static const char pc1[] = {
+ 57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4
+};
+
+/* number left rotations of pc1 */
+static const char totrot[] = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
+};
+
+/* permuted choice key (table) */
+static const char pc2[] = {
+ 14, 17, 11, 24, 1, 5,
+ 3, 28, 15, 6, 21, 10,
+ 23, 19, 12, 4, 26, 8,
+ 16, 7, 27, 20, 13, 2,
+ 41, 52, 31, 37, 47, 55,
+ 30, 40, 51, 45, 33, 48,
+ 44, 49, 39, 56, 34, 53,
+ 46, 42, 50, 36, 29, 32
+};
+
+/* The (in)famous S-boxes */
+static const char si[8][64] = {
+ /* S1 */
+ {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
+ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
+ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
+ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
+
+ /* S2 */
+ {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
+ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
+ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
+ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
+
+ /* S3 */
+ {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
+ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
+ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
+ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
+
+ /* S4 */
+ {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
+ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
+ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
+ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
+
+ /* S5 */
+ {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
+ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
+ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
+ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
+
+ /* S6 */
+ {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
+ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
+ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
+ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
+
+ /* S7 */
+ {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
+ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
+ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
+ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
+
+ /* S8 */
+ {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
+ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
+ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
+ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11},
+
+};
+
+/* 32-bit permutation function P used on the output of the S-boxes */
+static const char p32i[] = {
+ 16, 7, 20, 21,
+ 29, 12, 28, 17,
+ 1, 15, 23, 26,
+ 5, 18, 31, 10,
+ 2, 8, 24, 14,
+ 32, 27, 3, 9,
+ 19, 13, 30, 6,
+ 22, 11, 4, 25
+};
+
+/* End of DES-defined tables */
+
+/* Lookup tables initialized once only at startup by desinit() */
+
+/* bit 0 is left-most in byte */
+static const int bytebit[] = {
+ 0200, 0100, 040, 020, 010, 04, 02, 01
+};
+
+static const int nibblebit[] = {
+ 010, 04, 02, 01
+};
+
+/* Allocate space and initialize DES lookup arrays
+ * mode == 0: standard Data Encryption Algorithm
+ */
+static int
+desinit (DES_KEY * key)
+{
+
+ spinit (key);
+ perminit_ip (key);
+ perminit_fp (key);
+
+ return 0;
+}
+
+
+/* Set key (initialize key schedule array) */
+int
+ntlm_des_set_key (DES_KEY * dkey, char *user_key, int /*len*/)
+{
+ char pc1m[56]; /* place to modify pc1 into */
+ char pcr[56]; /* place to rotate pc1 into */
+ int i, j, l;
+ int m;
+
+ memset(dkey, 0, sizeof (DES_KEY));
+ desinit (dkey);
+
+ /* Clear key schedule */
+
+
+ for (j = 0; j < 56; j++)
+ { /* convert pc1 to bits of key */
+ l = pc1[j] - 1; /* integer bit location */
+ m = l & 07; /* find bit */
+ pc1m[j] = (user_key[l >> 3] & /* find which key byte l is in */
+ bytebit[m]) /* and which bit of that byte */
+ ? 1 : 0; /* and store 1-bit result */
+
+ }
+ for (i = 0; i < 16; i++)
+ { /* key chunk for each iteration */
+ for (j = 0; j < 56; j++) /* rotate pc1 the right amount */
+ pcr[j] = pc1m[(l = j + totrot[i]) < (j < 28 ? 28 : 56) ? l : l - 28];
+ /* rotate left and right halves independently */
+ for (j = 0; j < 48; j++)
+ { /* select bits individually */
+ /* check bit that goes to kn[j] */
+ if (pcr[pc2[j] - 1])
+ {
+ /* mask it in if it's there */
+ l = j % 6;
+ dkey->kn[i][j / 6] |= bytebit[l] >> 2;
+ }
+ }
+ }
+ return 0;
+}
+
+/* In-place encryption of 64-bit block */
+static void
+ntlm_des_encrypt (DES_KEY * key, unsigned char *block)
+{
+ Q_UINT32 left, right;
+ char *knp;
+ Q_UINT32 work[2]; /* Working data storage */
+
+ permute_ip (block, key, (unsigned char *) work); /* Initial Permutation */
+ left = KFromToBigEndian(work[0]);
+ right = KFromToBigEndian(work[1]);
+
+ /* Do the 16 rounds.
+ * The rounds are numbered from 0 to 15. On even rounds
+ * the right half is fed to f() and the result exclusive-ORs
+ * the left half; on odd rounds the reverse is done.
+ */
+ knp = &key->kn[0][0];
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+ knp += 8;
+ left ^= f (key, right, knp);
+ knp += 8;
+ right ^= f (key, left, knp);
+
+ /* Left/right half swap, plus byte swap if little-endian */
+ work[1] = KFromToBigEndian( left );
+ work[0] = KFromToBigEndian( right );
+
+ permute_fp ((unsigned char *) work, key, block); /* Inverse initial permutation */
+}
+
+/* Permute inblock with perm */
+static void
+permute_ip (unsigned char *inblock, DES_KEY * key, unsigned char *outblock)
+{
+ unsigned char *ib, *ob; /* ptr to input or output block */
+ char *p, *q;
+ int j;
+
+ /* Clear output block */
+ memset(outblock, 0, 8);
+
+ ib = inblock;
+ for (j = 0; j < 16; j += 2, ib++)
+ { /* for each input nibble */
+ ob = outblock;
+ p = key->iperm[j][(*ib >> 4) & 0xf];
+ q = key->iperm[j + 1][*ib & 0xf];
+ /* and each output byte, OR the masks together */
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ }
+}
+
+/* Permute inblock with perm */
+static void
+permute_fp (unsigned char *inblock, DES_KEY * key, unsigned char *outblock)
+{
+ unsigned char *ib, *ob; /* ptr to input or output block */
+ char *p, *q;
+ int j;
+
+ /* Clear output block */
+ memset(outblock, 0, 8);
+
+ ib = inblock;
+ for (j = 0; j < 16; j += 2, ib++)
+ { /* for each input nibble */
+ ob = outblock;
+ p = key->fperm[j][(*ib >> 4) & 0xf];
+ q = key->fperm[j + 1][*ib & 0xf];
+ /* and each output byte, OR the masks together */
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ *ob++ |= *p++ | *q++;
+ }
+}
+
+/* The nonlinear function f(r,k), the heart of DES */
+static Q_UINT32
+f (DES_KEY * key, Q_UINT32 r, char *subkey)
+{
+ Q_UINT32 *spp;
+ Q_UINT32 rval, rt;
+ int er;
+
+#ifdef TRACE
+ printf ("f(%08lx, %02x %02x %02x %02x %02x %02x %02x %02x) = ",
+ r,
+ subkey[0], subkey[1], subkey[2],
+ subkey[3], subkey[4], subkey[5], subkey[6], subkey[7]);
+#endif
+ /* Run E(R) ^ K through the combined S & P boxes.
+ * This code takes advantage of a convenient regularity in
+ * E, namely that each group of 6 bits in E(R) feeding
+ * a single S-box is a contiguous segment of R.
+ */
+ subkey += 7;
+
+ /* Compute E(R) for each block of 6 bits, and run thru boxes */
+ er = ((int) r << 1) | ((r & 0x80000000) ? 1 : 0);
+ spp = &key->sp[7][0];
+ rval = spp[(er ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt = (Q_UINT32) r >> 3;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rval |= spp[((int) rt ^ *subkey--) & 0x3f];
+ spp -= 64;
+ rt >>= 4;
+ rt |= (r & 1) << 5;
+ rval |= spp[((int) rt ^ *subkey) & 0x3f];
+#ifdef TRACE
+ printf (" %08lx\n", rval);
+#endif
+ return rval;
+}
+
+/* initialize a perm array */
+static void
+perminit_ip (DES_KEY * key)
+{
+ int l, j, k;
+ int i, m;
+
+ /* Clear the permutation array */
+ memset(key->iperm, 0, 16 * 16 * 8);
+
+ for (i = 0; i < 16; i++) /* each input nibble position */
+ for (j = 0; j < 16; j++) /* each possible input nibble */
+ for (k = 0; k < 64; k++)
+ { /* each output bit position */
+ l = ip[k] - 1; /* where does this bit come from */
+ if ((l >> 2) != i) /* does it come from input posn? */
+ continue; /* if not, bit k is 0 */
+ if (!(j & nibblebit[l & 3]))
+ continue; /* any such bit in input? */
+ m = k & 07; /* which bit is this in the byte */
+ key->iperm[i][j][k >> 3] |= bytebit[m];
+ }
+}
+
+static void
+perminit_fp (DES_KEY * key)
+{
+ int l, j, k;
+ int i, m;
+
+ /* Clear the permutation array */
+ memset(key->fperm, 0, 16 * 16 * 8);
+
+ for (i = 0; i < 16; i++) /* each input nibble position */
+ for (j = 0; j < 16; j++) /* each possible input nibble */
+ for (k = 0; k < 64; k++)
+ { /* each output bit position */
+ l = fp[k] - 1; /* where does this bit come from */
+ if ((l >> 2) != i) /* does it come from input posn? */
+ continue; /* if not, bit k is 0 */
+ if (!(j & nibblebit[l & 3]))
+ continue; /* any such bit in input? */
+ m = k & 07; /* which bit is this in the byte */
+ key->fperm[i][j][k >> 3] |= bytebit[m];
+ }
+}
+
+/* Initialize the lookup table for the combined S and P boxes */
+static void
+spinit (DES_KEY * key)
+{
+ char pbox[32];
+ int p, i, s, j, rowcol;
+ Q_UINT32 val;
+
+ /* Compute pbox, the inverse of p32i.
+ * This is easier to work with
+ */
+ for (p = 0; p < 32; p++)
+ {
+ for (i = 0; i < 32; i++)
+ {
+ if (p32i[i] - 1 == p)
+ {
+ pbox[p] = i;
+ break;
+ }
+ }
+ }
+ for (s = 0; s < 8; s++)
+ { /* For each S-box */
+ for (i = 0; i < 64; i++)
+ { /* For each possible input */
+ val = 0;
+ /* The row number is formed from the first and last
+ * bits; the column number is from the middle 4
+ */
+ rowcol = (i & 32) | ((i & 1) ? 16 : 0) | ((i >> 1) & 0xf);
+ for (j = 0; j < 4; j++)
+ { /* For each output bit */
+ if (si[s][rowcol] & (8 >> j))
+ {
+ val |= 1L << (31 - pbox[4 * s + j]);
+ }
+ }
+ key->sp[s][i] = val;
+ }
+ }
+}
+
+int
+ntlm_des_ecb_encrypt (const void *plaintext, int len, DES_KEY * akey,
+ unsigned char output[8])
+{
+ int j;
+ const unsigned char *plain = (const unsigned char *) plaintext;
+
+ for (j = 0; j < len / 8; j++)
+ {
+ memcpy (&output[j * 8], &plain[j * 8], 8);
+ ntlm_des_encrypt (akey, &output[j * 8]);
+ }
+
+ if (j == 0 && len != 0)
+ return -1; /* no blocks were encrypted */
+ return 0;
+}
diff --git a/kio/misc/kntlm/des.h b/kio/misc/kntlm/des.h
new file mode 100644
index 000000000..4125791b3
--- /dev/null
+++ b/kio/misc/kntlm/des.h
@@ -0,0 +1,19 @@
+#ifndef KNTLM_DES_H
+#define KNTLM_DES_H
+
+#include <qglobal.h>
+
+typedef struct des_key
+{
+ char kn[16][8];
+ Q_UINT32 sp[8][64];
+ char iperm[16][16][8];
+ char fperm[16][16][8];
+} DES_KEY;
+
+int
+ntlm_des_ecb_encrypt (const void *plaintext, int len, DES_KEY * akey, unsigned char output[8]);
+int
+ntlm_des_set_key (DES_KEY * dkey, char *user_key, int len);
+
+#endif /* KNTLM_DES_H */
diff --git a/kio/misc/kntlm/kntlm.cpp b/kio/misc/kntlm/kntlm.cpp
new file mode 100644
index 000000000..20c9f2a0c
--- /dev/null
+++ b/kio/misc/kntlm/kntlm.cpp
@@ -0,0 +1,389 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2004 Szombathelyi Gy�gy <gyurco@freemail.hu>
+
+ The implementation is based on the documentation and sample code
+ at http://davenport.sourceforge.net/ntlm.html
+ The DES encryption functions are from libntlm
+ at http://josefsson.org/libntlm/
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <string.h>
+
+#include <qdatetime.h>
+#include <kapplication.h>
+#include <kswap.h>
+#include <kmdcodec.h>
+#include <kdebug.h>
+
+#include "des.h"
+#include "kntlm.h"
+
+QString KNTLM::getString( const QByteArray &buf, const SecBuf &secbuf, bool unicode )
+{
+ //watch for buffer overflows
+ Q_UINT32 offset;
+ Q_UINT16 len;
+ offset = KFromToLittleEndian((Q_UINT32)secbuf.offset);
+ len = KFromToLittleEndian(secbuf.len);
+ if ( offset > buf.size() ||
+ offset + len > buf.size() ) return QString::null;
+
+ QString str;
+ const char *c = buf.data() + offset;
+
+ if ( unicode ) {
+ str = UnicodeLE2QString( (QChar*) c, len >> 1 );
+ } else {
+ str = QString::fromLatin1( c, len );
+ }
+ return str;
+}
+
+QByteArray KNTLM::getBuf( const QByteArray &buf, const SecBuf &secbuf )
+{
+ QByteArray ret;
+ Q_UINT32 offset;
+ Q_UINT16 len;
+ offset = KFromToLittleEndian((Q_UINT32)secbuf.offset);
+ len = KFromToLittleEndian(secbuf.len);
+ //watch for buffer overflows
+ if ( offset > buf.size() ||
+ offset + len > buf.size() ) return ret;
+ ret.duplicate( buf.data() + offset, buf.size() );
+ return ret;
+}
+
+void KNTLM::addString( QByteArray &buf, SecBuf &secbuf, const QString &str, bool unicode )
+{
+ QByteArray tmp;
+
+ if ( unicode ) {
+ tmp = QString2UnicodeLE( str );
+ addBuf( buf, secbuf, tmp );
+ } else {
+ const char *c;
+ c = str.latin1();
+ tmp.setRawData( c, str.length() );
+ addBuf( buf, secbuf, tmp );
+ tmp.resetRawData( c, str.length() );
+ }
+}
+
+void KNTLM::addBuf( QByteArray &buf, SecBuf &secbuf, QByteArray &data )
+{
+ Q_UINT32 offset;
+ Q_UINT16 len, maxlen;
+ offset = (buf.size() + 1) & 0xfffffffe;
+ len = data.size();
+ maxlen = data.size();
+
+ secbuf.offset = KFromToLittleEndian((Q_UINT32)offset);
+ secbuf.len = KFromToLittleEndian(len);
+ secbuf.maxlen = KFromToLittleEndian(maxlen);
+ buf.resize( offset + len );
+ memcpy( buf.data() + offset, data.data(), data.size() );
+}
+
+bool KNTLM::getNegotiate( QByteArray &negotiate, const QString &domain, const QString &workstation, Q_UINT32 flags )
+{
+ QByteArray rbuf( sizeof(Negotiate) );
+
+ rbuf.fill( 0 );
+ memcpy( rbuf.data(), "NTLMSSP", 8 );
+ ((Negotiate*) rbuf.data())->msgType = KFromToLittleEndian( (Q_UINT32)1 );
+ if ( !domain.isEmpty() ) {
+ flags |= Negotiate_Domain_Supplied;
+ addString( rbuf, ((Negotiate*) rbuf.data())->domain, domain );
+ }
+ if ( !workstation.isEmpty() ) {
+ flags |= Negotiate_WS_Supplied;
+ addString( rbuf, ((Negotiate*) rbuf.data())->domain, workstation );
+ }
+ ((Negotiate*) rbuf.data())->flags = KFromToLittleEndian( flags );
+ negotiate = rbuf;
+ return true;
+}
+
+bool KNTLM::getAuth( QByteArray &auth, const QByteArray &challenge, const QString &user,
+ const QString &password, const QString &domain, const QString &workstation,
+ bool forceNTLM, bool forceNTLMv2 )
+{
+ QByteArray rbuf( sizeof(Auth) );
+ Challenge *ch = (Challenge *) challenge.data();
+ QByteArray response;
+ uint chsize = challenge.size();
+ bool unicode = false;
+ QString dom;
+
+ //challenge structure too small
+ if ( chsize < 32 ) return false;
+
+ unicode = KFromToLittleEndian(ch->flags) & Negotiate_Unicode;
+ if ( domain.isEmpty() )
+ dom = getString( challenge, ch->targetName, unicode );
+ else
+ dom = domain;
+
+ rbuf.fill( 0 );
+ memcpy( rbuf.data(), "NTLMSSP", 8 );
+ ((Auth*) rbuf.data())->msgType = KFromToLittleEndian( (Q_UINT32)3 );
+ ((Auth*) rbuf.data())->flags = ch->flags;
+ QByteArray targetInfo = getBuf( challenge, ch->targetInfo );
+
+// if ( forceNTLMv2 || (!targetInfo.isEmpty() && (KFromToLittleEndian(ch->flags) & Negotiate_Target_Info)) /* may support NTLMv2 */ ) {
+// if ( KFromToLittleEndian(ch->flags) & Negotiate_NTLM ) {
+// if ( targetInfo.isEmpty() ) return false;
+// response = getNTLMv2Response( dom, user, password, targetInfo, ch->challengeData );
+// addBuf( rbuf, ((Auth*) rbuf.data())->ntResponse, response );
+// } else {
+// if ( !forceNTLM ) {
+// response = getLMv2Response( dom, user, password, ch->challengeData );
+// addBuf( rbuf, ((Auth*) rbuf.data())->lmResponse, response );
+// } else
+// return false;
+// }
+// } else { //if no targetinfo structure and NTLMv2 or LMv2 not forced, try the older methods
+
+ response = getNTLMResponse( password, ch->challengeData );
+ addBuf( rbuf, ((Auth*) rbuf.data())->ntResponse, response );
+ response = getLMResponse( password, ch->challengeData );
+ addBuf( rbuf, ((Auth*) rbuf.data())->lmResponse, response );
+// }
+ if ( !dom.isEmpty() )
+ addString( rbuf, ((Auth*) rbuf.data())->domain, dom, unicode );
+ addString( rbuf, ((Auth*) rbuf.data())->user, user, unicode );
+ if ( !workstation.isEmpty() )
+ addString( rbuf, ((Auth*) rbuf.data())->workstation, workstation, unicode );
+
+ auth = rbuf;
+
+ return true;
+}
+
+QByteArray KNTLM::getLMResponse( const QString &password, const unsigned char *challenge )
+{
+ QByteArray hash, answer;
+
+ hash = lmHash( password );
+ hash.resize( 21 );
+ memset( hash.data() + 16, 0, 5 );
+ answer = lmResponse( hash, challenge );
+ hash.fill( 0 );
+ return answer;
+}
+
+QByteArray KNTLM::lmHash( const QString &password )
+{
+ QByteArray keyBytes( 14 );
+ QByteArray hash( 16 );
+ DES_KEY ks;
+ const char *magic = "KGS!@#$%";
+
+ keyBytes.fill( 0 );
+ strncpy( keyBytes.data(), password.upper().latin1(), 14 );
+
+ convertKey( (unsigned char*) keyBytes.data(), &ks );
+ ntlm_des_ecb_encrypt( magic, 8, &ks, (unsigned char*) hash.data() );
+
+ convertKey( (unsigned char*) keyBytes.data() + 7, &ks );
+ ntlm_des_ecb_encrypt( magic, 8, &ks, (unsigned char*) hash.data() + 8 );
+
+ keyBytes.fill( 0 );
+ memset( &ks, 0, sizeof (ks) );
+
+ return hash;
+}
+
+QByteArray KNTLM::lmResponse( const QByteArray &hash, const unsigned char *challenge )
+{
+ DES_KEY ks;
+ QByteArray answer( 24 );
+
+ convertKey( (unsigned char*) hash.data(), &ks );
+ ntlm_des_ecb_encrypt( challenge, 8, &ks, (unsigned char*) answer.data() );
+
+ convertKey( (unsigned char*) hash.data() + 7, &ks );
+ ntlm_des_ecb_encrypt( challenge, 8, &ks, (unsigned char*) answer.data() + 8 );
+
+ convertKey( (unsigned char*) hash.data() + 14, &ks );
+ ntlm_des_ecb_encrypt( challenge, 8, &ks, (unsigned char*) answer.data() + 16 );
+
+ memset( &ks, 0, sizeof (ks) );
+ return answer;
+}
+
+QByteArray KNTLM::getNTLMResponse( const QString &password, const unsigned char *challenge )
+{
+ QByteArray hash, answer;
+
+ hash = ntlmHash( password );
+ hash.resize( 21 );
+ memset( hash.data() + 16, 0, 5 );
+ answer = lmResponse( hash, challenge );
+ hash.fill( 0 );
+ return answer;
+}
+
+QByteArray KNTLM::ntlmHash( const QString &password )
+{
+ KMD4::Digest digest;
+ QByteArray ret, unicode;
+ unicode = QString2UnicodeLE( password );
+
+ KMD4 md4( unicode );
+ md4.rawDigest( digest );
+ ret.duplicate( (const char*) digest, sizeof( digest ) );
+ return ret;
+}
+
+QByteArray KNTLM::getNTLMv2Response( const QString &target, const QString &user,
+ const QString &password, const QByteArray &targetInformation,
+ const unsigned char *challenge )
+{
+ QByteArray hash = ntlmv2Hash( target, user, password );
+ QByteArray blob = createBlob( targetInformation );
+ return lmv2Response( hash, blob, challenge );
+}
+
+QByteArray KNTLM::getLMv2Response( const QString &target, const QString &user,
+ const QString &password, const unsigned char *challenge )
+{
+ QByteArray hash = ntlmv2Hash( target, user, password );
+ QByteArray clientChallenge( 8 );
+ for ( uint i = 0; i<8; i++ ) {
+ clientChallenge.data()[i] = KApplication::random() % 0xff;
+ }
+ return lmv2Response( hash, clientChallenge, challenge );
+}
+
+QByteArray KNTLM::ntlmv2Hash( const QString &target, const QString &user, const QString &password )
+{
+ QByteArray hash1 = ntlmHash( password );
+ QByteArray key, ret;
+ QString id = user.upper() + target.upper();
+ key = QString2UnicodeLE( id );
+ ret = hmacMD5( key, hash1 );
+ return ret;
+}
+
+QByteArray KNTLM::lmv2Response( const QByteArray &hash,
+ const QByteArray &clientData, const unsigned char *challenge )
+{
+ QByteArray data( 8 + clientData.size() );
+ memcpy( data.data(), challenge, 8 );
+ memcpy( data.data() + 8, clientData.data(), clientData.size() );
+ QByteArray mac = hmacMD5( data, hash );
+ mac.resize( 16 + clientData.size() );
+ memcpy( mac.data() + 16, clientData.data(), clientData.size() );
+ return mac;
+}
+
+QByteArray KNTLM::createBlob( const QByteArray &targetinfo )
+{
+ QByteArray blob( sizeof(Blob) + 4 + targetinfo.size() );
+ blob.fill( 0 );
+
+ Blob *bl = (Blob *) blob.data();
+ bl->signature = KFromToBigEndian( (Q_UINT32) 0x01010000 );
+ Q_UINT64 now = QDateTime::currentDateTime().toTime_t();
+ now += (Q_UINT64)3600*(Q_UINT64)24*(Q_UINT64)134774;
+ now *= (Q_UINT64)10000000;
+ bl->timestamp = KFromToLittleEndian( now );
+ for ( uint i = 0; i<8; i++ ) {
+ bl->challenge[i] = KApplication::random() % 0xff;
+ }
+ memcpy( blob.data() + sizeof(Blob), targetinfo.data(), targetinfo.size() );
+ return blob;
+}
+
+QByteArray KNTLM::hmacMD5( const QByteArray &data, const QByteArray &key )
+{
+ Q_UINT8 ipad[64], opad[64];
+ KMD5::Digest digest;
+ QByteArray ret;
+
+ memset( ipad, 0x36, sizeof(ipad) );
+ memset( opad, 0x5c, sizeof(opad) );
+ for ( int i = key.size()-1; i >= 0; i-- ) {
+ ipad[i] ^= key[i];
+ opad[i] ^= key[i];
+ }
+
+ QByteArray content( data.size()+64 );
+ memcpy( content.data(), ipad, 64 );
+ memcpy( content.data() + 64, data.data(), data.size() );
+ KMD5 md5( content );
+ md5.rawDigest( digest );
+ content.resize( sizeof(digest) + 64 );
+ memcpy( content.data(), opad, 64 );
+ memcpy( content.data() + 64, digest, sizeof(digest) );
+ md5.reset();
+ md5.update( content );
+ md5.rawDigest( digest );
+
+ ret.duplicate( (const char*) digest, sizeof( digest ) );
+ return ret;
+}
+
+/*
+* turns a 56 bit key into the 64 bit, odd parity key and sets the key.
+* The key schedule ks is also set.
+*/
+void KNTLM::convertKey( unsigned char *key_56, void* ks )
+{
+ unsigned char key[8];
+
+ key[0] = key_56[0];
+ key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
+ key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
+ key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
+ key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
+ key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
+ key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
+ key[7] = (key_56[6] << 1) & 0xFF;
+
+ for ( uint i=0; i<8; i++ ) {
+ unsigned char b = key[i];
+ bool needsParity = (((b>>7) ^ (b>>6) ^ (b>>5) ^ (b>>4) ^ (b>>3) ^ (b>>2) ^ (b>>1)) & 0x01) == 0;
+ if ( needsParity )
+ key[i] |= 0x01;
+ else
+ key[i] &= 0xfe;
+ }
+
+ ntlm_des_set_key ( (DES_KEY*) ks, (char*) &key, sizeof (key));
+
+ memset (&key, 0, sizeof (key));
+}
+
+QByteArray KNTLM::QString2UnicodeLE( const QString &target )
+{
+ QByteArray unicode( target.length() * 2 );
+ for ( uint i = 0; i < target.length(); i++ ) {
+ ((Q_UINT16*)unicode.data())[ i ] = KFromToLittleEndian( target[i].unicode() );
+ }
+ return unicode;
+}
+
+QString KNTLM::UnicodeLE2QString( const QChar* data, uint len )
+{
+ QString ret;
+ for ( uint i = 0; i < len; i++ ) {
+ ret += KFromToLittleEndian( data[ i ].unicode() );
+ }
+ return ret;
+}
diff --git a/kio/misc/kntlm/kntlm.h b/kio/misc/kntlm/kntlm.h
new file mode 100644
index 000000000..6dbb62139
--- /dev/null
+++ b/kio/misc/kntlm/kntlm.h
@@ -0,0 +1,233 @@
+/*
+ This file is part of the KDE libraries.
+ Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KNTLM_H
+#define KNTLM_H
+
+#include <qglobal.h>
+#include <qcstring.h>
+#include <qstring.h>
+
+#include <kdelibs_export.h>
+
+/**
+ * @short KNTLM class implements the NTLM authentication protocol.
+ *
+ * The KNTLM class is useful for creating the authentication structures which
+ * can be used for various servers which implements NTLM type authentication.
+ * A comprehensive description of the NTLM authentication protocol can be found
+ * at http://davenport.sourceforge.net/ntlm.html
+ * The class also contains methods to create the LanManager and NT (MD4) hashes
+ * of a password.
+ * This class doesn't maintain any state information, so all methods are static.
+ */
+
+class KIO_EXPORT KNTLM {
+public:
+
+ enum Flags {
+ Negotiate_Unicode = 0x00000001,
+ Negotiate_OEM = 0x00000002,
+ Request_Target = 0x00000004,
+ Negotiate_Sign = 0x00000010,
+ Negotiate_Seal = 0x00000020,
+ Negotiate_Datagram_Style = 0x00000040,
+ Negotiate_LM_Key = 0x00000080,
+ Negotiate_Netware = 0x00000100,
+ Negotiate_NTLM = 0x00000200,
+ Negotiate_Domain_Supplied = 0x00001000,
+ Negotiate_WS_Supplied = 0x00002000,
+ Negotiate_Local_Call = 0x00004000,
+ Negotiate_Always_Sign = 0x00008000,
+ Target_Type_Domain = 0x00010000,
+ Target_Type_Server = 0x00020000,
+ Target_Type_Share = 0x00040000,
+ Negotiate_NTLM2_Key = 0x00080000,
+ Request_Init_Response = 0x00100000,
+ Request_Accept_Response = 0x00200000,
+ Request_NonNT_Key = 0x00400000,
+ Negotiate_Target_Info = 0x00800000,
+ Negotiate_128 = 0x20000000,
+ Negotiate_Key_Exchange = 0x40000000,
+ Negotiate_56 = 0x80000000
+ };
+
+ typedef struct
+ {
+ Q_UINT16 len;
+ Q_UINT16 maxlen;
+ Q_UINT32 offset;
+ } SecBuf;
+
+ /**
+ * The NTLM Type 1 structure
+ */
+ typedef struct
+ {
+ char signature[8]; /* "NTLMSSP\0" */
+ Q_UINT32 msgType; /* 1 */
+ Q_UINT32 flags;
+ SecBuf domain;
+ SecBuf workstation;
+ } Negotiate;
+
+ /**
+ * The NTLM Type 2 structure
+ */
+ typedef struct
+ {
+ char signature[8];
+ Q_UINT32 msgType; /* 2 */
+ SecBuf targetName;
+ Q_UINT32 flags;
+ Q_UINT8 challengeData[8];
+ Q_UINT32 context[2];
+ SecBuf targetInfo;
+ } Challenge;
+
+ /**
+ * The NTLM Type 3 structure
+ */
+ typedef struct
+ {
+ char signature[8];
+ Q_UINT32 msgType; /* 3 */
+ SecBuf lmResponse;
+ SecBuf ntResponse;
+ SecBuf domain;
+ SecBuf user;
+ SecBuf workstation;
+ SecBuf sessionKey;
+ Q_UINT32 flags;
+ } Auth;
+
+ typedef struct
+ {
+ Q_UINT32 signature;
+ Q_UINT32 reserved;
+ Q_UINT64 timestamp;
+ Q_UINT8 challenge[8];
+ Q_UINT8 unknown[4];
+ //Target info block - variable length
+ } Blob;
+
+ /**
+ * Creates the initial message (type 1) which should be sent to the server.
+ *
+ * @param negotiate - a buffer where the Type 1 message will returned.
+ * @param domain - the domain name which should be send with the message.
+ * @param workstation - the workstation name which should be send with the message.
+ * @param flags - various flags, in most cases the defaults will good.
+ *
+ * @return true if creating the structure succeeds, false otherwise.
+ */
+ static bool getNegotiate( QByteArray &negotiate, const QString &domain = QString::null,
+ const QString &workstation = QString::null,
+ Q_UINT32 flags = Negotiate_Unicode | Request_Target | Negotiate_NTLM );
+ /**
+ * Creates the type 3 message which should be sent to the server after
+ * the challenge (type 2) received.
+ *
+ * @param auth - a buffer where the Type 3 message will returned.
+ * @param challenge - the Type 2 message returned by the server.
+ * @param user - user's name.
+ * @param password - user's password.
+ * @param domain - the target domain. If left empty, it will be extracted
+ * from the challenge.
+ * @param workstation - the user's workstation.
+ * @param forceNTLM - force the use of NTLM authentication (either v1 or v2).
+ * @param forceNTLMv2 - force the use of NTLMv2 or LMv2 authentication. If false, NTLMv2
+ * support is autodetected from the challenge.
+ *
+ * @return true if auth filled with the Type 3 message, false if an error occured
+ * (challenge data invalid, or NTLM authentication forced, but the challenge data says
+ * no NTLM supported).
+ */
+ static bool getAuth( QByteArray &auth, const QByteArray &challenge, const QString &user,
+ const QString &password, const QString &domain = QString::null,
+ const QString &workstation = QString::null, bool forceNTLM = false, bool forceNTLMv2 = false );
+
+ /**
+ * Returns the LanManager response from the password and the server challenge.
+ */
+ static QByteArray getLMResponse( const QString &password, const unsigned char *challenge );
+ /**
+ * Calculates the LanManager hash of the specified password.
+ */
+ static QByteArray lmHash( const QString &password );
+ /**
+ * Calculates the LanManager response from the LanManager hash and the server challenge.
+ */
+ static QByteArray lmResponse( const QByteArray &hash, const unsigned char *challenge );
+
+ /**
+ * Returns the NTLM response from the password and the server challenge.
+ */
+ static QByteArray getNTLMResponse( const QString &password, const unsigned char *challenge );
+ /**
+ * Returns the NTLM hash (MD4) from the password.
+ */
+ static QByteArray ntlmHash( const QString &password );
+
+ /**
+ * Calculates the NTLMv2 response.
+ */
+ static QByteArray getNTLMv2Response( const QString &target, const QString &user,
+ const QString &password, const QByteArray &targetInformation,
+ const unsigned char *challenge );
+
+ /**
+ * Calculates the LMv2 response.
+ */
+ static QByteArray getLMv2Response( const QString &target, const QString &user,
+ const QString &password, const unsigned char *challenge );
+
+ /**
+ * Returns the NTLMv2 hash.
+ */
+ static QByteArray ntlmv2Hash( const QString &target, const QString &user, const QString &password );
+
+ /**
+ * Calculates the LMv2 response.
+ */
+ static QByteArray lmv2Response( const QByteArray &hash,
+ const QByteArray &clientData, const unsigned char *challenge );
+
+ /**
+ * Extracts a string field from an NTLM structure.
+ */
+ static QString getString( const QByteArray &buf, const SecBuf &secbuf, bool unicode );
+ /**
+ * Extracts a byte array from an NTLM structure.
+ */
+ static QByteArray getBuf( const QByteArray &buf, const SecBuf &secbuf );
+
+ static QByteArray createBlob( const QByteArray &targetinfo );
+
+ static QByteArray hmacMD5( const QByteArray &data, const QByteArray &key );
+private:
+ static QByteArray QString2UnicodeLE( const QString &target );
+ static QString UnicodeLE2QString( const QChar* data, uint len );
+
+ static void addBuf( QByteArray &buf, SecBuf &secbuf, QByteArray &data );
+ static void addString( QByteArray &buf, SecBuf &secbuf, const QString &str, bool unicode = false );
+ static void convertKey( unsigned char *key_56, void* ks );
+};
+
+#endif /* KNTLM_H */
diff --git a/kio/misc/kntlm/kswap.h b/kio/misc/kntlm/kswap.h
new file mode 100644
index 000000000..e9db968ed
--- /dev/null
+++ b/kio/misc/kntlm/kswap.h
@@ -0,0 +1,428 @@
+/*
+ This file is part of the KDE libraries.
+ Copyright (c) 2004 Szombathelyi György <gyurco@freemail.hu>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSWAP_H
+#define KSWAP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qglobal.h>
+
+/**
+ * \defgroup KSWAP Byte-swapping functions
+ * kswap.h contains functions that will help converting
+ * 16, 32 and 64 bit length data between little-endian and
+ * big-endian representations.
+ *
+ * The KSWAP_16, KSWAP_32 and KSWAP_64 functions are always
+ * swaps the byte order of the supplied argument (which should be
+ * 16, 32 or 64 bit wide). These functions are inline, and tries to
+ * use the most optimized function of the underlying system
+ * (bswap_xx functions from byteswap.h in GLIBC, or ntohs and ntohl
+ * on little-endian machines, and if neither are applicable, some fast
+ * custom code).
+ *
+ * The KFromTo{Little|Big}Endian functions are for converting big-endian and
+ * little-endian data to and from the machine endianness.
+ */
+
+#ifdef HAVE_BYTESWAP_H
+#include <byteswap.h>
+
+ inline Q_UINT16 KSWAP_16( Q_UINT16 b ) { return bswap_16( b ); }
+ inline Q_INT16 KSWAP_16( Q_INT16 b ) { return bswap_16( (Q_UINT16)b ); }
+ inline Q_UINT32 KSWAP_32( Q_UINT32 b ) { return bswap_32( b ); }
+ inline Q_INT32 KSWAP_32( Q_INT32 b ) { return bswap_32( (Q_UINT32)b ); }
+ inline Q_UINT64 KSWAP_64( Q_UINT64 b ) { return bswap_64( b ); }
+ inline Q_INT64 KSWAP_64( Q_INT64 b ) { return bswap_64( (Q_UINT64)b ); }
+
+#else /* HAVE_BYTESWAP_H */
+#ifdef WORDS_BIGENDIAN
+ inline Q_UINT16 KSWAP_16( Q_UINT16 b )
+ {
+ return (((b) & 0x00ff) << 8 | ((b) & 0xff00) >> 8);
+ }
+
+ inline Q_INT16 KSWAP_16( Q_INT16 b )
+ {
+ return ((((Q_UINT16)b) & 0x00ff) << 8 | (((Q_UINT16)b) & 0xff00) >> 8);
+ }
+
+ inline Q_UINT32 KSWAP_32( Q_UINT32 b )
+ {
+ return
+ ((((b) & 0xff000000) >> 24) | (((b) & 0x00ff0000) >> 8) | \
+ (((b) & 0x0000ff00) << 8) | (((b) & 0x000000ff) << 24));
+ }
+
+ inline Q_INT32 KSWAP_32( Q_INT32 b )
+ {
+ return
+ (((((Q_UINT32)b) & 0xff000000) >> 24) | ((((Q_UINT32)b) & 0x00ff0000) >> 8) | \
+ ((((Q_UINT32)b) & 0x0000ff00) << 8) | ((((Q_UINT32)b) & 0x000000ff) << 24));
+ }
+#else /* WORDS_BIGENDIAN */
+#include <sys/types.h>
+#include <netinet/in.h>
+
+ inline Q_UINT16 KSWAP_16( Q_UINT16 b ) { return htons(b); }
+ inline Q_INT16 KSWAP_16( Q_INT16 b ) { return htons((Q_UINT16)b); }
+ inline Q_UINT32 KSWAP_32( Q_UINT32 b ) { return htonl(b); }
+ inline Q_INT32 KSWAP_32( Q_INT32 b ) { return htonl((Q_UINT32)b); }
+#endif
+ inline Q_UINT64 KSWAP_64( Q_UINT64 b )
+ {
+ union {
+ Q_UINT64 ll;
+ Q_UINT32 l[2];
+ } w, r;
+ w.ll = b;
+ r.l[0] = KSWAP_32( w.l[1] );
+ r.l[1] = KSWAP_32( w.l[0] );
+ return r.ll;
+ }
+
+ inline Q_INT64 KSWAP_64( Q_INT64 b )
+ {
+ union {
+ Q_UINT64 ll;
+ Q_UINT32 l[2];
+ } w, r;
+ w.ll = (Q_UINT64) b;
+ r.l[0] = KSWAP_32( w.l[1] );
+ r.l[1] = KSWAP_32( w.l[0] );
+ return r.ll;
+ }
+#endif /* !HAVE_BYTESWAP_H */
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit unsigned value from/to big-endian byte order to/from the machine order.
+ */
+inline Q_UINT16 KFromToBigEndian( Q_UINT16 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_16(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit unsigned array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( Q_UINT16 *out, Q_UINT16 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<1 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_16( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit unsigned value from/to big-endian byte order to/from the machine order.
+ */
+inline Q_UINT32 KFromToBigEndian( Q_UINT32 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_32(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit unsigned array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( Q_UINT32 *out, Q_UINT32 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<2 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_32( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit unsigned value from/to big-endian byte order to/from the machine order.
+ */
+inline Q_UINT64 KFromToBigEndian( Q_UINT64 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_64(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit unsigned array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( Q_UINT64 *out, Q_UINT64 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<3 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_64( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit signed value from/to big-endian byte order to/from the machine order.
+ */
+inline Q_INT16 KFromToBigEndian( Q_INT16 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_16(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit signed array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( Q_INT16 *out, Q_INT16 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<1 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_16( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit signed value from/to big-endian byte order to/from the machine order.
+ */
+inline Q_INT32 KFromToBigEndian( Q_INT32 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_32(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit signed array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( Q_INT32 *out, Q_INT32 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<2 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_32( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit signed value from/to big-endian byte order to/from the machine order.
+ */
+inline Q_INT64 KFromToBigEndian( Q_INT64 b )
+{
+#ifdef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_64(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit signed array from/to big-endian byte order to/from the machine order.
+ */
+inline void KFromToBigEndian( Q_INT64 *out, Q_INT64 *in, uint len )
+{
+#ifdef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<3 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_64( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit unsigned value from/to little-endian byte order to/from the machine order.
+ */
+inline Q_UINT16 KFromToLittleEndian( Q_UINT16 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_16(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit unsigned array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( Q_UINT16 *out, Q_UINT16 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<1 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_16( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit unsigned value from/to little-endian byte order to/from the machine order.
+ */
+inline Q_UINT32 KFromToLittleEndian( Q_UINT32 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_32(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit unsigned array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( Q_UINT32 *out, Q_UINT32 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<2 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_32( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit unsigned value from/to little-endian byte order to/from the machine order.
+ */
+inline Q_UINT64 KFromToLittleEndian( Q_UINT64 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_64(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit unsigned array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( Q_UINT64 *out, Q_UINT64 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<3 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_64( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit signed value from/to little-endian byte order to/from the machine order.
+ */
+inline Q_INT16 KFromToLittleEndian( Q_INT16 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_16(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 16 bit signed array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( Q_INT16 *out, Q_INT16 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<1 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_16( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit signed value from/to little-endian byte order to/from the machine order.
+ */
+inline Q_INT32 KFromToLittleEndian( Q_INT32 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_32(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 32 bit signed array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( Q_INT32 *out, Q_INT32 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<2 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_32( *in ); out++; in++; len--; }
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit signed value from/to little-endian byte order to/from the machine order.
+ */
+inline Q_INT64 KFromToLittleEndian( Q_INT64 b )
+{
+#ifndef WORDS_BIGENDIAN
+ return b;
+#else
+ return KSWAP_64(b);
+#endif
+}
+
+/**
+ * \ingroup KSWAP
+ * Converts a 64 bit signed array from/to little-endian byte order to/from the machine order.
+ */
+inline void KFromToLittleEndian( Q_INT64 *out, Q_INT64 *in, uint len )
+{
+#ifndef WORDS_BIGENDIAN
+ if ( out != in ) memcpy( out, in, len<<3 ) ;
+#else
+ while ( len>0 ) { *out = KSWAP_64( *in ); out++; in++; len--; }
+#endif
+}
+
+#endif /* KSWAP_H */