diff --git a/app/src/main/java/com/owncloud/android/datamodel/e2e/v2/decrypted/DecryptedMetadata.kt b/app/src/main/java/com/owncloud/android/datamodel/e2e/v2/decrypted/DecryptedMetadata.kt index 7401571217c6..532f4c7dcf63 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/e2e/v2/decrypted/DecryptedMetadata.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/e2e/v2/decrypted/DecryptedMetadata.kt @@ -12,7 +12,7 @@ import com.owncloud.android.utils.EncryptionUtils data class DecryptedMetadata( val keyChecksums: MutableList = mutableListOf(), val deleted: Boolean = false, - var counter: Long = 0, + var counter: Long = EncryptionUtils.E2E_V2_INITIAL_COUNTER, val folders: MutableMap = mutableMapOf(), val files: MutableMap = mutableMapOf(), @Transient diff --git a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java index 795331f6c1d1..af0ed63b794f 100644 --- a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java @@ -137,7 +137,7 @@ private RemoteOperationResult encryptedCreateV1(OCFile parent, OwnCloudClient cl try { // lock folder - token = EncryptionUtils.lockFolder(parent, client); + token = EncryptionUtils.lockFolder(parent, client, EncryptionUtils.E2E_V1_INITIAL_COUNTER); // get metadata Pair metadataPair = EncryptionUtils.retrieveMetadataV1(parent, @@ -153,7 +153,7 @@ private RemoteOperationResult encryptedCreateV1(OCFile parent, OwnCloudClient cl // check if filename already exists if (isFileExisting(metadata, filename)) { - return new RemoteOperationResult(RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS); + return new RemoteOperationResult<>(RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS); } // generate new random file name, check if it exists in metadata @@ -275,7 +275,7 @@ private RemoteOperationResult encryptedCreateV2(OCFile parent, OwnCloudClient cl try { // lock folder - token = EncryptionUtils.lockFolder(parent, client); + token = EncryptionUtils.lockFolder(parent, client, EncryptionUtils.E2E_V2_INITIAL_COUNTER); // get metadata EncryptionUtilsV2 encryptionUtilsV2 = new EncryptionUtilsV2(); diff --git a/app/src/main/java/com/owncloud/android/operations/RemoveRemoteEncryptedFileOperation.kt b/app/src/main/java/com/owncloud/android/operations/RemoveRemoteEncryptedFileOperation.kt index e1b47c58e381..2bd1042ae4e9 100644 --- a/app/src/main/java/com/owncloud/android/operations/RemoveRemoteEncryptedFileOperation.kt +++ b/app/src/main/java/com/owncloud/android/operations/RemoveRemoteEncryptedFileOperation.kt @@ -59,7 +59,7 @@ class RemoveRemoteEncryptedFileOperation internal constructor( val isE2EVersionAtLeast2 = (E2EVersionHelper.isV2Plus(capability)) try { - token = EncryptionUtils.lockFolder(parentFolder, client) + token = EncryptionUtils.lockFolder(parentFolder, client, parentFolder.e2eCounter + 1) return if (isE2EVersionAtLeast2) { val deleteResult = deleteForV2(client, token) @@ -176,6 +176,10 @@ class RemoveRemoteEncryptedFileOperation internal constructor( encryptionUtilsV2.removeFileFromMetadata(fileName, metadata) } + parentFolder.setE2eCounter(metadata.metadata.counter) + val storageManager = FileDataStorageManager(user, context.contentResolver) + storageManager.saveFile(parentFolder) + encryptionUtilsV2.serializeAndUploadMetadata( parentFolder, metadata, @@ -184,7 +188,7 @@ class RemoveRemoteEncryptedFileOperation internal constructor( metadataExists, context, user, - FileDataStorageManager(user, context.contentResolver) + storageManager ) return Pair(result, delete) diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java index 4e0c11632045..a2c7616dda3c 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/OCFileListAdapter.java @@ -33,6 +33,7 @@ import com.nextcloud.client.jobs.upload.FileUploadHelper; import com.nextcloud.client.preferences.AppPreferences; import com.nextcloud.model.OfflineOperationType; +import com.nextcloud.utils.e2ee.E2EVersionHelper; import com.nextcloud.utils.extensions.ViewExtensionsKt; import com.nextcloud.utils.mdm.MDMConfig; import com.owncloud.android.MainApp; @@ -63,6 +64,7 @@ import com.owncloud.android.ui.interfaces.OCFileListFragmentInterface; import com.owncloud.android.ui.preview.PreviewTextFragment; import com.owncloud.android.utils.DisplayUtils; +import com.owncloud.android.utils.EncryptionUtils; import com.owncloud.android.utils.FileSortOrder; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.MimeTypeUtil; @@ -296,9 +298,14 @@ public void updateFileEncryptionById(String fileId, boolean encrypted) { .findFirst() .ifPresent(file -> { file.setEncrypted(encrypted); - file.setE2eCounter(0L); - mStorageManager.saveFile(file); + final var isE2EEV2 = E2EVersionHelper.INSTANCE.isV2Plus(capability); + long e2eCounter = EncryptionUtils.E2E_V1_INITIAL_COUNTER; + if (isE2EEV2) { + e2eCounter = EncryptionUtils.E2E_V2_INITIAL_COUNTER; + } + file.setE2eCounter(e2eCounter); + mStorageManager.saveFile(file); int position = getItemPosition(file); if (position != -1) { notifyItemChanged(position); diff --git a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java index 64aa7b02ea95..d31dd21f5fba 100644 --- a/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/app/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -1944,10 +1944,16 @@ private void encryptFolder(OCFile folder, .execute(client); if (remoteOperationResult.isSuccess()) { + OCCapability ocCapability = mContainerActivity.getStorageManager().getCapability(user.getAccountName()); + final var isE2EEV2 = E2EVersionHelper.INSTANCE.isV2Plus(ocCapability); + long e2eCounter = EncryptionUtils.E2E_V1_INITIAL_COUNTER; + if (isE2EEV2) { + e2eCounter = EncryptionUtils.E2E_V2_INITIAL_COUNTER; + } + // lock folder - String token = EncryptionUtils.lockFolder(folder, client); + String token = EncryptionUtils.lockFolder(folder, client, e2eCounter); - OCCapability ocCapability = mContainerActivity.getStorageManager().getCapability(user.getAccountName()); if (E2EVersionHelper.INSTANCE.isV2Plus(ocCapability)) { // Update metadata Pair metadataPair = EncryptionUtils.retrieveMetadata(folder, diff --git a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java index 9e7b1bd2de90..48d90c38981b 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -129,6 +129,10 @@ public final class EncryptionUtils { @VisibleForTesting public static final String MIGRATED_FOLDER_IDS = "MIGRATED_FOLDER_IDS"; + public static final long E2E_V1_INITIAL_COUNTER = 0L; + public static final long E2E_V2_INITIAL_COUNTER = 1L; + + private EncryptionUtils() { // utility class -> private constructor } @@ -1159,10 +1163,6 @@ public static boolean verifySHA512(String hashWithSalt, String compareToken) { return hashWithSalt.equals(newHash); } - public static String lockFolder(ServerFileInterface parentFile, OwnCloudClient client) throws UploadException { - return lockFolder(parentFile, client, -1); - } - public static String lockFolder(ServerFileInterface parentFile, OwnCloudClient client, long counter) throws UploadException { // Lock folder LockFileRemoteOperation lockFileOperation = new LockFileRemoteOperation(parentFile.getLocalId(), diff --git a/app/src/main/java/com/owncloud/android/utils/EncryptionUtilsV2.kt b/app/src/main/java/com/owncloud/android/utils/EncryptionUtilsV2.kt index 63d7616d920a..2a697c1e2bef 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtilsV2.kt +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtilsV2.kt @@ -57,7 +57,6 @@ import java.io.BufferedReader import java.io.ByteArrayOutputStream import java.io.InputStream import java.io.InputStreamReader -import java.math.BigInteger import java.security.MessageDigest import java.security.PrivateKey import java.security.cert.X509Certificate @@ -260,7 +259,7 @@ class EncryptionUtilsV2 { if (transferredFiledrop) { // lock folder - val token = EncryptionUtils.lockFolder(ocFile, client) + val token = EncryptionUtils.lockFolder(ocFile, client, ocFile.e2eCounter) serializeAndUploadMetadata( ocFile, @@ -528,6 +527,7 @@ class EncryptionUtilsV2 { metadataFile: DecryptedFolderMetadataFile ): DecryptedFolderMetadataFile { metadataFile.metadata.folders.remove(encryptedFileName) + metadataFile.metadata.counter++ return metadataFile } @@ -536,6 +536,7 @@ class EncryptionUtilsV2 { fun removeFileFromMetadata(fileName: String, metadata: DecryptedFolderMetadataFile) { metadata.metadata.files.remove(fileName) ?: throw IllegalStateException("File $fileName not found in metadata!") + metadata.metadata.counter++ } @Throws(IllegalStateException::class) @@ -697,7 +698,7 @@ class EncryptionUtilsV2 { storageManager ) // lock - val token = EncryptionUtils.lockFolder(folder, client) + val token = EncryptionUtils.lockFolder(folder, client, folder.e2eCounter) // upload serializeAndUploadMetadata( @@ -1009,17 +1010,10 @@ class EncryptionUtilsV2 { return DecryptedFolderMetadataFile(metadata) } - /** - * SHA-256 hash of metadata-key - */ - @Suppress("MagicNumber") - fun hashMetadataKey(metadataKey: ByteArray): String { - val bytes = MessageDigest - .getInstance("SHA-256") - .digest(metadataKey) - - return BigInteger(1, bytes).toString(16).padStart(32, '0') - } + fun hashMetadataKey(metadataKey: ByteArray): String = MessageDigest + .getInstance("SHA-256") + .digest(metadataKey) + .joinToString("") { "%02x".format(it) } fun getMessageSignature(cert: String, privateKey: String, metadataFile: EncryptedFolderMetadataFile): String = getMessageSignature( diff --git a/app/src/main/java/com/owncloud/android/utils/crypto/CryptoHelper.kt b/app/src/main/java/com/owncloud/android/utils/crypto/CryptoHelper.kt index 6e76ae379538..8228a29a1fa2 100644 --- a/app/src/main/java/com/owncloud/android/utils/crypto/CryptoHelper.kt +++ b/app/src/main/java/com/owncloud/android/utils/crypto/CryptoHelper.kt @@ -34,7 +34,7 @@ object CryptoHelper { private const val TRANSFORMATION = "AES/GCM/NoPadding" private const val GCM_TAG_LENGTH = 16 - private const val IV_LENGTH = 16 + private const val IV_LENGTH = 12 private const val SALT_LENGTH = 40 private const val GCM_TLEN = GCM_TAG_LENGTH * 8 private val charset = StandardCharsets.UTF_8 diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index e0e7087949d8..7e6a4d47ba28 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -21550,6 +21550,14 @@ + + + + + + + +