Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/totp
diff options
context:
space:
mode:
authorWeslly <weslly.honorato@gmail.com>2017-04-13 13:05:36 +0300
committerWeslly <weslly.honorato@gmail.com>2017-05-04 02:55:14 +0300
commitbf57a286545a5fce783c463d208c7ffce9c115ef (patch)
tree556908a0e052294273c6ef2d0e778f7dafacacdb /src/totp
parent7040bef27e105774da05ac372e0832d2affe008b (diff)
Add TOTP support
Diffstat (limited to 'src/totp')
-rw-r--r--src/totp/totp.cpp170
-rw-r--r--src/totp/totp.h34
2 files changed, 204 insertions, 0 deletions
diff --git a/src/totp/totp.cpp b/src/totp/totp.cpp
new file mode 100644
index 000000000..45e98d38d
--- /dev/null
+++ b/src/totp/totp.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2017 Weslly Honorato <weslly@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 or (at your option)
+ * version 3 of the License.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "totp.h"
+#include <cmath>
+#include <QtEndian>
+#include <QRegExp>
+#include <QDateTime>
+#include <QCryptographicHash>
+#include <QMessageAuthenticationCode>
+#include <QUrl>
+#include <QUrlQuery>
+
+
+const quint8 QTotp::defaultStep = 30;
+const quint8 QTotp::defaultDigits = 6;
+
+QTotp::QTotp()
+{
+}
+
+QString QTotp::parseOtpString(QString key, quint8 &digits, quint8 &step)
+{
+ QUrl url(key);
+
+ QString seed;
+ uint q_digits, q_step;
+
+ // Default OTP url format
+ if (url.isValid() && url.scheme() == "otpauth") {
+ QUrlQuery query(url);
+
+ seed = query.queryItemValue("secret");
+
+ q_digits = query.queryItemValue("digits").toUInt();
+ if (q_digits == 6 || q_digits == 8) {
+ digits = q_digits;
+ }
+
+ q_step = query.queryItemValue("period").toUInt();
+ if (q_step > 0 && q_step <= 60) {
+ step = q_step;
+ }
+
+
+ } else {
+ // Compatibility with "KeeOtp" plugin string format
+ QRegExp rx("key=(.+)", Qt::CaseInsensitive, QRegExp::RegExp);
+
+ if (rx.exactMatch(key)) {
+ QUrlQuery query(key);
+
+ seed = query.queryItemValue("key");
+ q_digits = query.queryItemValue("size").toUInt();
+ if (q_digits == 6 || q_digits == 8) {
+ digits = q_digits;
+ }
+
+ q_step = query.queryItemValue("step").toUInt();
+ if (q_step > 0 && q_step <= 60) {
+ step = q_step;
+ }
+
+ } else {
+ seed = key;
+ }
+ }
+
+ if (digits == 0) {
+ digits = defaultDigits;
+ }
+
+ if (step == 0) {
+ step = defaultStep;
+ }
+
+ return seed;
+}
+
+
+QByteArray QTotp::base32_decode(const QByteArray encoded)
+{
+ // Base32 implementation
+ // Copyright 2010 Google Inc.
+ // Author: Markus Gutschke
+ // Licensed under the Apache License, Version 2.0
+
+ QByteArray result;
+
+ int buffer = 0;
+ int bitsLeft = 0;
+
+ for (char ch : encoded) {
+ if (ch == 0 || ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-' || ch == '=') {
+ continue;
+ }
+
+ buffer <<= 5;
+
+ // Deal with commonly mistyped characters
+ if (ch == '0') {
+ ch = 'O';
+ } else if (ch == '1') {
+ ch = 'L';
+ } else if (ch == '8') {
+ ch = 'B';
+ }
+
+ // Look up one base32 digit
+ if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
+ ch = (ch & 0x1F) - 1;
+ } else if (ch >= '2' && ch <= '7') {
+ ch -= '2' - 26;
+ } else {
+ return QByteArray();
+ }
+
+ buffer |= ch;
+ bitsLeft += 5;
+
+ if (bitsLeft >= 8) {
+ result.append(static_cast<char> (buffer >> (bitsLeft - 8)));
+ bitsLeft -= 8;
+ }
+ }
+
+ return result;
+}
+
+
+QString QTotp::generateTotp(const QByteArray key, quint64 time, const quint8 numDigits = defaultDigits, const quint8 step = defaultStep)
+{
+ quint64 current = qToBigEndian(time / step);
+
+ QByteArray secret = QTotp::base32_decode(key);
+ if (secret.isEmpty()) {
+ return "Invalid TOTP secret key";
+ }
+
+ QMessageAuthenticationCode code(QCryptographicHash::Sha1);
+ code.setKey(secret);
+ code.addData(QByteArray(reinterpret_cast<char*>(&current), sizeof(current)));
+ QByteArray hmac = code.result();
+
+ int offset = (hmac[hmac.length() - 1] & 0xf);
+ int binary =
+ ((hmac[offset] & 0x7f) << 24)
+ | ((hmac[offset + 1] & 0xff) << 16)
+ | ((hmac[offset + 2] & 0xff) << 8)
+ | (hmac[offset + 3] & 0xff);
+
+ quint32 digitsPower = pow(10, numDigits);
+
+ quint64 password = binary % digitsPower;
+ return QString("%1").arg(password, numDigits, 10, QChar('0'));
+}
diff --git a/src/totp/totp.h b/src/totp/totp.h
new file mode 100644
index 000000000..8d7e86744
--- /dev/null
+++ b/src/totp/totp.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 Weslly Honorato <weslly@protonmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 or (at your option)
+ * version 3 of the License.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QTOTP_H
+#define QTOTP_H
+
+#include <QtCore/qglobal.h>
+
+class QTotp
+{
+public:
+ QTotp();
+ static QString parseOtpString(QString rawSecret, quint8 &digits, quint8 &step);
+ static QByteArray base32_decode(const QByteArray encoded);
+ static QString generateTotp(const QByteArray key, quint64 time, const quint8 numDigits, const quint8 step);
+ static const quint8 defaultStep;
+ static const quint8 defaultDigits;
+};
+
+#endif // QTOTP_H