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
diff options
context:
space:
mode:
Diffstat (limited to 'src/totp/totp.cpp')
-rw-r--r--src/totp/totp.cpp72
1 files changed, 61 insertions, 11 deletions
diff --git a/src/totp/totp.cpp b/src/totp/totp.cpp
index 7a584def2..f102335aa 100644
--- a/src/totp/totp.cpp
+++ b/src/totp/totp.cpp
@@ -28,14 +28,47 @@
#include <QtEndian>
#include <cmath>
-const quint8 QTotp::defaultStep = 30;
-const quint8 QTotp::defaultDigits = 6;
+const quint8 Totp::defaultStep = 30;
+const quint8 Totp::defaultDigits = 6;
-QTotp::QTotp()
+/**
+ * Custom encoder types. Each should be unique and >= 128 and < 255
+ * Values have no meaning outside of keepassxc
+ */
+/**
+ * Encoder for Steam Guard TOTP
+ */
+const quint8 Totp::ENCODER_STEAM = 254;
+
+const Totp::Encoder Totp::defaultEncoder = { "", "", "0123456789", 0, 0, false };
+const QMap<quint8, Totp::Encoder> Totp::encoders{
+ { Totp::ENCODER_STEAM, { "steam", "S", "23456789BCDFGHJKMNPQRTVWXY", 5, 30, true } },
+};
+
+/**
+ * These map the second field of the "TOTP Settings" field to our internal encoder number
+ * that overloads the digits field. Make sure that the key matches the shortName value
+ * in the corresponding Encoder
+ * NOTE: when updating this map, a corresponding edit to the settings regex must be made
+ * in Entry::totpSeed()
+ */
+const QMap<QString, quint8> Totp::shortNameToEncoder{
+ { "S", Totp::ENCODER_STEAM },
+};
+/**
+ * These map the "encoder=" URL parameter of the "otp" field to our internal encoder number
+ * that overloads the digits field. Make sure that the key matches the name value
+ * in the corresponding Encoder
+ */
+const QMap<QString, quint8> Totp::nameToEncoder{
+ { "steam", Totp::ENCODER_STEAM },
+};
+
+Totp::Totp()
{
}
-QString QTotp::parseOtpString(QString key, quint8& digits, quint8& step)
+QString Totp::parseOtpString(QString key, quint8& digits, quint8& step)
{
QUrl url(key);
@@ -57,7 +90,10 @@ QString QTotp::parseOtpString(QString key, quint8& digits, quint8& step)
if (q_step > 0 && q_step <= 60) {
step = q_step;
}
-
+ QString encName = query.queryItemValue("encoder");
+ if (!encName.isEmpty() && nameToEncoder.contains(encName)) {
+ digits = nameToEncoder[encName];
+ }
} else {
// Compatibility with "KeeOtp" plugin string format
QRegExp rx("key=(.+)", Qt::CaseInsensitive, QRegExp::RegExp);
@@ -92,7 +128,7 @@ QString QTotp::parseOtpString(QString key, quint8& digits, quint8& step)
return seed;
}
-QString QTotp::generateTotp(const QByteArray key,
+QString Totp::generateTotp(const QByteArray key,
quint64 time,
const quint8 numDigits = defaultDigits,
const quint8 step = defaultStep)
@@ -119,20 +155,34 @@ QString QTotp::generateTotp(const QByteArray key,
| (hmac[offset + 3] & 0xff);
// clang-format on
- quint32 digitsPower = pow(10, numDigits);
+ const Encoder& encoder = encoders.value(numDigits, defaultEncoder);
+ // if encoder.digits is 0, we need to use the passed-in number of digits (default encoder)
+ quint8 digits = encoder.digits == 0 ? numDigits : encoder.digits;
+ int direction = -1;
+ int startpos = digits - 1;
+ if (encoder.reverse) {
+ direction = 1;
+ startpos = 0;
+ }
+ quint32 digitsPower = pow(encoder.alphabet.size(), digits);
quint64 password = binary % digitsPower;
- return QString("%1").arg(password, numDigits, 10, QChar('0'));
+ QString retval(int(digits), encoder.alphabet[0]);
+ for (quint8 pos = startpos; password > 0; pos += direction) {
+ retval[pos] = encoder.alphabet[int(password % encoder.alphabet.size())];
+ password /= encoder.alphabet.size();
+ }
+ return retval;
}
// See: https://github.com/google/google-authenticator/wiki/Key-Uri-Format
-QUrl QTotp::generateOtpString(const QString& secret,
+QUrl Totp::generateOtpString(const QString& secret,
const QString& type,
const QString& issuer,
const QString& username,
const QString& algorithm,
- const quint8& digits,
- const quint8& step)
+ quint8 digits,
+ quint8 step)
{
QUrl keyUri;
keyUri.setScheme("otpauth");