• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KIO

  • sources
  • kde-4.12
  • kdelibs
  • kio
  • misc
  • kntlm
kntlm.cpp
Go to the documentation of this file.
1 /* This file is part of the KDE libraries
2  Copyright (c) 2004 Szombathelyi Gy�gy <gyurco@freemail.hu>
3 
4  The implementation is based on the documentation and sample code
5  at http://davenport.sourceforge.net/ntlm.html
6  The DES encryption functions are from libntlm
7  at http://josefsson.org/libntlm/
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Library General Public
11  License version 2 as published by the Free Software Foundation.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22 */
23 
24 #include "kntlm.h"
25 #include "des.h"
26 
27 #include <cstring>
28 
29 #include <QtCore/QDate>
30 #include <QtCore/QtEndian>
31 #include <QtCore/QCryptographicHash>
32 
33 #include <krandom.h>
34 #include <kdebug.h>
35 
36 static const char NTLM_SIGNATURE[] = "NTLMSSP";
37 
38 static QByteArray QString2UnicodeLE (const QString &target)
39 {
40  QByteArray unicode (target.length() * 2, 0);
41 
42  for (int i = 0; i < target.length(); i++) {
43  ((quint16 *) unicode.data()) [ i ] = qToLittleEndian (target[i].unicode());
44  }
45 
46  return unicode;
47 }
48 
49 static QString UnicodeLE2QString (const QChar *data, uint len)
50 {
51  QString ret;
52 
53  for (uint i = 0; i < len; i++) {
54  ret += qFromLittleEndian (data[ i ].unicode());
55  }
56 
57  return ret;
58 }
59 
60 static QByteArray getBuf (const QByteArray &buf, const KNTLM::SecBuf &secbuf)
61 {
62  quint32 offset = qFromLittleEndian ( (quint32) secbuf.offset);
63  quint16 len = qFromLittleEndian (secbuf.len);
64 
65  //watch for buffer overflows
66  if (offset > (quint32) buf.size() || offset + len > (quint32) buf.size()) {
67  return QByteArray();
68  }
69 
70  return QByteArray (buf.data() + offset, buf.size());
71 }
72 
73 static void addBuf (QByteArray &buf, KNTLM::SecBuf &secbuf, const QByteArray &data)
74 {
75  quint32 offset = (buf.size() + 1) & 0xfffffffe;
76  quint16 len = data.size();
77  quint16 maxlen = data.size();
78 
79  secbuf.offset = qToLittleEndian ( (quint32) offset);
80  secbuf.len = qToLittleEndian (len);
81  secbuf.maxlen = qToLittleEndian (maxlen);
82  buf.resize (offset + len);
83  memcpy (buf.data() + offset, data.data(), data.size());
84 }
85 
86 static QString getString (const QByteArray &buf, const KNTLM::SecBuf &secbuf, bool unicode)
87 {
88  //watch for buffer overflows
89  quint32 offset = qFromLittleEndian ( (quint32) secbuf.offset);
90  quint16 len = qFromLittleEndian (secbuf.len);
91 
92  if (offset > (quint32) buf.size() || offset + len > (quint32) buf.size()) {
93  return QString();
94  }
95 
96  const char *c = buf.data() + offset;
97 
98  if (unicode) {
99  return UnicodeLE2QString ( (QChar *) c, len >> 1);
100  }
101 
102  return QString::fromLatin1 (c, len);
103 }
104 
105 static void addString (QByteArray &buf, KNTLM::SecBuf &secbuf, const QString &str, bool unicode = false)
106 {
107  if (unicode) {
108  addBuf (buf, secbuf, QString2UnicodeLE (str));
109  return;
110  }
111 
112  addBuf (buf, secbuf, str.toLatin1());
113 }
114 
115 /*
116 * turns a 56 bit key into the 64 bit, odd parity key and sets the key.
117 * The key schedule ks is also set.
118 */
119 static void convertKey (unsigned char *key_56, void *ks)
120 {
121  unsigned char key[8];
122 
123  key[0] = key_56[0];
124  key[1] = ( (key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
125  key[2] = ( (key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
126  key[3] = ( (key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
127  key[4] = ( (key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
128  key[5] = ( (key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
129  key[6] = ( (key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
130  key[7] = (key_56[6] << 1) & 0xFF;
131 
132  for (uint i = 0; i < 8; i++) {
133  unsigned char b = key[i];
134  bool needsParity = ((((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 4) ^ (b >> 3) ^ (b >> 2) ^ (b >> 1)) & 0x01) == 0);
135 
136  if (needsParity) {
137  key[i] |= 0x01;
138  } else {
139  key[i] &= 0xfe;
140  }
141  }
142 
143  ntlm_des_set_key ( (DES_KEY *) ks, (char *) &key, sizeof (key));
144  memset (&key, 0, sizeof (key));
145 }
146 
147 static QByteArray createBlob (const QByteArray &targetinfo)
148 {
149  QByteArray blob (sizeof (KNTLM::Blob) + 4 + targetinfo.size(), 0);
150 
151  KNTLM::Blob *bl = (KNTLM::Blob *) blob.data();
152  bl->signature = qToBigEndian ( (quint32) 0x01010000);
153  quint64 now = QDateTime::currentDateTime().toTime_t();
154  now += (quint64) 3600 * (quint64) 24 * (quint64) 134774;
155  now *= (quint64) 10000000;
156  bl->timestamp = qToLittleEndian (now);
157 
158  for (uint i = 0; i < 8; i++) {
159  bl->challenge[i] = KRandom::random() % 0xff;
160  }
161 
162  memcpy (blob.data() + sizeof (KNTLM::Blob), targetinfo.data(), targetinfo.size());
163  return blob;
164 }
165 
166 static QByteArray hmacMD5 (const QByteArray &data, const QByteArray &key)
167 {
168  quint8 ipad[64], opad[64];
169  QByteArray ret;
170 
171  memset (ipad, 0x36, sizeof (ipad));
172  memset (opad, 0x5c, sizeof (opad));
173 
174  for (int i = key.size() - 1; i >= 0; i--) {
175  ipad[i] ^= key[i];
176  opad[i] ^= key[i];
177  }
178 
179  QByteArray content (data.size() + 64, 0);
180  memcpy (content.data(), ipad, 64);
181  memcpy (content.data() + 64, data.data(), data.size());
182 
183  QCryptographicHash md5 (QCryptographicHash::Md5);
184  md5.addData (content);
185  content.resize (64);
186  memcpy (content.data(), opad, 64);
187  content += md5.result();
188 
189  md5.reset();
190  md5.addData (content);
191 
192  return md5.result();
193 }
194 
195 
196 /*************************************** KNTLM implementation ***************************************/
197 
198 bool KNTLM::getNegotiate (QByteArray &negotiate, const QString &domain, const QString &workstation, quint32 flags)
199 {
200  QByteArray rbuf (sizeof (Negotiate), 0);
201 
202  memcpy (rbuf.data(), NTLM_SIGNATURE, sizeof (NTLM_SIGNATURE));
203  ((Negotiate *) rbuf.data())->msgType = qToLittleEndian ( (quint32) 1);
204 
205  if (!domain.isEmpty()) {
206  flags |= Negotiate_Domain_Supplied;
207  addString (rbuf, ((Negotiate *) rbuf.data())->domain, domain);
208  }
209 
210  if (!workstation.isEmpty()) {
211  flags |= Negotiate_WS_Supplied;
212  addString (rbuf, ((Negotiate *) rbuf.data())->workstation, workstation);
213  }
214 
215  ((Negotiate *) rbuf.data())->flags = qToLittleEndian (flags);
216  negotiate = rbuf;
217  return true;
218 }
219 
220 bool KNTLM::getAuth (QByteArray &auth, const QByteArray &challenge,
221  const QString &user, const QString &password, const QString &domain,
222  const QString &workstation, AuthFlags authflags)
223 {
224  QByteArray rbuf (sizeof (Auth), 0);
225  Challenge *ch = (Challenge *) challenge.data();
226  QByteArray response;
227  uint chsize = challenge.size();
228  bool unicode = false;
229  QString dom;
230 
231  //challenge structure too small
232  if (chsize < 32) {
233  return false;
234  }
235 
236  unicode = qFromLittleEndian (ch->flags) & Negotiate_Unicode;
237 
238  if (domain.isEmpty()) {
239  dom = getString (challenge, ch->targetName, unicode);
240  } else {
241  dom = domain;
242  }
243 
244  memcpy (rbuf.data(), NTLM_SIGNATURE, sizeof (NTLM_SIGNATURE));
245  ((Auth *) rbuf.data())->msgType = qToLittleEndian ( (quint32) 3);
246  ((Auth *) rbuf.data())->flags = ch->flags;
247  QByteArray targetInfo = getBuf (challenge, ch->targetInfo);
248 
249 
250  if (!(authflags & Force_V1) &&
251  ((authflags & Force_V2) ||
252  (!targetInfo.isEmpty() && (qFromLittleEndian(ch->flags) & Negotiate_Target_Info))) /* may support NTLMv2 */) {
253  bool ret = false;
254 
255  if (qFromLittleEndian (ch->flags) & Negotiate_NTLM) {
256  if (targetInfo.isEmpty())
257  return false;
258 
259  response = getNTLMv2Response (dom, user, password, targetInfo, ch->challengeData);
260  addBuf (rbuf, ((Auth *) rbuf.data())->ntResponse, response);
261  ret = true;
262  }
263 
264  if (authflags & Add_LM) {
265  response = getLMv2Response (dom, user, password, ch->challengeData);
266  addBuf (rbuf, ((Auth *) rbuf.data())->lmResponse, response);
267  ret = true;
268  }
269 
270  if (!ret) {
271  return false;
272  }
273  } else { //if no targetinfo structure and NTLMv2 or LMv2 not forced, or v1 forced, try the older methods
274  bool ret = false;
275 
276  if (qFromLittleEndian (ch->flags) & Negotiate_NTLM) {
277  response = getNTLMResponse (password, ch->challengeData);
278  addBuf (rbuf, ((Auth *) rbuf.data())->ntResponse, response);
279  ret = true;
280  }
281 
282  if (authflags & Add_LM) {
283  response = getLMResponse (password, ch->challengeData);
284  addBuf (rbuf, ((Auth *) rbuf.data())->lmResponse, response);
285  ret = true;
286  }
287 
288  if (!ret) {
289  return false;
290  }
291  }
292 
293  if (!dom.isEmpty()) {
294  addString (rbuf, ((Auth *) rbuf.data())->domain, dom, unicode);
295  }
296 
297  addString (rbuf, ((Auth *) rbuf.data())->user, user, unicode);
298 
299  if (!workstation.isEmpty()) {
300  addString (rbuf, ((Auth *) rbuf.data())->workstation, workstation, unicode);
301  }
302 
303  auth = rbuf;
304  return true;
305 }
306 
307 QByteArray KNTLM::getLMResponse (const QString &password, const unsigned char *challenge)
308 {
309  QByteArray hash, answer;
310 
311  hash = lmHash (password);
312  hash.resize (21);
313  memset (hash.data() + 16, 0, 5);
314  answer = lmResponse (hash, challenge);
315  hash.fill (0);
316  return answer;
317 }
318 
319 QByteArray KNTLM::lmHash (const QString &password)
320 {
321  QByteArray keyBytes (14, 0);
322  QByteArray hash (16, 0);
323  DES_KEY ks;
324  const char *magic = "KGS!@#$%";
325 
326  strncpy (keyBytes.data(), password.toUpper().toLatin1(), 14);
327 
328  convertKey ( (unsigned char *) keyBytes.data(), &ks);
329  ntlm_des_ecb_encrypt (magic, 8, &ks, (unsigned char *) hash.data());
330 
331  convertKey ( (unsigned char *) keyBytes.data() + 7, &ks);
332  ntlm_des_ecb_encrypt (magic, 8, &ks, (unsigned char *) hash.data() + 8);
333 
334  keyBytes.fill (0);
335  memset (&ks, 0, sizeof (ks));
336 
337  return hash;
338 }
339 
340 QByteArray KNTLM::lmResponse (const QByteArray &hash, const unsigned char *challenge)
341 {
342  DES_KEY ks;
343  QByteArray answer (24, 0);
344 
345  convertKey ( (unsigned char *) hash.data(), &ks);
346  ntlm_des_ecb_encrypt (challenge, 8, &ks, (unsigned char *) answer.data());
347 
348  convertKey ( (unsigned char *) hash.data() + 7, &ks);
349  ntlm_des_ecb_encrypt (challenge, 8, &ks, (unsigned char *) answer.data() + 8);
350 
351  convertKey ( (unsigned char *) hash.data() + 14, &ks);
352  ntlm_des_ecb_encrypt (challenge, 8, &ks, (unsigned char *) answer.data() + 16);
353 
354  memset (&ks, 0, sizeof (ks));
355  return answer;
356 }
357 
358 QByteArray KNTLM::getNTLMResponse (const QString &password, const unsigned char *challenge)
359 {
360  QByteArray hash = ntlmHash (password);
361  hash.resize (21);
362  memset (hash.data() + 16, 0, 5);
363  QByteArray answer = lmResponse (hash, challenge);
364  hash.fill (0);
365  return answer;
366 }
367 
368 QByteArray KNTLM::ntlmHash (const QString &password)
369 {
370  QByteArray unicode;
371  unicode = QString2UnicodeLE (password);
372 
373  return QCryptographicHash::hash (unicode, QCryptographicHash::Md4);
374 }
375 
376 QByteArray KNTLM::getNTLMv2Response (const QString &target, const QString &user,
377  const QString &password, const QByteArray &targetInformation,
378  const unsigned char *challenge)
379 {
380  QByteArray hash = ntlmv2Hash (target, user, password);
381  QByteArray blob = createBlob (targetInformation);
382  return lmv2Response (hash, blob, challenge);
383 }
384 
385 QByteArray KNTLM::getLMv2Response (const QString &target, const QString &user,
386  const QString &password, const unsigned char *challenge)
387 {
388  QByteArray hash = ntlmv2Hash (target, user, password);
389  QByteArray clientChallenge (8, 0);
390 
391  for (uint i = 0; i < 8; i++) {
392  clientChallenge.data() [i] = KRandom::random() % 0xff;
393  }
394 
395  return lmv2Response (hash, clientChallenge, challenge);
396 }
397 
398 QByteArray KNTLM::ntlmv2Hash (const QString &target, const QString &user, const QString &password)
399 {
400  const QByteArray hash = ntlmHash (password);
401  const QByteArray key = QString2UnicodeLE (user.toUpper() + target);
402  return hmacMD5 (key, hash);
403 }
404 
405 QByteArray KNTLM::lmv2Response (const QByteArray &hash,
406  const QByteArray &clientData, const unsigned char *challenge)
407 {
408  QByteArray data (8 + clientData.size(), 0);
409  memcpy (data.data(), challenge, 8);
410  memcpy (data.data() + 8, clientData.data(), clientData.size());
411 
412  QByteArray mac = hmacMD5 (data, hash);
413  mac.resize (16 + clientData.size());
414  memcpy (mac.data() + 16, clientData.data(), clientData.size());
415  return mac;
416 }
KNTLM::SecBuf::len
quint16 len
Definition: kntlm.h:80
krandom.h
KNTLM::Negotiate_Unicode
Definition: kntlm.h:45
kdebug.h
NTLM_SIGNATURE
static const char NTLM_SIGNATURE[]
Definition: kntlm.cpp:36
KNTLM::lmHash
static QByteArray lmHash(const QString &password)
Calculates the LanManager hash of the specified password.
Definition: kntlm.cpp:319
KNTLM::Challenge::targetInfo
SecBuf targetInfo
Definition: kntlm.h:106
KNTLM::Negotiate_Domain_Supplied
Definition: kntlm.h:54
createBlob
static QByteArray createBlob(const QByteArray &targetinfo)
Definition: kntlm.cpp:147
addBuf
static void addBuf(QByteArray &buf, KNTLM::SecBuf &secbuf, const QByteArray &data)
Definition: kntlm.cpp:73
KNTLM::Negotiate_NTLM
Definition: kntlm.h:53
KNTLM::ntlmv2Hash
static QByteArray ntlmv2Hash(const QString &target, const QString &user, const QString &password)
Returns the NTLMv2 hash.
Definition: kntlm.cpp:398
KNTLM::getAuth
static bool getAuth(QByteArray &auth, const QByteArray &challenge, const QString &user, const QString &password, const QString &domain=QString(), const QString &workstation=QString(), AuthFlags authflags=Add_LM)
Creates the type 3 message which should be sent to the server after the challenge (type 2) received...
Definition: kntlm.cpp:220
quint32
QString
KRandom::random
int random()
KNTLM::getNegotiate
static bool getNegotiate(QByteArray &negotiate, const QString &domain=QString(), const QString &workstation=QString(), quint32 flags=Negotiate_Unicode|Request_Target|Negotiate_NTLM)
Creates the initial message (type 1) which should be sent to the server.
Definition: kntlm.cpp:198
KNTLM::SecBuf::maxlen
quint16 maxlen
Definition: kntlm.h:81
QString2UnicodeLE
static QByteArray QString2UnicodeLE(const QString &target)
Definition: kntlm.cpp:38
UnicodeLE2QString
static QString UnicodeLE2QString(const QChar *data, uint len)
Definition: kntlm.cpp:49
KNTLM::Negotiate
The NTLM Type 1 structure.
Definition: kntlm.h:88
KNTLM::getNTLMv2Response
static QByteArray getNTLMv2Response(const QString &target, const QString &user, const QString &password, const QByteArray &targetInformation, const unsigned char *challenge)
Calculates the NTLMv2 response.
Definition: kntlm.cpp:376
hmacMD5
static QByteArray hmacMD5(const QByteArray &data, const QByteArray &key)
Definition: kntlm.cpp:166
KNTLM::getLMResponse
static QByteArray getLMResponse(const QString &password, const unsigned char *challenge)
Returns the LanManager response from the password and the server challenge.
Definition: kntlm.cpp:307
KNTLM::SecBuf
Definition: kntlm.h:79
addString
static void addString(QByteArray &buf, KNTLM::SecBuf &secbuf, const QString &str, bool unicode=false)
Definition: kntlm.cpp:105
KNTLM::Force_V1
Definition: kntlm.h:72
KNTLM::Challenge::targetName
SecBuf targetName
Definition: kntlm.h:102
kntlm.h
ntlm_des_set_key
int ntlm_des_set_key(DES_KEY *dkey, char *user_key, int)
Definition: des.cpp:220
KNTLM::Add_LM
Definition: kntlm.h:74
KNTLM::Challenge::challengeData
quint8 challengeData[8]
Definition: kntlm.h:104
KNTLM::Negotiate_WS_Supplied
Definition: kntlm.h:55
getString
static QString getString(const QByteArray &buf, const KNTLM::SecBuf &secbuf, bool unicode)
Definition: kntlm.cpp:86
des.h
KNTLM::Blob::signature
quint32 signature
Definition: kntlm.h:125
KNTLM::getNTLMResponse
static QByteArray getNTLMResponse(const QString &password, const unsigned char *challenge)
Returns the NTLM response from the password and the server challenge.
Definition: kntlm.cpp:358
KNTLM::Challenge
The NTLM Type 2 structure.
Definition: kntlm.h:99
KNTLM::Force_V2
Definition: kntlm.h:73
des_key
Definition: des.h:29
quint64
KNTLM::lmv2Response
static QByteArray lmv2Response(const QByteArray &hash, const QByteArray &clientData, const unsigned char *challenge)
Calculates the LMv2 response.
Definition: kntlm.cpp:405
KNTLM::ntlmHash
static QByteArray ntlmHash(const QString &password)
Returns the NTLM hash (MD4) from the password.
Definition: kntlm.cpp:368
KNTLM::Blob
Definition: kntlm.h:124
KNTLM::getLMv2Response
static QByteArray getLMv2Response(const QString &target, const QString &user, const QString &password, const unsigned char *challenge)
Calculates the LMv2 response.
Definition: kntlm.cpp:385
KNTLM::Negotiate_Target_Info
Definition: kntlm.h:65
getBuf
static QByteArray getBuf(const QByteArray &buf, const KNTLM::SecBuf &secbuf)
Definition: kntlm.cpp:60
KNTLM::Challenge::flags
quint32 flags
Definition: kntlm.h:103
KNTLM::SecBuf::offset
quint32 offset
Definition: kntlm.h:82
convertKey
static void convertKey(unsigned char *key_56, void *ks)
Definition: kntlm.cpp:119
ntlm_des_ecb_encrypt
int ntlm_des_ecb_encrypt(const void *plaintext, int len, DES_KEY *akey, unsigned char output[8])
Definition: des.cpp:520
KNTLM::Auth
The NTLM Type 3 structure.
Definition: kntlm.h:112
KNTLM::lmResponse
static QByteArray lmResponse(const QByteArray &hash, const unsigned char *challenge)
Calculates the LanManager response from the LanManager hash and the server challenge.
Definition: kntlm.cpp:340
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:50:02 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal