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