diff options
Diffstat (limited to 'tdeio/misc/tdentlm')
-rw-r--r-- | tdeio/misc/tdentlm/CMakeLists.txt | 43 | ||||
-rw-r--r-- | tdeio/misc/tdentlm/Makefile.am | 12 | ||||
-rw-r--r-- | tdeio/misc/tdentlm/des.cpp | 513 | ||||
-rw-r--r-- | tdeio/misc/tdentlm/des.h | 19 | ||||
-rw-r--r-- | tdeio/misc/tdentlm/kswap.h | 428 | ||||
-rw-r--r-- | tdeio/misc/tdentlm/tdentlm.cpp | 389 | ||||
-rw-r--r-- | tdeio/misc/tdentlm/tdentlm.h | 233 |
7 files changed, 1637 insertions, 0 deletions
diff --git a/tdeio/misc/tdentlm/CMakeLists.txt b/tdeio/misc/tdentlm/CMakeLists.txt new file mode 100644 index 000000000..dc26da9a1 --- /dev/null +++ b/tdeio/misc/tdentlm/CMakeLists.txt @@ -0,0 +1,43 @@ +################################################# +# +# (C) 2010 Serghei Amelian +# serghei (DOT) amelian (AT) gmail.com +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + +include_directories( + ${TQT_INCLUDE_DIRS} + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}/tdecore + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/tdecore +) + +link_directories( + ${TQT_LIBRARY_DIRS} +) + + +##### headers ################################### + +install(FILES tdentlm.h DESTINATION ${INCLUDE_INSTALL_DIR}/tdeio ) + + +##### tdentlm ################################### + +set( target tdentlm ) + +set( ${target}_SRCS + tdentlm.cpp des.cpp +) + +tde_add_library( ${target} SHARED + SOURCES ${${target}_SRCS} + VERSION 0.0.0 + LINK tdecore-shared + DESTINATION ${LIB_INSTALL_DIR} +) diff --git a/tdeio/misc/tdentlm/Makefile.am b/tdeio/misc/tdentlm/Makefile.am new file mode 100644 index 000000000..16164dbe3 --- /dev/null +++ b/tdeio/misc/tdentlm/Makefile.am @@ -0,0 +1,12 @@ +INCLUDES=$(all_includes) + +lib_LTLIBRARIES = libtdentlm.la +METASOURCES = AUTO + +tdentlmincludedir = $(includedir)/tdeio +tdentlminclude_HEADERS = tdentlm.h + +libtdentlm_la_SOURCES = tdentlm.cpp des.cpp +libtdentlm_la_LDFLAGS = $(all_libraries) -version-info 0:0:0 -no-undefined +libtdentlm_la_LIBADD = $(LIB_TDECORE) $(LIB_QT) + diff --git a/tdeio/misc/tdentlm/des.cpp b/tdeio/misc/tdentlm/des.cpp new file mode 100644 index 000000000..bb4fab88b --- /dev/null +++ b/tdeio/misc/tdentlm/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 TQ_UINT32 f (DES_KEY * key, TQ_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) +{ + TQ_UINT32 left, right; + char *knp; + TQ_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 TQ_UINT32 +f (DES_KEY * key, TQ_UINT32 r, char *subkey) +{ + TQ_UINT32 *spp; + TQ_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 = (TQ_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; + TQ_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/tdeio/misc/tdentlm/des.h b/tdeio/misc/tdentlm/des.h new file mode 100644 index 000000000..0f6f59dc9 --- /dev/null +++ b/tdeio/misc/tdentlm/des.h @@ -0,0 +1,19 @@ +#ifndef KNTLM_DES_H +#define KNTLM_DES_H + +#include <tqglobal.h> + +typedef struct des_key +{ + char kn[16][8]; + TQ_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/tdeio/misc/tdentlm/kswap.h b/tdeio/misc/tdentlm/kswap.h new file mode 100644 index 000000000..9eca243de --- /dev/null +++ b/tdeio/misc/tdentlm/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 <tqglobal.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 TQ_UINT16 KSWAP_16( TQ_UINT16 b ) { return bswap_16( b ); } + inline TQ_INT16 KSWAP_16( TQ_INT16 b ) { return bswap_16( (TQ_UINT16)b ); } + inline TQ_UINT32 KSWAP_32( TQ_UINT32 b ) { return bswap_32( b ); } + inline TQ_INT32 KSWAP_32( TQ_INT32 b ) { return bswap_32( (TQ_UINT32)b ); } + inline TQ_UINT64 KSWAP_64( TQ_UINT64 b ) { return bswap_64( b ); } + inline TQ_INT64 KSWAP_64( TQ_INT64 b ) { return bswap_64( (TQ_UINT64)b ); } + +#else /* HAVE_BYTESWAP_H */ +#ifdef WORDS_BIGENDIAN + inline TQ_UINT16 KSWAP_16( TQ_UINT16 b ) + { + return (((b) & 0x00ff) << 8 | ((b) & 0xff00) >> 8); + } + + inline TQ_INT16 KSWAP_16( TQ_INT16 b ) + { + return ((((TQ_UINT16)b) & 0x00ff) << 8 | (((TQ_UINT16)b) & 0xff00) >> 8); + } + + inline TQ_UINT32 KSWAP_32( TQ_UINT32 b ) + { + return + ((((b) & 0xff000000) >> 24) | (((b) & 0x00ff0000) >> 8) | \ + (((b) & 0x0000ff00) << 8) | (((b) & 0x000000ff) << 24)); + } + + inline TQ_INT32 KSWAP_32( TQ_INT32 b ) + { + return + (((((TQ_UINT32)b) & 0xff000000) >> 24) | ((((TQ_UINT32)b) & 0x00ff0000) >> 8) | \ + ((((TQ_UINT32)b) & 0x0000ff00) << 8) | ((((TQ_UINT32)b) & 0x000000ff) << 24)); + } +#else /* WORDS_BIGENDIAN */ +#include <sys/types.h> +#include <netinet/in.h> + + inline TQ_UINT16 KSWAP_16( TQ_UINT16 b ) { return htons(b); } + inline TQ_INT16 KSWAP_16( TQ_INT16 b ) { return htons((TQ_UINT16)b); } + inline TQ_UINT32 KSWAP_32( TQ_UINT32 b ) { return htonl(b); } + inline TQ_INT32 KSWAP_32( TQ_INT32 b ) { return htonl((TQ_UINT32)b); } +#endif + inline TQ_UINT64 KSWAP_64( TQ_UINT64 b ) + { + union { + TQ_UINT64 ll; + TQ_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 TQ_INT64 KSWAP_64( TQ_INT64 b ) + { + union { + TQ_UINT64 ll; + TQ_UINT32 l[2]; + } w, r; + w.ll = (TQ_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 TQ_UINT16 KFromToBigEndian( TQ_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( TQ_UINT16 *out, TQ_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 TQ_UINT32 KFromToBigEndian( TQ_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( TQ_UINT32 *out, TQ_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 TQ_UINT64 KFromToBigEndian( TQ_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( TQ_UINT64 *out, TQ_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 TQ_INT16 KFromToBigEndian( TQ_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( TQ_INT16 *out, TQ_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 TQ_INT32 KFromToBigEndian( TQ_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( TQ_INT32 *out, TQ_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 TQ_INT64 KFromToBigEndian( TQ_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( TQ_INT64 *out, TQ_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 TQ_UINT16 KFromToLittleEndian( TQ_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( TQ_UINT16 *out, TQ_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 TQ_UINT32 KFromToLittleEndian( TQ_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( TQ_UINT32 *out, TQ_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 TQ_UINT64 KFromToLittleEndian( TQ_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( TQ_UINT64 *out, TQ_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 TQ_INT16 KFromToLittleEndian( TQ_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( TQ_INT16 *out, TQ_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 TQ_INT32 KFromToLittleEndian( TQ_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( TQ_INT32 *out, TQ_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 TQ_INT64 KFromToLittleEndian( TQ_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( TQ_INT64 *out, TQ_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 */ diff --git a/tdeio/misc/tdentlm/tdentlm.cpp b/tdeio/misc/tdentlm/tdentlm.cpp new file mode 100644 index 000000000..2ef5d1cb6 --- /dev/null +++ b/tdeio/misc/tdentlm/tdentlm.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 <tqdatetime.h> +#include <kapplication.h> +#include <kswap.h> +#include <kmdcodec.h> +#include <kdebug.h> + +#include "des.h" +#include "tdentlm.h" + +TQString KNTLM::getString( const TQByteArray &buf, const SecBuf &secbuf, bool unicode ) +{ + //watch for buffer overflows + TQ_UINT32 offset; + TQ_UINT16 len; + offset = KFromToLittleEndian((TQ_UINT32)secbuf.offset); + len = KFromToLittleEndian(secbuf.len); + if ( offset > buf.size() || + offset + len > buf.size() ) return TQString::null; + + TQString str; + const char *c = buf.data() + offset; + + if ( unicode ) { + str = UnicodeLE2TQString( (TQChar*) c, len >> 1 ); + } else { + str = TQString::fromLatin1( c, len ); + } + return str; +} + +TQByteArray KNTLM::getBuf( const TQByteArray &buf, const SecBuf &secbuf ) +{ + TQByteArray ret; + TQ_UINT32 offset; + TQ_UINT16 len; + offset = KFromToLittleEndian((TQ_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( TQByteArray &buf, SecBuf &secbuf, const TQString &str, bool unicode ) +{ + TQByteArray 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( TQByteArray &buf, SecBuf &secbuf, TQByteArray &data ) +{ + TQ_UINT32 offset; + TQ_UINT16 len, maxlen; + offset = (buf.size() + 1) & 0xfffffffe; + len = data.size(); + maxlen = data.size(); + + secbuf.offset = KFromToLittleEndian((TQ_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( TQByteArray &negotiate, const TQString &domain, const TQString &workstation, TQ_UINT32 flags ) +{ + TQByteArray rbuf( sizeof(Negotiate) ); + + rbuf.fill( 0 ); + memcpy( rbuf.data(), "NTLMSSP", 8 ); + ((Negotiate*) rbuf.data())->msgType = KFromToLittleEndian( (TQ_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( TQByteArray &auth, const TQByteArray &challenge, const TQString &user, + const TQString &password, const TQString &domain, const TQString &workstation, + bool forceNTLM, bool forceNTLMv2 ) +{ + TQByteArray rbuf( sizeof(Auth) ); + Challenge *ch = (Challenge *) challenge.data(); + TQByteArray response; + uint chsize = challenge.size(); + bool unicode = false; + TQString 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( (TQ_UINT32)3 ); + ((Auth*) rbuf.data())->flags = ch->flags; + TQByteArray 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; +} + +TQByteArray KNTLM::getLMResponse( const TQString &password, const unsigned char *challenge ) +{ + TQByteArray hash, answer; + + hash = lmHash( password ); + hash.resize( 21 ); + memset( hash.data() + 16, 0, 5 ); + answer = lmResponse( hash, challenge ); + hash.fill( 0 ); + return answer; +} + +TQByteArray KNTLM::lmHash( const TQString &password ) +{ + TQByteArray keyBytes( 14 ); + TQByteArray 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; +} + +TQByteArray KNTLM::lmResponse( const TQByteArray &hash, const unsigned char *challenge ) +{ + DES_KEY ks; + TQByteArray 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; +} + +TQByteArray KNTLM::getNTLMResponse( const TQString &password, const unsigned char *challenge ) +{ + TQByteArray hash, answer; + + hash = ntlmHash( password ); + hash.resize( 21 ); + memset( hash.data() + 16, 0, 5 ); + answer = lmResponse( hash, challenge ); + hash.fill( 0 ); + return answer; +} + +TQByteArray KNTLM::ntlmHash( const TQString &password ) +{ + KMD4::Digest digest; + TQByteArray ret, unicode; + unicode = QString2UnicodeLE( password ); + + KMD4 md4( unicode ); + md4.rawDigest( digest ); + ret.duplicate( (const char*) digest, sizeof( digest ) ); + return ret; +} + +TQByteArray KNTLM::getNTLMv2Response( const TQString &target, const TQString &user, + const TQString &password, const TQByteArray &targetInformation, + const unsigned char *challenge ) +{ + TQByteArray hash = ntlmv2Hash( target, user, password ); + TQByteArray blob = createBlob( targetInformation ); + return lmv2Response( hash, blob, challenge ); +} + +TQByteArray KNTLM::getLMv2Response( const TQString &target, const TQString &user, + const TQString &password, const unsigned char *challenge ) +{ + TQByteArray hash = ntlmv2Hash( target, user, password ); + TQByteArray clientChallenge( 8 ); + for ( uint i = 0; i<8; i++ ) { + clientChallenge.data()[i] = TDEApplication::random() % 0xff; + } + return lmv2Response( hash, clientChallenge, challenge ); +} + +TQByteArray KNTLM::ntlmv2Hash( const TQString &target, const TQString &user, const TQString &password ) +{ + TQByteArray hash1 = ntlmHash( password ); + TQByteArray key, ret; + TQString id = user.upper() + target.upper(); + key = QString2UnicodeLE( id ); + ret = hmacMD5( key, hash1 ); + return ret; +} + +TQByteArray KNTLM::lmv2Response( const TQByteArray &hash, + const TQByteArray &clientData, const unsigned char *challenge ) +{ + TQByteArray data( 8 + clientData.size() ); + memcpy( data.data(), challenge, 8 ); + memcpy( data.data() + 8, clientData.data(), clientData.size() ); + TQByteArray mac = hmacMD5( data, hash ); + mac.resize( 16 + clientData.size() ); + memcpy( mac.data() + 16, clientData.data(), clientData.size() ); + return mac; +} + +TQByteArray KNTLM::createBlob( const TQByteArray &targetinfo ) +{ + TQByteArray blob( sizeof(Blob) + 4 + targetinfo.size() ); + blob.fill( 0 ); + + Blob *bl = (Blob *) blob.data(); + bl->signature = KFromToBigEndian( (TQ_UINT32) 0x01010000 ); + TQ_UINT64 now = TQDateTime::currentDateTime().toTime_t(); + now += (TQ_UINT64)3600*(TQ_UINT64)24*(TQ_UINT64)134774; + now *= (TQ_UINT64)10000000; + bl->timestamp = KFromToLittleEndian( now ); + for ( uint i = 0; i<8; i++ ) { + bl->challenge[i] = TDEApplication::random() % 0xff; + } + memcpy( blob.data() + sizeof(Blob), targetinfo.data(), targetinfo.size() ); + return blob; +} + +TQByteArray KNTLM::hmacMD5( const TQByteArray &data, const TQByteArray &key ) +{ + TQ_UINT8 ipad[64], opad[64]; + KMD5::Digest digest; + TQByteArray 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]; + } + + TQByteArray 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)); +} + +TQByteArray KNTLM::QString2UnicodeLE( const TQString &target ) +{ + TQByteArray unicode( target.length() * 2 ); + for ( uint i = 0; i < target.length(); i++ ) { + ((TQ_UINT16*)unicode.data())[ i ] = KFromToLittleEndian( target[i].unicode() ); + } + return unicode; +} + +TQString KNTLM::UnicodeLE2TQString( const TQChar* data, uint len ) +{ + TQString ret; + for ( uint i = 0; i < len; i++ ) { + ret += KFromToLittleEndian( data[ i ].unicode() ); + } + return ret; +} diff --git a/tdeio/misc/tdentlm/tdentlm.h b/tdeio/misc/tdentlm/tdentlm.h new file mode 100644 index 000000000..06b8febab --- /dev/null +++ b/tdeio/misc/tdentlm/tdentlm.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 <tqglobal.h> +#include <tqcstring.h> +#include <tqstring.h> + +#include <tdelibs_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 TDEIO_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 + { + TQ_UINT16 len; + TQ_UINT16 maxlen; + TQ_UINT32 offset; + } SecBuf; + + /** + * The NTLM Type 1 structure + */ + typedef struct + { + char signature[8]; /* "NTLMSSP\0" */ + TQ_UINT32 msgType; /* 1 */ + TQ_UINT32 flags; + SecBuf domain; + SecBuf workstation; + } Negotiate; + + /** + * The NTLM Type 2 structure + */ + typedef struct + { + char signature[8]; + TQ_UINT32 msgType; /* 2 */ + SecBuf targetName; + TQ_UINT32 flags; + TQ_UINT8 challengeData[8]; + TQ_UINT32 context[2]; + SecBuf targetInfo; + } Challenge; + + /** + * The NTLM Type 3 structure + */ + typedef struct + { + char signature[8]; + TQ_UINT32 msgType; /* 3 */ + SecBuf lmResponse; + SecBuf ntResponse; + SecBuf domain; + SecBuf user; + SecBuf workstation; + SecBuf sessionKey; + TQ_UINT32 flags; + } Auth; + + typedef struct + { + TQ_UINT32 signature; + TQ_UINT32 reserved; + TQ_UINT64 timestamp; + TQ_UINT8 challenge[8]; + TQ_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( TQByteArray &negotiate, const TQString &domain = TQString::null, + const TQString &workstation = TQString::null, + TQ_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( TQByteArray &auth, const TQByteArray &challenge, const TQString &user, + const TQString &password, const TQString &domain = TQString::null, + const TQString &workstation = TQString::null, bool forceNTLM = false, bool forceNTLMv2 = false ); + + /** + * Returns the LanManager response from the password and the server challenge. + */ + static TQByteArray getLMResponse( const TQString &password, const unsigned char *challenge ); + /** + * Calculates the LanManager hash of the specified password. + */ + static TQByteArray lmHash( const TQString &password ); + /** + * Calculates the LanManager response from the LanManager hash and the server challenge. + */ + static TQByteArray lmResponse( const TQByteArray &hash, const unsigned char *challenge ); + + /** + * Returns the NTLM response from the password and the server challenge. + */ + static TQByteArray getNTLMResponse( const TQString &password, const unsigned char *challenge ); + /** + * Returns the NTLM hash (MD4) from the password. + */ + static TQByteArray ntlmHash( const TQString &password ); + + /** + * Calculates the NTLMv2 response. + */ + static TQByteArray getNTLMv2Response( const TQString &target, const TQString &user, + const TQString &password, const TQByteArray &targetInformation, + const unsigned char *challenge ); + + /** + * Calculates the LMv2 response. + */ + static TQByteArray getLMv2Response( const TQString &target, const TQString &user, + const TQString &password, const unsigned char *challenge ); + + /** + * Returns the NTLMv2 hash. + */ + static TQByteArray ntlmv2Hash( const TQString &target, const TQString &user, const TQString &password ); + + /** + * Calculates the LMv2 response. + */ + static TQByteArray lmv2Response( const TQByteArray &hash, + const TQByteArray &clientData, const unsigned char *challenge ); + + /** + * Extracts a string field from an NTLM structure. + */ + static TQString getString( const TQByteArray &buf, const SecBuf &secbuf, bool unicode ); + /** + * Extracts a byte array from an NTLM structure. + */ + static TQByteArray getBuf( const TQByteArray &buf, const SecBuf &secbuf ); + + static TQByteArray createBlob( const TQByteArray &targetinfo ); + + static TQByteArray hmacMD5( const TQByteArray &data, const TQByteArray &key ); +private: + static TQByteArray QString2UnicodeLE( const TQString &target ); + static TQString UnicodeLE2TQString( const TQChar* data, uint len ); + + static void addBuf( TQByteArray &buf, SecBuf &secbuf, TQByteArray &data ); + static void addString( TQByteArray &buf, SecBuf &secbuf, const TQString &str, bool unicode = false ); + static void convertKey( unsigned char *key_56, void* ks ); +}; + +#endif /* KNTLM_H */ |