00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
#include <string.h>
00025
00026
#include <qdatetime.h>
00027
#include <kapplication.h>
00028
#include <kswap.h>
00029
#include <kmdcodec.h>
00030
#include <kdebug.h>
00031
00032
#include "des.h"
00033
#include "kntlm.h"
00034
00035 QString KNTLM::getString(
const QByteArray &buf,
const SecBuf &secbuf,
bool unicode )
00036 {
00037
00038
if ( secbuf.offset > buf.size() ||
00039 secbuf.offset + secbuf.len > buf.size() )
return QString::null;
00040
00041
QString str;
00042
const char *c = buf.data() + secbuf.offset;
00043
00044
if ( unicode ) {
00045 str = UnicodeLE2QString( (
QChar*) c, secbuf.len >> 1 );
00046 }
else {
00047 str = QString::fromLatin1( c, secbuf.len );
00048 }
00049
return str;
00050 }
00051
00052 QByteArray KNTLM::getBuf(
const QByteArray &buf,
const SecBuf &secbuf )
00053 {
00054
QByteArray ret;
00055
00056
if ( secbuf.offset > buf.size() ||
00057 secbuf.offset + secbuf.len > buf.size() )
return ret;
00058 ret.duplicate( buf.data() + secbuf.offset, buf.size() );
00059
return ret;
00060 }
00061
00062
void KNTLM::addString(
QByteArray &buf, SecBuf &secbuf,
const QString &str,
bool unicode )
00063 {
00064
QByteArray tmp;
00065
00066
if ( unicode ) {
00067 tmp = QString2UnicodeLE( str );
00068 addBuf( buf, secbuf, tmp );
00069 }
else {
00070
const char *c;
00071 c = str.
latin1();
00072 tmp.setRawData( c, str.
length() );
00073 addBuf( buf, secbuf, tmp );
00074 tmp.resetRawData( c, str.
length() );
00075 }
00076 }
00077
00078
void KNTLM::addBuf(
QByteArray &buf, SecBuf &secbuf,
QByteArray &data )
00079 {
00080 secbuf.offset = buf.size();
00081 secbuf.len = data.size();
00082 secbuf.maxlen = data.size();
00083 buf.resize( buf.size() + data.size() );
00084 memcpy( buf.data() + secbuf.offset, data.data(), data.size() );
00085 }
00086
00087 bool KNTLM::getNegotiate(
QByteArray &negotiate,
const QString &domain,
const QString &workstation, Q_UINT32 flags )
00088 {
00089
QByteArray rbuf(
sizeof(
Negotiate) );
00090
00091 rbuf.fill( 0 );
00092 memcpy( rbuf.data(),
"NTLMSSP", 8 );
00093 ((Negotiate*) rbuf.data())->msgType =
KFromToLittleEndian( (Q_UINT32)1 );
00094
if ( !domain.
isEmpty() ) {
00095 flags |= Negotiate_Domain_Supplied;
00096 addString( rbuf, ((Negotiate*) rbuf.data())->domain, domain );
00097 }
00098
if ( !workstation.
isEmpty() ) {
00099 flags |= Negotiate_WS_Supplied;
00100 addString( rbuf, ((Negotiate*) rbuf.data())->domain, workstation );
00101 }
00102 ((Negotiate*) rbuf.data())->flags =
KFromToLittleEndian( flags );
00103 negotiate = rbuf;
00104
return true;
00105 }
00106
00107 bool KNTLM::getAuth(
QByteArray &auth,
const QByteArray &challenge,
const QString &user,
00108
const QString &password,
const QString &domain,
const QString &workstation,
00109
bool forceNTLM,
bool forceNTLMv2 )
00110 {
00111
QByteArray rbuf(
sizeof(
Auth) );
00112
Challenge *ch = (
Challenge *) challenge.data();
00113
QByteArray response;
00114 uint chsize = challenge.size();
00115
bool unicode =
false;
00116
QString dom;
00117
00118
00119
if ( chsize < 32 )
return false;
00120
00121 unicode = ch->
flags & Negotiate_Unicode;
00122
if ( domain.
isEmpty() )
00123 dom =
getString( challenge, ch->
targetName, unicode );
00124
else
00125 dom = domain;
00126
00127 rbuf.fill( 0 );
00128 memcpy( rbuf.data(),
"NTLMSSP", 8 );
00129 ((Auth*) rbuf.data())->msgType =
KFromToLittleEndian( (Q_UINT32)3 );
00130 ((Auth*) rbuf.data())->flags = ch->
flags;
00131
QByteArray targetInfo =
getBuf( challenge, ch->
targetInfo );
00132
00133
if ( forceNTLMv2 || !targetInfo.isEmpty() ) {
00134
if ( ch->
flags & Negotiate_NTLM ) {
00135
if ( targetInfo.isEmpty() )
return false;
00136 response =
getNTLMv2Response( dom, user, password, targetInfo, ch->
challengeData );
00137 addBuf( rbuf, ((Auth*) rbuf.data())->ntResponse, response );
00138 }
else {
00139
if ( !forceNTLM ) {
00140 response =
getLMv2Response( dom, user, password, ch->
challengeData );
00141 addBuf( rbuf, ((Auth*) rbuf.data())->lmResponse, response );
00142 }
else
00143
return false;
00144 }
00145 }
else {
00146
if ( ch->
flags & Negotiate_NTLM ) {
00147 response =
getNTLMResponse( password, ch->
challengeData );
00148 addBuf( rbuf, ((Auth*) rbuf.data())->ntResponse, response );
00149 }
else {
00150
if ( !forceNTLM ) {
00151 response =
getLMResponse( password, ch->
challengeData );
00152 addBuf( rbuf, ((Auth*) rbuf.data())->lmResponse, response );
00153 }
else
00154
return false;
00155 }
00156 }
00157
if ( !dom.
isEmpty() )
00158 addString( rbuf, ((Auth*) rbuf.data())->domain, dom, unicode );
00159 addString( rbuf, ((Auth*) rbuf.data())->user, user, unicode );
00160
if ( !workstation.
isEmpty() )
00161 addString( rbuf, ((Auth*) rbuf.data())->workstation, workstation, unicode );
00162
00163 auth = rbuf;
00164
00165
return true;
00166 }
00167
00168 QByteArray KNTLM::getLMResponse(
const QString &password,
const unsigned char *challenge )
00169 {
00170
QByteArray hash, answer;
00171
00172 hash =
lmHash( password );
00173 hash.resize( 21 );
00174 memset( hash.data() + 16, 0, 5 );
00175 answer =
lmResponse( hash, challenge );
00176 hash.fill( 0 );
00177
return answer;
00178 }
00179
00180 QByteArray KNTLM::lmHash(
const QString &password )
00181 {
00182
QByteArray keyBytes( 14 );
00183
QByteArray hash( 16 );
00184 DES_KEY ks;
00185
const char *magic =
"KGS!@#$%";
00186
00187 keyBytes.fill( 0 );
00188 strncpy( keyBytes.data(), password.
upper().latin1(), 14 );
00189
00190 convertKey( (
unsigned char*) keyBytes.data(), &ks );
00191 ntlm_des_ecb_encrypt( magic, 8, &ks, (
unsigned char*) hash.data() );
00192
00193 convertKey( (
unsigned char*) keyBytes.data() + 7, &ks );
00194 ntlm_des_ecb_encrypt( magic, 8, &ks, (
unsigned char*) hash.data() + 8 );
00195
00196 keyBytes.fill( 0 );
00197 memset( &ks, 0,
sizeof (ks) );
00198
00199
return hash;
00200 }
00201
00202 QByteArray KNTLM::lmResponse(
const QByteArray &hash,
const unsigned char *challenge )
00203 {
00204 DES_KEY ks;
00205
QByteArray answer( 24 );
00206
00207 convertKey( (
unsigned char*) hash.data(), &ks );
00208 ntlm_des_ecb_encrypt( challenge, 8, &ks, (
unsigned char*) answer.data() );
00209
00210 convertKey( (
unsigned char*) hash.data() + 7, &ks );
00211 ntlm_des_ecb_encrypt( challenge, 8, &ks, (
unsigned char*) answer.data() + 8 );
00212
00213 convertKey( (
unsigned char*) hash.data() + 14, &ks );
00214 ntlm_des_ecb_encrypt( challenge, 8, &ks, (
unsigned char*) answer.data() + 16 );
00215
00216 memset( &ks, 0,
sizeof (ks) );
00217
return answer;
00218 }
00219
00220 QByteArray KNTLM::getNTLMResponse(
const QString &password,
const unsigned char *challenge )
00221 {
00222
QByteArray hash, answer;
00223
00224 hash =
ntlmHash( password );
00225 hash.resize( 21 );
00226 memset( hash.data() + 16, 0, 5 );
00227 answer =
lmResponse( hash, challenge );
00228 hash.fill( 0 );
00229
return answer;
00230 }
00231
00232 QByteArray KNTLM::ntlmHash(
const QString &password )
00233 {
00234
KMD4::Digest digest;
00235
QByteArray ret, unicode;
00236 unicode = QString2UnicodeLE( password );
00237
00238
KMD4 md4( unicode );
00239 md4.
rawDigest( digest );
00240 ret.duplicate( (
const char*) digest,
sizeof( digest ) );
00241
return ret;
00242 }
00243
00244 QByteArray KNTLM::getNTLMv2Response(
const QString &target,
const QString &user,
00245
const QString &password,
const QByteArray &targetInformation,
00246
const unsigned char *challenge )
00247 {
00248
QByteArray hash =
ntlmv2Hash( target, user, password );
00249
QByteArray blob = createBlob( targetInformation );
00250
return lmv2Response( hash, blob, challenge );
00251 }
00252
00253 QByteArray KNTLM::getLMv2Response(
const QString &target,
const QString &user,
00254
const QString &password,
const unsigned char *challenge )
00255 {
00256
QByteArray hash =
ntlmv2Hash( target, user, password );
00257
QByteArray clientChallenge( 8 );
00258
for ( uint i = 0; i<8; i++ ) {
00259 clientChallenge.data()[i] =
KApplication::random() % 0xff;
00260 }
00261
return lmv2Response( hash, clientChallenge, challenge );
00262 }
00263
00264 QByteArray KNTLM::ntlmv2Hash(
const QString &target,
const QString &user,
const QString &password )
00265 {
00266
QByteArray hash1 =
ntlmHash( password );
00267
QByteArray key, ret;
00268
QString id = user.
upper() + target.
upper();
00269 key = QString2UnicodeLE(
id );
00270 ret = hmacMD5( key, hash1 );
00271
return ret;
00272 }
00273
00274 QByteArray KNTLM::lmv2Response(
const QByteArray &hash,
00275
const QByteArray &clientData,
const unsigned char *challenge )
00276 {
00277
QByteArray data( 8 + clientData.size() );
00278 memcpy( data.data(), challenge, 8 );
00279 memcpy( data.data() + 8, clientData.data(), clientData.size() );
00280
QByteArray mac = hmacMD5( data, hash );
00281 mac.resize( 16 + clientData.size() );
00282 memcpy( mac.data() + 16, clientData.data(), clientData.size() );
00283
return mac;
00284 }
00285
00286
QByteArray KNTLM::createBlob(
const QByteArray &targetinfo )
00287 {
00288
QByteArray blob(
sizeof(Blob) + 4 + targetinfo.size() );
00289 blob.fill( 0 );
00290
00291 Blob *bl = (Blob *) blob.data();
00292 bl->signature =
KFromToBigEndian( (Q_UINT32) 0x01010000 );
00293 Q_UINT64 now =
QDateTime::currentDateTime().toTime_t();
00294 now += (Q_UINT64)3600*(Q_UINT64)24*(Q_UINT64)134774;
00295 now *= (Q_UINT64)10000000;
00296 bl->timestamp =
KFromToLittleEndian( now );
00297
for ( uint i = 0; i<8; i++ ) {
00298 bl->challenge[i] =
KApplication::random() % 0xff;
00299 }
00300 memcpy( blob.data() +
sizeof(Blob), targetinfo.data(), targetinfo.size() );
00301
return blob;
00302 }
00303
00304
QByteArray KNTLM::hmacMD5(
const QByteArray &data,
const QByteArray &key )
00305 {
00306 Q_UINT8 ipad[64], opad[64];
00307
KMD5::Digest digest;
00308
QByteArray ret;
00309
00310 memset( ipad, 0x36,
sizeof(ipad) );
00311 memset( opad, 0x5c,
sizeof(opad) );
00312
for (
int i =
key.size()-1; i >= 0; i-- ) {
00313 ipad[i] ^=
key[i];
00314 opad[i] ^=
key[i];
00315 }
00316
00317
QByteArray content( data.size()+64 );
00318 memcpy( content.data(), ipad, 64 );
00319 memcpy( content.data() + 64, data.data(), data.size() );
00320
KMD5 md5( content );
00321 md5.
rawDigest( digest );
00322 content.resize(
sizeof(digest) + 64 );
00323 memcpy( content.data(), opad, 64 );
00324 memcpy( content.data() + 64, digest,
sizeof(digest) );
00325 md5.
reset();
00326 md5.
update( content );
00327 md5.
rawDigest( digest );
00328
00329 ret.duplicate( (
const char*) digest,
sizeof( digest ) );
00330
return ret;
00331 }
00332
00333
00334
00335
00336
00337
void KNTLM::convertKey(
unsigned char *key_56,
void* ks )
00338 {
00339
unsigned char key[8];
00340
00341
key[0] = key_56[0];
00342
key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
00343
key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
00344
key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
00345
key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
00346
key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
00347
key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
00348
key[7] = (key_56[6] << 1) & 0xFF;
00349
00350
for ( uint i=0; i<8; i++ ) {
00351
unsigned char b =
key[i];
00352
bool needsParity = (((b>>7) ^ (b>>6) ^ (b>>5) ^ (b>>4) ^ (b>>3) ^ (b>>2) ^ (b>>1)) & 0x01) == 0;
00353
if ( needsParity )
00354
key[i] |= 0x01;
00355
else
00356
key[i] &= 0xfe;
00357 }
00358
00359 ntlm_des_set_key ( (DES_KEY*) ks, (
char*) &key,
sizeof (key));
00360
00361 memset (&key, 0,
sizeof (key));
00362 }
00363
00364
QByteArray KNTLM::QString2UnicodeLE(
const QString &target )
00365 {
00366
QByteArray unicode( target.
length() * 2 );
00367
for ( uint i = 0; i < target.
length(); i++ ) {
00368 ((Q_UINT16*)unicode.data())[ i ] =
KFromToLittleEndian( target[i].unicode() );
00369 }
00370
return unicode;
00371 }
00372
00373
QString KNTLM::UnicodeLE2QString(
const QChar* data, uint len )
00374 {
00375
QString ret;
00376
for ( uint i = 0; i < len; i++ ) {
00377 ret +=
KFromToLittleEndian( data[ i ].unicode() );
00378 }
00379
return ret;
00380 }