From 8a19281f6d31c7d13a348609c8e211822acf173e Mon Sep 17 00:00:00 2001 From: varjolintu Date: Sun, 4 Feb 2024 11:18:18 +0200 Subject: [PATCH] Fix Base32 --- src/core/Base32.cpp | 9 ++-- src/core/Base32.h | 5 +- src/core/Entry.cpp | 6 +-- src/totp/totp.cpp | 8 +-- tests/TestBase32.cpp | 120 +++++++++++++++++++++---------------------- 5 files changed, 73 insertions(+), 75 deletions(-) diff --git a/src/core/Base32.cpp b/src/core/Base32.cpp index d0a148eec6..01ded4697c 100644 --- a/src/core/Base32.cpp +++ b/src/core/Base32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * 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 @@ -24,7 +24,6 @@ #include "Base32.h" #include -#include constexpr quint64 MASK_40BIT = quint64(0xF8) << 32; constexpr quint64 MASK_35BIT = quint64(0x7C0000000); @@ -43,10 +42,10 @@ constexpr quint8 ASCII_a = static_cast('a'); constexpr quint8 ASCII_z = static_cast('z'); constexpr quint8 ASCII_EQ = static_cast('='); -QVariant Base32::decode(const QByteArray& encodedData) +QByteArray Base32::decode(const QByteArray& encodedData) { if (encodedData.size() <= 0) { - return QVariant::fromValue(QByteArray("")); + return {}; } if (encodedData.size() % 8 != 0) { @@ -139,7 +138,7 @@ QVariant Base32::decode(const QByteArray& encodedData) Q_ASSERT(encodedData.size() == i); Q_ASSERT(nBytes == o); - return QVariant::fromValue(data); + return data; } QByteArray Base32::encode(const QByteArray& data) diff --git a/src/core/Base32.h b/src/core/Base32.h index 07b16a0cc7..5af9e444c4 100644 --- a/src/core/Base32.h +++ b/src/core/Base32.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * 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 @@ -25,13 +25,12 @@ #define BASE32_H #include -#include class Base32 { public: Base32() = default; - Q_REQUIRED_RESULT static QVariant decode(const QByteArray&); + Q_REQUIRED_RESULT static QByteArray decode(const QByteArray&); Q_REQUIRED_RESULT static QByteArray encode(const QByteArray&); Q_REQUIRED_RESULT static QByteArray addPadding(const QByteArray&); Q_REQUIRED_RESULT static QByteArray removePadding(const QByteArray&); diff --git a/src/core/Entry.cpp b/src/core/Entry.cpp index 1abbe93a66..a8b86033e3 100644 --- a/src/core/Entry.cpp +++ b/src/core/Entry.cpp @@ -1312,7 +1312,7 @@ Database* Entry::database() QString Entry::maskPasswordPlaceholders(const QString& str) const { QString result = str; - result.replace(QRegularExpression("(\\{PASSWORD\\})", QRegularExpression::CaseInsensitiveOption), "******"); + result.replace(QRegularExpression(R"(\\{PASSWORD\\})", QRegularExpression::CaseInsensitiveOption), "******"); return result; } @@ -1431,8 +1431,8 @@ QString Entry::resolveUrl(const QString& url) const { QString newUrl = url; - QRegularExpression fileRegEx("^([a-z]:)?[\\\\/]", QRegularExpression::CaseInsensitiveOption); - if (!fileRegEx.match(newUrl).hasMatch()) { + QRegularExpression fileRegEx(R"(^([a-z]:)?[\\\\/])", QRegularExpression::CaseInsensitiveOption); + if (fileRegEx.match(newUrl).hasMatch()) { // Match possible file paths without the scheme and convert it to a file URL newUrl = QDir::fromNativeSeparators(newUrl); newUrl = QUrl::fromLocalFile(newUrl).toString(); diff --git a/src/totp/totp.cpp b/src/totp/totp.cpp index cd98d38a1d..47375b96d9 100644 --- a/src/totp/totp.cpp +++ b/src/totp/totp.cpp @@ -1,6 +1,6 @@ /* + * Copyright (C) 2024 KeePassXC Team * Copyright (C) 2017 Weslly Honorato <weslly@protonmail.com> - * Copyright (C) 2017 KeePassXC Team * * 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 @@ -200,8 +200,8 @@ QString Totp::generateTotp(const QSharedPointer& settings, const current = qToBigEndian(time / step); } - QVariant secret = Base32::decode(Base32::sanitizeInput(settings->key.toLatin1())); - if (secret.isNull()) { + const auto secret = Base32::decode(Base32::sanitizeInput(settings->key.toLatin1())); + if (secret.isEmpty()) { return QObject::tr("Invalid Key", "TOTP"); } @@ -218,7 +218,7 @@ QString Totp::generateTotp(const QSharedPointer& settings, const break; } QMessageAuthenticationCode code(cryptoHash); - code.setKey(secret.toByteArray()); + code.setKey(secret); code.addData(QByteArray(reinterpret_cast(¤t), sizeof(current))); QByteArray hmac = code.result(); diff --git a/tests/TestBase32.cpp b/tests/TestBase32.cpp index 4c14e4b46d..537fd60001 100644 --- a/tests/TestBase32.cpp +++ b/tests/TestBase32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 KeePassXC Team + * Copyright (C) 2024 KeePassXC Team * * 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 @@ -26,134 +26,134 @@ void TestBase32::testDecode() { // 3 quanta, all upper case + padding QByteArray encodedData = "JBSWY3DPEB3W64TMMQXC4LQ="; - QVariant data = Base32::decode(encodedData); + QByteArray data = Base32::decode(encodedData); QString expectedData = "Hello world..."; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 4 quanta, all upper case encodedData = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"; data = Base32::decode(encodedData); expectedData = "12345678901234567890"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 4 quanta, all lower case encodedData = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq"; data = Base32::decode(encodedData); expectedData = "12345678901234567890"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 4 quanta, mixed upper and lower case encodedData = "Gezdgnbvgy3tQojqgezdGnbvgy3tQojQ"; data = Base32::decode(encodedData); expectedData = "12345678901234567890"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 1 pad characters encodedData = "ORSXG5A="; data = Base32::decode(encodedData); expectedData = "test"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 3 pad characters encodedData = "L5PV6==="; data = Base32::decode(encodedData); expectedData = "___"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // 4 pad characters encodedData = "MZXW6IDCMFZA===="; data = Base32::decode(encodedData); expectedData = "foo bar"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // six pad characters encodedData = "MZXW6YTBOI======"; data = Base32::decode(encodedData); expectedData = "foobar"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "IA======"; data = Base32::decode(encodedData); expectedData = "@"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); // error: illegal character encodedData = "1MZXW6YTBOI====="; data = Base32::decode(encodedData); - QVERIFY(data.isNull()); + QVERIFY(data.isEmpty()); // error: missing pad character encodedData = "MZXW6YTBOI====="; data = Base32::decode(encodedData); - QVERIFY(data.isNull()); + QVERIFY(data.isEmpty()); // RFC 4648 test vectors encodedData = ""; data = Base32::decode(encodedData); expectedData = ""; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MY======"; data = Base32::decode(encodedData); expectedData = "f"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MZXQ===="; data = Base32::decode(encodedData); expectedData = "fo"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MZXW6==="; data = Base32::decode(encodedData); - QVERIFY(!data.isNull()); + QVERIFY(!data.isEmpty()); expectedData = "foo"; - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MZXW6YQ="; data = Base32::decode(encodedData); expectedData = "foob"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MZXW6YTB"; expectedData = "fooba"; data = Base32::decode(encodedData); - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); encodedData = "MZXW6YTBOI======"; data = Base32::decode(encodedData); expectedData = "foobar"; - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), expectedData); - QVERIFY(data.value().size() == expectedData.size()); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), expectedData); + QVERIFY(data.size() == expectedData.size()); } void TestBase32::testEncode() @@ -307,25 +307,25 @@ void TestBase32::testSanitizeInput() // sanitize input (white space + missing padding) QByteArray encodedData = "JBSW Y3DP EB3W 64TM MQXC 4LQA"; auto data = Base32::decode(Base32::sanitizeInput(encodedData)); - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), QString("Hello world...")); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), QString("Hello world...")); // sanitize input (typo + missing padding) encodedData = "J8SWY3DPE83W64TMMQXC4LQA"; data = Base32::decode(Base32::sanitizeInput(encodedData)); - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), QString("Hello world...")); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), QString("Hello world...")); // sanitize input (other illegal characters) encodedData = "J8SWY3D[PE83W64TMMQ]XC!4LQA"; data = Base32::decode(Base32::sanitizeInput(encodedData)); - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), QString("Hello world...")); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), QString("Hello world...")); // sanitize input (NUL character) encodedData = "J8SWY3DPE83W64TMMQXC4LQA"; encodedData.insert(3, '\0'); data = Base32::decode(Base32::sanitizeInput(encodedData)); - QVERIFY(!data.isNull()); - QCOMPARE(data.toString(), QString("Hello world...")); + QVERIFY(!data.isEmpty()); + QCOMPARE(QString(data.toStdString().c_str()), QString("Hello world...")); }