File indexing completed on 2024-05-12 13:54:24

0001 /*
0002  * SPDX-License-Identifier: GPL-3.0-or-later
0003  * SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com>
0004  */
0005 #ifndef OATH_H
0006 #define OATH_H
0007 
0008 #include <QByteArray>
0009 #include <QCryptographicHash>
0010 #include <QDateTime>
0011 #include <QSharedPointer>
0012 
0013 #include <functional>
0014 #include <optional>
0015 
0016 namespace oath
0017 {
0018     class Encoder
0019     {
0020     public:
0021         Encoder(uint tokenLength, bool addChecksum = false);
0022         virtual ~Encoder();
0023         virtual QString encode(quint32) const;
0024         uint tokenLength(void) const;
0025         bool checksum(void) const;
0026         static quint32 reduceMod10(quint32 value, uint tokenLength);
0027     private:
0028         Q_DISABLE_COPY_MOVE(Encoder)
0029     private:
0030         static constexpr const quint32 powerTable[10] = {
0031             1, 10, 100, 1'000, 10'000, 100'000, 1'000'000, 10'000'000, 100'000'000, 1'000'000'000
0032         };
0033         const uint m_tokenLength;
0034         const bool m_addChecksum;
0035     };
0036 
0037     class Algorithm
0038     {
0039     public:
0040         static bool validate(const Encoder *encoder);
0041         static bool validate(QCryptographicHash::Algorithm algorithm, const std::optional<uint> offset);
0042         static std::optional<Algorithm> create(QCryptographicHash::Algorithm algorithm, const std::optional<uint> offset, const QSharedPointer<const Encoder> &encoder, bool requireSaneKeyLength = false);
0043         static std::optional<Algorithm> totp(QCryptographicHash::Algorithm algorithm, uint tokenLength, bool requireSaneKeyLength = false);
0044         static std::optional<Algorithm> hotp(const std::optional<uint> offset, uint tokenLength, bool checksum, bool requireSaneKeyLength = false);
0045         std::optional<QString> compute(quint64 counter, char * secretBuffer, int length) const;
0046     private:
0047         Algorithm(const QSharedPointer<const Encoder> &encoder, const std::function<quint32(const QByteArray &)> &truncation, QCryptographicHash::Algorithm algorithm, bool requireSaneKeyLength);
0048     private:
0049         const QSharedPointer<const Encoder> m_encoder;
0050         const std::function<quint32(const QByteArray &)> m_truncation;
0051         bool m_enforceKeyLength;
0052         const QCryptographicHash::Algorithm m_algorithm;
0053     };
0054 
0055     uint luhnChecksum(quint32 value, uint digits);
0056     std::optional<quint64> count(const QDateTime &epoch, uint timeStep, const std::function<qint64(void)> &clock = &QDateTime::currentMSecsSinceEpoch);
0057     std::optional<QDateTime> fromCounter(quint64 count, const QDateTime &epoch, uint timeStep);
0058 }
0059 
0060 #endif