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

KIO

  • 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
36static const char NTLM_SIGNATURE[] = "NTLMSSP";
37
38static 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
49static 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
60static 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
73static 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
86static 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
105static 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*/
119static 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
147static 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
166static 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
198bool 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
220bool 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 const 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;
248 if (chsize >= sizeof(Challenge)) {
249 targetInfo = getBuf(challenge, ch->targetInfo);
250 }
251
252 if (!(authflags & Force_V1) &&
253 ((authflags & Force_V2) ||
254 (!targetInfo.isEmpty() && (qFromLittleEndian(ch->flags) & Negotiate_Target_Info))) /* may support NTLMv2 */) {
255 bool ret = false;
256
257 if (qFromLittleEndian (ch->flags) & Negotiate_NTLM) {
258 if (targetInfo.isEmpty())
259 return false;
260
261 response = getNTLMv2Response (dom, user, password, targetInfo, ch->challengeData);
262 addBuf (rbuf, ((Auth *) rbuf.data())->ntResponse, response);
263 ret = true;
264 }
265
266 if (authflags & Add_LM) {
267 response = getLMv2Response (dom, user, password, ch->challengeData);
268 addBuf (rbuf, ((Auth *) rbuf.data())->lmResponse, response);
269 ret = true;
270 }
271
272 if (!ret) {
273 return false;
274 }
275 } else { //if no targetinfo structure and NTLMv2 or LMv2 not forced, or v1 forced, try the older methods
276 bool ret = false;
277
278 if (qFromLittleEndian (ch->flags) & Negotiate_NTLM) {
279 response = getNTLMResponse (password, ch->challengeData);
280 addBuf (rbuf, ((Auth *) rbuf.data())->ntResponse, response);
281 ret = true;
282 }
283
284 if (authflags & Add_LM) {
285 response = getLMResponse (password, ch->challengeData);
286 addBuf (rbuf, ((Auth *) rbuf.data())->lmResponse, response);
287 ret = true;
288 }
289
290 if (!ret) {
291 return false;
292 }
293 }
294
295 if (!dom.isEmpty()) {
296 addString (rbuf, ((Auth *) rbuf.data())->domain, dom, unicode);
297 }
298
299 addString (rbuf, ((Auth *) rbuf.data())->user, user, unicode);
300
301 if (!workstation.isEmpty()) {
302 addString (rbuf, ((Auth *) rbuf.data())->workstation, workstation, unicode);
303 }
304
305 auth = rbuf;
306 return true;
307}
308
309QByteArray KNTLM::getLMResponse (const QString &password, const unsigned char *challenge)
310{
311 QByteArray hash, answer;
312
313 hash = lmHash (password);
314 hash.resize (21);
315 memset (hash.data() + 16, 0, 5);
316 answer = lmResponse (hash, challenge);
317 hash.fill (0);
318 return answer;
319}
320
321QByteArray KNTLM::lmHash (const QString &password)
322{
323 QByteArray keyBytes (14, 0);
324 QByteArray hash (16, 0);
325 DES_KEY ks;
326 const char *magic = "KGS!@#$%";
327
328 strncpy (keyBytes.data(), password.toUpper().toLatin1(), 14);
329
330 convertKey ( (unsigned char *) keyBytes.data(), &ks);
331 ntlm_des_ecb_encrypt (magic, 8, &ks, (unsigned char *) hash.data());
332
333 convertKey ( (unsigned char *) keyBytes.data() + 7, &ks);
334 ntlm_des_ecb_encrypt (magic, 8, &ks, (unsigned char *) hash.data() + 8);
335
336 keyBytes.fill (0);
337 memset (&ks, 0, sizeof (ks));
338
339 return hash;
340}
341
342QByteArray KNTLM::lmResponse (const QByteArray &hash, const unsigned char *challenge)
343{
344 DES_KEY ks;
345 QByteArray answer (24, 0);
346
347 convertKey ( (unsigned char *) hash.data(), &ks);
348 ntlm_des_ecb_encrypt (challenge, 8, &ks, (unsigned char *) answer.data());
349
350 convertKey ( (unsigned char *) hash.data() + 7, &ks);
351 ntlm_des_ecb_encrypt (challenge, 8, &ks, (unsigned char *) answer.data() + 8);
352
353 convertKey ( (unsigned char *) hash.data() + 14, &ks);
354 ntlm_des_ecb_encrypt (challenge, 8, &ks, (unsigned char *) answer.data() + 16);
355
356 memset (&ks, 0, sizeof (ks));
357 return answer;
358}
359
360QByteArray KNTLM::getNTLMResponse (const QString &password, const unsigned char *challenge)
361{
362 QByteArray hash = ntlmHash (password);
363 hash.resize (21);
364 memset (hash.data() + 16, 0, 5);
365 QByteArray answer = lmResponse (hash, challenge);
366 hash.fill (0);
367 return answer;
368}
369
370QByteArray KNTLM::ntlmHash (const QString &password)
371{
372 QByteArray unicode;
373 unicode = QString2UnicodeLE (password);
374
375 return QCryptographicHash::hash (unicode, QCryptographicHash::Md4);
376}
377
378QByteArray KNTLM::getNTLMv2Response (const QString &target, const QString &user,
379 const QString &password, const QByteArray &targetInformation,
380 const unsigned char *challenge)
381{
382 QByteArray hash = ntlmv2Hash (target, user, password);
383 QByteArray blob = createBlob (targetInformation);
384 return lmv2Response (hash, blob, challenge);
385}
386
387QByteArray KNTLM::getLMv2Response (const QString &target, const QString &user,
388 const QString &password, const unsigned char *challenge)
389{
390 QByteArray hash = ntlmv2Hash (target, user, password);
391 QByteArray clientChallenge (8, 0);
392
393 for (uint i = 0; i < 8; i++) {
394 clientChallenge.data() [i] = KRandom::random() % 0xff;
395 }
396
397 return lmv2Response (hash, clientChallenge, challenge);
398}
399
400QByteArray KNTLM::ntlmv2Hash (const QString &target, const QString &user, const QString &password)
401{
402 const QByteArray hash = ntlmHash (password);
403 const QByteArray key = QString2UnicodeLE (user.toUpper() + target);
404 return hmacMD5 (key, hash);
405}
406
407QByteArray KNTLM::lmv2Response (const QByteArray &hash,
408 const QByteArray &clientData, const unsigned char *challenge)
409{
410 QByteArray data (8 + clientData.size(), 0);
411 memcpy (data.data(), challenge, 8);
412 memcpy (data.data() + 8, clientData.data(), clientData.size());
413
414 QByteArray mac = hmacMD5 (data, hash);
415 mac.resize (16 + clientData.size());
416 memcpy (mac.data() + 16, clientData.data(), clientData.size());
417 return mac;
418}
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:342
KNTLM::lmv2Response
static QByteArray lmv2Response(const QByteArray &hash, const QByteArray &clientData, const unsigned char *challenge)
Calculates the LMv2 response.
Definition: kntlm.cpp:407
KNTLM::ntlmHash
static QByteArray ntlmHash(const QString &password)
Returns the NTLM hash (MD4) from the password.
Definition: kntlm.cpp:370
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:387
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:309
KNTLM::Force_V1
@ Force_V1
Definition: kntlm.h:72
KNTLM::Add_LM
@ Add_LM
Definition: kntlm.h:74
KNTLM::Force_V2
@ Force_V2
Definition: kntlm.h:73
KNTLM::ntlmv2Hash
static QByteArray ntlmv2Hash(const QString &target, const QString &user, const QString &password)
Returns the NTLMv2 hash.
Definition: kntlm.cpp:400
KNTLM::lmHash
static QByteArray lmHash(const QString &password)
Calculates the LanManager hash of the specified password.
Definition: kntlm.cpp:321
KNTLM::Negotiate_WS_Supplied
@ Negotiate_WS_Supplied
Definition: kntlm.h:55
KNTLM::Negotiate_Target_Info
@ Negotiate_Target_Info
Definition: kntlm.h:65
KNTLM::Negotiate_Domain_Supplied
@ Negotiate_Domain_Supplied
Definition: kntlm.h:54
KNTLM::Negotiate_Unicode
@ Negotiate_Unicode
Definition: kntlm.h:45
KNTLM::Negotiate_NTLM
@ Negotiate_NTLM
Definition: kntlm.h:53
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
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:378
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::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:360
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
ntlm_des_set_key
int ntlm_des_set_key(DES_KEY *dkey, char *user_key, int)
Definition: des.cpp:220
des.h
kdebug.h
createBlob
static QByteArray createBlob(const QByteArray &targetinfo)
Definition: kntlm.cpp:147
convertKey
static void convertKey(unsigned char *key_56, void *ks)
Definition: kntlm.cpp:119
QString2UnicodeLE
static QByteArray QString2UnicodeLE(const QString &target)
Definition: kntlm.cpp:38
getBuf
static QByteArray getBuf(const QByteArray &buf, const KNTLM::SecBuf &secbuf)
Definition: kntlm.cpp:60
addString
static void addString(QByteArray &buf, KNTLM::SecBuf &secbuf, const QString &str, bool unicode=false)
Definition: kntlm.cpp:105
NTLM_SIGNATURE
static const char NTLM_SIGNATURE[]
Definition: kntlm.cpp:36
hmacMD5
static QByteArray hmacMD5(const QByteArray &data, const QByteArray &key)
Definition: kntlm.cpp:166
getString
static QString getString(const QByteArray &buf, const KNTLM::SecBuf &secbuf, bool unicode)
Definition: kntlm.cpp:86
UnicodeLE2QString
static QString UnicodeLE2QString(const QChar *data, uint len)
Definition: kntlm.cpp:49
addBuf
static void addBuf(QByteArray &buf, KNTLM::SecBuf &secbuf, const QByteArray &data)
Definition: kntlm.cpp:73
kntlm.h
krandom.h
KRandom::random
int random()
KNTLM::Auth
The NTLM Type 3 structure.
Definition: kntlm.h:112
KNTLM::Blob
Definition: kntlm.h:124
KNTLM::Blob::challenge
quint8 challenge[8]
Definition: kntlm.h:128
KNTLM::Blob::timestamp
quint64 timestamp
Definition: kntlm.h:127
KNTLM::Blob::signature
quint32 signature
Definition: kntlm.h:125
KNTLM::Challenge
The NTLM Type 2 structure.
Definition: kntlm.h:99
KNTLM::Challenge::flags
quint32 flags
Definition: kntlm.h:103
KNTLM::Challenge::targetInfo
SecBuf targetInfo
Definition: kntlm.h:106
KNTLM::Challenge::challengeData
quint8 challengeData[8]
Definition: kntlm.h:104
KNTLM::Challenge::targetName
SecBuf targetName
Definition: kntlm.h:102
KNTLM::Negotiate
The NTLM Type 1 structure.
Definition: kntlm.h:88
KNTLM::SecBuf
Definition: kntlm.h:79
KNTLM::SecBuf::maxlen
quint16 maxlen
Definition: kntlm.h:81
KNTLM::SecBuf::len
quint16 len
Definition: kntlm.h:80
KNTLM::SecBuf::offset
quint32 offset
Definition: kntlm.h:82
des_key
Definition: des.h:30
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 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-4.14.38 API Reference

Skip menu "kdelibs-4.14.38 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
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
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