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() + 1) & 0xfffffffe;
00081 secbuf.len = data.size();
00082 secbuf.maxlen = data.size();
00083 buf.resize( secbuf.offset + 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() && (ch->flags & Negotiate_Target_Info)) ) {
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 }