Skip to content

Commit

Permalink
Implement XEP-0300: Use of Cryptographic Hash Functions in XMPP
Browse files Browse the repository at this point in the history
Parsing and serialization for XEP-0300
https://xmpp.org/extensions/xep-0300.html in version 1.0.
  • Loading branch information
lnjX committed Sep 5, 2022
1 parent a9dc491 commit 649d56d
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/xep.doc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Complete:
- \xep{0245, The /me Command} (v1.0)
- \xep{0249, Direct MUC Invitations} (v1.2)
- \xep{0280, Message Carbons}
- \xep{0300, Use of Cryptographic Hash Functions in XMPP} (v1.0)
- \xep{0308, Last Message Correction}
- \xep{0313, Message Archive Management} (v0.6)
- \xep{0319, Last User Interaction in Presence}
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ set(INSTALL_HEADER_FILES
base/QXmppFutureUtils_p.h
base/QXmppGeolocItem.h
base/QXmppGlobal.h
base/QXmppHash.h
base/QXmppHttpUploadIq.h
base/QXmppIbbIq.h
base/QXmppIq.h
Expand Down Expand Up @@ -157,6 +158,7 @@ set(SOURCE_FILES
base/QXmppEntityTimeIq.cpp
base/QXmppGeolocItem.cpp
base/QXmppGlobal.cpp
base/QXmppHash.cpp
base/QXmppHttpUploadIq.cpp
base/QXmppIbbIq.cpp
base/QXmppIq.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/base/QXmppConstants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ const char *ns_conference = "jabber:x:conference";
const char *ns_carbons = "urn:xmpp:carbons:2";
// XEP-0297: Stanza Forwarding
const char *ns_forwarding = "urn:xmpp:forward:0";
// XEP-0300: Use of Cryptographic Hash Functions in XMPP
const char *ns_hashes = "urn:xmpp:hashes:2";
// XEP-0308: Last Message Correction
const char *ns_message_correct = "urn:xmpp:message-correct:0";
// XEP-0313: Message Archive Management
Expand Down
2 changes: 2 additions & 0 deletions src/base/QXmppConstants_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ extern const char *ns_conference;
extern const char *ns_carbons;
// XEP-0297: Stanza Forwarding
extern const char *ns_forwarding;
// XEP-0300: Use of Cryptographic Hash Functions in XMPP
extern const char *ns_hashes;
// XEP-0308: Last Message Correction
extern const char *ns_message_correct;
// XEP-0313: Message Archive Management
Expand Down
222 changes: 222 additions & 0 deletions src/base/QXmppHash.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
// SPDX-FileCopyrightText: 2022 Linus Jahn <[email protected]>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

#include "QXmppHash.h"

#include "QXmppConstants_p.h"

#include <QDomElement>
#include <QXmlStreamWriter>

using namespace QXmpp;

///
/// \enum QXmpp::HashAlgorithm
///
/// One of the hash algorithms specified by the IANA registry or \xep{0300, Use
/// of Cryptographic Hash Functions in XMPP}.
///
/// \since QXmpp 1.5
///

static QString algorithmToString(HashAlgorithm algorithm)
{
switch (algorithm) {
case HashAlgorithm::Unknown:
return {};
case HashAlgorithm::Md2:
return QStringLiteral("md2");
case HashAlgorithm::Md5:
return QStringLiteral("md5");
case HashAlgorithm::Shake128:
return QStringLiteral("shake128");
case HashAlgorithm::Shake256:
return QStringLiteral("shake256");
case HashAlgorithm::Sha1:
return QStringLiteral("sha-1");
case HashAlgorithm::Sha224:
return QStringLiteral("sha-224");
case HashAlgorithm::Sha256:
return QStringLiteral("sha-256");
case HashAlgorithm::Sha384:
return QStringLiteral("sha-384");
case HashAlgorithm::Sha512:
return QStringLiteral("sha-512");
case HashAlgorithm::Sha3_256:
return QStringLiteral("sha3-256");
case HashAlgorithm::Sha3_512:
return QStringLiteral("sha3-512");
case HashAlgorithm::Blake2b_256:
return QStringLiteral("blake2b-256");
case HashAlgorithm::Blake2b_512:
return QStringLiteral("blake2b-512");
}
Q_UNREACHABLE();
}

static HashAlgorithm hashAlgorithmFromString(const QString &str)
{
if (str == "md2") {
return HashAlgorithm::Md2;
}
if (str == "md5") {
return HashAlgorithm::Md5;
}
if (str == "shake128") {
return HashAlgorithm::Shake128;
}
if (str == "shake256") {
return HashAlgorithm::Shake256;
}
if (str == "sha-1") {
return HashAlgorithm::Sha1;
}
if (str == "sha-224") {
return HashAlgorithm::Sha224;
}
if (str == "sha-256") {
return HashAlgorithm::Sha256;
}
if (str == "sha-384") {
return HashAlgorithm::Sha384;
}
if (str == "sha-512") {
return HashAlgorithm::Sha512;
}
if (str == "sha3-256") {
return HashAlgorithm::Sha3_256;
}
if (str == "sha3-512") {
return HashAlgorithm::Sha3_512;
}
if (str == "blake2b-256") {
return HashAlgorithm::Blake2b_256;
}
if (str == "blake2b-512") {
return HashAlgorithm::Blake2b_512;
}
return HashAlgorithm::Unknown;
}

///
/// \class QXmppHash
///
/// Contains a hash value and its algorithm.
///
/// \since QXmpp 1.5
///

QXmppHash::QXmppHash() = default;

/// \cond
bool QXmppHash::parse(const QDomElement &el)
{
if (el.tagName() == "hash" && el.namespaceURI() == ns_hashes) {
m_algorithm = hashAlgorithmFromString(el.attribute("algo"));
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
if (auto hashResult = QByteArray::fromBase64Encoding(el.text().toUtf8())) {
m_hash = std::move(*hashResult);
} else {
return false;
}
#else
m_hash = QByteArray::fromBase64(el.text().toUtf8());
#endif
}
return false;
}

void QXmppHash::toXml(QXmlStreamWriter *writer) const
{
writer->writeDefaultNamespace(ns_hashes);
writer->writeStartElement("hash");
writer->writeAttribute("algo", algorithmToString(m_algorithm));
writer->writeCharacters(m_hash.toBase64());
writer->writeEndElement();
}
/// \endcond

///
/// \class QXmppHashUsed
///
/// Annotates the used hashing algorithm.
///
/// \since QXmpp 1.5
///

QXmppHashUsed::QXmppHashUsed() = default;

///
/// Creates an object that tells other XMPP entities to use this hash algorithm.
///
QXmppHashUsed::QXmppHashUsed(QXmpp::HashAlgorithm algorithm)
: m_algorithm(algorithm)
{
}

/// \cond
bool QXmppHashUsed::parse(const QDomElement &el)
{
if (el.tagName() == "hash-used" && el.namespaceURI() == ns_hashes) {
m_algorithm = hashAlgorithmFromString(el.attribute("algo"));
}
return false;
}

void QXmppHashUsed::toXml(QXmlStreamWriter *writer) const
{
writer->writeDefaultNamespace(ns_hashes);
writer->writeStartElement("hash-used");
writer->writeAttribute("algo", algorithmToString(m_algorithm));
writer->writeEndElement();
}
/// \endcond

///
/// Returns the algorithm used to create the hash.
///
HashAlgorithm QXmppHash::algorithm() const
{
return m_algorithm;
}

///
/// Sets the algorithm that was used to create the hashed data
///
void QXmppHash::setAlgorithm(QXmpp::HashAlgorithm algorithm)
{
m_algorithm = algorithm;
}

///
/// Returns the binary data of the hash.
///
QByteArray QXmppHash::hash() const
{
return m_hash;
}

///
/// Sets the hashed data.
///
void QXmppHash::setHash(const QByteArray &data)
{
m_hash = data;
}

///
/// Returns the algorithm that is supposed to be used for hashing.
///
HashAlgorithm QXmppHashUsed::algorithm() const
{
return m_algorithm;
}

///
/// Sets the algorithm that was used to create the hashed data
///
void QXmppHashUsed::setAlgorithm(QXmpp::HashAlgorithm algorithm)
{
m_algorithm = algorithm;
}
75 changes: 75 additions & 0 deletions src/base/QXmppHash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: 2022 Linus Jahn <[email protected]>
//
// SPDX-License-Identifier: LGPL-2.1-or-later

#ifndef QXMPPHASH_H
#define QXMPPHASH_H

#include "QXmppGlobal.h"

#include <QByteArray>

class QDomElement;
class QXmlStreamWriter;

namespace QXmpp {

enum class HashAlgorithm : uint32_t {
Unknown,
Md2,
Md5,
Shake128,
Shake256,
Sha1,
Sha224,
Sha256,
Sha384,
Sha512,
Sha3_256,
Sha3_512,
Blake2b_256,
Blake2b_512,
};

}

class QXMPP_EXPORT QXmppHash
{
public:
QXmppHash();

/// \cond
bool parse(const QDomElement &el);
void toXml(QXmlStreamWriter *writer) const;
/// \endcond

QXmpp::HashAlgorithm algorithm() const;
void setAlgorithm(QXmpp::HashAlgorithm algorithm);

QByteArray hash() const;
void setHash(const QByteArray &data);

private:
QXmpp::HashAlgorithm m_algorithm = QXmpp::HashAlgorithm::Unknown;
QByteArray m_hash;
};

class QXMPP_EXPORT QXmppHashUsed
{
public:
QXmppHashUsed();
QXmppHashUsed(QXmpp::HashAlgorithm algorithm);

/// \cond
bool parse(const QDomElement &el);
void toXml(QXmlStreamWriter *writer) const;
/// \endcond

QXmpp::HashAlgorithm algorithm() const;
void setAlgorithm(QXmpp::HashAlgorithm algorithm);

private:
QXmpp::HashAlgorithm m_algorithm = QXmpp::HashAlgorithm::Unknown;
};

#endif // QXMPPHASH_H

0 comments on commit 649d56d

Please sign in to comment.