From c153e66db4558f2facff4f12420535f45447bd6a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Mar 2024 16:52:11 +0100 Subject: [PATCH 01/13] Fix upload problem for bigger files Signed-off-by: alperozturk --- .../e2e/v1/encrypted/EncryptedFile.kt | 4 +- .../operations/UploadFileOperation.java | 5 +- .../android/utils/EncryptionUtils.java | 95 +++++++++++-------- 3 files changed, 57 insertions(+), 47 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/e2e/v1/encrypted/EncryptedFile.kt b/app/src/main/java/com/owncloud/android/datamodel/e2e/v1/encrypted/EncryptedFile.kt index ee3c23d8b3e5..31eb05146f3f 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/e2e/v1/encrypted/EncryptedFile.kt +++ b/app/src/main/java/com/owncloud/android/datamodel/e2e/v1/encrypted/EncryptedFile.kt @@ -21,4 +21,6 @@ */ package com.owncloud.android.datamodel.e2e.v1.encrypted -class EncryptedFile(var encryptedBytes: ByteArray, var authenticationTag: String) +import java.io.File + +class EncryptedFile(var encryptedFile: File, var authenticationTag: String) diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index 4ac5c162daaf..89dc48fe34f4 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -580,10 +580,7 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare } } - File encryptedTempFile = File.createTempFile("encFile", encryptedFileName); - FileOutputStream fileOutputStream = new FileOutputStream(encryptedTempFile); - fileOutputStream.write(encryptedFile.getEncryptedBytes()); - fileOutputStream.close(); + File encryptedTempFile = encryptedFile.getEncryptedFile(); /***** E2E *****/ 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 e3980bdfde71..bda4156d496e 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -22,11 +22,13 @@ package com.owncloud.android.utils; import android.content.Context; +import android.os.Build; import android.text.TextUtils; import android.util.Base64; import android.util.Pair; import com.google.common.collect.Lists; +import com.google.common.primitives.Bytes; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; @@ -71,13 +73,17 @@ import java.io.BufferedReader; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.math.BigInteger; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.Key; @@ -95,6 +101,7 @@ import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.InvalidKeySpecException; +import java.security.spec.InvalidParameterSpecException; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; @@ -107,6 +114,7 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; +import javax.crypto.CipherOutputStream; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; @@ -118,6 +126,7 @@ import javax.crypto.spec.SecretKeySpec; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.annotation.VisibleForTesting; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @@ -567,44 +576,46 @@ public static byte[] decodeStringToBase64Bytes(String string) { */ public static EncryptedFile encryptFile(OCFile ocFile, byte[] encryptionKeyBytes, byte[] iv) throws NoSuchAlgorithmException, - InvalidAlgorithmParameterException, NoSuchPaddingException, InvalidKeyException, - BadPaddingException, IllegalBlockSizeException, IOException { + InvalidAlgorithmParameterException, NoSuchPaddingException, InvalidKeyException, IOException, InvalidParameterSpecException { File file = new File(ocFile.getStoragePath()); - return encryptFile(file, encryptionKeyBytes, iv); + Cipher cipher = getEncoderCipher(encryptionKeyBytes, iv); + return encryptFile(file, cipher); } - /** - * @param file file do crypt - * @param encryptionKeyBytes key, either from metadata or {@link EncryptionUtils#generateKey()} - * @param iv initialization vector, either from metadata or - * {@link EncryptionUtils#randomBytes(int)} - * @return encryptedFile with encryptedBytes and authenticationTag - */ - public static EncryptedFile encryptFile(File file, byte[] encryptionKeyBytes, byte[] iv) - throws NoSuchAlgorithmException, - InvalidAlgorithmParameterException, NoSuchPaddingException, InvalidKeyException, - BadPaddingException, IllegalBlockSizeException, IOException { + public static EncryptedFile encryptFile(File file, Cipher cipher) throws IOException, InvalidParameterSpecException { + File encryptedFile = new File(file.getAbsolutePath() + ".enc"); + encryptFileWithGivenCipher(file, encryptedFile, cipher); + byte[] authenticationTag = cipher.getParameters().getParameterSpec(GCMParameterSpec.class).getIV(); + String authenticationTagString = new String(authenticationTag, StandardCharsets.UTF_8); + return new EncryptedFile(encryptedFile, authenticationTagString); + } + private static Cipher getEncoderCipher(byte[] encryptionKeyBytes, byte[] iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException { Cipher cipher = Cipher.getInstance(AES_CIPHER); - Key key = new SecretKeySpec(encryptionKeyBytes, AES); - GCMParameterSpec spec = new GCMParameterSpec(128, iv); cipher.init(Cipher.ENCRYPT_MODE, key, spec); + return cipher; + } - RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); - byte[] fileBytes = new byte[(int) randomAccessFile.length()]; - randomAccessFile.readFully(fileBytes); + public static void encryptFileWithGivenCipher(File inputFile, File encryptedFile, Cipher cipher) throws IOException { + FileInputStream inputStream = new FileInputStream(inputFile); + FileOutputStream fileOutputStream = new FileOutputStream(encryptedFile); + CipherOutputStream outputStream = new CipherOutputStream(fileOutputStream, cipher); - byte[] cryptedBytes = cipher.doFinal(fileBytes); - String authenticationTag = encodeBytesToBase64String(Arrays.copyOfRange(cryptedBytes, - cryptedBytes.length - (128 / 8), - cryptedBytes.length)); + byte[] buffer = new byte[4096]; + int bytesRead; - return new EncryptedFile(cryptedBytes, authenticationTag); + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + + outputStream.close(); + inputStream.close(); } + // FIXME Decryption is broken /** * @param file encrypted file * @param encryptionKeyBytes key from metadata @@ -840,7 +851,7 @@ public static String encryptStringSymmetricAsStringOld(String string, byte[] enc return metadata.getCiphertext(); } -// /** + // /** // * Encrypt string with AES/GCM/NoPadding // * // * @param string string to encrypt @@ -872,22 +883,22 @@ public static String encryptStringSymmetricAsStringOld(String string, byte[] enc // // return encodedCryptedBytes + delimiter + encodedIV; // } -public static String decryptStringSymmetricAsString(String string, - byte[] encryptionKeyBytes, - byte[] iv, - byte[] authenticationTag, - ArbitraryDataProvider arbitraryDataProvider, - User user - ) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { - return decryptStringSymmetricAsString( - decodeStringToBase64Bytes(string), - encryptionKeyBytes, - iv, - authenticationTag, - false, - arbitraryDataProvider, - user); -} + public static String decryptStringSymmetricAsString(String string, + byte[] encryptionKeyBytes, + byte[] iv, + byte[] authenticationTag, + ArbitraryDataProvider arbitraryDataProvider, + User user + ) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException { + return decryptStringSymmetricAsString( + decodeStringToBase64Bytes(string), + encryptionKeyBytes, + iv, + authenticationTag, + false, + arbitraryDataProvider, + user); + } public static String decryptStringSymmetricAsString(String string, byte[] encryptionKeyBytes, @@ -1196,7 +1207,7 @@ public static String privateKeyToPEM(PrivateKey privateKey) { return "-----BEGIN PRIVATE KEY-----\n" + privateKeyString.replaceAll("(.{65})", "$1\n") + "\n-----END PRIVATE KEY-----"; } - + public static PrivateKey PEMtoPrivateKey(String pem) throws NoSuchAlgorithmException, InvalidKeySpecException { byte[] privateKeyBytes = EncryptionUtils.decodeStringToBase64Bytes(pem); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes); From b8af027528994ae75c93d7e7a3d585a370483387 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Thu, 21 Mar 2024 17:17:47 +0100 Subject: [PATCH 02/13] Use correctly encoded authenticationTagString Signed-off-by: alperozturk --- .../main/java/com/owncloud/android/utils/EncryptionUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 bda4156d496e..9647f7e4171f 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -587,7 +587,7 @@ public static EncryptedFile encryptFile(File file, Cipher cipher) throws IOExcep File encryptedFile = new File(file.getAbsolutePath() + ".enc"); encryptFileWithGivenCipher(file, encryptedFile, cipher); byte[] authenticationTag = cipher.getParameters().getParameterSpec(GCMParameterSpec.class).getIV(); - String authenticationTagString = new String(authenticationTag, StandardCharsets.UTF_8); + String authenticationTagString = encodeBytesToBase64String(authenticationTag); return new EncryptedFile(encryptedFile, authenticationTagString); } From c2f7d005052173e389de5a4981225c095fd1791a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 09:11:02 +0100 Subject: [PATCH 03/13] Extract cipher from decryption Signed-off-by: alperozturk --- .../operations/DownloadFileOperation.java | 8 +++-- .../android/utils/EncryptionUtils.java | 30 +++++-------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index 8091553ca277..cdbfa4677076 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -51,6 +51,8 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import javax.crypto.Cipher; + import static com.owncloud.android.utils.EncryptionUtils.decodeStringToBase64Bytes; /** @@ -265,9 +267,9 @@ protected RemoteOperationResult run(OwnCloudClient client) { byte[] authenticationTag = decodeStringToBase64Bytes(authenticationTagString); try { - byte[] decryptedBytes = EncryptionUtils.decryptFile(tmpFile, - key, - iv, + Cipher cipher = EncryptionUtils.getCipher(Cipher.DECRYPT_MODE, key, iv); + byte[] decryptedBytes = EncryptionUtils.decryptFile(cipher, + tmpFile, authenticationTag, new ArbitraryDataProviderImpl(operationContext), user); 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 9647f7e4171f..21ffed773cc2 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -579,7 +579,7 @@ public static EncryptedFile encryptFile(OCFile ocFile, byte[] encryptionKeyBytes InvalidAlgorithmParameterException, NoSuchPaddingException, InvalidKeyException, IOException, InvalidParameterSpecException { File file = new File(ocFile.getStoragePath()); - Cipher cipher = getEncoderCipher(encryptionKeyBytes, iv); + Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, encryptionKeyBytes, iv); return encryptFile(file, cipher); } @@ -591,11 +591,11 @@ public static EncryptedFile encryptFile(File file, Cipher cipher) throws IOExcep return new EncryptedFile(encryptedFile, authenticationTagString); } - private static Cipher getEncoderCipher(byte[] encryptionKeyBytes, byte[] iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException { + public static Cipher getCipher(int mode, byte[] encryptionKeyBytes, byte[] iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException { Cipher cipher = Cipher.getInstance(AES_CIPHER); Key key = new SecretKeySpec(encryptionKeyBytes, AES); GCMParameterSpec spec = new GCMParameterSpec(128, iv); - cipher.init(Cipher.ENCRYPT_MODE, key, spec); + cipher.init(mode, key, spec); return cipher; } @@ -616,29 +616,13 @@ public static void encryptFileWithGivenCipher(File inputFile, File encryptedFile } // FIXME Decryption is broken - /** - * @param file encrypted file - * @param encryptionKeyBytes key from metadata - * @param iv initialization vector from metadata - * @param authenticationTag authenticationTag from metadata - * @return decrypted byte[] - */ - public static byte[] decryptFile(File file, - byte[] encryptionKeyBytes, - byte[] iv, + public static byte[] decryptFile( + Cipher cipher, + File file, byte[] authenticationTag, ArbitraryDataProvider arbitraryDataProvider, User user) - throws NoSuchAlgorithmException, - InvalidAlgorithmParameterException, NoSuchPaddingException, InvalidKeyException, - BadPaddingException, IllegalBlockSizeException, IOException { - - - Cipher cipher = Cipher.getInstance(AES_CIPHER); - Key key = new SecretKeySpec(encryptionKeyBytes, AES); - GCMParameterSpec spec = new GCMParameterSpec(128, iv); - cipher.init(Cipher.DECRYPT_MODE, key, spec); - + throws BadPaddingException, IllegalBlockSizeException, IOException { RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); byte[] fileBytes = new byte[(int) randomAccessFile.length()]; randomAccessFile.readFully(fileBytes); From f9e50338ee025c33fe89856020102bf70db3d3d7 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 09:17:29 +0100 Subject: [PATCH 04/13] Extract getAuthenticationTag Signed-off-by: alperozturk --- .../operations/UploadFileOperation.java | 7 ++++- .../android/utils/EncryptionUtils.java | 26 +++++-------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index 89dc48fe34f4..a37dffaf71d0 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -94,6 +94,8 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import javax.crypto.Cipher; + import androidx.annotation.CheckResult; import androidx.annotation.Nullable; @@ -565,7 +567,10 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare // IV, always generate new one byte[] iv = EncryptionUtils.randomBytes(EncryptionUtils.ivLength); - EncryptedFile encryptedFile = EncryptionUtils.encryptFile(mFile, key, iv); + Cipher cipher = EncryptionUtils.getCipher(Cipher.ENCRYPT_MODE, key, iv); + File file = new File(mFile.getStoragePath()); + + EncryptedFile encryptedFile = EncryptionUtils.encryptFile(file, cipher); // new random file name, check if it exists in metadata String encryptedFileName = EncryptionUtils.generateUid(); 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 21ffed773cc2..8affc8ed5181 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -566,31 +566,18 @@ public static byte[] decodeStringToBase64Bytes(String string) { /* ENCRYPTION */ - - /** - * @param ocFile file do crypt - * @param encryptionKeyBytes key, either from metadata or {@link EncryptionUtils#generateKey()} - * @param iv initialization vector, either from metadata or - * {@link EncryptionUtils#randomBytes(int)} - * @return encryptedFile with encryptedBytes and authenticationTag - */ - public static EncryptedFile encryptFile(OCFile ocFile, byte[] encryptionKeyBytes, byte[] iv) - throws NoSuchAlgorithmException, - InvalidAlgorithmParameterException, NoSuchPaddingException, InvalidKeyException, IOException, InvalidParameterSpecException { - File file = new File(ocFile.getStoragePath()); - - Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, encryptionKeyBytes, iv); - return encryptFile(file, cipher); - } - public static EncryptedFile encryptFile(File file, Cipher cipher) throws IOException, InvalidParameterSpecException { File encryptedFile = new File(file.getAbsolutePath() + ".enc"); encryptFileWithGivenCipher(file, encryptedFile, cipher); - byte[] authenticationTag = cipher.getParameters().getParameterSpec(GCMParameterSpec.class).getIV(); - String authenticationTagString = encodeBytesToBase64String(authenticationTag); + String authenticationTagString = getAuthenticationTag(cipher); return new EncryptedFile(encryptedFile, authenticationTagString); } + private static String getAuthenticationTag(Cipher cipher) throws InvalidParameterSpecException { + byte[] authenticationTag = cipher.getParameters().getParameterSpec(GCMParameterSpec.class).getIV(); + return encodeBytesToBase64String(authenticationTag); + } + public static Cipher getCipher(int mode, byte[] encryptionKeyBytes, byte[] iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException { Cipher cipher = Cipher.getInstance(AES_CIPHER); Key key = new SecretKeySpec(encryptionKeyBytes, AES); @@ -623,6 +610,7 @@ public static byte[] decryptFile( ArbitraryDataProvider arbitraryDataProvider, User user) throws BadPaddingException, IllegalBlockSizeException, IOException { + RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); byte[] fileBytes = new byte[(int) randomAccessFile.length()]; randomAccessFile.readFully(fileBytes); From c0f23c435a07603eae08dab61c3d99c48dfcd762 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 09:38:33 +0100 Subject: [PATCH 05/13] Simplify Signed-off-by: alperozturk --- .../operations/DownloadFileOperation.java | 11 +----- .../operations/UploadFileOperation.java | 6 ---- .../android/utils/EncryptionUtils.java | 36 +++++++++++++++++-- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index cdbfa4677076..fc286dfd4a2d 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -264,19 +264,10 @@ protected RemoteOperationResult run(OwnCloudClient client) { byte[] key = decodeStringToBase64Bytes(keyString); byte[] iv = decodeStringToBase64Bytes(nonceString); - byte[] authenticationTag = decodeStringToBase64Bytes(authenticationTagString); try { Cipher cipher = EncryptionUtils.getCipher(Cipher.DECRYPT_MODE, key, iv); - byte[] decryptedBytes = EncryptionUtils.decryptFile(cipher, - tmpFile, - authenticationTag, - new ArbitraryDataProviderImpl(operationContext), - user); - - try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile)) { - fileOutputStream.write(decryptedBytes); - } + tmpFile = EncryptionUtils.decryptFile(tmpFile, authenticationTagString, cipher, new ArbitraryDataProviderImpl(operationContext), user); } catch (Exception e) { return new RemoteOperationResult(e); } diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index a37dffaf71d0..a031c7f852b4 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -560,16 +560,10 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare Long creationTimestamp = FileUtil.getCreationTimestamp(originalFile); /***** E2E *****/ - - // Key, always generate new one byte[] key = EncryptionUtils.generateKey(); - - // IV, always generate new one byte[] iv = EncryptionUtils.randomBytes(EncryptionUtils.ivLength); - Cipher cipher = EncryptionUtils.getCipher(Cipher.ENCRYPT_MODE, key, iv); File file = new File(mFile.getStoragePath()); - EncryptedFile encryptedFile = EncryptionUtils.encryptFile(file, cipher); // new random file name, check if it exists in metadata 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 8affc8ed5181..8a03cd7b3ef0 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -114,6 +114,7 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; @@ -563,9 +564,6 @@ public static byte[] decodeStringToBase64Bytes(String string) { return Base64.decode(string, Base64.NO_WRAP); } - /* - ENCRYPTION - */ public static EncryptedFile encryptFile(File file, Cipher cipher) throws IOException, InvalidParameterSpecException { File encryptedFile = new File(file.getAbsolutePath() + ".enc"); encryptFileWithGivenCipher(file, encryptedFile, cipher); @@ -602,7 +600,37 @@ public static void encryptFileWithGivenCipher(File inputFile, File encryptedFile inputStream.close(); } + public static File decryptFile(File encryptedFile, + String authenticationTag, + Cipher cipher, + ArbitraryDataProvider arbitraryDataProvider, + User user) throws InvalidParameterSpecException { + File decryptedFile = new File(encryptedFile.getAbsolutePath().replace(".enc", "_decrypted")); + + try (FileInputStream inputStream = new FileInputStream(encryptedFile); + FileOutputStream fileOutputStream = new FileOutputStream(decryptedFile); + CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher)) { + + byte[] buffer = new byte[4096]; + int bytesRead; + + while ((bytesRead = cipherInputStream.read(buffer)) != -1) { + fileOutputStream.write(buffer, 0, bytesRead); + } + } catch (Exception e) { + Log_OC.d(TAG, "Error caught at decryptFile(): " + e.getLocalizedMessage()); + } + + if (!getAuthenticationTag(cipher).equals(authenticationTag)) { + reportE2eError(arbitraryDataProvider, user); + throw new SecurityException("Tag not correct"); + } + + return decryptedFile; + } + // FIXME Decryption is broken + /* public static byte[] decryptFile( Cipher cipher, File file, @@ -627,6 +655,8 @@ public static byte[] decryptFile( return cipher.doFinal(fileBytes); } + */ + /** * Encrypt string with RSA algorithm, ECB mode, OAEPWithSHA-256AndMGF1 padding Asymmetric encryption, with private From 67ddd0ba38cff9b6483ae511557df6421f38c146 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 10:05:31 +0100 Subject: [PATCH 06/13] Fix decryption Signed-off-by: alperozturk --- .../operations/DownloadFileOperation.java | 8 +--- .../android/utils/EncryptionUtils.java | 37 ++++++++++--------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index fc286dfd4a2d..def606f504dd 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -267,18 +267,14 @@ protected RemoteOperationResult run(OwnCloudClient client) { try { Cipher cipher = EncryptionUtils.getCipher(Cipher.DECRYPT_MODE, key, iv); - tmpFile = EncryptionUtils.decryptFile(tmpFile, authenticationTagString, cipher, new ArbitraryDataProviderImpl(operationContext), user); + EncryptionUtils.decryptFile(cipher, tmpFile, newFile, authenticationTagString, new ArbitraryDataProviderImpl(operationContext), user); } catch (Exception e) { return new RemoteOperationResult(e); } } if (downloadType == DownloadType.DOWNLOAD) { - moved = tmpFile.renameTo(newFile); - newFile.setLastModified(file.getModificationTimestamp()); - if (!moved) { - result = new RemoteOperationResult(RemoteOperationResult.ResultCode.LOCAL_STORAGE_NOT_MOVED); - } + } else if (downloadType == DownloadType.EXPORT) { new FileExportUtils().exportFile(file.getFileName(), file.getMimeType(), 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 8a03cd7b3ef0..a47073458f83 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -568,6 +568,7 @@ public static EncryptedFile encryptFile(File file, Cipher cipher) throws IOExcep File encryptedFile = new File(file.getAbsolutePath() + ".enc"); encryptFileWithGivenCipher(file, encryptedFile, cipher); String authenticationTagString = getAuthenticationTag(cipher); + Log_OC.d("", "KAVGAM!!: " + authenticationTagString); return new EncryptedFile(encryptedFile, authenticationTagString); } @@ -600,33 +601,35 @@ public static void encryptFileWithGivenCipher(File inputFile, File encryptedFile inputStream.close(); } - public static File decryptFile(File encryptedFile, + public static void decryptFile(Cipher cipher, + File encryptedFile, + File decryptedFile, String authenticationTag, - Cipher cipher, ArbitraryDataProvider arbitraryDataProvider, - User user) throws InvalidParameterSpecException { - File decryptedFile = new File(encryptedFile.getAbsolutePath().replace(".enc", "_decrypted")); + User user) throws IOException, + BadPaddingException, IllegalBlockSizeException, InvalidParameterSpecException { - try (FileInputStream inputStream = new FileInputStream(encryptedFile); - FileOutputStream fileOutputStream = new FileOutputStream(decryptedFile); - CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher)) { - - byte[] buffer = new byte[4096]; - int bytesRead; - - while ((bytesRead = cipherInputStream.read(buffer)) != -1) { - fileOutputStream.write(buffer, 0, bytesRead); + FileInputStream inputStream = new FileInputStream(encryptedFile); + FileOutputStream outputStream = new FileOutputStream(decryptedFile); + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + byte[] output = cipher.update(buffer, 0, bytesRead); + if (output != null) { + outputStream.write(output); } - } catch (Exception e) { - Log_OC.d(TAG, "Error caught at decryptFile(): " + e.getLocalizedMessage()); } + byte[] output = cipher.doFinal(); + if (output != null) { + outputStream.write(output); + } + inputStream.close(); + outputStream.close(); if (!getAuthenticationTag(cipher).equals(authenticationTag)) { reportE2eError(arbitraryDataProvider, user); throw new SecurityException("Tag not correct"); } - - return decryptedFile; } // FIXME Decryption is broken From c7e53633fc20d54a16d203b0f8838fd6dfe3ece0 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 10:16:56 +0100 Subject: [PATCH 07/13] Fix duplicate .enc files Signed-off-by: alperozturk --- .../com/owncloud/android/operations/UploadFileOperation.java | 2 ++ .../main/java/com/owncloud/android/utils/EncryptionUtils.java | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index a031c7f852b4..a127895061ec 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -738,6 +738,8 @@ private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile pare token = null; } } + + encryptedTempFile.delete(); } } catch (FileNotFoundException e) { Log_OC.d(TAG, mFile.getStoragePath() + " not exists anymore"); 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 a47073458f83..1efa411c5b81 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -568,7 +568,6 @@ public static EncryptedFile encryptFile(File file, Cipher cipher) throws IOExcep File encryptedFile = new File(file.getAbsolutePath() + ".enc"); encryptFileWithGivenCipher(file, encryptedFile, cipher); String authenticationTagString = getAuthenticationTag(cipher); - Log_OC.d("", "KAVGAM!!: " + authenticationTagString); return new EncryptedFile(encryptedFile, authenticationTagString); } From 566fa2de6ee29b2b440dc18c708d40e7fb2c9f87 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 10:17:23 +0100 Subject: [PATCH 08/13] Fix duplicate .enc files Signed-off-by: alperozturk --- .../owncloud/android/operations/DownloadFileOperation.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index def606f504dd..8bda3a62213e 100644 --- a/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java @@ -273,9 +273,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } } - if (downloadType == DownloadType.DOWNLOAD) { - - } else if (downloadType == DownloadType.EXPORT) { + if (downloadType == DownloadType.EXPORT) { new FileExportUtils().exportFile(file.getFileName(), file.getMimeType(), operationContext.getContentResolver(), From c5bae2dbc5eb01b5418f6101fe5b45e260398032 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 10:49:15 +0100 Subject: [PATCH 09/13] Fix Test compilation Signed-off-by: alperozturk --- .../android/util/EncryptionTestIT.java | 46 ++++++------------- .../android/utils/EncryptionUtils.java | 2 +- 2 files changed, 15 insertions(+), 33 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java b/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java index 17c3fc8a2f7f..4b305333c0a9 100644 --- a/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java +++ b/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java @@ -66,6 +66,7 @@ import java.util.Set; import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; import static com.owncloud.android.utils.EncryptionUtils.decodeStringToBase64Bytes; import static com.owncloud.android.utils.EncryptionUtils.decryptFile; @@ -395,9 +396,8 @@ public void testMigrateMetadataKey() throws Exception { public void testCryptFileWithoutMetadata() throws Exception { byte[] key = decodeStringToBase64Bytes("WANM0gRv+DhaexIsI0T3Lg=="); byte[] iv = decodeStringToBase64Bytes("gKm3n+mJzeY26q4OfuZEqg=="); - byte[] authTag = decodeStringToBase64Bytes("PboI9tqHHX3QeAA22PIu4w=="); - assertTrue(cryptFile("ia7OEEEyXMoRa1QWQk8r", "78f42172166f9dc8fd1a7156b1753353", key, iv, authTag)); + assertTrue(cryptFile("ia7OEEEyXMoRa1QWQk8r", "78f42172166f9dc8fd1a7156b1753353", key, iv)); } @Test @@ -410,9 +410,7 @@ public void cryptFileWithMetadata() throws Exception { decodeStringToBase64Bytes(metadata.getFiles().get("ia7OEEEyXMoRa1QWQk8r") .getEncrypted().getKey()), decodeStringToBase64Bytes(metadata.getFiles().get("ia7OEEEyXMoRa1QWQk8r") - .getInitializationVector()), - decodeStringToBase64Bytes(metadata.getFiles().get("ia7OEEEyXMoRa1QWQk8r") - .getAuthenticationTag()))); + .getInitializationVector()))); // n9WXAIXO2wRY4R8nXwmo assertTrue(cryptFile("n9WXAIXO2wRY4R8nXwmo", @@ -420,9 +418,7 @@ public void cryptFileWithMetadata() throws Exception { decodeStringToBase64Bytes(metadata.getFiles().get("n9WXAIXO2wRY4R8nXwmo") .getEncrypted().getKey()), decodeStringToBase64Bytes(metadata.getFiles().get("n9WXAIXO2wRY4R8nXwmo") - .getInitializationVector()), - decodeStringToBase64Bytes(metadata.getFiles().get("n9WXAIXO2wRY4R8nXwmo") - .getAuthenticationTag()))); + .getInitializationVector()))); } @Test @@ -846,35 +842,21 @@ private DecryptedFolderMetadataFileV1 generateFolderMetadataV1_1() throws Except return new DecryptedFolderMetadataFileV1(metadata1, files); } - - private boolean cryptFile(String fileName, String md5, byte[] key, byte[] iv, byte[] expectedAuthTag) + // FIXME + private boolean cryptFile(String fileName, String md5, byte[] key, byte[] iv) throws Exception { - File file = getFile(fileName); + File file = File.createTempFile(fileName, "enc"); assertEquals(md5, getMD5Sum(file)); - EncryptedFile encryptedFile = encryptFile(file, key, iv); - - File encryptedTempFile = File.createTempFile("file", "tmp"); - FileOutputStream fileOutputStream = new FileOutputStream(encryptedTempFile); - fileOutputStream.write(encryptedFile.getEncryptedBytes()); - fileOutputStream.close(); - - byte[] authenticationTag = decodeStringToBase64Bytes(encryptedFile.getAuthenticationTag()); - - // verify authentication tag - assertTrue(Arrays.equals(expectedAuthTag, authenticationTag)); - - byte[] decryptedBytes = decryptFile(encryptedTempFile, - key, - iv, - authenticationTag, - new ArbitraryDataProviderImpl(targetContext), - user); + // Encryption + Cipher encryptorCipher = EncryptionUtils.getCipher(Cipher.ENCRYPT_MODE, key, iv); + EncryptionUtils.encryptFile(file, encryptorCipher); + String encryptorCipherAuthTag = EncryptionUtils.getAuthenticationTag(encryptorCipher); + // Decryption + Cipher decryptorCipher = EncryptionUtils.getCipher(Cipher.DECRYPT_MODE, key, iv); File decryptedFile = File.createTempFile("file", "dec"); - FileOutputStream fileOutputStream1 = new FileOutputStream(decryptedFile); - fileOutputStream1.write(decryptedBytes); - fileOutputStream1.close(); + decryptFile(decryptorCipher, file, decryptedFile, encryptorCipherAuthTag, new ArbitraryDataProviderImpl(targetContext), user); return md5.compareTo(getMD5Sum(decryptedFile)) == 0; } 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 1efa411c5b81..3601fab6a16e 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -571,7 +571,7 @@ public static EncryptedFile encryptFile(File file, Cipher cipher) throws IOExcep return new EncryptedFile(encryptedFile, authenticationTagString); } - private static String getAuthenticationTag(Cipher cipher) throws InvalidParameterSpecException { + public static String getAuthenticationTag(Cipher cipher) throws InvalidParameterSpecException { byte[] authenticationTag = cipher.getParameters().getParameterSpec(GCMParameterSpec.class).getIV(); return encodeBytesToBase64String(authenticationTag); } From a87c0e7df8f6a30cc0ab93c56d375c4f8c613485 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 12:28:25 +0100 Subject: [PATCH 10/13] Increase performance Signed-off-by: alperozturk --- .../android/utils/EncryptionUtils.java | 71 +++++++++++-------- 1 file changed, 40 insertions(+), 31 deletions(-) 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 3601fab6a16e..b7c8bef2082d 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -564,7 +564,7 @@ public static byte[] decodeStringToBase64Bytes(String string) { return Base64.decode(string, Base64.NO_WRAP); } - public static EncryptedFile encryptFile(File file, Cipher cipher) throws IOException, InvalidParameterSpecException { + public static EncryptedFile encryptFile(File file, Cipher cipher) throws InvalidParameterSpecException { File encryptedFile = new File(file.getAbsolutePath() + ".enc"); encryptFileWithGivenCipher(file, encryptedFile, cipher); String authenticationTagString = getAuthenticationTag(cipher); @@ -584,20 +584,24 @@ public static Cipher getCipher(int mode, byte[] encryptionKeyBytes, byte[] iv) t return cipher; } - public static void encryptFileWithGivenCipher(File inputFile, File encryptedFile, Cipher cipher) throws IOException { - FileInputStream inputStream = new FileInputStream(inputFile); - FileOutputStream fileOutputStream = new FileOutputStream(encryptedFile); - CipherOutputStream outputStream = new CipherOutputStream(fileOutputStream, cipher); + public static void encryptFileWithGivenCipher(File inputFile, File encryptedFile, Cipher cipher) { + try( FileInputStream inputStream = new FileInputStream(inputFile); + FileOutputStream fileOutputStream = new FileOutputStream(encryptedFile); + CipherOutputStream outputStream = new CipherOutputStream(fileOutputStream, cipher)) { + byte[] buffer = new byte[4096]; + int bytesRead; - byte[] buffer = new byte[4096]; - int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } - while ((bytesRead = inputStream.read(buffer)) != -1) { - outputStream.write(buffer, 0, bytesRead); - } + outputStream.close(); + inputStream.close(); - outputStream.close(); - inputStream.close(); + Log_OC.d(TAG, encryptedFile.getName() + "encrypted successfully"); + } catch (IOException exception) { + Log_OC.d(TAG, "Error caught at encryptFileWithGivenCipher(): " + exception.getLocalizedMessage()); + } } public static void decryptFile(Cipher cipher, @@ -605,29 +609,34 @@ public static void decryptFile(Cipher cipher, File decryptedFile, String authenticationTag, ArbitraryDataProvider arbitraryDataProvider, - User user) throws IOException, - BadPaddingException, IllegalBlockSizeException, InvalidParameterSpecException { - - FileInputStream inputStream = new FileInputStream(encryptedFile); - FileOutputStream outputStream = new FileOutputStream(decryptedFile); - byte[] buffer = new byte[4096]; - int bytesRead; - while ((bytesRead = inputStream.read(buffer)) != -1) { - byte[] output = cipher.update(buffer, 0, bytesRead); + User user) { + try (FileInputStream inputStream = new FileInputStream(encryptedFile); + FileOutputStream outputStream = new FileOutputStream(decryptedFile)) { + + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + byte[] output = cipher.update(buffer, 0, bytesRead); + if (output != null) { + outputStream.write(output); + } + } + byte[] output = cipher.doFinal(); if (output != null) { outputStream.write(output); } - } - byte[] output = cipher.doFinal(); - if (output != null) { - outputStream.write(output); - } - inputStream.close(); - outputStream.close(); + inputStream.close(); + outputStream.close(); - if (!getAuthenticationTag(cipher).equals(authenticationTag)) { - reportE2eError(arbitraryDataProvider, user); - throw new SecurityException("Tag not correct"); + if (!getAuthenticationTag(cipher).equals(authenticationTag)) { + reportE2eError(arbitraryDataProvider, user); + throw new SecurityException("Tag not correct"); + } + + Log_OC.d(TAG, encryptedFile.getName() + "decrypted successfully"); + } catch (IOException | BadPaddingException | IllegalBlockSizeException | InvalidParameterSpecException | + SecurityException exception) { + Log_OC.d(TAG, "Error caught at decryptFile(): " + exception.getLocalizedMessage()); } } From 99f7b672d80fd88b4adc179b99b56a771687044a Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 12:40:54 +0100 Subject: [PATCH 11/13] Fix test Signed-off-by: alperozturk --- .../android/util/EncryptionTestIT.java | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java b/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java index 4b305333c0a9..2d993e4933aa 100644 --- a/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java +++ b/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java @@ -43,6 +43,7 @@ import com.owncloud.android.utils.EncryptionUtils; import org.apache.commons.codec.binary.Hex; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; @@ -51,9 +52,11 @@ import java.io.FileOutputStream; import java.io.IOException; import java.math.BigInteger; +import java.security.DigestInputStream; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.SecureRandom; import java.security.interfaces.RSAPrivateCrtKey; @@ -100,6 +103,8 @@ public class EncryptionTestIT extends AbstractIT { ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(targetContext); + private static final String MD5_ALGORITHM = "MD5"; + public static final String privateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAo" + "IBAQDsn0JKS/THu328z1IgN0VzYU53HjSX03WJIgWkmyTaxbiKpoJaKbksXmfSpgzV" + "GzKFvGfZ03fwFrN7Q8P8R2e8SNiell7mh1TDw9/0P7Bt/ER8PJrXORo+GviKHxaLr7" + @@ -842,11 +847,10 @@ private DecryptedFolderMetadataFileV1 generateFolderMetadataV1_1() throws Except return new DecryptedFolderMetadataFileV1(metadata1, files); } - // FIXME private boolean cryptFile(String fileName, String md5, byte[] key, byte[] iv) throws Exception { File file = File.createTempFile(fileName, "enc"); - assertEquals(md5, getMD5Sum(file)); + String md5BeforeEncryption = getMD5Sum(file); // Encryption Cipher encryptorCipher = EncryptionUtils.getCipher(Cipher.ENCRYPT_MODE, key, iv); @@ -858,35 +862,36 @@ private boolean cryptFile(String fileName, String md5, byte[] key, byte[] iv) File decryptedFile = File.createTempFile("file", "dec"); decryptFile(decryptorCipher, file, decryptedFile, encryptorCipherAuthTag, new ArbitraryDataProviderImpl(targetContext), user); - return md5.compareTo(getMD5Sum(decryptedFile)) == 0; - } - - private String getMD5Sum(File file) { - FileInputStream fileInputStream = null; - try { - fileInputStream = new FileInputStream(file); - MessageDigest md5 = MessageDigest.getInstance("MD5"); - byte[] bytes = new byte[2048]; - int readBytes; + String md5AfterEncryption = getMD5Sum(decryptedFile); - while ((readBytes = fileInputStream.read(bytes)) != -1) { - md5.update(bytes, 0, readBytes); - } + if (md5BeforeEncryption == null) { + Assert.fail(); + } - return new String(Hex.encodeHex(md5.digest())); + return md5BeforeEncryption.equals(md5AfterEncryption); + } - } catch (Exception e) { - Log_OC.e(this, e.getMessage()); - } finally { - if (fileInputStream != null) { - try { - fileInputStream.close(); - } catch (IOException e) { - Log_OC.e(this, "Error getting MD5 checksum for file", e); - } + public static String getMD5Sum(File file) { + try (FileInputStream fis = new FileInputStream(file)) { + MessageDigest md = MessageDigest.getInstance(MD5_ALGORITHM); + DigestInputStream dis = new DigestInputStream(fis, md); + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = dis.read(buffer)) != -1) { + md.update(buffer, 0, bytesRead); } + byte[] digest = md.digest(); + return bytesToHex(digest); + } catch (IOException | NoSuchAlgorithmException e) { + return null; } + } - return ""; + private static String bytesToHex(byte[] bytes) { + StringBuilder sb = new StringBuilder(); + for (byte b : bytes) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); } } From caaacab0a7507fa15dc1e65e6e5a76ba9e911250 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 12:45:39 +0100 Subject: [PATCH 12/13] Remove unused codes Signed-off-by: alperozturk --- .../android/utils/EncryptionUtils.java | 29 ------------------- 1 file changed, 29 deletions(-) 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 b7c8bef2082d..434bc5a83a89 100644 --- a/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/EncryptionUtils.java @@ -640,35 +640,6 @@ public static void decryptFile(Cipher cipher, } } - // FIXME Decryption is broken - /* - public static byte[] decryptFile( - Cipher cipher, - File file, - byte[] authenticationTag, - ArbitraryDataProvider arbitraryDataProvider, - User user) - throws BadPaddingException, IllegalBlockSizeException, IOException { - - RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); - byte[] fileBytes = new byte[(int) randomAccessFile.length()]; - randomAccessFile.readFully(fileBytes); - - // check authentication tag - byte[] extractedAuthenticationTag = Arrays.copyOfRange(fileBytes, - fileBytes.length - (128 / 8), - fileBytes.length); - - if (!Arrays.equals(extractedAuthenticationTag, authenticationTag)) { - reportE2eError(arbitraryDataProvider, user); - throw new SecurityException("Tag not correct"); - } - - return cipher.doFinal(fileBytes); - } - */ - - /** * Encrypt string with RSA algorithm, ECB mode, OAEPWithSHA-256AndMGF1 padding Asymmetric encryption, with private * and public key From 84d8c78bd520602cb2acfb9cfd09351a2c327a12 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Fri, 22 Mar 2024 13:03:01 +0100 Subject: [PATCH 13/13] Fix code analytics Signed-off-by: alperozturk --- .../android/util/EncryptionTestIT.java | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java b/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java index 2d993e4933aa..4a0b5193f0d4 100644 --- a/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java +++ b/app/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java @@ -36,20 +36,17 @@ import com.owncloud.android.datamodel.e2e.v1.decrypted.DecryptedFolderMetadataFileV1; import com.owncloud.android.datamodel.e2e.v1.decrypted.DecryptedMetadata; import com.owncloud.android.datamodel.e2e.v1.decrypted.Encrypted; -import com.owncloud.android.datamodel.e2e.v1.encrypted.EncryptedFile; import com.owncloud.android.datamodel.e2e.v1.encrypted.EncryptedFolderMetadataFileV1; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.e2ee.CsrHelper; import com.owncloud.android.utils.EncryptionUtils; -import org.apache.commons.codec.binary.Hex; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.math.BigInteger; import java.security.DigestInputStream; @@ -79,7 +76,6 @@ import static com.owncloud.android.utils.EncryptionUtils.decryptStringSymmetric; import static com.owncloud.android.utils.EncryptionUtils.deserializeJSON; import static com.owncloud.android.utils.EncryptionUtils.encodeBytesToBase64String; -import static com.owncloud.android.utils.EncryptionUtils.encryptFile; import static com.owncloud.android.utils.EncryptionUtils.encryptFolderMetadata; import static com.owncloud.android.utils.EncryptionUtils.generateChecksum; import static com.owncloud.android.utils.EncryptionUtils.generateKey; @@ -105,6 +101,9 @@ public class EncryptionTestIT extends AbstractIT { private static final String MD5_ALGORITHM = "MD5"; + private static final String filename = "ia7OEEEyXMoRa1QWQk8r"; + private static final String secondFilename = "n9WXAIXO2wRY4R8nXwmo"; + public static final String privateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAo" + "IBAQDsn0JKS/THu328z1IgN0VzYU53HjSX03WJIgWkmyTaxbiKpoJaKbksXmfSpgzV" + "GzKFvGfZ03fwFrN7Q8P8R2e8SNiell7mh1TDw9/0P7Bt/ER8PJrXORo+GviKHxaLr7" + @@ -402,27 +401,25 @@ public void testCryptFileWithoutMetadata() throws Exception { byte[] key = decodeStringToBase64Bytes("WANM0gRv+DhaexIsI0T3Lg=="); byte[] iv = decodeStringToBase64Bytes("gKm3n+mJzeY26q4OfuZEqg=="); - assertTrue(cryptFile("ia7OEEEyXMoRa1QWQk8r", "78f42172166f9dc8fd1a7156b1753353", key, iv)); + assertTrue(cryptFile(filename, "78f42172166f9dc8fd1a7156b1753353", key, iv)); } @Test public void cryptFileWithMetadata() throws Exception { DecryptedFolderMetadataFileV1 metadata = generateFolderMetadataV1_1(); - // n9WXAIXO2wRY4R8nXwmo - assertTrue(cryptFile("ia7OEEEyXMoRa1QWQk8r", + assertTrue(cryptFile(filename, "78f42172166f9dc8fd1a7156b1753353", - decodeStringToBase64Bytes(metadata.getFiles().get("ia7OEEEyXMoRa1QWQk8r") + decodeStringToBase64Bytes(metadata.getFiles().get(filename) .getEncrypted().getKey()), - decodeStringToBase64Bytes(metadata.getFiles().get("ia7OEEEyXMoRa1QWQk8r") + decodeStringToBase64Bytes(metadata.getFiles().get(filename) .getInitializationVector()))); - // n9WXAIXO2wRY4R8nXwmo - assertTrue(cryptFile("n9WXAIXO2wRY4R8nXwmo", + assertTrue(cryptFile(secondFilename, "825143ed1f21ebb0c3b3c3f005b2f5db", - decodeStringToBase64Bytes(metadata.getFiles().get("n9WXAIXO2wRY4R8nXwmo") + decodeStringToBase64Bytes(metadata.getFiles().get(secondFilename) .getEncrypted().getKey()), - decodeStringToBase64Bytes(metadata.getFiles().get("n9WXAIXO2wRY4R8nXwmo") + decodeStringToBase64Bytes(metadata.getFiles().get(secondFilename) .getInitializationVector()))); } @@ -739,8 +736,8 @@ public void testChecksum() throws Exception { DecryptedFolderMetadataFileV1 metadata = new DecryptedFolderMetadataFileV1(); String mnemonic = "chimney potato joke science ridge trophy result estate spare vapor much room"; - metadata.getFiles().put("n9WXAIXO2wRY4R8nXwmo", new DecryptedFile()); - metadata.getFiles().put("ia7OEEEyXMoRa1QWQk8r", new DecryptedFile()); + metadata.getFiles().put(secondFilename, new DecryptedFile()); + metadata.getFiles().put(filename, new DecryptedFile()); String encryptedMetadataKey = "GuFPAULudgD49S4+VDFck3LiqQ8sx4zmbrBtdpCSGcT+T0W0z4F5gYQYPlzTG6WOkdW5LJZK/"; metadata.getMetadata().setMetadataKey(encryptedMetadataKey); @@ -788,9 +785,8 @@ public void testAddIdToMigratedIds() { // Helper public static boolean compareJsonStrings(String expected, String actual) { - JsonParser parser = new JsonParser(); - JsonElement o1 = parser.parse(expected); - JsonElement o2 = parser.parse(actual); + JsonElement o1 = JsonParser.parseString(expected); + JsonElement o2 = JsonParser.parseString(actual); if (o1.equals(o2)) { return true; @@ -829,7 +825,7 @@ private DecryptedFolderMetadataFileV1 generateFolderMetadataV1_1() throws Except file1.setMetadataKey(0); file1.setAuthenticationTag("PboI9tqHHX3QeAA22PIu4w=="); - files.put("ia7OEEEyXMoRa1QWQk8r", file1); + files.put(filename, file1); Data data2 = new Data(); data2.setKey("9dfzbIYDt28zTyZfbcll+g=="); @@ -842,7 +838,7 @@ private DecryptedFolderMetadataFileV1 generateFolderMetadataV1_1() throws Except file2.setMetadataKey(0); file2.setAuthenticationTag("qOQZdu5soFO77Y7y4rAOVA=="); - files.put("n9WXAIXO2wRY4R8nXwmo", file2); + files.put(secondFilename, file2); return new DecryptedFolderMetadataFileV1(metadata1, files); }