aboutsummaryrefslogtreecommitdiff
path: root/src/base/QXmppSaslAuth.cpp
diff options
context:
space:
mode:
authorJeremy Lainé <jeremy.laine@m4x.org>2012-02-08 12:51:15 +0000
committerJeremy Lainé <jeremy.laine@m4x.org>2012-02-08 12:51:15 +0000
commitdeb9d6cb53057ca8b90d10d6a3bdc5dcfd1b3ee4 (patch)
treed956bad28e28aadc3c83dbf88b3eddb5e1d9a9f4 /src/base/QXmppSaslAuth.cpp
parente8a1ad0cc608f12874ba4bafbd8282fa537ec9fb (diff)
downloadqxmpp-deb9d6cb53057ca8b90d10d6a3bdc5dcfd1b3ee4.tar.gz
move files common to client/server into "base"
Diffstat (limited to 'src/base/QXmppSaslAuth.cpp')
-rw-r--r--src/base/QXmppSaslAuth.cpp214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/base/QXmppSaslAuth.cpp b/src/base/QXmppSaslAuth.cpp
new file mode 100644
index 00000000..a528cd6d
--- /dev/null
+++ b/src/base/QXmppSaslAuth.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2008-2011 The QXmpp developers
+ *
+ * Authors:
+ * Manjeet Dahiya
+ * Jeremy Lainé
+ *
+ * Source:
+ * http://code.google.com/p/qxmpp
+ *
+ * This file is a part of QXmpp library.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#include <cstdlib>
+
+#include <QCryptographicHash>
+
+#include "QXmppSaslAuth.h"
+#include "QXmppUtils.h"
+
+QByteArray QXmppSaslDigestMd5::authzid() const
+{
+ return m_authzid;
+}
+
+void QXmppSaslDigestMd5::setAuthzid(const QByteArray &authzid)
+{
+ m_authzid = authzid;
+}
+
+QByteArray QXmppSaslDigestMd5::cnonce() const
+{
+ return m_cnonce;
+}
+
+void QXmppSaslDigestMd5::setCnonce(const QByteArray &cnonce)
+{
+ m_cnonce = cnonce;
+}
+
+QByteArray QXmppSaslDigestMd5::digestUri() const
+{
+ return m_digestUri;
+}
+
+void QXmppSaslDigestMd5::setDigestUri(const QByteArray &digestUri)
+{
+ m_digestUri = digestUri;
+}
+
+QByteArray QXmppSaslDigestMd5::nc() const
+{
+ return m_nc;
+}
+
+void QXmppSaslDigestMd5::setNc(const QByteArray &nc)
+{
+ m_nc = nc;
+}
+
+QByteArray QXmppSaslDigestMd5::nonce() const
+{
+ return m_nonce;
+}
+
+void QXmppSaslDigestMd5::setNonce(const QByteArray &nonce)
+{
+ m_nonce = nonce;
+}
+
+QByteArray QXmppSaslDigestMd5::qop() const
+{
+ return m_qop;
+}
+
+void QXmppSaslDigestMd5::setQop(const QByteArray &qop)
+{
+ m_qop = qop;
+}
+
+void QXmppSaslDigestMd5::setSecret(const QByteArray &secret)
+{
+ m_secret = secret;
+}
+
+QByteArray QXmppSaslDigestMd5::generateNonce()
+{
+ QByteArray nonce = generateRandomBytes(32);
+
+ // The random data can the '=' char is not valid as it is a delimiter,
+ // so to be safe, base64 the nonce
+ return nonce.toBase64();
+}
+
+/// Calculate digest response for use with XMPP/SASL.
+///
+/// \param A2
+///
+
+QByteArray QXmppSaslDigestMd5::calculateDigest(const QByteArray &A2) const
+{
+ QByteArray ha1 = m_secret + ':' + m_nonce + ':' + m_cnonce;
+
+ if (!m_authzid.isEmpty())
+ ha1 += ':' + m_authzid;
+
+ return calculateDigest(ha1, A2);
+}
+
+/// Calculate generic digest response.
+///
+/// \param A1
+/// \param A2
+///
+
+QByteArray QXmppSaslDigestMd5::calculateDigest(const QByteArray &A1, const QByteArray &A2) const
+{
+ QByteArray HA1 = QCryptographicHash::hash(A1, QCryptographicHash::Md5).toHex();
+ QByteArray HA2 = QCryptographicHash::hash(A2, QCryptographicHash::Md5).toHex();
+ QByteArray KD;
+ if (m_qop == "auth" || m_qop == "auth-int")
+ KD = HA1 + ':' + m_nonce + ':' + m_nc + ':' + m_cnonce + ':' + m_qop + ':' + HA2;
+ else
+ KD = HA1 + ':' + m_nonce + ':' + HA2;
+ return QCryptographicHash::hash(KD, QCryptographicHash::Md5).toHex();
+}
+
+QMap<QByteArray, QByteArray> QXmppSaslDigestMd5::parseMessage(const QByteArray &ba)
+{
+ QMap<QByteArray, QByteArray> map;
+ int startIndex = 0;
+ int pos = 0;
+ while ((pos = ba.indexOf("=", startIndex)) >= 0)
+ {
+ // key get name and skip equals
+ const QByteArray key = ba.mid(startIndex, pos - startIndex).trimmed();
+ pos++;
+
+ // check whether string is quoted
+ if (ba.at(pos) == '"')
+ {
+ // skip opening quote
+ pos++;
+ int endPos = ba.indexOf('"', pos);
+ // skip quoted quotes
+ while (endPos >= 0 && ba.at(endPos - 1) == '\\')
+ endPos = ba.indexOf('"', endPos + 1);
+ if (endPos < 0)
+ {
+ qWarning("Unfinished quoted string");
+ return map;
+ }
+ // unquote
+ QByteArray value = ba.mid(pos, endPos - pos);
+ value.replace("\\\"", "\"");
+ value.replace("\\\\", "\\");
+ map[key] = value;
+ // skip closing quote and comma
+ startIndex = endPos + 2;
+ } else {
+ // non-quoted string
+ int endPos = ba.indexOf(',', pos);
+ if (endPos < 0)
+ endPos = ba.size();
+ map[key] = ba.mid(pos, endPos - pos);
+ // skip comma
+ startIndex = endPos + 1;
+ }
+ }
+ return map;
+}
+
+QByteArray QXmppSaslDigestMd5::serializeMessage(const QMap<QByteArray, QByteArray> &map)
+{
+ QByteArray ba;
+ foreach (const QByteArray &key, map.keys())
+ {
+ if (!ba.isEmpty())
+ ba.append(',');
+ ba.append(key + "=");
+ QByteArray value = map[key];
+ const char *separators = "()<>@,;:\\\"/[]?={} \t";
+ bool quote = false;
+ for (const char *c = separators; *c; c++)
+ {
+ if (value.contains(*c))
+ {
+ quote = true;
+ break;
+ }
+ }
+ if (quote)
+ {
+ value.replace("\\", "\\\\");
+ value.replace("\"", "\\\"");
+ ba.append("\"" + value + "\"");
+ }
+ else
+ ba.append(value);
+ }
+ return ba;
+}
+