Qt 4.8
qauthenticator.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtNetwork module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <qauthenticator.h>
43 #include <qauthenticator_p.h>
44 #include <qdebug.h>
45 #include <qhash.h>
46 #include <qbytearray.h>
47 #include <qcryptographichash.h>
48 #include <qhttp.h>
49 #include <qiodevice.h>
50 #include <qdatastream.h>
51 #include <qendian.h>
52 #include <qstring.h>
53 #include <qdatetime.h>
54 
55 //#define NTLMV1_CLIENT
56 
58 
59 #ifdef NTLMV1_CLIENT
60 #include "../../3rdparty/des/des.cpp"
61 #endif
62 
63 static QByteArray qNtlmPhase1();
64 static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data);
65 
138  : d(0)
139 {
140 }
141 
146 {
147  if (d)
148  delete d;
149 }
150 
155  : d(0)
156 {
157  if (other.d)
158  *this = other;
159 }
160 
165 {
166  if (d == other.d)
167  return *this;
168 
169  // Do not share the d since challenge reponse/based changes
170  // could corrupt the internal store and different network requests
171  // can utilize different types of proxies.
172  detach();
173  if (other.d) {
174  d->user = other.d->user;
175  d->userDomain = other.d->userDomain;
176  d->workstation = other.d->workstation;
177  d->extractedUser = other.d->extractedUser;
178  d->password = other.d->password;
179  d->realm = other.d->realm;
180  d->method = other.d->method;
181  d->options = other.d->options;
182  } else if (d->phase == QAuthenticatorPrivate::Start) {
183  delete d;
184  d = 0;
185  }
186  return *this;
187 }
188 
194 {
195  if (d == other.d)
196  return true;
197  return d->user == other.d->user
198  && d->password == other.d->password
199  && d->realm == other.d->realm
200  && d->method == other.d->method
201  && d->options == other.d->options;
202 }
203 
218 {
219  return d ? d->user : QString();
220 }
221 
226 {
227  detach();
228  d->user = user;
229  d->updateCredentials();
230 }
231 
236 {
237  return d ? d->password : QString();
238 }
239 
244 {
245  detach();
246  d->password = password;
247 }
248 
253 {
254  if (!d) {
255  d = new QAuthenticatorPrivate;
256  return;
257  }
258 
261 }
262 
267 {
268  return d ? d->realm : QString();
269 }
270 
283 {
284  return d ? d->options.value(opt) : QVariant();
285 }
286 
299 {
300  return d ? d->options : QVariantHash();
301 }
302 
314 void QAuthenticator::setOption(const QString &opt, const QVariant &value)
315 {
316  detach();
317  d->options.insert(opt, value);
318 }
319 
320 
325 {
326  return !d;
327 }
328 
330  : method(None)
331  , hasFailed(false)
332  , phase(Start)
333  , nonceCount(0)
334 {
337  nonceCount = 0;
338 }
339 
340 #ifndef QT_NO_HTTP
342 {
343  const QList<QPair<QString, QString> > values = header.values();
345 
346  QList<QPair<QString, QString> >::const_iterator it, end;
347  for (it = values.constBegin(), end = values.constEnd(); it != end; ++it)
348  rawValues.append(qMakePair(it->first.toLatin1(), it->second.toUtf8()));
349 
350  // continue in byte array form
351  parseHttpResponse(rawValues, isProxy);
352 }
353 #endif
354 
356 {
357 }
358 
360 {
361  int separatorPosn = 0;
362 
363  switch (method) {
365  if ((separatorPosn = user.indexOf(QLatin1String("\\"))) != -1) {
366  //domain name is present
367  realm.clear();
368  userDomain = user.left(separatorPosn);
369  extractedUser = user.mid(separatorPosn + 1);
370  } else {
372  realm.clear();
373  userDomain.clear();
374  }
375  break;
376  default:
377  userDomain.clear();
378  break;
379  }
380 }
381 
383 {
384  const char *search = isProxy ? "proxy-authenticate" : "www-authenticate";
385 
386  method = None;
387  /*
388  Fun from the HTTP 1.1 specs, that we currently ignore:
389 
390  User agents are advised to take special care in parsing the WWW-
391  Authenticate field value as it might contain more than one challenge,
392  or if more than one WWW-Authenticate header field is provided, the
393  contents of a challenge itself can contain a comma-separated list of
394  authentication parameters.
395  */
396 
397  QByteArray headerVal;
398  for (int i = 0; i < values.size(); ++i) {
399  const QPair<QByteArray, QByteArray> &current = values.at(i);
400  if (current.first.toLower() != search)
401  continue;
402  QByteArray str = current.second.toLower();
403  if (method < Basic && str.startsWith("basic")) {
404  method = Basic;
405  headerVal = current.second.mid(6);
406  } else if (method < Ntlm && str.startsWith("ntlm")) {
407  method = Ntlm;
408  headerVal = current.second.mid(5);
409  } else if (method < DigestMd5 && str.startsWith("digest")) {
410  method = DigestMd5;
411  headerVal = current.second.mid(7);
412  }
413  }
414 
415  // Reparse credentials since we know the method now
417  challenge = headerVal.trimmed();
419 
420  switch(method) {
421  case Basic:
422  this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm"));
423  if (user.isEmpty() && password.isEmpty())
424  phase = Done;
425  break;
426  case Ntlm:
427  // #### extract from header
428  if (user.isEmpty() && password.isEmpty())
429  phase = Done;
430  break;
431  case DigestMd5: {
432  this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm"));
433  if (options.value("stale").toLower() == "true")
434  phase = Start;
435  if (user.isEmpty() && password.isEmpty())
436  phase = Done;
437  break;
438  }
439  default:
440  realm.clear();
441  challenge = QByteArray();
442  phase = Invalid;
443  }
444 }
445 
447 {
448  QByteArray response;
449  const char *methodString = 0;
450  switch(method) {
452  methodString = "";
453  phase = Done;
454  break;
456  response = '\0' + user.toUtf8() + '\0' + password.toUtf8();
457  phase = Done;
458  break;
460  methodString = "Basic ";
461  response = user.toLatin1() + ':' + password.toLatin1();
462  response = response.toBase64();
463  phase = Done;
464  break;
466  if (challenge.contains("VXNlciBOYW1lAA==")) {
467  response = user.toUtf8().toBase64();
468  phase = Phase2;
469  } else if (challenge.contains("UGFzc3dvcmQA")) {
470  response = password.toUtf8().toBase64();
471  phase = Done;
472  }
473  break;
475  break;
477  methodString = "Digest ";
478  response = digestMd5Response(challenge, requestMethod, path);
479  phase = Done;
480  break;
482  methodString = "NTLM ";
483  if (challenge.isEmpty()) {
484  response = qNtlmPhase1().toBase64();
485  if (user.isEmpty())
486  phase = Done;
487  else
488  phase = Phase2;
489  } else {
491  phase = Done;
492  }
493 
494  break;
495  }
496  return QByteArray(methodString) + response;
497 }
498 
499 
500 // ---------------------------- Digest Md5 code ----------------------------------------
501 
503 {
505  // parse the challenge
506  const char *d = challenge.constData();
507  const char *end = d + challenge.length();
508  while (d < end) {
509  while (d < end && (*d == ' ' || *d == '\n' || *d == '\r'))
510  ++d;
511  const char *start = d;
512  while (d < end && *d != '=')
513  ++d;
514  QByteArray key = QByteArray(start, d - start);
515  ++d;
516  if (d >= end)
517  break;
518  bool quote = (*d == '"');
519  if (quote)
520  ++d;
521  if (d >= end)
522  break;
523  start = d;
524  QByteArray value;
525  while (d < end) {
526  bool backslash = false;
527  if (*d == '\\' && d < end - 1) {
528  ++d;
529  backslash = true;
530  }
531  if (!backslash) {
532  if (quote) {
533  if (*d == '"')
534  break;
535  } else {
536  if (*d == ',')
537  break;
538  }
539  }
540  value += *d;
541  ++d;
542  }
543  while (d < end && *d != ',')
544  ++d;
545  ++d;
546  options[key] = value;
547  }
548 
549  QByteArray qop = options.value("qop");
550  if (!qop.isEmpty()) {
551  QList<QByteArray> qopoptions = qop.split(',');
552  if (!qopoptions.contains("auth"))
554  // #### can't do auth-int currently
555 // if (qop.contains("auth-int"))
556 // qop = "auth-int";
557 // else if (qop.contains("auth"))
558 // qop = "auth";
559 // else
560 // qop = QByteArray();
561  options["qop"] = "auth";
562  }
563 
564  return options;
565 }
566 
567 /*
568  Digest MD5 implementation
569 
570  Code taken from RFC 2617
571 
572  Currently we don't support the full SASL authentication mechanism (which includes cyphers)
573 */
574 
575 
576 /* calculate request-digest/response-digest as per HTTP Digest spec */
578  const QByteArray &alg,
579  const QByteArray &userName,
580  const QByteArray &realm,
581  const QByteArray &password,
582  const QByteArray &nonce, /* nonce from server */
583  const QByteArray &nonceCount, /* 8 hex digits */
584  const QByteArray &cNonce, /* client nonce */
585  const QByteArray &qop, /* qop-value: "", "auth", "auth-int" */
586  const QByteArray &method, /* method from the request */
587  const QByteArray &digestUri, /* requested URL */
588  const QByteArray &hEntity /* H(entity body) if qop="auth-int" */
589  )
590 {
592  hash.addData(userName);
593  hash.addData(":", 1);
594  hash.addData(realm);
595  hash.addData(":", 1);
596  hash.addData(password);
597  QByteArray ha1 = hash.result();
598  if (alg.toLower() == "md5-sess") {
599  hash.reset();
600  // RFC 2617 contains an error, it was:
601  // hash.addData(ha1);
602  // but according to the errata page at http://www.rfc-editor.org/errata_list.php, ID 1649, it
603  // must be the following line:
604  hash.addData(ha1.toHex());
605  hash.addData(":", 1);
606  hash.addData(nonce);
607  hash.addData(":", 1);
608  hash.addData(cNonce);
609  ha1 = hash.result();
610  };
611  ha1 = ha1.toHex();
612 
613  // calculate H(A2)
614  hash.reset();
615  hash.addData(method);
616  hash.addData(":", 1);
617  hash.addData(digestUri);
618  if (qop.toLower() == "auth-int") {
619  hash.addData(":", 1);
620  hash.addData(hEntity);
621  }
622  QByteArray ha2hex = hash.result().toHex();
623 
624  // calculate response
625  hash.reset();
626  hash.addData(ha1);
627  hash.addData(":", 1);
628  hash.addData(nonce);
629  hash.addData(":", 1);
630  if (!qop.isNull()) {
631  hash.addData(nonceCount);
632  hash.addData(":", 1);
633  hash.addData(cNonce);
634  hash.addData(":", 1);
635  hash.addData(qop);
636  hash.addData(":", 1);
637  }
638  hash.addData(ha2hex);
639  return hash.result().toHex();
640 }
641 
643 {
645 
646  ++nonceCount;
647  QByteArray nonceCountString = QByteArray::number(nonceCount, 16);
648  while (nonceCountString.length() < 8)
649  nonceCountString.prepend('0');
650 
651  QByteArray nonce = options.value("nonce");
652  QByteArray opaque = options.value("opaque");
653  QByteArray qop = options.value("qop");
654 
655 // qDebug() << "calculating digest: method=" << method << "path=" << path;
656  QByteArray response = digestMd5ResponseHelper(options.value("algorithm"), user.toLatin1(),
658  nonce, nonceCountString,
659  cnonce, qop, method,
660  path, QByteArray());
661 
662 
663  QByteArray credentials;
664  credentials += "username=\"" + user.toLatin1() + "\", ";
665  credentials += "realm=\"" + realm.toLatin1() + "\", ";
666  credentials += "nonce=\"" + nonce + "\", ";
667  credentials += "uri=\"" + path + "\", ";
668  if (!opaque.isEmpty())
669  credentials += "opaque=\"" + opaque + "\", ";
670  credentials += "response=\"" + response + '\"';
671  if (!options.value("algorithm").isEmpty())
672  credentials += ", algorithm=" + options.value("algorithm");
673  if (!options.value("qop").isEmpty()) {
674  credentials += ", qop=" + qop + ", ";
675  credentials += "nc=" + nonceCountString + ", ";
676  credentials += "cnonce=\"" + cnonce + '\"';
677  }
678 
679  return credentials;
680 }
681 
682 // ---------------------------- Digest Md5 code ----------------------------------------
683 
684 
685 
686 /*
687  * NTLM message flags.
688  *
689  * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
690  *
691  * This software is released under the MIT license.
692  */
693 
694 /*
695  * Indicates that Unicode strings are supported for use in security
696  * buffer data.
697  */
698 #define NTLMSSP_NEGOTIATE_UNICODE 0x00000001
699 
700 /*
701  * Indicates that OEM strings are supported for use in security buffer data.
702  */
703 #define NTLMSSP_NEGOTIATE_OEM 0x00000002
704 
705 /*
706  * Requests that the server's authentication realm be included in the
707  * Type 2 message.
708  */
709 #define NTLMSSP_REQUEST_TARGET 0x00000004
710 
711 /*
712  * Specifies that authenticated communication between the client and server
713  * should carry a digital signature (message integrity).
714  */
715 #define NTLMSSP_NEGOTIATE_SIGN 0x00000010
716 
717 /*
718  * Specifies that authenticated communication between the client and server
719  * should be encrypted (message confidentiality).
720  */
721 #define NTLMSSP_NEGOTIATE_SEAL 0x00000020
722 
723 /*
724  * Indicates that datagram authentication is being used.
725  */
726 #define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040
727 
728 /*
729  * Indicates that the LAN Manager session key should be
730  * used for signing and sealing authenticated communications.
731  */
732 #define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080
733 
734 /*
735  * Indicates that NTLM authentication is being used.
736  */
737 #define NTLMSSP_NEGOTIATE_NTLM 0x00000200
738 
739 /*
740  * Sent by the client in the Type 1 message to indicate that the name of the
741  * domain in which the client workstation has membership is included in the
742  * message. This is used by the server to determine whether the client is
743  * eligible for local authentication.
744  */
745 #define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000
746 
747 /*
748  * Sent by the client in the Type 1 message to indicate that the client
749  * workstation's name is included in the message. This is used by the server
750  * to determine whether the client is eligible for local authentication.
751  */
752 #define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000
753 
754 /*
755  * Sent by the server to indicate that the server and client are on the same
756  * machine. Implies that the client may use the established local credentials
757  * for authentication instead of calculating a response to the challenge.
758  */
759 #define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x00004000
760 
761 /*
762  * Indicates that authenticated communication between the client and server
763  * should be signed with a "dummy" signature.
764  */
765 #define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
766 
767 /*
768  * Sent by the server in the Type 2 message to indicate that the target
769  * authentication realm is a domain.
770  */
771 #define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000
772 
773 /*
774  * Sent by the server in the Type 2 message to indicate that the target
775  * authentication realm is a server.
776  */
777 #define NTLMSSP_TARGET_TYPE_SERVER 0x00020000
778 
779 /*
780  * Sent by the server in the Type 2 message to indicate that the target
781  * authentication realm is a share. Presumably, this is for share-level
782  * authentication. Usage is unclear.
783  */
784 #define NTLMSSP_TARGET_TYPE_SHARE 0x00040000
785 
786 /*
787  * Indicates that the NTLM2 signing and sealing scheme should be used for
788  * protecting authenticated communications. Note that this refers to a
789  * particular session security scheme, and is not related to the use of
790  * NTLMv2 authentication.
791  */
792 #define NTLMSSP_NEGOTIATE_NTLM2 0x00080000
793 
794 /*
795  * Sent by the server in the Type 2 message to indicate that it is including
796  * a Target Information block in the message. The Target Information block
797  * is used in the calculation of the NTLMv2 response.
798  */
799 #define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000
800 
801 /*
802  * Indicates that 128-bit encryption is supported.
803  */
804 #define NTLMSSP_NEGOTIATE_128 0x20000000
805 
806 /*
807  * Indicates that the client will provide an encrypted master session key in
808  * the "Session Key" field of the Type 3 message. This is used in signing and
809  * sealing, and is RC4-encrypted using the previous session key as the
810  * encryption key.
811  */
812 #define NTLMSSP_NEGOTIATE_KEY_EXCHANGE 0x40000000
813 
814 /*
815  * Indicates that 56-bit encryption is supported.
816  */
817 #define NTLMSSP_NEGOTIATE_56 0x80000000
818 
819 /*
820  * AvId values
821  */
822 #define AVTIMESTAMP 7
823 
824 //#define NTLMV1_CLIENT
825 
826 
827 //************************Global variables***************************
828 
829 const int blockSize = 64; //As per RFC2104 Block-size is 512 bits
830 const int nDigestLen = 16; //Trunctaion Length of the Hmac-Md5 digest
831 const quint8 respversion = 1;
833 
834 /* usage:
835  // fill up ctx with what we know.
836  QByteArray response = qNtlmPhase1(ctx);
837  // send response (b64 encoded??)
838  // get response from server (b64 decode?)
839  Phase2Block pb;
840  qNtlmDecodePhase2(response, pb);
841  response = qNtlmPhase3(ctx, pb);
842  // send response (b64 encoded??)
843 */
844 
845 /*
846  TODO:
847  - Fix unicode handling
848  - add v2 handling
849 */
850 
851 class QNtlmBuffer {
852 public:
853  QNtlmBuffer() : len(0), maxLen(0), offset(0) {}
857  enum { Size = 8 };
858 };
859 
861 {
862 public:
863  char magic[8];
868  enum { Size = 32 };
869 };
870 
871 // ################# check paddings
873 {
874 public:
875  char magic[8];
879  unsigned char challenge[8];
880  quint32 context[2];
882  enum { Size = 48 };
883 };
884 
886 public:
887  char magic[8];
896  enum { Size = 64 };
897 };
898 
899 static void qStreamNtlmBuffer(QDataStream& ds, const QByteArray& s)
900 {
901  ds.writeRawData(s.constData(), s.size());
902 }
903 
904 
905 static void qStreamNtlmString(QDataStream& ds, const QString& s, bool unicode)
906 {
907  if (!unicode) {
908  qStreamNtlmBuffer(ds, s.toLatin1());
909  return;
910  }
911  const ushort *d = s.utf16();
912  for (int i = 0; i < s.length(); ++i)
913  ds << d[i];
914 }
915 
916 
917 
918 static int qEncodeNtlmBuffer(QNtlmBuffer& buf, int offset, const QByteArray& s)
919 {
920  buf.len = s.size();
921  buf.maxLen = buf.len;
922  buf.offset = (offset + 1) & ~1;
923  return buf.offset + buf.len;
924 }
925 
926 
927 static int qEncodeNtlmString(QNtlmBuffer& buf, int offset, const QString& s, bool unicode)
928 {
929  if (!unicode)
930  return qEncodeNtlmBuffer(buf, offset, s.toLatin1());
931  buf.len = 2 * s.length();
932  buf.maxLen = buf.len;
933  buf.offset = (offset + 1) & ~1;
934  return buf.offset + buf.len;
935 }
936 
937 
939 {
940  s << b.len << b.maxLen << b.offset;
941  return s;
942 }
943 
945 {
946  s >> b.len >> b.maxLen >> b.offset;
947  return s;
948 }
949 
950 
952 { // request
953 public:
955  qstrncpy(magic, "NTLMSSP", 8);
956  type = 1;
958  }
959 
960  // extracted
962 };
963 
964 
966 { // challenge
967 public:
969  magic[0] = 0;
970  type = 0xffffffff;
971  }
972 
973  // extracted
974  QString targetNameStr, targetInfoStr;
976 };
977 
978 
979 
980 class QNtlmPhase3Block : public QNtlmPhase3BlockBase { // response
981 public:
983  qstrncpy(magic, "NTLMSSP", 8);
984  type = 3;
986  }
987 
988  // extracted
989  QByteArray lmResponseBuf, ntlmResponseBuf;
990  QString domainStr, userStr, workstationStr, sessionKeyStr;
992 };
993 
994 
996  bool unicode = (b.flags & NTLMSSP_NEGOTIATE_UNICODE);
997 
998  s.writeRawData(b.magic, sizeof(b.magic));
999  s << b.type;
1000  s << b.flags;
1001  s << b.domain;
1002  s << b.workstation;
1003  if (!b.domainStr.isEmpty())
1004  qStreamNtlmString(s, b.domainStr, unicode);
1005  if (!b.workstationStr.isEmpty())
1006  qStreamNtlmString(s, b.workstationStr, unicode);
1007  return s;
1008 }
1009 
1010 
1012  bool unicode = (b.flags & NTLMSSP_NEGOTIATE_UNICODE);
1013  s.writeRawData(b.magic, sizeof(b.magic));
1014  s << b.type;
1015  s << b.lmResponse;
1016  s << b.ntlmResponse;
1017  s << b.domain;
1018  s << b.user;
1019  s << b.workstation;
1020  s << b.sessionKey;
1021  s << b.flags;
1022 
1023  if (!b.domainStr.isEmpty())
1024  qStreamNtlmString(s, b.domainStr, unicode);
1025 
1026  qStreamNtlmString(s, b.userStr, unicode);
1027 
1028  if (!b.workstationStr.isEmpty())
1029  qStreamNtlmString(s, b.workstationStr, unicode);
1030 
1031  // Send auth info
1034 
1035 
1036  return s;
1037 }
1038 
1039 
1041 {
1042  QByteArray rc;
1045  QNtlmPhase1Block pb;
1046  ds << pb;
1047  return rc;
1048 }
1049 
1050 
1052 {
1053  QByteArray rc(2*src.length(), 0);
1054  const unsigned short *s = src.utf16();
1055  unsigned short *d = (unsigned short*)rc.data();
1056  for (int i = 0; i < src.length(); ++i) {
1057  d[i] = qToLittleEndian(s[i]);
1058  }
1059  return rc;
1060 }
1061 
1062 
1064 {
1065  Q_ASSERT(src.size() % 2 == 0);
1066  unsigned short *d = (unsigned short*)src.data();
1067  for (int i = 0; i < src.length() / 2; ++i) {
1068  d[i] = qFromLittleEndian(d[i]);
1069  }
1070  return QString((const QChar *)src.data(), src.size()/2);
1071 }
1072 
1073 #ifdef NTLMV1_CLIENT
1074 static QByteArray qEncodeNtlmResponse(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block& ch)
1075 {
1077  QByteArray asUcs2Le = qStringAsUcs2Le(ctx->password);
1078  md4.addData(asUcs2Le.data(), asUcs2Le.size());
1079 
1080  unsigned char md4hash[22];
1081  memset(md4hash, 0, sizeof(md4hash));
1082  QByteArray hash = md4.result();
1083  Q_ASSERT(hash.size() == 16);
1084  memcpy(md4hash, hash.constData(), 16);
1085 
1086  QByteArray rc(24, 0);
1087  deshash((unsigned char *)rc.data(), md4hash, (unsigned char *)ch.challenge);
1088  deshash((unsigned char *)rc.data() + 8, md4hash + 7, (unsigned char *)ch.challenge);
1089  deshash((unsigned char *)rc.data() + 16, md4hash + 14, (unsigned char *)ch.challenge);
1090 
1091  hash.fill(0);
1092  return rc;
1093 }
1094 
1095 
1096 static QByteArray qEncodeLmResponse(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block& ch)
1097 {
1098  QByteArray hash(21, 0);
1099  QByteArray key(14, 0);
1100  qstrncpy(key.data(), ctx->password.toUpper().toLatin1(), 14);
1101  const char *block = "KGS!@#$%";
1102 
1103  deshash((unsigned char *)hash.data(), (unsigned char *)key.data(), (unsigned char *)block);
1104  deshash((unsigned char *)hash.data() + 8, (unsigned char *)key.data() + 7, (unsigned char *)block);
1105  key.fill(0);
1106 
1107  QByteArray rc(24, 0);
1108  deshash((unsigned char *)rc.data(), (unsigned char *)hash.data(), ch.challenge);
1109  deshash((unsigned char *)rc.data() + 8, (unsigned char *)hash.data() + 7, ch.challenge);
1110  deshash((unsigned char *)rc.data() + 16, (unsigned char *)hash.data() + 14, ch.challenge);
1111 
1112  hash.fill(0);
1113  return rc;
1114 }
1115 #endif
1116 
1117 /*********************************************************************
1118 * Function Name: qEncodeHmacMd5
1119 * Params:
1120 * key: Type - QByteArray
1121 * - It is the Authentication key
1122 * message: Type - QByteArray
1123 * - This is the actual message which will be encoded
1124 * using HMacMd5 hash algorithm
1125 *
1126 * Return Value:
1127 * hmacDigest: Type - QByteArray
1128 *
1129 * Description:
1130 * This function will be used to encode the input message using
1131 * HMacMd5 hash algorithm.
1132 *
1133 * As per the RFC2104 the HMacMd5 algorithm can be specified
1134 * ---------------------------------------
1135 * MD5(K XOR opad, MD5(K XOR ipad, text))
1136 * ---------------------------------------
1137 *
1138 *********************************************************************/
1140 {
1141  Q_ASSERT_X(!(message.isEmpty()),"qEncodeHmacMd5", "Empty message check");
1142  Q_ASSERT_X(!(key.isEmpty()),"qEncodeHmacMd5", "Empty key check");
1143 
1145  QByteArray hMsg;
1146 
1147  QByteArray iKeyPad(blockSize, 0x36);
1148  QByteArray oKeyPad(blockSize, 0x5c);
1149 
1150  hash.reset();
1151  // Adjust the key length to blockSize
1152 
1153  if(blockSize < key.length()) {
1154  hash.addData(key);
1155  key = hash.result(); //MD5 will always return 16 bytes length output
1156  }
1157 
1158  //Key will be <= 16 or 20 bytes as hash function (MD5 or SHA hash algorithms)
1159  //key size can be max of Block size only
1160  key = key.leftJustified(blockSize,0,true);
1161 
1162  //iKeyPad, oKeyPad and key are all of same size "blockSize"
1163 
1164  //xor of iKeyPad with Key and store the result into iKeyPad
1165  for(int i = 0; i<key.size();i++) {
1166  iKeyPad[i] = key[i]^iKeyPad[i];
1167  }
1168 
1169  //xor of oKeyPad with Key and store the result into oKeyPad
1170  for(int i = 0; i<key.size();i++) {
1171  oKeyPad[i] = key[i]^oKeyPad[i];
1172  }
1173 
1174  iKeyPad.append(message); // (K0 xor ipad) || text
1175 
1176  hash.reset();
1177  hash.addData(iKeyPad);
1178  hMsg = hash.result();
1179  //Digest gen after pass-1: H((K0 xor ipad)||text)
1180 
1181  QByteArray hmacDigest;
1182  oKeyPad.append(hMsg);
1183  hash.reset();
1184  hash.addData(oKeyPad);
1185  hmacDigest = hash.result();
1186  // H((K0 xor opad )|| H((K0 xor ipad) || text))
1187 
1188  /*hmacDigest should not be less than half the length of the HMAC output
1189  (to match the birthday attack bound) and not less than 80 bits
1190  (a suitable lower bound on the number of bits that need to be
1191  predicted by an attacker).
1192  Refer RFC 2104 for more details on truncation part */
1193 
1194  /*MD5 hash always returns 16 byte digest only and HMAC-MD5 spec
1195  (RFC 2104) also says digest length should be 16 bytes*/
1196  return hmacDigest;
1197 }
1198 
1200  QNtlmPhase3Block *phase3)
1201 {
1202  Q_ASSERT(phase3 != 0);
1203  // since v2 Hash is need for both NTLMv2 and LMv2 it is calculated
1204  // only once and stored and reused
1205  if(phase3->v2Hash.size() == 0) {
1207  QByteArray passUnicode = qStringAsUcs2Le(ctx->password);
1208  md4.addData(passUnicode.data(), passUnicode.size());
1209 
1210  QByteArray hashKey = md4.result();
1211  Q_ASSERT(hashKey.size() == 16);
1212  // Assuming the user and domain is always unicode in challenge
1213  QByteArray message =
1215  qStringAsUcs2Le(phase3->domainStr);
1216 
1217  phase3->v2Hash = qEncodeHmacMd5(hashKey, message);
1218  }
1219  return phase3->v2Hash;
1220 }
1221 
1223 {
1224  Q_ASSERT(ctx->cnonce.size() >= 8);
1225  QByteArray clientCh = ctx->cnonce.right(8);
1226  return clientCh;
1227 }
1228 
1229 // caller has to ensure a valid targetInfoBuff
1230 static QByteArray qExtractServerTime(const QByteArray& targetInfoBuff)
1231 {
1232  QByteArray timeArray;
1233  QDataStream ds(targetInfoBuff);
1235 
1236  quint16 avId;
1237  quint16 avLen;
1238 
1239  ds >> avId;
1240  ds >> avLen;
1241  while(avId != 0) {
1242  if(avId == AVTIMESTAMP) {
1243  timeArray.resize(avLen);
1244  //avLen size of QByteArray is allocated
1245  ds.readRawData(timeArray.data(), avLen);
1246  break;
1247  }
1248  ds.skipRawData(avLen);
1249  ds >> avId;
1250  ds >> avLen;
1251  }
1252  return timeArray;
1253 }
1254 
1256  const QNtlmPhase2Block& ch,
1257  QNtlmPhase3Block *phase3)
1258 {
1259  Q_ASSERT(phase3 != 0);
1260  // return value stored in phase3
1261  qCreatev2Hash(ctx, phase3);
1262 
1263  QByteArray temp;
1264  QDataStream ds(&temp, QIODevice::WriteOnly);
1266 
1267  ds << respversion;
1268  ds << hirespversion;
1269 
1270  //Reserved
1271  QByteArray reserved1(6, 0);
1272  ds.writeRawData(reserved1.constData(), reserved1.size());
1273 
1274  quint64 time = 0;
1275  QByteArray timeArray;
1276 
1277  if(ch.targetInfo.len)
1278  {
1279  timeArray = qExtractServerTime(ch.targetInfoBuff);
1280  }
1281 
1282  //if server sends time, use it instead of current time
1283  if(timeArray.size()) {
1284  ds.writeRawData(timeArray.constData(), timeArray.size());
1285  } else {
1286  QDateTime currentTime(QDate::currentDate(),
1288 
1289  // number of seconds between 1601 and epoc(1970)
1290  // 369 years, 89 leap years
1291  // ((369 * 365) + 89) * 24 * 3600 = 11644473600
1292 
1293  time = Q_UINT64_C(currentTime.toTime_t() + 11644473600);
1294 
1295  // represented as 100 nano seconds
1296  time = Q_UINT64_C(time * 10000000);
1297  ds << time;
1298  }
1299 
1300  //8 byte client challenge
1301  QByteArray clientCh = clientChallenge(ctx);
1302  ds.writeRawData(clientCh.constData(), clientCh.size());
1303 
1304  //Reserved
1305  QByteArray reserved2(4, 0);
1306  ds.writeRawData(reserved2.constData(), reserved2.size());
1307 
1308  if (ch.targetInfo.len > 0) {
1310  ch.targetInfoBuff.size());
1311  }
1312 
1313  //Reserved
1314  QByteArray reserved3(4, 0);
1315  ds.writeRawData(reserved3.constData(), reserved3.size());
1316 
1317  QByteArray message((const char*)ch.challenge, sizeof(ch.challenge));
1318  message.append(temp);
1319 
1320  QByteArray ntChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message);
1321  ntChallengeResp.append(temp);
1322 
1323  return ntChallengeResp;
1324 }
1325 
1327  const QNtlmPhase2Block& ch,
1328  QNtlmPhase3Block *phase3)
1329 {
1330  Q_ASSERT(phase3 != 0);
1331  // return value stored in phase3
1332  qCreatev2Hash(ctx, phase3);
1333 
1334  QByteArray message((const char*)ch.challenge, sizeof(ch.challenge));
1335  QByteArray clientCh = clientChallenge(ctx);
1336 
1337  message.append(clientCh);
1338 
1339  QByteArray lmChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message);
1340  lmChallengeResp.append(clientCh);
1341 
1342  return lmChallengeResp;
1343 }
1344 
1346 {
1348  if (data.size() < QNtlmPhase2BlockBase::Size)
1349  return false;
1350 
1351 
1352  QDataStream ds(data);
1354  if (ds.readRawData(ch.magic, 8) < 8)
1355  return false;
1356  if (strncmp(ch.magic, "NTLMSSP", 8) != 0)
1357  return false;
1358 
1359  ds >> ch.type;
1360  if (ch.type != 2)
1361  return false;
1362 
1363  ds >> ch.targetName;
1364  ds >> ch.flags;
1365  if (ds.readRawData((char *)ch.challenge, 8) < 8)
1366  return false;
1367  ds >> ch.context[0] >> ch.context[1];
1368  ds >> ch.targetInfo;
1369 
1370  if (ch.targetName.len > 0) {
1371  if (ch.targetName.len + ch.targetName.offset >= (unsigned)data.size())
1372  return false;
1373 
1375  }
1376 
1377  if (ch.targetInfo.len > 0) {
1378  if (ch.targetInfo.len + ch.targetInfo.offset > (unsigned)data.size())
1379  return false;
1380 
1381  ch.targetInfoBuff = data.mid(ch.targetInfo.offset, ch.targetInfo.len);
1382  }
1383 
1384  return true;
1385 }
1386 
1387 
1389 {
1390  QNtlmPhase2Block ch;
1391  if (!qNtlmDecodePhase2(phase2data, ch))
1392  return QByteArray();
1393 
1394  QByteArray rc;
1397  QNtlmPhase3Block pb;
1398 
1399  bool unicode = ch.flags & NTLMSSP_NEGOTIATE_UNICODE;
1400 
1402  if (unicode)
1404  else
1406 
1407 
1408  int offset = QNtlmPhase3BlockBase::Size;
1410 
1411  // for kerberos style user@domain logins, NTLM domain string should be left empty
1412  if (ctx->userDomain.isEmpty() && !ctx->extractedUser.contains(QLatin1Char('@'))) {
1413  offset = qEncodeNtlmString(pb.domain, offset, ch.targetNameStr, unicode);
1414  pb.domainStr = ch.targetNameStr;
1415  } else {
1416  offset = qEncodeNtlmString(pb.domain, offset, ctx->userDomain, unicode);
1417  pb.domainStr = ctx->userDomain;
1418  }
1419 
1420  offset = qEncodeNtlmString(pb.user, offset, ctx->extractedUser, unicode);
1421  pb.userStr = ctx->extractedUser;
1422 
1423  offset = qEncodeNtlmString(pb.workstation, offset, ctx->workstation, unicode);
1424  pb.workstationStr = ctx->workstation;
1425 
1426  // Get LM response
1427 #ifdef NTLMV1_CLIENT
1428  pb.lmResponseBuf = qEncodeLmResponse(ctx, ch);
1429 #else
1430  if (ch.targetInfo.len > 0) {
1431  pb.lmResponseBuf = QByteArray();
1432  } else {
1433  pb.lmResponseBuf = qEncodeLmv2Response(ctx, ch, &pb);
1434  }
1435 #endif
1436  offset = qEncodeNtlmBuffer(pb.lmResponse, offset, pb.lmResponseBuf);
1437 
1438  // Get NTLM response
1439 #ifdef NTLMV1_CLIENT
1440  pb.ntlmResponseBuf = qEncodeNtlmResponse(ctx, ch);
1441 #else
1442  pb.ntlmResponseBuf = qEncodeNtlmv2Response(ctx, ch, &pb);
1443 #endif
1444  offset = qEncodeNtlmBuffer(pb.ntlmResponse, offset, pb.ntlmResponseBuf);
1445 
1446 
1447  // Encode and send
1448  ds << pb;
1449 
1450  return rc;
1451 }
1452 
1453 
1454 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
#define NTLMSSP_NEGOTIATE_TARGET_INFO
QBool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.h:904
double d
Definition: qnumeric_p.h:62
static uint hash(const uchar *p, int n)
Definition: qhash.cpp:68
const int blockSize
const unsigned char magic[QSXE_MAGIC_BYTES]
int type
Definition: qmetatype.cpp:239
QHash< QString, QVariant > QVariantHash
Definition: qvariant.h:445
QByteArray & fill(char c, int size=-1)
Sets every byte in the byte array to character ch.
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
static QByteArray digestMd5ResponseHelper(const QByteArray &alg, const QByteArray &userName, const QByteArray &realm, const QByteArray &password, const QByteArray &nonce, const QByteArray &nonceCount, const QByteArray &cNonce, const QByteArray &qop, const QByteArray &method, const QByteArray &digestUri, const QByteArray &hEntity)
#define it(className, varName)
QByteArray & append(char c)
Appends the character ch to this byte array.
#define NTLMSSP_NEGOTIATE_OEM
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
void parseHttpResponse(const QHttpResponseHeader &, bool isProxy)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
QString toUpper() const Q_REQUIRED_RESULT
Returns an uppercase copy of the string.
Definition: qstring.cpp:5483
T1 first
Definition: qpair.h:65
static void qStreamNtlmString(QDataStream &ds, const QString &s, bool unicode)
~QAuthenticator()
Destructs the object.
T2 second
Definition: qpair.h:66
uint toTime_t() const
Returns the datetime as the number of seconds that have passed since 1970-01-01T00:00:00, Coordinated Universal Time (Qt::UTC).
Definition: qdatetime.cpp:2505
const_iterator constBegin() const
Returns a const STL-style iterator pointing to the first item in the list.
Definition: qlist.h:269
static QByteArray qStringAsUcs2Le(const QString &src)
QByteArray qEncodeHmacMd5(QByteArray &key, const QByteArray &message)
bool operator==(const QAuthenticator &other) const
Returns true if this authenticator is identical to other; otherwise returns false.
QByteArray toLower() const
Returns a lowercase copy of the byte array.
static QString qStringFromUcs2Le(const QByteArray &src)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
QByteArray lmResponseBuf
unsigned char quint8
Definition: qglobal.h:934
QByteArray & prepend(char c)
Prepends the character ch to this byte array.
The QString class provides a Unicode character string.
Definition: qstring.h:83
Q_CORE_EXPORT int qrand()
void setUser(const QString &user)
Sets the user used for authentication.
QByteArray toHex() const
Returns a hex encoded copy of the byte array.
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
bool startsWith(const QByteArray &a) const
Returns true if this byte array starts with byte array ba; otherwise returns false.
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
const T value(const Key &key) const
Returns the value associated with the key.
Definition: qhash.h:606
QByteArray targetInfoBuff
const quint8 respversion
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition: qhash.h:753
const int nDigestLen
QByteArray right(int len) const
Returns a byte array that contains the rightmost len bytes of this byte array.
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
QList< QPair< QString, QString > > values() const
Returns all the entries in the header.
Definition: qhttp.cpp:852
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QBool contains(const T &t) const
Returns true if the list contains an occurrence of value; otherwise returns false.
Definition: qlist.h:880
QAuthenticator & operator=(const QAuthenticator &other)
Assigns the contents of other to this authenticator.
int readRawData(char *, int len)
Reads at most len bytes from the stream into s and returns the number of bytes read.
unsigned __int64 quint64
Definition: qglobal.h:943
QString left(int n) const Q_REQUIRED_RESULT
Returns a substring that contains the n leftmost characters of the string.
Definition: qstring.cpp:3664
static QDate currentDate()
Returns the current date, as reported by the system clock.
Definition: qdatetime.cpp:3115
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
static QByteArray qNtlmPhase1()
QByteArray trimmed() const
Returns a byte array that has whitespace removed from the start and the end.
QByteArray ntlmResponseBuf
QAuthenticatorPrivate * d
QByteArray leftJustified(int width, char fill=' ', bool truncate=false) const
Returns a byte array of size width that contains this byte array padded by the fill character...
unsigned short quint16
Definition: qglobal.h:936
#define NTLMSSP_NEGOTIATE_UNICODE
static const char * data(const QByteArray &arr)
int indexOf(QChar c, int from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.cpp:2838
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
static QByteArray clientChallenge(const QAuthenticatorPrivate *ctx)
void setByteOrder(ByteOrder)
Sets the serialization byte order to bo.
QByteArray toLatin1() const Q_REQUIRED_RESULT
Returns a Latin-1 representation of the string as a QByteArray.
Definition: qstring.cpp:3993
static QByteArray qCreatev2Hash(const QAuthenticatorPrivate *ctx, QNtlmPhase3Block *phase3)
friend class QAuthenticatorPrivate
quint16 values[128]
static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray &phase2data)
bool isNull() const
Returns true if this byte array is null; otherwise returns false.
QByteArray mid(int index, int len=-1) const
Returns a byte array containing len bytes from this byte array, starting at position pos...
const quint8 hirespversion
The QAuthenticator class provides an authentication object.
#define None
#define NTLMSSP_NEGOTIATE_NTLM
static QHash< QByteArray, QByteArray > parseDigestAuthenticationChallenge(const QByteArray &challenge)
QAuthenticator()
Constructs an empty authentication object.
int length() const
Same as size().
Definition: qbytearray.h:356
T & first()
Returns a reference to the first item in the list.
Definition: qlist.h:282
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
static QByteArray fromBase64(const QByteArray &base64)
Returns a decoded copy of the Base64 array base64.
QList< QByteArray > split(char sep) const
Splits the byte array into subarrays wherever sep occurs, and returns the list of those arrays...
#define AVTIMESTAMP
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
QVariant option(const QString &opt) const
Returns the value related to option opt if it was set by the server.
unsigned char challenge[8]
The QDateTime class provides date and time functions.
Definition: qdatetime.h:216
void clear()
Clears the contents of the string and makes it empty.
Definition: qstring.h:723
static QTime currentTime()
Returns the current time as reported by the system clock.
Definition: qdatetime.cpp:3125
unsigned short ushort
Definition: qglobal.h:995
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
bool isNull() const
Returns true if the authenticator is null.
void addData(const char *data, int length)
Adds the first length chars of data to the cryptographic hash.
static QDataStream & operator<<(QDataStream &s, const QNtlmBuffer &b)
#define ctx
Definition: qgl.cpp:6094
void setOption(const QString &opt, const QVariant &value)
Sets the outgoing option opt to value value.
static bool qNtlmDecodePhase2(const QByteArray &data, QNtlmPhase2Block &ch)
QString user() const
returns the user used for authentication.
Q_OUTOFLINE_TEMPLATE QPair< T1, T2 > qMakePair(const T1 &x, const T2 &y)
Definition: qpair.h:102
int key
static int qEncodeNtlmString(QNtlmBuffer &buf, int offset, const QString &s, bool unicode)
void resize(int size)
Sets the size of the byte array to size bytes.
unsigned int quint32
Definition: qglobal.h:938
QByteArray digestMd5Response(const QByteArray &challenge, const QByteArray &method, const QByteArray &path)
QVariantHash options() const
Returns all incoming options set in this QAuthenticator object by parsing the server reply...
QByteArray result() const
Returns the final hash value.
QByteArray toBase64() const
Returns a copy of the byte array, encoded as Base64.
QByteArray calculateResponse(const QByteArray &method, const QByteArray &path)
static int qEncodeNtlmBuffer(QNtlmBuffer &buf, int offset, const QByteArray &s)
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
static QByteArray qEncodeNtlmv2Response(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block &ch, QNtlmPhase3Block *phase3)
The QDataStream class provides serialization of binary data to a QIODevice.
Definition: qdatastream.h:71
void setPassword(const QString &password)
Sets the password used for authentication.
static QByteArray qEncodeLmv2Response(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block &ch, QNtlmPhase3Block *phase3)
QString password() const
returns the password used for authentication.
int skipRawData(int len)
Skips len bytes from the device.
#define Q_UINT64_C(c)
Definition: qglobal.h:941
static QDataStream & operator>>(QDataStream &s, QNtlmBuffer &b)
static QByteArray qExtractServerTime(const QByteArray &targetInfoBuff)
static void qStreamNtlmBuffer(QDataStream &ds, const QByteArray &s)
static const KeyPair *const end
#define NTLMSSP_REQUEST_TARGET
The QHttpResponseHeader class contains response header information for HTTP.
Definition: qhttp.h:119
T qToLittleEndian(T source)
Definition: qendian.h:341
static QByteArray number(int, int base=10)
Returns a byte array containing the string equivalent of the number n to base base (10 by default)...
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
int writeRawData(const char *, int len)
Writes len bytes from s to the stream.
static QByteArray hash(const QByteArray &data, Algorithm method)
Returns the hash of data using method.
Q_CORE_EXPORT char * qstrncpy(char *dst, const char *src, uint len)
QString realm() const
returns the realm requiring authentication.
T qFromLittleEndian(const uchar *src)
void reset()
Resets the object.
The QCryptographicHash class provides a way to generate cryptographic hashes.
QBool contains(char c) const
Returns true if the byte array contains the character ch; otherwise returns false.
Definition: qbytearray.h:525
The QList class is a template class that provides lists.
Definition: qdatastream.h:62
const_iterator constEnd() const
Returns a const STL-style iterator pointing to the imaginary item after the last item in the list...
Definition: qlist.h:272
const ushort * utf16() const
Returns the QString as a &#39;\0\&#39;-terminated array of unsigned shorts.
Definition: qstring.cpp:5290