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