diff --git a/src/libsync/clientsideencryption.cpp b/src/libsync/clientsideencryption.cpp index 9a1d37f5d97a7..693c1bcee16b1 100644 --- a/src/libsync/clientsideencryption.cpp +++ b/src/libsync/clientsideencryption.cpp @@ -340,7 +340,7 @@ QByteArray encryptPrivateKey( } /* Initialise key and IV */ - if(!EVP_EncryptInit_ex(ctx, nullptr, nullptr, (unsigned char *)key.constData(), (unsigned char *)iv.constData())) { + if(!EVP_EncryptInit_ex(ctx, nullptr, nullptr, reinterpret_cast(key.constData()), reinterpret_cast(iv.constData()))) { qCInfo(lcCse()) << "Error initialising key and iv" << handleErrors(); } @@ -352,7 +352,7 @@ QByteArray encryptPrivateKey( // Do the actual encryption int len = 0; - if(!EVP_EncryptUpdate(ctx, unsignedData(ctext), &len, (unsigned char *)privateKeyB64.constData(), privateKeyB64.size())) { + if(!EVP_EncryptUpdate(ctx, unsignedData(ctext), &len, reinterpret_cast(privateKeyB64.constData()), privateKeyB64.size())) { qCInfo(lcCse()) << "Error encrypting" << handleErrors(); } @@ -430,7 +430,7 @@ QByteArray decryptPrivateKey(const QByteArray& key, const QByteArray& data) { } /* Initialise key and IV */ - if(!EVP_DecryptInit_ex(ctx, nullptr, nullptr, (unsigned char *)key.constData(), (unsigned char *)iv.constData())) { + if(!EVP_DecryptInit_ex(ctx, nullptr, nullptr, reinterpret_cast(key.constData()), reinterpret_cast(iv.constData()))) { qCInfo(lcCse()) << "Error initialising key and iv"; return QByteArray(); } @@ -441,13 +441,13 @@ QByteArray decryptPrivateKey(const QByteArray& key, const QByteArray& data) { /* Provide the message to be decrypted, and obtain the plaintext output. * EVP_DecryptUpdate can be called multiple times if necessary */ - if(!EVP_DecryptUpdate(ctx, unsignedData(ptext), &plen, (unsigned char *)cipherTXT.constData(), cipherTXT.size())) { + if(!EVP_DecryptUpdate(ctx, unsignedData(ptext), &plen, reinterpret_cast(cipherTXT.constData()), cipherTXT.size())) { qCInfo(lcCse()) << "Could not decrypt"; return QByteArray(); } /* Set expected e2EeTag value. Works in OpenSSL 1.0.1d and later */ - if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), (unsigned char *)e2EeTag.constData())) { + if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), const_cast(reinterpret_cast(e2EeTag.constData())))) { qCInfo(lcCse()) << "Could not set e2EeTag"; return QByteArray(); } @@ -520,7 +520,7 @@ QByteArray decryptStringSymmetric(const QByteArray& key, const QByteArray& data) } /* Initialise key and IV */ - if(!EVP_DecryptInit_ex(ctx, nullptr, nullptr, (unsigned char *)key.constData(), (unsigned char *)iv.constData())) { + if(!EVP_DecryptInit_ex(ctx, nullptr, nullptr, reinterpret_cast(key.constData()), reinterpret_cast(iv.constData()))) { qCInfo(lcCse()) << "Error initialising key and iv"; return QByteArray(); } @@ -531,13 +531,13 @@ QByteArray decryptStringSymmetric(const QByteArray& key, const QByteArray& data) /* Provide the message to be decrypted, and obtain the plaintext output. * EVP_DecryptUpdate can be called multiple times if necessary */ - if(!EVP_DecryptUpdate(ctx, unsignedData(ptext), &plen, (unsigned char *)cipherTXT.constData(), cipherTXT.size())) { + if(!EVP_DecryptUpdate(ctx, unsignedData(ptext), &plen, reinterpret_cast(cipherTXT.constData()), cipherTXT.size())) { qCInfo(lcCse()) << "Could not decrypt"; return QByteArray(); } /* Set expected e2EeTag value. Works in OpenSSL 1.0.1d and later */ - if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), (unsigned char *)e2EeTag.constData())) { + if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), const_cast(reinterpret_cast(e2EeTag.constData())))) { qCInfo(lcCse()) << "Could not set e2EeTag"; return QByteArray(); } @@ -586,14 +586,14 @@ std::optional encryptStringAsymmetric(const CertificateInformation & const QByteArray &binaryData) { if (!encryptionEngine.isInitialized()) { - qCWarning(lcCseDecryption()) << "end-to-end encryption is disabled"; + qCWarning(lcCseEncryption()) << "end-to-end encryption is disabled"; return {}; } if (encryptionEngine.useTokenBasedEncryption()) { - qCDebug(lcCseDecryption()) << "use certificate on hardware token" << selectedCertificate.sha256Fingerprint(); + qCDebug(lcCseEncryption()) << "use certificate on hardware token" << selectedCertificate.sha256Fingerprint(); } else { - qCDebug(lcCseDecryption()) << "use certificate on software storage" << selectedCertificate.sha256Fingerprint(); + qCDebug(lcCseEncryption()) << "use certificate on software storage" << selectedCertificate.sha256Fingerprint(); } auto encryptedBase64Result = QByteArray{}; @@ -612,7 +612,7 @@ std::optional encryptStringAsymmetric(const CertificateInformation & encryptedBase64Result = *encryptionResult; break; } else if (encryptionResult.error() == ClientSideEncryption::EncryptionErrorType::RetryOnError) { - qCInfo(lcCseDecryption()) << "retry encryption after error"; + qCInfo(lcCseEncryption()) << "retry encryption after error"; needHardwareTokenEncryptionInit = true; continue; } else { @@ -706,7 +706,7 @@ QByteArray encryptStringSymmetric(const QByteArray& key, const QByteArray& data) } /* Initialise key and IV */ - if(!EVP_EncryptInit_ex(ctx, nullptr, nullptr, (unsigned char *)key.constData(), (unsigned char *)iv.constData())) { + if(!EVP_EncryptInit_ex(ctx, nullptr, nullptr, reinterpret_cast(key.constData()), reinterpret_cast(iv.constData()))) { qCInfo(lcCse()) << "Error initialising key and iv" << handleErrors(); return {}; } @@ -719,7 +719,7 @@ QByteArray encryptStringSymmetric(const QByteArray& key, const QByteArray& data) // Do the actual encryption int len = 0; - if(!EVP_EncryptUpdate(ctx, unsignedData(ctext), &len, (unsigned char *)dataB64.constData(), dataB64.size())) { + if(!EVP_EncryptUpdate(ctx, unsignedData(ctext), &len, reinterpret_cast(dataB64.constData()), dataB64.size())) { qCInfo(lcCse()) << "Error encrypting" << handleErrors(); return {}; } @@ -792,7 +792,7 @@ OCC::Result decryptS } size_t outlen = 0; - err = EVP_PKEY_decrypt(ctx, nullptr, &outlen, (unsigned char *)binaryData.constData(), binaryData.size()); + err = EVP_PKEY_decrypt(ctx, nullptr, &outlen, reinterpret_cast(binaryData.constData()), binaryData.size()); if (err <= 0) { qCInfo(lcCseDecryption()) << "Could not determine the buffer length" << handleErrors(); return {OCC::ClientSideEncryption::EncryptionErrorType::FatalError}; @@ -800,7 +800,7 @@ OCC::Result decryptS QByteArray out(static_cast(outlen), '\0'); - if (EVP_PKEY_decrypt(ctx, unsignedData(out), &outlen, (unsigned char *)binaryData.constData(), binaryData.size()) <= 0) { + if (EVP_PKEY_decrypt(ctx, unsignedData(out), &outlen, reinterpret_cast(binaryData.constData()), binaryData.size()) <= 0) { const auto error = handleErrors(); if (ClientSideEncryption::checkEncryptionErrorForHardwareTokenResetState(error)) { return {OCC::ClientSideEncryption::EncryptionErrorType::RetryOnError}; @@ -846,7 +846,7 @@ OCC::Result encryptString } size_t outLen = 0; - if (EVP_PKEY_encrypt(ctx, nullptr, &outLen, (unsigned char *)binaryData.constData(), binaryData.size()) != 1) { + if (EVP_PKEY_encrypt(ctx, nullptr, &outLen, reinterpret_cast(binaryData.constData()), binaryData.size()) != 1) { const auto error = handleErrors(); if (ClientSideEncryption::checkEncryptionErrorForHardwareTokenResetState(error)) { encryptionEngine.initializeHardwareTokenEncryption(nullptr); @@ -857,7 +857,7 @@ OCC::Result encryptString } QByteArray out(static_cast(outLen), '\0'); - if (EVP_PKEY_encrypt(ctx, unsignedData(out), &outLen, (unsigned char *)binaryData.constData(), binaryData.size()) != 1) { + if (EVP_PKEY_encrypt(ctx, unsignedData(out), &outLen, reinterpret_cast(binaryData.constData()), binaryData.size()) != 1) { const auto error = handleErrors(); if (ClientSideEncryption::checkEncryptionErrorForHardwareTokenResetState(error)) { encryptionEngine.initializeHardwareTokenEncryption(nullptr); @@ -1364,9 +1364,9 @@ void ClientSideEncryption::fetchPublicKeyFromKeyChain() bool ClientSideEncryption::checkEncryptionIsWorking(const CertificateInformation ¤tCertificate) { qCInfo(lcCse) << "check encryption is working before enabling end-to-end encryption feature"; - QByteArray data = EncryptionHelper::generateRandom(64); + const auto binaryData = EncryptionHelper::generateRandom(64); - auto encryptedData = EncryptionHelper::encryptStringAsymmetric(currentCertificate, paddingMode(), *this, data); + auto encryptedData = EncryptionHelper::encryptStringAsymmetric(currentCertificate, paddingMode(), *this, binaryData); if (!encryptedData) { qCWarning(lcCse()) << "encryption error"; return false; @@ -1384,7 +1384,7 @@ bool ClientSideEncryption::checkEncryptionIsWorking(const CertificateInformation QByteArray decryptResult = QByteArray::fromBase64(*decryptionResult); - if (data != decryptResult) { + if (binaryData != decryptResult) { qCInfo(lcCse()) << "recovered data does not match the initial data after encryption and decryption of it"; return false; } @@ -2455,7 +2455,7 @@ bool EncryptionHelper::fileEncryption(const QByteArray &key, const QByteArray &i return false; } - if(!EVP_EncryptUpdate(ctx, unsignedData(out), &len, (unsigned char *)data.constData(), data.size())) { + if(!EVP_EncryptUpdate(ctx, unsignedData(out), &len, reinterpret_cast(data.constData()), data.size())) { qCInfo(lcCse()) << "Could not encrypt"; return false; } @@ -2539,7 +2539,7 @@ bool EncryptionHelper::fileDecryption(const QByteArray &key, const QByteArray& i return false; } - if(!EVP_DecryptUpdate(ctx, unsignedData(out), &len, (unsigned char *)data.constData(), data.size())) { + if(!EVP_DecryptUpdate(ctx, unsignedData(out), &len, reinterpret_cast(data.constData()), data.size())) { qCInfo(lcCse()) << "Could not decrypt"; return false; } @@ -2550,7 +2550,7 @@ bool EncryptionHelper::fileDecryption(const QByteArray &key, const QByteArray& i const QByteArray e2EeTag = input->read(OCC::Constants::e2EeTagSize); /* Set expected e2EeTag value. Works in OpenSSL 1.0.1d and later */ - if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), (unsigned char *)e2EeTag.constData())) { + if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), const_cast(reinterpret_cast(e2EeTag.constData())))) { qCInfo(lcCse()) << "Could not set expected e2EeTag"; return false; } @@ -2626,7 +2626,7 @@ bool EncryptionHelper::dataEncryption(const QByteArray &key, const QByteArray &i return false; } - if (!EVP_EncryptUpdate(ctx, unsignedData(out), &len, (unsigned char *)data.constData(), data.size())) { + if (!EVP_EncryptUpdate(ctx, unsignedData(out), &len, reinterpret_cast(data.constData()), data.size())) { qCInfo(lcCse()) << "Could not encrypt"; return false; } @@ -2721,7 +2721,7 @@ bool EncryptionHelper::dataDecryption(const QByteArray &key, const QByteArray &i return false; } - if (!EVP_DecryptUpdate(ctx, unsignedData(out), &len, (unsigned char *)data.constData(), data.size())) { + if (!EVP_DecryptUpdate(ctx, unsignedData(out), &len, reinterpret_cast(data.constData()), data.size())) { qCWarning(lcCse()) << "Could not decrypt"; return false; } @@ -2732,7 +2732,7 @@ bool EncryptionHelper::dataDecryption(const QByteArray &key, const QByteArray &i const QByteArray e2EeTag = inputBuffer.read(OCC::Constants::e2EeTagSize); /* Set expected e2EeTag value. Works in OpenSSL 1.0.1d and later */ - if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), (unsigned char *)e2EeTag.constData())) { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, e2EeTag.size(), const_cast(reinterpret_cast(e2EeTag.constData())))) { qCWarning(lcCse()) << "Could not set expected e2EeTag"; return false; } diff --git a/src/libsync/encryptedfoldermetadatahandler.cpp b/src/libsync/encryptedfoldermetadatahandler.cpp index 7b141ab192ca3..6fa3fe52aef50 100644 --- a/src/libsync/encryptedfoldermetadatahandler.cpp +++ b/src/libsync/encryptedfoldermetadatahandler.cpp @@ -281,6 +281,7 @@ void EncryptedFolderMetadataHandler::startUploadMetadata() return; } + folderMetadata()->updateSelfCertificate(); const auto encryptedMetadata = folderMetadata()->encryptedMetadata(); if (_isNewMetadataCreated) { const auto job = new StoreMetaDataApiJob(_account, _folderId, _folderToken, encryptedMetadata, folderMetadata()->metadataSignature()); diff --git a/src/libsync/foldermetadata.cpp b/src/libsync/foldermetadata.cpp index 9c78605ca5126..77b949ca07a0a 100644 --- a/src/libsync/foldermetadata.cpp +++ b/src/libsync/foldermetadata.cpp @@ -74,8 +74,8 @@ FolderMetadata::FolderMetadata(AccountPtr account, , _remoteFolderRoot(Utility::noLeadingSlashPath(Utility::noTrailingSlashPath(remoteFolderRoot))) , _initialMetadata(metadata) , _isRootEncryptedFolder(rootEncryptedFolderInfo.path == QStringLiteral("/")) - , _metadataKeyForEncryption(rootEncryptedFolderInfo.keyForEncryption) - , _metadataKeyForDecryption(rootEncryptedFolderInfo.keyForDecryption) + , _binaryMetadataKeyForEncryption(rootEncryptedFolderInfo.binaryKeyForEncryption) + , _binaryMetadataKeyForDecryption(rootEncryptedFolderInfo.binaryKeyForDecryption) , _keyChecksums(rootEncryptedFolderInfo.keyChecksums) , _initialSignature(signature) { @@ -103,7 +103,7 @@ void FolderMetadata::initMetadata() qCDebug(lcCseMetadata()) << "Setting up existing metadata"; setupExistingMetadata(_initialMetadata); - if (metadataKeyForDecryption().isEmpty() || metadataKeyForEncryption().isEmpty()) { + if (binaryMetadataKeyForDecryption().isEmpty() || binaryMetadataKeyForEncryption().isEmpty()) { qCWarning(lcCseMetadata()) << "Failed to setup FolderMetadata. Could not parse/create metadataKey!"; } emitSetupComplete(); @@ -182,8 +182,8 @@ void FolderMetadata::setupExistingMetadata(const QByteArray &metadata) if (_folderUsers.contains(_account->davUser())) { const auto currentFolderUser = _folderUsers.value(_account->davUser()); const auto currentUserCertificate = QSslCertificate{currentFolderUser.certificatePem}; - _metadataKeyForEncryption = QByteArray::fromBase64(decryptDataWithPrivateKey(currentFolderUser.encryptedMetadataKey, currentUserCertificate.digest(QCryptographicHash::Sha256).toBase64())); - _metadataKeyForDecryption = _metadataKeyForEncryption; + _binaryMetadataKeyForEncryption = QByteArray::fromBase64(decryptDataWithPrivateKey(currentFolderUser.encryptedMetadataKey, currentUserCertificate.digest(QCryptographicHash::Sha256).toBase64())); + _binaryMetadataKeyForDecryption = _binaryMetadataKeyForEncryption; } if (!parseFileDropPart(metaDataDoc)) { @@ -191,7 +191,7 @@ void FolderMetadata::setupExistingMetadata(const QByteArray &metadata) return; } - if (metadataKeyForDecryption().isEmpty() || metadataKeyForEncryption().isEmpty()) { + if (binaryMetadataKeyForDecryption().isEmpty() || binaryMetadataKeyForEncryption().isEmpty()) { qCWarning(lcCseMetadata()) << "Could not setup metadata key!"; _account->reportClientStatus(OCC::ClientStatusReportingStatus::E2EeError_GeneralError); return; @@ -205,7 +205,7 @@ void FolderMetadata::setupExistingMetadata(const QByteArray &metadata) // for compatibility, the format is "cipheredpart|initializationVector", so we need to extract the "cipheredpart" const auto cipherTextPartExtracted = cipherTextEncrypted.split('|').at(0); - const auto cipherTextDecrypted = EncryptionHelper::decryptThenUnGzipData(metadataKeyForDecryption(), QByteArray::fromBase64(cipherTextPartExtracted), _metadataNonce); + const auto cipherTextDecrypted = EncryptionHelper::decryptThenUnGzipData(binaryMetadataKeyForDecryption(), QByteArray::fromBase64(cipherTextPartExtracted), _metadataNonce); if (cipherTextDecrypted.isEmpty()) { qCWarning(lcCseMetadata()) << "Could not decrypt cipher text!"; _account->reportClientStatus(OCC::ClientStatusReportingStatus::E2EeError_GeneralError); @@ -227,7 +227,7 @@ void FolderMetadata::setupExistingMetadata(const QByteArray &metadata) } } - if (!verifyMetadataKey(metadataKeyForDecryption())) { + if (!verifyMetadataKey(binaryMetadataKeyForDecryption())) { qCWarning(lcCseMetadata()) << "Could not verify metadataKey!"; _account->reportClientStatus(OCC::ClientStatusReportingStatus::E2EeError_GeneralError); return; @@ -275,7 +275,7 @@ void FolderMetadata::setupExistingMetadataLegacy(const QByteArray &metadata) const auto &fullMetaDataObj = metaDataObj[metadataJsonKey].toObject(); // we will use metadata key from metadata to decrypt legacy metadata, so let's clear the decryption key if any provided by top-level folder - _metadataKeyForDecryption.clear(); + _binaryMetadataKeyForDecryption.clear(); const auto metadataKeyFromJson = fullMetaDataObj[metadataKeyKey].toString().toLocal8Bit(); if (!metadataKeyFromJson.isEmpty()) { @@ -283,11 +283,11 @@ void FolderMetadata::setupExistingMetadataLegacy(const QByteArray &metadata) const auto decryptedMetadataKeyBase64 = decryptDataWithPrivateKey(metadataKeyFromJson, _account->e2e()->certificateSha256Fingerprint()); if (!decryptedMetadataKeyBase64.isEmpty()) { // fromBase64() multiple times just to stick with the old wrong way - _metadataKeyForDecryption = QByteArray::fromBase64(QByteArray::fromBase64(decryptedMetadataKeyBase64)); + _binaryMetadataKeyForDecryption = QByteArray::fromBase64(QByteArray::fromBase64(QByteArray::fromBase64(decryptedMetadataKeyBase64))); } } - if (metadataKeyForDecryption().isEmpty() && _existingMetadataVersion < MetadataVersion::Version1_2) { + if (binaryMetadataKeyForDecryption().isEmpty() && _existingMetadataVersion < MetadataVersion::Version1_2) { // parse version 1.0 (before security-vulnerability fix for metadata keys was released qCDebug(lcCseMetadata()) << "Migrating from" << _existingMetadataVersion << "to" << latestSupportedMetadataVersion(); @@ -305,20 +305,20 @@ void FolderMetadata::setupExistingMetadataLegacy(const QByteArray &metadata) if (!lastMetadataKeyValueFromJson.isEmpty()) { const auto lastMetadataKeyValueFromJsonBase64 = decryptDataWithPrivateKey(lastMetadataKeyValueFromJson, _account->e2e()->certificateSha256Fingerprint()); if (!lastMetadataKeyValueFromJsonBase64.isEmpty()) { - _metadataKeyForDecryption = QByteArray::fromBase64(QByteArray::fromBase64(lastMetadataKeyValueFromJsonBase64)); + _binaryMetadataKeyForDecryption = QByteArray::fromBase64(QByteArray::fromBase64(lastMetadataKeyValueFromJsonBase64)); } } } } - if (metadataKeyForDecryption().isEmpty()) { + if (binaryMetadataKeyForDecryption().isEmpty()) { qCWarning(lcCseMetadata()) << "Could not setup existing metadata with missing metadataKeys!"; _account->reportClientStatus(OCC::ClientStatusReportingStatus::E2EeError_GeneralError); return; } - if (metadataKeyForEncryption().isEmpty()) { - _metadataKeyForEncryption = metadataKeyForDecryption(); + if (binaryMetadataKeyForEncryption().isEmpty()) { + _binaryMetadataKeyForEncryption = binaryMetadataKeyForDecryption(); } const auto &files = metaDataObj[filesKey].toObject(); @@ -339,7 +339,7 @@ void FolderMetadata::setupExistingMetadataLegacy(const QByteArray &metadata) // Decrypt encrypted part const auto encryptedFile = fileObj[encryptedKey].toString().toLocal8Bit(); - const auto decryptedFile = decryptJsonObject(encryptedFile, metadataKeyForDecryption()); + const auto decryptedFile = decryptJsonObject(encryptedFile, binaryMetadataKeyForDecryption()); const auto decryptedFileDoc = QJsonDocument::fromJson(decryptedFile); const auto decryptedFileObj = decryptedFileDoc.object(); @@ -540,9 +540,9 @@ QJsonObject FolderMetadata::convertFileToJsonObject(const EncryptedFile *encrypt return file; } -const QByteArray FolderMetadata::metadataKeyForEncryption() const +const QByteArray FolderMetadata::binaryMetadataKeyForEncryption() const { - return _metadataKeyForEncryption; + return _binaryMetadataKeyForEncryption; } const QSet& FolderMetadata::keyChecksums() const @@ -565,7 +565,7 @@ void FolderMetadata::initEmptyMetadata() _account->reportClientStatus(OCC::ClientStatusReportingStatus::E2EeError_GeneralError); return; } - _metadataKeyForDecryption = _metadataKeyForEncryption; + _binaryMetadataKeyForDecryption = _binaryMetadataKeyForEncryption; } _isMetadataValid = true; @@ -574,8 +574,8 @@ void FolderMetadata::initEmptyMetadata() void FolderMetadata::initEmptyMetadataLegacy() { - _metadataKeyForEncryption = EncryptionHelper::generateRandom(metadataKeySize); - _metadataKeyForDecryption = _metadataKeyForEncryption; + _binaryMetadataKeyForEncryption = EncryptionHelper::generateRandom(metadataKeySize); + _binaryMetadataKeyForDecryption = _binaryMetadataKeyForEncryption; _isMetadataValid = true; @@ -599,11 +599,21 @@ QByteArray FolderMetadata::encryptedMetadata() createNewMetadataKeyForEncryption(); } - if (metadataKeyForEncryption().isEmpty()) { + if (binaryMetadataKeyForEncryption().isEmpty()) { qCWarning(lcCseMetadata()) << "Encrypting metadata failed! Empty metadata key!"; return {}; } + if (_isRootEncryptedFolder) { + for (auto &folderUser : _folderUsers) { + if (folderUser.userId == _account->davUser()) { + folderUser.certificatePem = _account->e2e()->getCertificate().toPem(); + } + } + + updateUsersEncryptedMetadataKey(); + } + QJsonObject files, folders; for (auto it = _files.constBegin(), end = _files.constEnd(); it != end; ++it) { const auto file = convertFileToJsonObject(&(*it)); @@ -644,7 +654,7 @@ QByteArray FolderMetadata::encryptedMetadata() QByteArray authenticationTag; const auto initializationVector = EncryptionHelper::generateRandom(metadataKeySize); const auto initializationVectorBase64 = initializationVector.toBase64(); - const auto gzippedThenEncryptData = EncryptionHelper::gzipThenEncryptData(metadataKeyForEncryption(), cipherTextDoc.toJson(QJsonDocument::Compact), initializationVector, authenticationTag).toBase64(); + const auto gzippedThenEncryptData = EncryptionHelper::gzipThenEncryptData(binaryMetadataKeyForEncryption(), cipherTextDoc.toJson(QJsonDocument::Compact), initializationVector, authenticationTag).toBase64(); // backwards compatible with old versions ("ciphertext|initializationVector") const auto encryptedCipherText = QByteArray(gzippedThenEncryptData + QByteArrayLiteral("|") + initializationVectorBase64); const QJsonObject metadata{{cipherTextKey, QJsonValue::fromVariant(encryptedCipherText)}, @@ -655,14 +665,7 @@ QByteArray FolderMetadata::encryptedMetadata() QJsonArray folderUsers; if (_isRootEncryptedFolder) { - for (auto it = _folderUsers.constBegin(), end = _folderUsers.constEnd(); it != end; ++it) { - auto folderUser = it.value(); - - if (folderUser.userId == _account->davUser()) { - folderUser.certificatePem = _account->e2e()->getCertificate().toPem(); - updateUsersEncryptedMetadataKey(); - } - + for (const auto &folderUser : _folderUsers) { const QJsonObject folderUserJson{{usersUserIdKey, folderUser.userId}, {usersCertificateKey, QJsonValue::fromVariant(folderUser.certificatePem)}, {usersEncryptedMetadataKey, QJsonValue::fromVariant(folderUser.encryptedMetadataKey)}}; @@ -701,14 +704,14 @@ QByteArray FolderMetadata::encryptedMetadata() QByteArray FolderMetadata::encryptedMetadataLegacy() { - if (_metadataKeyForEncryption.isEmpty()) { + if (_binaryMetadataKeyForEncryption.isEmpty()) { qCWarning(lcCseMetadata) << "Metadata generation failed! Empty metadata key!"; _account->reportClientStatus(OCC::ClientStatusReportingStatus::E2EeError_GeneralError); return {}; } const auto version = _account->capabilities().clientSideEncryptionVersion(); // multiple toBase64() just to keep with the old (wrong way) - const auto encryptedMetadataKey = encryptDataWithPublicKey(metadataKeyForEncryption(), _account->e2e()->getCertificateInformation()).toBase64(); + const auto encryptedMetadataKey = encryptDataWithPublicKey(binaryMetadataKeyForEncryption(), _account->e2e()->getCertificateInformation()).toBase64(); const QJsonObject metadata{ {versionKey, version}, {metadataKeyKey, QJsonValue::fromVariant(encryptedMetadataKey)}, @@ -724,7 +727,7 @@ QByteArray FolderMetadata::encryptedMetadataLegacy() QJsonDocument encryptedDoc; encryptedDoc.setObject(encrypted); - QString encryptedEncrypted = encryptJsonObject(encryptedDoc.toJson(QJsonDocument::Compact), metadataKeyForEncryption()); + QString encryptedEncrypted = encryptJsonObject(encryptedDoc.toJson(QJsonDocument::Compact), binaryMetadataKeyForEncryption()); if (encryptedEncrypted.isEmpty()) { qCWarning(lcCseMetadata) << "Metadata generation failed!"; _account->reportClientStatus(OCC::ClientStatusReportingStatus::E2EeError_GeneralError); @@ -839,6 +842,15 @@ QByteArray FolderMetadata::initialMetadata() const return _initialMetadata; } +void FolderMetadata::updateSelfCertificate() +{ + for (auto &oneFolderUser : _folderUsers) { + if (oneFolderUser.userId == _account->davUser()) { + oneFolderUser.certificatePem = _account->e2e()->getCertificate().toPem(); + } + } +} + quint64 FolderMetadata::newCounter() const { return _counter + 1; @@ -916,9 +928,9 @@ void FolderMetadata::addEncryptedFile(const EncryptedFile &f) { _files.append(f); } -const QByteArray FolderMetadata::metadataKeyForDecryption() const +const QByteArray FolderMetadata::binaryMetadataKeyForDecryption() const { - return _metadataKeyForDecryption; + return _binaryMetadataKeyForDecryption; } void FolderMetadata::removeEncryptedFile(const EncryptedFile &f) @@ -1020,15 +1032,15 @@ void FolderMetadata::slotRootE2eeFolderMetadataReceived(int statusCode, const QS return; } - _metadataKeyForEncryption = rootE2eeFolderMetadata->metadataKeyForEncryption(); + _binaryMetadataKeyForEncryption = rootE2eeFolderMetadata->binaryMetadataKeyForEncryption(); if (!isVersion2AndUp()) { initMetadata(); return; } - _metadataKeyForDecryption = rootE2eeFolderMetadata->metadataKeyForDecryption(); - _metadataKeyForEncryption = rootE2eeFolderMetadata->metadataKeyForEncryption(); + _binaryMetadataKeyForDecryption = rootE2eeFolderMetadata->binaryMetadataKeyForDecryption(); + _binaryMetadataKeyForEncryption = rootE2eeFolderMetadata->binaryMetadataKeyForEncryption(); _keyChecksums = rootE2eeFolderMetadata->keyChecksums(); initMetadata(); } @@ -1068,7 +1080,7 @@ bool FolderMetadata::addUser(const QString &userId, UserWithFolderAccess newFolderUser; newFolderUser.userId = userId; newFolderUser.certificatePem = certificate.toPem(); - newFolderUser.encryptedMetadataKey = encryptDataWithPublicKey(metadataKeyForEncryption(), shareUserCertificate); + newFolderUser.encryptedMetadataKey = encryptDataWithPublicKey(binaryMetadataKeyForEncryption(), shareUserCertificate); _folderUsers[userId] = newFolderUser; updateUsersEncryptedMetadataKey(); @@ -1102,8 +1114,8 @@ void FolderMetadata::updateUsersEncryptedMetadataKey() qCWarning(lcCseMetadata()) << "Could not update folder users in a non top level folder."; return; } - Q_ASSERT(!metadataKeyForEncryption().isEmpty()); - if (metadataKeyForEncryption().isEmpty()) { + Q_ASSERT(!binaryMetadataKeyForEncryption().isEmpty()); + if (binaryMetadataKeyForEncryption().isEmpty()) { qCWarning(lcCseMetadata()) << "Could not update folder users with empty metadataKey!"; return; } @@ -1113,7 +1125,7 @@ void FolderMetadata::updateUsersEncryptedMetadataKey() const QSslCertificate certificate(folderUser.certificatePem); CertificateInformation shareUserCertificate = CertificateInformation{{}, QSslCertificate{certificate}}; - const auto encryptedMetadataKey = encryptDataWithPublicKey(metadataKeyForEncryption(), shareUserCertificate); + const auto encryptedMetadataKey = encryptDataWithPublicKey(binaryMetadataKeyForEncryption(), shareUserCertificate); if (encryptedMetadataKey.isEmpty()) { qCWarning(lcCseMetadata()) << "Could not update folder users with empty encryptedMetadataKey!"; continue; @@ -1130,9 +1142,9 @@ void FolderMetadata::createNewMetadataKeyForEncryption() if (!_isRootEncryptedFolder) { return; } - _metadataKeyForEncryption = EncryptionHelper::generateRandom(metadataKeySize); - if (!metadataKeyForEncryption().isEmpty()) { - _keyChecksums.insert(calcSha256(metadataKeyForEncryption())); + _binaryMetadataKeyForEncryption = EncryptionHelper::generateRandom(metadataKeySize); + if (!binaryMetadataKeyForEncryption().isEmpty()) { + _keyChecksums.insert(calcSha256(binaryMetadataKeyForEncryption())); } } diff --git a/src/libsync/foldermetadata.h b/src/libsync/foldermetadata.h index 0cb9aa615ad28..536de6e7bb990 100644 --- a/src/libsync/foldermetadata.h +++ b/src/libsync/foldermetadata.h @@ -124,8 +124,8 @@ class OWNCLOUDSYNC_EXPORT FolderMetadata : public QObject [[nodiscard]] bool updateUser(const QString &userId, const QSslCertificate &certificate, CertificateType certificateType); - [[nodiscard]] const QByteArray metadataKeyForEncryption() const; - [[nodiscard]] const QByteArray metadataKeyForDecryption() const; + [[nodiscard]] const QByteArray binaryMetadataKeyForEncryption() const; + [[nodiscard]] const QByteArray binaryMetadataKeyForDecryption() const; [[nodiscard]] const QSet &keyChecksums() const; [[nodiscard]] QByteArray encryptedMetadata(); @@ -141,6 +141,8 @@ class OWNCLOUDSYNC_EXPORT FolderMetadata : public QObject [[nodiscard]] QByteArray initialMetadata() const; + void updateSelfCertificate(); + public slots: void addEncryptedFile(const FolderMetadata::EncryptedFile &f); void removeEncryptedFile(const FolderMetadata::EncryptedFile &f); @@ -206,9 +208,9 @@ private slots: bool _isRootEncryptedFolder = false; // always contains the last generated metadata key (non-encrypted and non-base64) - QByteArray _metadataKeyForEncryption; + QByteArray _binaryMetadataKeyForEncryption; // used for storing initial metadataKey to use for decryption, especially in nested folders when changing the metadataKey and re-encrypting nested dirs - QByteArray _metadataKeyForDecryption; + QByteArray _binaryMetadataKeyForDecryption; QByteArray _metadataNonce; // metadatakey checksums for validation during setting up from existing metadata QSet _keyChecksums; diff --git a/src/libsync/rootencryptedfolderinfo.cpp b/src/libsync/rootencryptedfolderinfo.cpp index d3133f6552cec..32052430dc9b2 100644 --- a/src/libsync/rootencryptedfolderinfo.cpp +++ b/src/libsync/rootencryptedfolderinfo.cpp @@ -18,8 +18,8 @@ RootEncryptedFolderInfo::RootEncryptedFolderInfo(const QString &remotePath, const QSet &checksums, const quint64 counter) : path(remotePath) - , keyForEncryption(encryptionKey) - , keyForDecryption(decryptionKey) + , binaryKeyForEncryption(encryptionKey) + , binaryKeyForDecryption(decryptionKey) , keyChecksums(checksums) , counter(counter) { @@ -40,6 +40,6 @@ QString RootEncryptedFolderInfo::createRootPath(const QString ¤tPath, cons bool RootEncryptedFolderInfo::keysSet() const { - return !keyForEncryption.isEmpty() && !keyForDecryption.isEmpty() && !keyChecksums.isEmpty(); + return !binaryKeyForEncryption.isEmpty() && !binaryKeyForDecryption.isEmpty() && !keyChecksums.isEmpty(); } } diff --git a/src/libsync/rootencryptedfolderinfo.h b/src/libsync/rootencryptedfolderinfo.h index 4e876cb3e5d78..4f842f7522f46 100644 --- a/src/libsync/rootencryptedfolderinfo.h +++ b/src/libsync/rootencryptedfolderinfo.h @@ -25,8 +25,8 @@ struct OWNCLOUDSYNC_EXPORT RootEncryptedFolderInfo { static QString createRootPath(const QString ¤tPath, const QString &topLevelPath); QString path; - QByteArray keyForEncryption; // it can be different from keyForDecryption when new metadatKey is generated in root E2EE foler - QByteArray keyForDecryption; // always storing previous metadataKey to be able to decrypt nested E2EE folders' previous metadata + QByteArray binaryKeyForEncryption; // it can be different from binaryKeyForDecryption when new metadatKey is generated in root E2EE foler + QByteArray binaryKeyForDecryption; // always storing previous metadataKey to be able to decrypt nested E2EE folders' previous metadata QSet keyChecksums; quint64 counter = 0; [[nodiscard]] bool keysSet() const; diff --git a/src/libsync/updatee2eefolderusersmetadatajob.cpp b/src/libsync/updatee2eefolderusersmetadatajob.cpp index 10e2759c7345d..94a88ec400760 100644 --- a/src/libsync/updatee2eefolderusersmetadatajob.cpp +++ b/src/libsync/updatee2eefolderusersmetadatajob.cpp @@ -201,8 +201,8 @@ void UpdateE2eeFolderUsersMetadataJob::scheduleSubJobs() if (record.isDirectory()) { const auto folderMetadata = _encryptedFolderMetadataHandler->folderMetadata(); const auto subJob = new UpdateE2eeFolderUsersMetadataJob(_account, _journalDb, _syncFolderRemotePath, UpdateE2eeFolderUsersMetadataJob::ReEncrypt, Utility::trailingSlashPath(_syncFolderRemotePath) + QString::fromUtf8(record._e2eMangledName)); - subJob->setMetadataKeyForEncryption(folderMetadata->metadataKeyForEncryption()); - subJob->setMetadataKeyForDecryption(folderMetadata->metadataKeyForDecryption()); + subJob->setMetadataKeyForEncryption(folderMetadata->binaryMetadataKeyForEncryption()); + subJob->setMetadataKeyForDecryption(folderMetadata->binaryMetadataKeyForDecryption()); subJob->setKeyChecksums(folderMetadata->keyChecksums()); subJob->setParent(this); subJob->setFolderToken(_encryptedFolderMetadataHandler->folderToken()); diff --git a/test/testclientsideencryptionv2.cpp b/test/testclientsideencryptionv2.cpp index 6dfc4a7dd3902..9e75af70e3ae7 100644 --- a/test/testclientsideencryptionv2.cpp +++ b/test/testclientsideencryptionv2.cpp @@ -215,7 +215,7 @@ private slots: QCOMPARE(metadataSetupExistingCompleteSpy.count(), 1); QVERIFY(metadataFromJson->metadataSignature().isEmpty()); - QVERIFY(metadataFromJson->metadataKeyForDecryption().isEmpty()); + QVERIFY(metadataFromJson->binaryMetadataKeyForDecryption().isEmpty()); QVERIFY(!metadataFromJson->isValid()); } diff --git a/test/testsecurefiledrop.cpp b/test/testsecurefiledrop.cpp index 016f5aadb278e..8e7162ae34d7d 100644 --- a/test/testsecurefiledrop.cpp +++ b/test/testsecurefiledrop.cpp @@ -123,7 +123,7 @@ private slots: QByteArray authenticationTag; const auto initializationVector = EncryptionHelper::generateRandom(16); - const auto cipherTextEncrypted = EncryptionHelper::gzipThenEncryptData(metadata->_metadataKeyForEncryption, + const auto cipherTextEncrypted = EncryptionHelper::gzipThenEncryptData(metadata->_binaryMetadataKeyForEncryption, fakeFileDropMetadata.toJson(QJsonDocument::JsonFormat::Compact), initializationVector, authenticationTag);