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..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,24 +36,24 @@ 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; 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; @@ -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; @@ -75,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; @@ -99,6 +99,11 @@ public class EncryptionTestIT extends AbstractIT { ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(targetContext); + 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" + @@ -395,34 +400,27 @@ 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(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") - .getInitializationVector()), - decodeStringToBase64Bytes(metadata.getFiles().get("ia7OEEEyXMoRa1QWQk8r") - .getAuthenticationTag()))); + 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") - .getInitializationVector()), - decodeStringToBase64Bytes(metadata.getFiles().get("n9WXAIXO2wRY4R8nXwmo") - .getAuthenticationTag()))); + decodeStringToBase64Bytes(metadata.getFiles().get(secondFilename) + .getInitializationVector()))); } @Test @@ -738,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); @@ -787,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; @@ -828,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=="); @@ -841,70 +838,56 @@ 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); } - - private boolean cryptFile(String fileName, String md5, byte[] key, byte[] iv, byte[] expectedAuthTag) + private boolean cryptFile(String fileName, String md5, byte[] key, byte[] iv) throws Exception { - File file = getFile(fileName); - assertEquals(md5, getMD5Sum(file)); - - EncryptedFile encryptedFile = encryptFile(file, key, iv); + File file = File.createTempFile(fileName, "enc"); + String md5BeforeEncryption = getMD5Sum(file); - 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; - } + String md5AfterEncryption = getMD5Sum(decryptedFile); - 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; - - 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(); } } 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/DownloadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/DownloadFileOperation.java index 8091553ca277..8bda3a62213e 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; /** @@ -262,31 +264,16 @@ protected RemoteOperationResult run(OwnCloudClient client) { byte[] key = decodeStringToBase64Bytes(keyString); byte[] iv = decodeStringToBase64Bytes(nonceString); - byte[] authenticationTag = decodeStringToBase64Bytes(authenticationTagString); try { - byte[] decryptedBytes = EncryptionUtils.decryptFile(tmpFile, - key, - iv, - authenticationTag, - new ArbitraryDataProviderImpl(operationContext), - user); - - try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile)) { - fileOutputStream.write(decryptedBytes); - } + Cipher cipher = EncryptionUtils.getCipher(Cipher.DECRYPT_MODE, key, iv); + 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) { + if (downloadType == DownloadType.EXPORT) { new FileExportUtils().exportFile(file.getFileName(), file.getMimeType(), operationContext.getContentResolver(), 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..a127895061ec 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; @@ -558,14 +560,11 @@ 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); - - 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(); @@ -580,10 +579,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 *****/ @@ -742,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 e3980bdfde71..434bc5a83a89 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,8 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; @@ -118,6 +127,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; @@ -554,95 +564,80 @@ public static byte[] decodeStringToBase64Bytes(String string) { return Base64.decode(string, Base64.NO_WRAP); } - /* - 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, - BadPaddingException, IllegalBlockSizeException, IOException { - File file = new File(ocFile.getStoragePath()); - - return encryptFile(file, encryptionKeyBytes, iv); + 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); + return new EncryptedFile(encryptedFile, authenticationTagString); } - /** - * @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 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); - GCMParameterSpec spec = new GCMParameterSpec(128, iv); - cipher.init(Cipher.ENCRYPT_MODE, key, spec); - - RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); - byte[] fileBytes = new byte[(int) randomAccessFile.length()]; - randomAccessFile.readFully(fileBytes); - - byte[] cryptedBytes = cipher.doFinal(fileBytes); - String authenticationTag = encodeBytesToBase64String(Arrays.copyOfRange(cryptedBytes, - cryptedBytes.length - (128 / 8), - cryptedBytes.length)); - - return new EncryptedFile(cryptedBytes, authenticationTag); + cipher.init(mode, key, spec); + return cipher; } - /** - * @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, - byte[] authenticationTag, - ArbitraryDataProvider arbitraryDataProvider, - User user) - throws NoSuchAlgorithmException, - InvalidAlgorithmParameterException, NoSuchPaddingException, InvalidKeyException, - BadPaddingException, IllegalBlockSizeException, IOException { + 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; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } - 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); + outputStream.close(); + inputStream.close(); - RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); - byte[] fileBytes = new byte[(int) randomAccessFile.length()]; - randomAccessFile.readFully(fileBytes); + Log_OC.d(TAG, encryptedFile.getName() + "encrypted successfully"); + } catch (IOException exception) { + Log_OC.d(TAG, "Error caught at encryptFileWithGivenCipher(): " + exception.getLocalizedMessage()); + } + } - // check authentication tag - byte[] extractedAuthenticationTag = Arrays.copyOfRange(fileBytes, - fileBytes.length - (128 / 8), - fileBytes.length); + public static void decryptFile(Cipher cipher, + File encryptedFile, + File decryptedFile, + String authenticationTag, + ArbitraryDataProvider arbitraryDataProvider, + 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); + } + inputStream.close(); + outputStream.close(); - if (!Arrays.equals(extractedAuthenticationTag, authenticationTag)) { - reportE2eError(arbitraryDataProvider, user); - throw new SecurityException("Tag not correct"); - } + if (!getAuthenticationTag(cipher).equals(authenticationTag)) { + reportE2eError(arbitraryDataProvider, user); + throw new SecurityException("Tag not correct"); + } - return cipher.doFinal(fileBytes); + 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()); + } } /** @@ -840,7 +835,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 +867,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 +1191,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);