Do not include any secret padding in the otpauth URI

The IETF draft-linuxgemini-otpauth-uri-02 recommends to not include the padding in Section 3.3.1.
cf. https://www.ietf.org/archive/id/draft-linuxgemini-otpauth-uri-02.html#section-3.3.1

(fixes issue #12540)

Signed-off-by: Sven Strickroth <email@cs-ware.de>
This commit is contained in:
Sven Strickroth 2025-11-09 20:24:47 +01:00
parent 44daca921a
commit c5c06ce665
5 changed files with 35 additions and 3 deletions

View file

@ -267,7 +267,7 @@ QByteArray Base32::removePadding(const QByteArray& encodedData)
return newEncodedData;
}
QByteArray Base32::sanitizeInput(const QByteArray& encodedData)
QByteArray Base32::sanitizeInput(const QByteArray& encodedData, bool withPadding /* = true */)
{
if (encodedData.size() <= 0) {
return encodedData;
@ -294,5 +294,8 @@ QByteArray Base32::sanitizeInput(const QByteArray& encodedData)
}
newEncodedData.resize(i);
if (!withPadding)
return removePadding(newEncodedData);
return addPadding(newEncodedData);
}

View file

@ -35,7 +35,7 @@ public:
Q_REQUIRED_RESULT static QByteArray encode(const QByteArray&);
Q_REQUIRED_RESULT static QByteArray addPadding(const QByteArray&);
Q_REQUIRED_RESULT static QByteArray removePadding(const QByteArray&);
Q_REQUIRED_RESULT static QByteArray sanitizeInput(const QByteArray&);
Q_REQUIRED_RESULT static QByteArray sanitizeInput(const QByteArray&, bool withPadding = true);
};
#endif // BASE32_H

View file

@ -180,7 +180,7 @@ QString Totp::writeSettings(const QSharedPointer<Totp::Settings>& settings,
auto urlstring = QString("otpauth://totp/%1:%2?secret=%3&period=%4&digits=%5&issuer=%1")
.arg(title.isEmpty() ? "KeePassXC" : QString(QUrl::toPercentEncoding(title)),
username.isEmpty() ? "none" : QString(QUrl::toPercentEncoding(username)),
QString(QUrl::toPercentEncoding(Base32::sanitizeInput(settings->key.toLatin1()))),
QString(QUrl::toPercentEncoding(Base32::sanitizeInput(settings->key.toLatin1(), !forceOtp))),
QString::number(settings->step),
QString::number(settings->digits));

View file

@ -107,6 +107,34 @@ void TestTotp::testParseSecret()
QVERIFY(settings.isNull());
}
void TestTotp::testTotpWriteSettings()
{
auto settings1 = Totp::createSettings("GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ", Totp::DEFAULT_DIGITS, Totp::DEFAULT_STEP);
QCOMPARE(
Totp::writeSettings(settings1, "ACME Co", "john", true),
"otpauth://totp/ACME%20Co:john?secret=GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ&period=30&digits=6&issuer=ACME%20Co");
auto settings2 = Totp::createSettings("63BEDWCQZKTQWPESARIERL5DTTQFCJTK", 3, 25);
QCOMPARE(
Totp::writeSettings(settings2, "ACME Co", "", true),
"otpauth://totp/ACME%20Co:none?secret=63BEDWCQZKTQWPESARIERL5DTTQFCJTK&period=25&digits=3&issuer=ACME%20Co");
auto settings3 = Totp::createSettings("HXDMVJECJJWSRBY", Totp::DEFAULT_DIGITS, Totp::DEFAULT_STEP);
QCOMPARE(
Totp::writeSettings(settings3, "", "john", true),
"otpauth://totp/KeePassXC:john?secret=HXDMVJECJJWSRBY&period=30&digits=6&issuer=KeePassXC");
auto settings4 = Totp::createSettings("HXDMVJECJJWSRBY=", Totp::DEFAULT_DIGITS, Totp::DEFAULT_STEP);
QCOMPARE(
Totp::writeSettings(settings4, "NoPadding", "john", true),
"otpauth://totp/NoPadding:john?secret=HXDMVJECJJWSRBY&period=30&digits=6&issuer=NoPadding");
auto settings5 = Totp::createSettings("HXDMVJECJJWSRBY=", Totp::DEFAULT_DIGITS, Totp::DEFAULT_STEP);
QCOMPARE(
Totp::writeSettings(settings5, "WithPadding", "john"),
"otpauth://totp/WithPadding:john?secret=HXDMVJECJJWSRBY%3D&period=30&digits=6&issuer=WithPadding");
}
void TestTotp::testTotpCode()
{
// Test vectors from RFC 6238

View file

@ -28,6 +28,7 @@ class TestTotp : public QObject
private slots:
void initTestCase();
void testParseSecret();
void testTotpWriteSettings();
void testTotpCode();
void testSteamTotp();
void testEntryHistory();