From ef3c516598e35a4e7e7986fb7826e9dabfe6e837 Mon Sep 17 00:00:00 2001 From: Kevin Ottens Date: Mon, 10 Aug 2020 12:45:32 +0200 Subject: [PATCH] Add support for BASE64 encoded '|' when decrypting Signed-off-by: Kevin Ottens --- src/libsync/clientsideencryption.cpp | 44 +++++++++++++++++++++------- test/testclientsideencryption.cpp | 36 +++++++++++++++++++++++ 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/src/libsync/clientsideencryption.cpp b/src/libsync/clientsideencryption.cpp index 76017ec9c..2ddb5f1f2 100644 --- a/src/libsync/clientsideencryption.cpp +++ b/src/libsync/clientsideencryption.cpp @@ -61,6 +61,31 @@ namespace { const char e2e_cert[] = "_e2e-certificate"; const char e2e_private[] = "_e2e-private"; const char e2e_mnemonic[] = "_e2e-mnemonic"; + + QList oldCipherFormatSplit(const QByteArray &cipher) + { + const auto separator = QByteArrayLiteral("fA=="); // BASE64 encoded '|' + auto result = QList(); + + auto data = cipher; + auto index = data.indexOf(separator); + while (index >=0) { + result.append(data.left(index)); + data = data.mid(index + separator.size()); + index = data.indexOf(separator); + } + + result.append(data); + return result; + } + + QList splitCipherParts(const QByteArray &data) + { + const auto isOldFormat = !data.contains('|'); + const auto parts = isOldFormat ? oldCipherFormatSplit(data) : data.split('|'); + qCInfo(lcCse()) << "found parts:" << parts << "old format?" << isOldFormat; + return parts; + } } // ns namespace { @@ -371,9 +396,7 @@ QByteArray decryptPrivateKey(const QByteArray& key, const QByteArray& data) { qCInfo(lcCse()) << "decryptStringSymmetric key: " << key; qCInfo(lcCse()) << "decryptStringSymmetric data: " << data; - const auto parts = data.split('|'); - qCInfo(lcCse()) << "found parts:" << parts; - + const auto parts = splitCipherParts(data); if (parts.size() < 2) { qCInfo(lcCse()) << "Not enough parts found"; return QByteArray(); @@ -450,9 +473,7 @@ QByteArray decryptPrivateKey(const QByteArray& key, const QByteArray& data) { QByteArray extractPrivateKeySalt(const QByteArray &data) { - const auto parts = data.split('|'); - qCInfo(lcCse()) << "found parts:" << parts; - + const auto parts = splitCipherParts(data); if (parts.size() < 3) { qCInfo(lcCse()) << "Not enough parts found"; return QByteArray(); @@ -465,11 +486,14 @@ QByteArray decryptStringSymmetric(const QByteArray& key, const QByteArray& data) qCInfo(lcCse()) << "decryptStringSymmetric key: " << key; qCInfo(lcCse()) << "decryptStringSymmetric data: " << data; - int sep = data.indexOf('|'); - qCInfo(lcCse()) << "sep at" << sep; + const auto parts = splitCipherParts(data); + if (parts.size() < 2) { + qCInfo(lcCse()) << "Not enough parts found"; + return QByteArray(); + } - QByteArray cipherTXT64 = data.left(sep); - QByteArray ivB64 = data.right(data.size() - sep - 1); + QByteArray cipherTXT64 = parts.at(0); + QByteArray ivB64 = parts.at(1); qCInfo(lcCse()) << "decryptStringSymmetric cipherTXT: " << cipherTXT64; qCInfo(lcCse()) << "decryptStringSymmetric IV: " << ivB64; diff --git a/test/testclientsideencryption.cpp b/test/testclientsideencryption.cpp index 91ecb0da8..2b0ea5a2c 100644 --- a/test/testclientsideencryption.cpp +++ b/test/testclientsideencryption.cpp @@ -14,6 +14,11 @@ class TestClientSideEncryption : public QObject { Q_OBJECT + QByteArray convertToOldStorageFormat(const QByteArray &data) + { + return data.split('|').join("fA=="); + } + private slots: void shouldEncryptPrivateKeys() { @@ -59,6 +64,23 @@ private slots: QCOMPARE(salt, originalSalt); } + void shouldDecryptPrivateKeysInOldStorageFormat() + { + // GIVEN + const auto encryptionKey = QByteArrayLiteral("foo"); + const auto originalPrivateKey = QByteArrayLiteral("bar"); + const auto originalSalt = QByteArrayLiteral("baz"); + const auto cipher = convertToOldStorageFormat(EncryptionHelper::encryptPrivateKey(encryptionKey, originalPrivateKey, originalSalt)); + + // WHEN + const auto privateKey = EncryptionHelper::decryptPrivateKey(encryptionKey, cipher); + const auto salt = EncryptionHelper::extractPrivateKeySalt(cipher); + + // THEN + QCOMPARE(privateKey, originalPrivateKey); + QCOMPARE(salt, originalSalt); + } + void shouldSymmetricEncryptStrings() { // GIVEN @@ -96,6 +118,20 @@ private slots: // THEN QCOMPARE(data, originalData); } + + void shouldSymmetricDecryptStringsInOldStorageFormat() + { + // GIVEN + const auto encryptionKey = QByteArrayLiteral("foo"); + const auto originalData = QByteArrayLiteral("bar"); + const auto cipher = convertToOldStorageFormat(EncryptionHelper::encryptStringSymmetric(encryptionKey, originalData)); + + // WHEN + const auto data = EncryptionHelper::decryptStringSymmetric(encryptionKey, cipher); + + // THEN + QCOMPARE(data, originalData); + } }; QTEST_APPLESS_MAIN(TestClientSideEncryption) -- 2.30.2