diff --git a/build.gradle b/build.gradle
index 6a6db47660..2e6f812538 100644
--- a/build.gradle
+++ b/build.gradle
@@ -212,6 +212,9 @@ dependencies {
implementation 'org.greenrobot:eventbus:3.0.0'
implementation 'com.googlecode.ez-vcard:ez-vcard:0.10.2'
implementation 'org.lukhnos:nnio:0.2'
+
+ compile 'com.madgag.spongycastle:pkix:1.54.0.0'
+
// uncomment for gplay, modified
// implementation "com.google.firebase:firebase-messaging:${googleLibraryVersion}"
// implementation "com.google.android.gms:play-services-base:${googleLibraryVersion}"
@@ -236,7 +239,7 @@ dependencies {
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.0.1'
// UIAutomator - for cross-app UI tests, and to grant screen is turned on in Espresso tests
- //androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
+ androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.2'
// fix conflict in dependencies; see http://g.co/androidstudio/app-test-app-conflict for details
//androidTestImplementation "com.android.support:support-annotations:${supportLibraryVersion}"
implementation 'org.jetbrains:annotations:15.0'
diff --git a/drawable_resources/decrypt.svg b/drawable_resources/decrypt.svg
new file mode 100644
index 0000000000..c66a9a9bcd
--- /dev/null
+++ b/drawable_resources/decrypt.svg
@@ -0,0 +1 @@
+
diff --git a/drawable_resources/encrypt.svg b/drawable_resources/encrypt.svg
new file mode 100644
index 0000000000..3d161917f6
--- /dev/null
+++ b/drawable_resources/encrypt.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/drawable_resources/ic_list_encrypted_folder.svg b/drawable_resources/ic_list_encrypted_folder.svg
new file mode 100644
index 0000000000..e2b62a99b0
--- /dev/null
+++ b/drawable_resources/ic_list_encrypted_folder.svg
@@ -0,0 +1 @@
+
diff --git a/lint.xml b/lint.xml
index 3d202e0e1a..9791cbefc5 100644
--- a/lint.xml
+++ b/lint.xml
@@ -3,6 +3,7 @@
+
diff --git a/settings.gradle b/settings.gradle
index 6a2e4c284a..cb1608d965 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':'
\ No newline at end of file
+include ':nextcloud-android-library'
\ No newline at end of file
diff --git a/src/androidTest/assets/decrypted.json b/src/androidTest/assets/decrypted.json
new file mode 100644
index 0000000000..8aa7f4a2cf
--- /dev/null
+++ b/src/androidTest/assets/decrypted.json
@@ -0,0 +1,42 @@
+{
+ "metadata":{
+ "encrypted":{
+ "metadataKeys":{
+ "0":"s4k4LPDpxoO53TKwem3Lo1",
+ "2":"…",
+ "3":"NEWESTMETADATAKEY"
+ }
+ },
+ "initializationVector":"kahzfT4u86Knc+e3",
+ "sharing":{
+ "recipient":{
+ "blah@schiessle.org":"PUBLIC KEY",
+ "bjoern@schiessle.org":"PUBLIC KEY"
+ },
+ "signature":"HMACOFRECIPIENTANDNEWESTMETADATAKEY"
+ },
+ "version":1
+ },
+ "files":{
+ "ia7OEEEyXMoRa1QWQk8r":{
+ "encrypted":{
+ "key":"jtboLmgGR1OQf2uneqCVHpklQLlIwWL5TXAQ0keK",
+ "filename":"test.txt",
+ "authenticationTag":"HMAC of file",
+ "version":1
+ },
+ "metadataKey":0,
+ "initializationVector":"+mHu52HyZq+pAAIN"
+ },
+ "n9WXAIXO2wRY4R8nXwmo":{
+ "encrypted":{
+ "key":"s4k4LPDpxoO53TKwem3Lo1yJnbNUYH2KLrSFT8Ea",
+ "filename":"test2.txt",
+ "authenticationTag":"HMAC of file",
+ "version":1
+ },
+ "metadataKey":0,
+ "initializationVector":"sOFd17hCKWIv0gyB"
+ }
+ }
+}
diff --git a/src/androidTest/assets/encrypted.json b/src/androidTest/assets/encrypted.json
new file mode 100644
index 0000000000..c865d4cedf
--- /dev/null
+++ b/src/androidTest/assets/encrypted.json
@@ -0,0 +1,26 @@
+{
+ "metadata":{
+ "encrypted":"L01QcEZlcnBGbGJYZk0zQVRpME5venpiMlorZkVKNEo0YXFyV0Vla25Ed0kzOWtFYUg3V0Y3RVRKdDYrOWc0Y095bmhJU1hCRDlVVWkvdFJTa2swa1NTcXlPTEFiRmhVUDZFSzRzUXhiYWkrRkRPQ3VuNk1PakVxNDlBSUhWYUZucUJIZWhyeWNQZzF2d1d0VHh0cFhud3FacE55TmZOaFRRaVA2Zz09",
+ "initializationVector":"kahzfT4u86Knc+e3",
+ "sharing":{
+ "recipient":{
+ "blah@schiessle.org":"PUBLIC KEY",
+ "bjoern@schiessle.org":"PUBLIC KEY"
+ },
+ "signature":"HMACOFRECIPIENTANDNEWESTMETADATAKEY"
+ },
+ "version":1
+ },
+ "files":{
+ "ia7OEEEyXMoRa1QWQk8r":{
+ "encrypted":"a2xMcFI0cERHa2lCM3U1ajR5UXdnLzNmN0dCK2xnSmk5ck93bHhYTTI2ZmdQQlNaLzkxOTRJK3pHTlJzSjhoTTNjdlBhb2VVaEhHdGtBd0MvVUJlbWd1VFlvZDFKM2hLSkNmZWhoNlhIclBJaGU3ZllQY3lnMHprV1M1QUpIOCs2aUE5Tno2ZkZtRHpYMExabXRZcUpyZnk5Y2hyUTEyL2M4RDE1VmliR1ltbUxqKzBTUlJyc2ZCdTRwenZiR1hCVjk5OTA5UDVjb0llUCtPcjhVM1VBL1ZUNkpPaDYvSlpSaHlHTkVDbEpDRT0\\u003d",
+ "metadataKey":0,
+ "initializationVector":"+mHu52HyZq+pAAIN"
+ },
+ "n9WXAIXO2wRY4R8nXwmo":{
+ "encrypted":"VncyZU4yZStaRmFqeXJEQkpZNlNZa09yL3FIbVNNVW1wVDFWTENJN0pnSVBkdzIySUlrRnFDMGdzcTMwdHZneFlweEJjeGt5Z0crSVlUUkdGVk5iUzlBczJaejFlNTZzeEQrTUVHVldjRGQ4VDVIN0p6ZFFlRWsvRkN4M2FoQXlFOHpXOHQ5TnhXQUYycmpvNE5xNVowUStPTGZPc0hqaVdpUUR3dm9TV0hPS3JSaVd5c1YwSEhOYmVzZkZQaEF4Mk0rLzdDU05jK2dmNmdqb2ZndzIwOC91YXNlQUlPb2FnV3k0dWd0SFAvYz0\\u003d",
+ "metadataKey":0,
+ "initializationVector":"sOFd17hCKWIv0gyB"
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/androidTest/assets/encrypted/ia7OEEEyXMoRa1QWQk8r b/src/androidTest/assets/encrypted/ia7OEEEyXMoRa1QWQk8r
new file mode 100644
index 0000000000..566f365aef
Binary files /dev/null and b/src/androidTest/assets/encrypted/ia7OEEEyXMoRa1QWQk8r differ
diff --git a/src/androidTest/assets/encrypted/n9WXAIXO2wRY4R8nXwmo b/src/androidTest/assets/encrypted/n9WXAIXO2wRY4R8nXwmo
new file mode 100644
index 0000000000..f1673ec062
Binary files /dev/null and b/src/androidTest/assets/encrypted/n9WXAIXO2wRY4R8nXwmo differ
diff --git a/src/androidTest/assets/ia7OEEEyXMoRa1QWQk8r b/src/androidTest/assets/ia7OEEEyXMoRa1QWQk8r
new file mode 100644
index 0000000000..628c953700
--- /dev/null
+++ b/src/androidTest/assets/ia7OEEEyXMoRa1QWQk8r
@@ -0,0 +1,103 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/androidTest/assets/n9WXAIXO2wRY4R8nXwmo b/src/androidTest/assets/n9WXAIXO2wRY4R8nXwmo
new file mode 100644
index 0000000000..c16ef846c2
Binary files /dev/null and b/src/androidTest/assets/n9WXAIXO2wRY4R8nXwmo differ
diff --git a/src/androidTest/assets/srEPevoPqPZpPEaeDnS3 b/src/androidTest/assets/srEPevoPqPZpPEaeDnS3
new file mode 100644
index 0000000000..c16ef846c2
Binary files /dev/null and b/src/androidTest/assets/srEPevoPqPZpPEaeDnS3 differ
diff --git a/androidTest/java/com/owncloud/android/authentication/AuthenticatorActivityTest.java b/src/androidTest/java/com/owncloud/android/authentication/AuthenticatorActivityTest.java
similarity index 99%
rename from androidTest/java/com/owncloud/android/authentication/AuthenticatorActivityTest.java
rename to src/androidTest/java/com/owncloud/android/authentication/AuthenticatorActivityTest.java
index d367976d8f..9a63e9a981 100644
--- a/androidTest/java/com/owncloud/android/authentication/AuthenticatorActivityTest.java
+++ b/src/androidTest/java/com/owncloud/android/authentication/AuthenticatorActivityTest.java
@@ -19,6 +19,7 @@
package com.owncloud.android.authentication;
+import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -29,7 +30,6 @@ import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiDevice;
import android.test.suitebuilder.annotation.LargeTest;
-import static org.junit.Assert.assertTrue;
import com.owncloud.android.R;
import org.junit.Before;
@@ -39,18 +39,15 @@ import org.junit.runner.RunWith;
import java.lang.reflect.Field;
-import android.app.Activity;
-
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
import static android.support.test.espresso.action.ViewActions.typeText;
-
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
-
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertTrue;
@RunWith(AndroidJUnit4.class)
@LargeTest
diff --git a/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java b/src/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java
similarity index 98%
rename from androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java
rename to src/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java
index 725f855553..c2277144b7 100644
--- a/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java
+++ b/src/androidTest/java/com/owncloud/android/datamodel/OCFileUnitTest.java
@@ -120,7 +120,7 @@ public class OCFileUnitTest {
);
assertThat(fileReadFromParcel.getLastSyncDateForProperties(), is(LAST_SYNC_DATE_FOR_PROPERTIES));
assertThat(fileReadFromParcel.getLastSyncDateForData(), is(LAST_SYNC_DATE_FOR_DATA));
- assertThat(fileReadFromParcel.setAvailableOffline(), is(true));
+ assertThat(fileReadFromParcel.isAvailableOffline(), is(true));
assertThat(fileReadFromParcel.getEtag(), is(ETAG));
assertThat(fileReadFromParcel.isSharedViaLink(), is(true));
assertThat(fileReadFromParcel.isSharedWithSharee(), is(true));
diff --git a/androidTest/java/com/owncloud/android/datamodel/UploadStorageManagerTest.java b/src/androidTest/java/com/owncloud/android/datamodel/UploadStorageManagerTest.java
similarity index 86%
rename from androidTest/java/com/owncloud/android/datamodel/UploadStorageManagerTest.java
rename to src/androidTest/java/com/owncloud/android/datamodel/UploadStorageManagerTest.java
index 0cf7304284..f59a5bc00f 100644
--- a/androidTest/java/com/owncloud/android/datamodel/UploadStorageManagerTest.java
+++ b/src/androidTest/java/com/owncloud/android/datamodel/UploadStorageManagerTest.java
@@ -10,7 +10,6 @@ import android.support.test.runner.AndroidJUnit4;
import com.owncloud.android.db.OCUpload;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,14 +39,14 @@ public class UploadStorageManagerTest {
public void testDeleteAllUploads() {
//Clean
for (Account account : Accounts) {
- uploadsStorageManager.removeAccountUploads(account);
+// uploadsStorageManager.removeAccountUploads(account);
}
int accountRowsA = 3;
int accountRowsB = 4;
insertUploads(Accounts[0], accountRowsA);
insertUploads(Accounts[1], accountRowsB);
- Assert.assertTrue("Expected 4 removed uploads files", uploadsStorageManager.removeAccountUploads(Accounts[1]) == 4);
+// Assert.assertTrue("Expected 4 removed uploads files", uploadsStorageManager.removeAccountUploads(Accounts[1]) == 4);
}
private void insertUploads(Account account, int rowsToInsert) {
@@ -66,7 +65,7 @@ public class UploadStorageManagerTest {
@After
public void tearDown() {
for (Account account : Accounts) {
- uploadsStorageManager.removeAccountUploads(account);
+// uploadsStorageManager.removeAccountUploads(account);
}
}
}
diff --git a/androidTest/java/com/owncloud/android/uiautomator/InitialTest.java b/src/androidTest/java/com/owncloud/android/uiautomator/InitialTest.java
similarity index 100%
rename from androidTest/java/com/owncloud/android/uiautomator/InitialTest.java
rename to src/androidTest/java/com/owncloud/android/uiautomator/InitialTest.java
diff --git a/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java b/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java
new file mode 100644
index 0000000000..5a89250672
--- /dev/null
+++ b/src/androidTest/java/com/owncloud/android/util/EncryptionTestIT.java
@@ -0,0 +1,357 @@
+/*
+ * Nextcloud Android client application
+ *
+ * @author Tobias Kaminsky
+ * Copyright (C) 2017 Tobias Kaminsky
+ * Copyright (C) 2017 Nextcloud GmbH.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package com.owncloud.android.util;
+
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.gson.reflect.TypeToken;
+import com.owncloud.android.datamodel.DecryptedFolderMetadata;
+import com.owncloud.android.datamodel.EncryptedFolderMetadata;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.utils.CsrHelper;
+import com.owncloud.android.utils.EncryptionUtils;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import static android.support.test.InstrumentationRegistry.getInstrumentation;
+import static com.owncloud.android.utils.EncryptionUtils.decodeStringToBase64Bytes;
+import static com.owncloud.android.utils.EncryptionUtils.encodeBytesToBase64String;
+import static com.owncloud.android.utils.EncryptionUtils.generateIV;
+import static com.owncloud.android.utils.EncryptionUtils.generateKey;
+import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+@RequiresApi(api = Build.VERSION_CODES.KITKAT)
+@RunWith(AndroidJUnit4.class)
+public class EncryptionTestIT {
+ private static String TAG = EncryptionTestIT.class.getSimpleName();
+
+ private String privateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAo" +
+ "IBAQDsn0JKS/THu328z1IgN0VzYU53HjSX03WJIgWkmyTaxbiKpoJaKbksXmfSpgzV" +
+ "GzKFvGfZ03fwFrN7Q8P8R2e8SNiell7mh1TDw9/0P7Bt/ER8PJrXORo+GviKHxaLr7" +
+ "Y0BJX9i/nW/L0L/VaE8CZTAqYBdcSJGgHJjY4UMf892ZPTa9T2Dl3ggdMZ7BQ2kiCi" +
+ "CC3qV99b0igRJGmmLQaGiAflhFzuDQPMifUMq75wI8RSRPdxUAtjTfkl68QHu7Umye" +
+ "yy33OQgdUKaTl5zcS3VSQbNjveVCNM4RDH1RlEc+7Wf1BY8APqT6jbiBcROJD2CeoL" +
+ "H2eiIJCi+61ZkSGfAgMBAAECggEBALFStCHrhBf+GL9a+qer4/8QZ/X6i91PmaBX/7" +
+ "SYk2jjjWVSXRNmex+V6+Y/jBRT2mvAgm8J+7LPwFdatE+lz0aZrMRD2gCWYF6Itpda" +
+ "90OlLkmQPVWWtGTgX2ta2tF5r2iSGzk0IdoL8zw98Q2UzpOcw30KnWtFMxuxWk0mHq" +
+ "pgp00g80cDWg3+RPbWOhdLp5bflQ36fKDfmjq05cGlIk6unnVyC5HXpvh4d4k2EWlX" +
+ "rjGsndVBPCjGkZePlLRgDHxT06r+5XdJ+1CBDZgCsmjGz3M8uOHyCfVW0WhB7ynzDT" +
+ "agVgz0iqpuhAi9sPt6iWWwpAnRw8cQgqEKw9bvKKECgYEA/WPi2PJtL6u/xlysh/H7" +
+ "A717CId6fPHCMDace39ZNtzUzc0nT5BemlcF0wZ74NeJSur3Q395YzB+eBMLs5p8mA" +
+ "95wgGvJhM65/J+HX+k9kt6Z556zLMvtG+j1yo4D0VEwm3xahB4SUUP+1kD7dNvo4+8" +
+ "xeSCyjzNllvYZZC0DrECgYEA7w8pEqhHHn0a+twkPCZJS+gQTB9Rm+FBNGJqB3XpWs" +
+ "TeLUxYRbVGk0iDve+eeeZ41drxcdyWP+WcL34hnrjgI1Fo4mK88saajpwUIYMy6+qM" +
+ "LY+jC2NRSBox56eH7nsVYvQQK9eKqv9wbB+PF9SwOIvuETN7fd8mAY02UnoaaU8CgY" +
+ "BoHRKocXPLkpZJuuppMVQiRUi4SHJbxDo19Tp2w+y0TihiJ1lvp7I3WGpcOt3LlMQk" +
+ "tEbExSvrRZGxZKH6Og/XqwQsYuTEkEIz679F/5yYVosE6GkskrOXQAfh8Mb3/04xVV" +
+ "tMaVgDQw0+CWVD4wyL+BNofGwBDNqsXTCdCsfxAQKBgQCDv2EtbRw0y1HRKv21QIxo" +
+ "ju5cZW4+cDfVPN+eWPdQFOs1H7wOPsc0aGRiiupV2BSEF3O1ApKziEE5U1QH+29bR4" +
+ "R8L1pemeGX8qCNj5bCubKjcWOz5PpouDcEqimZ3q98p3E6GEHN15UHoaTkx0yO/V8o" +
+ "j6zhQ9fYRxDHB5ACtQKBgQCOO7TJUO1IaLTjcrwS4oCfJyRnAdz49L1AbVJkIBK0fh" +
+ "JLecOFu3ZlQl/RStQb69QKb5MNOIMmQhg8WOxZxHcpmIDbkDAm/J/ovJXFSoBdOr5o" +
+ "uQsYsDZhsWW97zvLMzg5pH9/3/1BNz5q3Vu4HgfBSwWGt4E2NENj+XA+QAVmGA==";
+
+ private String cert = "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDpzCCAo+gAwIBAgIBADANBgkqhkiG9w0BAQUFADBuMRowGAYDVQQDDBF3d3cu\n" +
+ "bmV4dGNsb3VkLmNvbTESMBAGA1UECgwJTmV4dGNsb3VkMRIwEAYDVQQHDAlTdHV0\n" +
+ "dGdhcnQxGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzELMAkGA1UEBhMCREUw\n" +
+ "HhcNMTcwOTI2MTAwNDMwWhcNMzcwOTIxMTAwNDMwWjBuMRowGAYDVQQDDBF3d3cu\n" +
+ "bmV4dGNsb3VkLmNvbTESMBAGA1UECgwJTmV4dGNsb3VkMRIwEAYDVQQHDAlTdHV0\n" +
+ "dGdhcnQxGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzELMAkGA1UEBhMCREUw\n" +
+ "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDsn0JKS/THu328z1IgN0Vz\n" +
+ "YU53HjSX03WJIgWkmyTaxbiKpoJaKbksXmfSpgzVGzKFvGfZ03fwFrN7Q8P8R2e8\n" +
+ "SNiell7mh1TDw9/0P7Bt/ER8PJrXORo+GviKHxaLr7Y0BJX9i/nW/L0L/VaE8CZT\n" +
+ "AqYBdcSJGgHJjY4UMf892ZPTa9T2Dl3ggdMZ7BQ2kiCiCC3qV99b0igRJGmmLQaG\n" +
+ "iAflhFzuDQPMifUMq75wI8RSRPdxUAtjTfkl68QHu7Umyeyy33OQgdUKaTl5zcS3\n" +
+ "VSQbNjveVCNM4RDH1RlEc+7Wf1BY8APqT6jbiBcROJD2CeoLH2eiIJCi+61ZkSGf\n" +
+ "AgMBAAGjUDBOMB0GA1UdDgQWBBTFrXz2tk1HivD9rQ75qeoyHrAgIjAfBgNVHSME\n" +
+ "GDAWgBTFrXz2tk1HivD9rQ75qeoyHrAgIjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3\n" +
+ "DQEBBQUAA4IBAQARQTX21QKO77gAzBszFJ6xVnjfa23YZF26Z4X1KaM8uV8TGzuN\n" +
+ "JA95XmReeP2iO3r8EWXS9djVCD64m2xx6FOsrUI8HZaw1JErU8mmOaLAe8q9RsOm\n" +
+ "9Eq37e4vFp2YUEInYUqs87ByUcA4/8g3lEYeIUnRsRsWsA45S3wD7wy07t+KAn7j\n" +
+ "yMmfxdma6hFfG9iN/egN6QXUAyIPXvUvlUuZ7/BhWBj/3sHMrF9quy9Q2DOI8F3t\n" +
+ "1wdQrkq4BtStKhciY5AIXz9SqsctFHTv4Lwgtkapoel4izJnO0ZqYTXVe7THwri9\n" +
+ "H/gua6uJDWH9jk2/CiZDWfsyFuNUuXvDSp05\n" +
+ "-----END CERTIFICATE-----";
+
+ @Test
+ public void encryptStringAsymmetric() throws Exception {
+ byte[] key1 = EncryptionUtils.generateKey();
+ String base64encodedKey = encodeBytesToBase64String(key1);
+
+ String encryptedString = EncryptionUtils.encryptStringAsymmetric(base64encodedKey, cert);
+ String decryptedString = EncryptionUtils.decryptStringAsymmetric(encryptedString, privateKey);
+
+ byte[] key2 = EncryptionUtils.decodeStringToBase64Bytes(decryptedString);
+
+ assertTrue(Arrays.equals(key1, key2));
+ }
+
+ @Test
+ public void encryptStringSymmetric() throws Exception {
+ byte[] key = generateKey();
+
+ String encryptedString = EncryptionUtils.encryptStringSymmetric(privateKey, key);
+ String decryptedString = EncryptionUtils.decryptStringSymmetric(encryptedString, key);
+
+ assertEquals(privateKey, decryptedString);
+ }
+
+ @Test
+ public void encryptPrivateKey() throws Exception {
+ String keyPhrase = "moreovertelevisionfactorytendencyindependenceinternationalintellectualimpress" +
+ "interestvolunteer";
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(4096, new SecureRandom());
+ KeyPair keyPair = keyGen.generateKeyPair();
+ PrivateKey privateKey = keyPair.getPrivate();
+ byte[] privateKeyBytes = privateKey.getEncoded();
+ String privateKeyString = encodeBytesToBase64String(privateKeyBytes);
+
+ String encryptedString = EncryptionUtils.encryptPrivateKey(privateKeyString, keyPhrase);
+ String decryptedString = EncryptionUtils.decryptPrivateKey(encryptedString, keyPhrase);
+
+ assertEquals(privateKeyString, decryptedString);
+ }
+
+ @Test
+ public void generateCSR() throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ keyGen.initialize(2048, new SecureRandom());
+ KeyPair keyPair = keyGen.generateKeyPair();
+
+ String string = CsrHelper.generateCsrPemEncodedString(keyPair);
+ String urlEncoded = URLEncoder.encode("-----BEGIN CERTIFICATE REQUEST-----\n" + string +
+ "\n-----END CERTIFICATE REQUEST-----", "UTF-8");
+
+ Log_OC.d(TAG, "public: " + encodeBytesToBase64String(keyPair.getPublic().getEncoded()));
+ Log_OC.d(TAG, "csrPEM: " + string);
+ Log_OC.d(TAG, "csrPEM: " + urlEncoded);
+ }
+
+ /**
+ * DecryptedFolderMetadata -> EncryptedFolderMetadata -> JSON -> encrypt
+ * -> decrypt -> JSON -> EncryptedFolderMetadata -> DecryptedFolderMetadata
+ */
+ @Test
+ public void encryptionMetadata() throws Exception {
+ DecryptedFolderMetadata decryptedFolderMetadata1 = generateFolderMetadata();
+
+ // encrypt
+ EncryptedFolderMetadata encryptedFolderMetadata1 = EncryptionUtils.encryptFolderMetadata(
+ decryptedFolderMetadata1, privateKey);
+
+ // serialize
+ String encryptedJson = EncryptionUtils.serializeJSON(encryptedFolderMetadata1);
+
+ // de-serialize
+ EncryptedFolderMetadata encryptedFolderMetadata2 = EncryptionUtils.deserializeJSON(encryptedJson,
+ new TypeToken() {
+ });
+
+ // decrypt
+ DecryptedFolderMetadata decryptedFolderMetadata2 = EncryptionUtils.decryptFolderMetaData(
+ encryptedFolderMetadata2, privateKey);
+
+ // compare
+ assertTrue(compareJsonStrings(EncryptionUtils.serializeJSON(decryptedFolderMetadata1),
+ EncryptionUtils.serializeJSON(decryptedFolderMetadata2)));
+ }
+
+ @Test
+ public void testCryptFileWithoutMetadata() throws Exception {
+ byte[] key = EncryptionUtils.decodeStringToBase64Bytes("WANM0gRv+DhaexIsI0T3Lg==");
+ byte[] iv = EncryptionUtils.decodeStringToBase64Bytes("gKm3n+mJzeY26q4OfuZEqg==");
+ byte[] authTag = EncryptionUtils.decodeStringToBase64Bytes("PboI9tqHHX3QeAA22PIu4w==");
+
+ cryptFile("ia7OEEEyXMoRa1QWQk8r", "78f42172166f9dc8fd1a7156b1753353", key, iv, authTag);
+ }
+
+ @Test
+ public void cryptFileWithMetadata() throws Exception {
+ DecryptedFolderMetadata metadata = generateFolderMetadata();
+
+ // n9WXAIXO2wRY4R8nXwmo
+ cryptFile("ia7OEEEyXMoRa1QWQk8r",
+ "78f42172166f9dc8fd1a7156b1753353",
+ EncryptionUtils.decodeStringToBase64Bytes(metadata.files.get("ia7OEEEyXMoRa1QWQk8r").encrypted.key),
+ EncryptionUtils.decodeStringToBase64Bytes(metadata.files.get("ia7OEEEyXMoRa1QWQk8r").initializationVector),
+ EncryptionUtils.decodeStringToBase64Bytes(metadata.files.get("ia7OEEEyXMoRa1QWQk8r").authenticationTag));
+
+ // n9WXAIXO2wRY4R8nXwmo
+ cryptFile("n9WXAIXO2wRY4R8nXwmo",
+ "825143ed1f21ebb0c3b3c3f005b2f5db",
+ EncryptionUtils.decodeStringToBase64Bytes(metadata.files.get("n9WXAIXO2wRY4R8nXwmo").encrypted.key),
+ EncryptionUtils.decodeStringToBase64Bytes(metadata.files.get("n9WXAIXO2wRY4R8nXwmo").initializationVector),
+ EncryptionUtils.decodeStringToBase64Bytes(metadata.files.get("n9WXAIXO2wRY4R8nXwmo").authenticationTag));
+ }
+
+ /**
+ * generates new keys and tests if they are unique
+ */
+ @Test
+ public void testKey() {
+ Set keys = new HashSet<>();
+
+ for (int i = 0; i < 50; i++) {
+ assertTrue(keys.add(encodeBytesToBase64String(generateKey())));
+ }
+ }
+
+ /**
+ * generates new ivs and tests if they are unique
+ */
+ @Test
+ public void testIV() {
+ Set ivs = new HashSet<>();
+
+ for (int i = 0; i < 50; i++) {
+ assertTrue(ivs.add(encodeBytesToBase64String(generateIV())));
+ }
+ }
+
+
+ // Helper
+ private boolean compareJsonStrings(String expected, String actual) {
+ JsonParser parser = new JsonParser();
+ JsonElement o1 = parser.parse(expected);
+ JsonElement o2 = parser.parse(actual);
+
+ if (o1.equals(o2)) {
+ return true;
+ } else {
+ System.out.println("expected: " + o1);
+ System.out.println("actual: " + o2);
+ return false;
+ }
+ }
+
+ private DecryptedFolderMetadata generateFolderMetadata() throws Exception {
+ String metadataKey0 = encodeBytesToBase64String(EncryptionUtils.generateKey());
+ String metadataKey1 = encodeBytesToBase64String(EncryptionUtils.generateKey());
+ String metadataKey2 = encodeBytesToBase64String(EncryptionUtils.generateKey());
+ HashMap metadataKeys = new HashMap<>();
+ metadataKeys.put(0, EncryptionUtils.encryptStringAsymmetric(metadataKey0, cert));
+ metadataKeys.put(1, EncryptionUtils.encryptStringAsymmetric(metadataKey1, cert));
+ metadataKeys.put(2, EncryptionUtils.encryptStringAsymmetric(metadataKey2, cert));
+ DecryptedFolderMetadata.Encrypted encrypted = new DecryptedFolderMetadata.Encrypted();
+ encrypted.metadataKeys = metadataKeys;
+
+ DecryptedFolderMetadata.Metadata metadata1 = new DecryptedFolderMetadata.Metadata();
+ metadata1.metadataKeys = metadataKeys;
+ metadata1.version = 1;
+
+ DecryptedFolderMetadata.Sharing sharing = new DecryptedFolderMetadata.Sharing();
+ sharing.signature = "HMACOFRECIPIENTANDNEWESTMETADATAKEY";
+ HashMap recipient = new HashMap<>();
+ recipient.put("blah@schiessle.org", "PUBLIC KEY");
+ recipient.put("bjoern@schiessle.org", "PUBLIC KEY");
+ sharing.recipient = recipient;
+ metadata1.sharing = sharing;
+
+ HashMap files = new HashMap<>();
+
+ DecryptedFolderMetadata.Data data1 = new DecryptedFolderMetadata.Data();
+ data1.key = "WANM0gRv+DhaexIsI0T3Lg==";
+ data1.filename = "test.txt";
+ data1.version = 1;
+
+ DecryptedFolderMetadata.DecryptedFile file1 = new DecryptedFolderMetadata.DecryptedFile();
+ file1.initializationVector = "gKm3n+mJzeY26q4OfuZEqg==";
+ file1.encrypted = data1;
+ file1.metadataKey = 0;
+ file1.authenticationTag = "PboI9tqHHX3QeAA22PIu4w==";
+
+ files.put("ia7OEEEyXMoRa1QWQk8r", file1);
+
+ DecryptedFolderMetadata.Data data2 = new DecryptedFolderMetadata.Data();
+ data2.key = "9dfzbIYDt28zTyZfbcll+g==";
+ data2.filename = "test2.txt";
+ data2.version = 1;
+
+ DecryptedFolderMetadata.DecryptedFile file2 = new DecryptedFolderMetadata.DecryptedFile();
+ file2.initializationVector = "hnJLF8uhDvDoFK4ajuvwrg==";
+ file2.encrypted = data2;
+ file2.metadataKey = 0;
+ file2.authenticationTag = "qOQZdu5soFO77Y7y4rAOVA==";
+
+ files.put("n9WXAIXO2wRY4R8nXwmo", file2);
+
+ return new DecryptedFolderMetadata(metadata1, files);
+ }
+
+ private void cryptFile(String fileName, String md5, byte[] key, byte[] iv, byte[] expectedAuthTag)
+ throws Exception {
+ File file = getFile(fileName);
+ assertEquals(md5, EncryptionUtils.getMD5Sum(file));
+
+ EncryptionUtils.EncryptedFile encryptedFile = EncryptionUtils.encryptFile(file, key, iv);
+
+ File encryptedTempFile = File.createTempFile("file", "tmp");
+ FileOutputStream fileOutputStream = new FileOutputStream(encryptedTempFile);
+ fileOutputStream.write(encryptedFile.encryptedBytes);
+ fileOutputStream.close();
+
+ byte[] authenticationTag = decodeStringToBase64Bytes(encryptedFile.authenticationTag);
+
+ // verify authentication tag
+ assertTrue(Arrays.equals(expectedAuthTag, authenticationTag));
+
+ byte[] decryptedBytes = EncryptionUtils.decryptFile(encryptedTempFile, key, iv, authenticationTag);
+
+ File decryptedFile = File.createTempFile("file", "dec");
+ FileOutputStream fileOutputStream1 = new FileOutputStream(decryptedFile);
+ fileOutputStream1.write(decryptedBytes);
+ fileOutputStream1.close();
+
+ assertEquals(md5, EncryptionUtils.getMD5Sum(decryptedFile));
+ }
+
+ private File getFile(String filename) throws IOException {
+ InputStream inputStream = getInstrumentation().getContext().getAssets().open(filename);
+ File temp = File.createTempFile("file", "file");
+ FileUtils.copyInputStreamToFile(inputStream, temp);
+
+ return temp;
+ }
+}
\ No newline at end of file
diff --git a/src/gplay/AndroidManifest.xml b/src/gplay/AndroidManifest.xml
index b32ab3b432..f24dfb4af7 100644
--- a/src/gplay/AndroidManifest.xml
+++ b/src/gplay/AndroidManifest.xml
@@ -18,7 +18,9 @@
-->
+ package="com.owncloud.android"
+ android:versionCode="20000052"
+ android:versionName="2.0.0-e2e-02">
.
-->
+ package="com.owncloud.android"
+ android:versionCode="20000052"
+ android:versionName="2.0.0-e2e-02">
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/res/layout/setup_encryption_dialog.xml b/src/main/res/layout/setup_encryption_dialog.xml
new file mode 100644
index 0000000000..9c095ea7dd
--- /dev/null
+++ b/src/main/res/layout/setup_encryption_dialog.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/res/menu/file_actions_menu.xml b/src/main/res/menu/file_actions_menu.xml
index 719759655f..3deca1bc27 100644
--- a/src/main/res/menu/file_actions_menu.xml
+++ b/src/main/res/menu/file_actions_menu.xml
@@ -107,6 +107,18 @@
app:showAsAction="never"
android:showAsAction="never"
android:orderInCategory="1" />
+
+
- Mit verschiedenen Kontos verbinden
Automatisches Hochladen von Bildern & Videos
Kalender & Kontakte mit DAVdroid synchronisieren
-
-
+Keine Information verfügbar!
+ Keine neue Version verfügbar!
+
+ Verzeichnis nicht leer!
+ Fehler beim entschlüsseln. Falsches Passwort??
+ Entschlüsseln…
+ Hole Schlüssel…
+ Zum entschlüsseln des privaten Schlüssels bitte Passwort eingeben!
+ Erstelle neue Schlüssel…
+ Dieser 12 Worte Satz ist wie ein starkes Passwort: Es emöglicht Zugang zu den verschlüsselten Dateien. Bitte notieren Sie sich den Satz und bewahren ihn sicher auf.
+ Verschlüsselung einrichten
+ Notieren Sie sich den Verschlüsselungssatz.
+ Verschlüsselung erst ab KitKat unterstützt.
+ Verschlüsselung einrichten
+ Passwort…
+
diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml
index fc56de5202..2179aebbf4 100644
--- a/src/main/res/values/colors.xml
+++ b/src/main/res/values/colors.xml
@@ -38,6 +38,7 @@
#757575
#555555
+ #EEEEEE
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index dacf302e33..9be8b9be17 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -268,6 +268,8 @@
Set as favorite
Unset favorite
Available offline
+ Set as encrypted
+ Unset encryption
Rename
Delete
Do you really want to delete %1$s?
@@ -753,4 +755,17 @@
Add name, picture and contact details on your profile page.
Background image of drawer header
Account icon
+
+ Folder not empty!
+ Error while decrypting. Wrong password?
+ Decrypting…
+ Retrieving keys…
+ Please enter password to decrypt private key!
+ Generating new keys…
+ This 12 word phrase is like a very strong password: It provides full access to view and use your encrypted files. Please write it down and keep it somewhere safe.
+ Set up encryption
+ Note your encryption passphrase
+ Encryption not supported before KitKat.
+ Set up encryption
+ Password…
diff --git a/src/modified/AndroidManifest.xml b/src/modified/AndroidManifest.xml
index 77b4e52b6d..6a7ae040e1 100644
--- a/src/modified/AndroidManifest.xml
+++ b/src/modified/AndroidManifest.xml
@@ -18,7 +18,9 @@
-->
+ package="com.owncloud.android"
+ android:versionCode="20000052"
+ android:versionName="2.0.0-e2e-02">
.
+ */
+
+package com.owncloud.android.utils;
+
+import android.os.Build;
+import android.support.annotation.RequiresApi;
+
+import com.google.gson.reflect.TypeToken;
+import com.owncloud.android.datamodel.DecryptedFolderMetadata;
+
+import org.junit.Test;
+
+import java.util.HashMap;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+@RequiresApi(api = Build.VERSION_CODES.KITKAT)
+public class EncryptionTest {
+ private String encryptedString = "{\"metadata\":{\"encrypted\":\"np1sIwoAFCb/vRqV/jWOIe1UtyVO02EJhvPoh3VwcZuiSbDjwQO5QHUWtKXpHLyX6wfbkRX6nr8mSG0+HhLRud1t126UMxQK5BNINu99WlzPMa5PaKhTXlpuRUf3tR6PTQ\\u003d\\u003d\",\"initializationVector\":" +
+ "\"kahzfT4u86Knc+e3\",\"sharing\":{\"recipient\":{\"blah@schiessle.org\":\"PUBLIC KEY\"," +
+ "\"bjoern@schiessle.org\":\"PUBLIC KEY\"},\"signature\":\"HMACOFRECIPIENTANDNEWESTMETADATAKEY\"}," +
+ "\"version\":1},\"files\":{\"ia7OEEEyXMoRa1QWQk8r\":{\"encrypted\":\"yl52TIccvo62LezCaFjQFJs7a1Q281pOuj59oNXMX7ti+7+h1SjK1AAk1HuwT+CI7BT64+R0ZLgyR/vBPjWvAQuxi9JWgsCjFMX91Mv2m2zI/bNQCarczOfnmf4FZ3Nv6yPLSjShmfQzemQ99Z3g7UHyrZ6pKT18m17IueJHF3V5kOhd9vcH\",\"metadataKey\":0," +
+ "\"initializationVector\":\"+mHu52HyZq+pAAIN\"}," +
+ "\"n9WXAIXO2wRY4R8nXwmo\":{\"encrypted\":\"Z9YTAgY/0YqKQlDwiqENcZRRupjgmJ1f0bTy0hOHP2/mHxFtoHCftT4STvt21OJMx8wF6V3cquQIGJ976WxkhA4SQxaQNpznhm1W9e8y+B5x8QnxSasYnOSFtZ/xVgQq6IZRjvYdPo7rvZk49hnqkwnUyvqtCj14aCE42qoxVZCd9M6XaZEBTA\\u003d\\u003d\",\"metadataKey\":0,\"initializationVector\":" +
+ "\"sOFd17hCKWIv0gyB\"}}}";
+
+ private String decryptedString = "{\"metadata\":{\"encrypted\":{\"metadataKeys\":{\"0\":" +
+ "\"s4k4LPDpxoO53TKwem3Lo1\",\"2\":\"…\",\"3\":\"NEWESTMETADATAKEY\"}},\"initializationVector\":" +
+ "\"kahzfT4u86Knc+e3\",\"sharing\":{\"recipient\":{\"blah@schiessle.org\":\"PUBLIC KEY\"," +
+ "\"bjoern@schiessle.org\":\"PUBLIC KEY\"},\"signature\":\"HMACOFRECIPIENTANDNEWESTMETADATAKEY\"}," +
+ "\"version\":1},\"files\":{\"ia7OEEEyXMoRa1QWQk8r\":{\"encrypted\":{\"key\":" +
+ "\"jtboLmgGR1OQf2uneqCVHpklQLlIwWL5TXAQ0keK\",\"filename\":\"test.txt\",\"authenticationTag\":" +
+ "\"HMAC of file\",\"version\":1},\"metadataKey\":0,\"initializationVector\":\"+mHu52HyZq+pAAIN\"}," +
+ "\"n9WXAIXO2wRY4R8nXwmo\":{\"encrypted\":{\"key\":\"s4k4LPDpxoO53TKwem3Lo1yJnbNUYH2KLrSFT8Ea\"," +
+ "\"filename\":\"test2.txt\",\"authenticationTag\":\"HMAC of file\",\"version\":1}," +
+ "\"metadataKey\":0,\"initializationVector\":\"sOFd17hCKWIv0gyB\"}}}";
+
+ private String privateKey = "TUlJRXZRSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2N3Z2dTakFnRUFBb0lCQVFEV0FKMDNuNlBLVDNJWlZTT1paSzgyd3dqRTVWSW4vclZ5L0VLbmsyMVgzQ1dPbkdsb0ZrUXdiSWFsYjlkVWNRcmQzM250NVFoMmhJeXM5TkdsMjdMUmhreU1qemYzaFdzbnljSVhZQURVSExweGJZbWpJRzRjbWlNQnI4ckhjVFEvM0dUTlBKWG00ZzUwQlZEOXZlRThoMkQrTXdIQXlTSkxZcG5FaDBKWExES0pvVnpQYldxdVZVdHZNMmdmWVFHNFgwbS9kamR5VzJ4ZGN2UkpZeUtpWDZ3UmY3U3ViaWJkR1V1MHgxckhRdGhnM1dtaXdLd09NR2pQQ3oxRDAwMC9vWjZnckRHcW03TG5XMVZaN0VNTWtWWjVjVlc4NlpGQ2lrcXNtcDd1MVg1YjdCTzBiaThyV2Z0Zm8zZnJaOUptdmkvZHpmeXo2RFRFOWIrZU9CNzlBZ01CQUFFQ2dnRUJBSURYYzlCR1k5VnRDWFBwQjNyVjNJdXExcis4bFQ4UklldHRweSsvR2dqWXVSL29XYW5hSmduRmZUZGpZNUFxVXZHTUY1dTcxZUdOSWlrTGFLRmo2WUF1VEM0Z0dBRUZLYU9WM0M0NGxhY2UrTDFMeHA4WTZsSjhGbkZ3aGpTWG1tNk1ZWUFUWnVqUDF3WFJJWmJ6V0FVYU9MSXl3VzV4YWgxYTZ0c2cyRGNrZ2h3YVoxMURiRTVkNEpNNXl0Q1J6YmZzWTA3cElrUmU4WlFLcm1sMXU0THlsWXVHVHBDZGMwSnNXdUx3d1NWbm8vK056RURiVVNKZThIRmpnM1k3L2JkajgzNE9INzBtQWdBVUdEQTJqQ1BqY1hzNHJnN25udkhuQm5WcVFaemFvVWhHYzFOak9pZzMwNitUV25OL1JUNWc0TThucDNuMXZETWF2dVBiM0lFQ2dZRUE2NVpQV243UlYxZVVVS20zcVRUN1BSa3NuLzZDVWdFaFQ1WDloc0c3cXJXMUVlalhuODE2S1A0R3VsaDc1S0dhQ3hUVmdGZDhHdHF1QVU3MGdaKzB5MHVGd2hTdGtWN1A0K2xlUXlYSmxtNDNWNU9zT3Jxb25ocTZyOCthZ3lGbnNuOEhGd3lVcG1VM0FqR2tXVUNzYWFNdWM4SEt0ajU4RkdGRlh6K3ZlcDBDZ1lFQTZJdUZVZmljLytpUXpsVjczTDdWSS9kRjJNcFRPeHVKb1c4MmM1OE1tdEhGMFFQSktlYU5YVGJuYzluUXZ0aFBWM3c1eEZWc3FkN3pKOEM4ZkJ5S21Xc2ZLOU1abGQvY3RZTk9EMTNLWlM2WTNvWXpGVU5ZRzFPSEhpamNZT3RSWUsvY3k0cS9SRnExQ0pZVCtPaEVTOXlmeGFqZlZXdzFPdGxNZGNuNlYrRUNnWUFwNlN5bTBjYldQZnRodWorMU4zcTJyT0xXZDhXaFp4Z1ErNE1GMVROWXRFakpMZDRtVEx5OXpDdFFQV3VWQ2ZiSW4rVTNsdGk2UWtzUWFvWnZCUVY1NFM2amoyQXRhMnVhaFNyQzBWY2lqdXNEaG43dVY4U2xrK1hBWHpPQ3ZvK2ZIcUFaUnFDdlZYUkt6S0FMVE1rZlpldGVwb3cwamJzdk9QckpiaC8rdFFLQmdIQUFpd1R4RmtVWGNXOC9zdm1lSERCSGI2ZTd3eHlyNWIwUVFJeXRwVGVJSTV2SkZBR1BYclR2dGNpUnR6M0VGMnJPbFZBZnlNZUViMTdOTUxzaVVBc1draHZjZiswMHRpdmlneDFaa2hycnQ0c3QzYnEzQmQrYmVtK25SSVdWc1VzOVNMM3NKTFU2Yndra3A1ZngzcnNmRndEdmxpbWhoWDNEblZUNkpBNWhBb0dBZUtSZGRBVFAxZmVDL1pIZWE0VWh1MEVIencrY2xraDBrdjFDQkNHNnhjM002Y245SzFUNlIwMHRZYlFjS1JvZHJ1ZnBZNUNOL3V2Zyt0VWRucTUxRFhwTU5tbDVMdGpRYnV3MktuZ1F1ZG9NQ1NFMHMzT0dnaGJqMzZtbEVsRERjUGxLaE0rb1hyaVRYdXUvWmljclZqcGxTcWxuSlN2aDh6STJGNFBLaDlnPQ==";
+
+ private String publicKey = "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDpzCCAo+gAwIBAgIBADANBgkqhkiG9w0BAQUFADBuMRowGAYDVQQDDBF3d3cu\n" +
+ "bmV4dGNsb3VkLmNvbTESMBAGA1UECgwJTmV4dGNsb3VkMRIwEAYDVQQHDAlTdHV0\n" +
+ "dGdhcnQxGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzELMAkGA1UEBhMCREUw\n" +
+ "HhcNMTcwOTA0MTEwNTQyWhcNMzcwODMwMTEwNTQyWjBuMRowGAYDVQQDDBF3d3cu\n" +
+ "bmV4dGNsb3VkLmNvbTESMBAGA1UECgwJTmV4dGNsb3VkMRIwEAYDVQQHDAlTdHV0\n" +
+ "dGdhcnQxGzAZBgNVBAgMEkJhZGVuLVd1ZXJ0dGVtYmVyZzELMAkGA1UEBhMCREUw\n" +
+ "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDWAJ03n6PKT3IZVSOZZK82\n" +
+ "wwjE5VIn/rVy/EKnk21X3CWOnGloFkQwbIalb9dUcQrd33nt5Qh2hIys9NGl27LR\n" +
+ "hkyMjzf3hWsnycIXYADUHLpxbYmjIG4cmiMBr8rHcTQ/3GTNPJXm4g50BVD9veE8\n" +
+ "h2D+MwHAySJLYpnEh0JXLDKJoVzPbWquVUtvM2gfYQG4X0m/djdyW2xdcvRJYyKi\n" +
+ "X6wRf7SubibdGUu0x1rHQthg3WmiwKwOMGjPCz1D000/oZ6grDGqm7LnW1VZ7EMM\n" +
+ "kVZ5cVW86ZFCikqsmp7u1X5b7BO0bi8rWftfo3frZ9Jmvi/dzfyz6DTE9b+eOB79\n" +
+ "AgMBAAGjUDBOMB0GA1UdDgQWBBS3zNF86LEZFT/KDdscr4ZJEisXqDAfBgNVHSME\n" +
+ "GDAWgBS3zNF86LEZFT/KDdscr4ZJEisXqDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3\n" +
+ "DQEBBQUAA4IBAQCPMu5AKNlh0gTr/k9Vc7RJ01uF07D+lTPGIErfW7+qXO21kXyw\n" +
+ "+w8sxw+e1B/gah/bxotfO7ZuOhs49d8QRUzPy/miBFaZXfjfiqs7UXSDQ6oUbX3a\n" +
+ "X9eTFMHDcsSUbyqhwn2cghmPJEhE10mtH2DJNPqDYvdpekJ6sEUVaqx63CD3nxcl\n" +
+ "7fXh0IfmvDQOrSBszRqPY8pvnZJIEwqaENPk9Vgbzs8oXVstKl6wCqM0B36tmhBl\n" +
+ "f6Dz/EhriF3Rq9w5RrWZOpS6XAWwRpyHPN+lKPa321dF6EEsnvhX8G3UbLbr0uEg\n" +
+ "dR8lPhuKejU/Ds0ARwQGmFXFzidFNZL5ymos\n" +
+ "-----END CERTIFICATE-----";
+
+ @Test
+ public void deserializeJSON() {
+ String file = "ia7OEEEyXMoRa1QWQk8r";
+ DecryptedFolderMetadata metadata = EncryptionUtils.deserializeJSON(decryptedString,
+ new TypeToken() {});
+
+ assertEquals("jtboLmgGR1OQf2uneqCVHpklQLlIwWL5TXAQ0keK", metadata.files.get(file).encrypted.key);
+ assertEquals("+mHu52HyZq+pAAIN", metadata.files.get(file).initializationVector);
+ }
+
+ @Test
+ public void serializeJSON() {
+ try {
+ HashMap metadataKeys = new HashMap<>();
+ metadataKeys.put(0, EncryptionUtils.encryptStringAsymmetric("s4k4LPDpxoO53TKwem3Lo1", publicKey));
+ metadataKeys.put(1, EncryptionUtils.encryptStringAsymmetric("Q3ZobVJHbTlkK1VHT0g3ME", publicKey));
+ metadataKeys.put(2, EncryptionUtils.encryptStringAsymmetric("lkK1VHT0g3ME3TKwem3Lo1", publicKey));
+ DecryptedFolderMetadata.Encrypted encrypted = new DecryptedFolderMetadata.Encrypted();
+ encrypted.metadataKeys = metadataKeys;
+
+ DecryptedFolderMetadata.Metadata metadata1 = new DecryptedFolderMetadata.Metadata();
+ metadata1.metadataKeys = metadataKeys;
+ metadata1.version = 1;
+
+ DecryptedFolderMetadata.Sharing sharing = new DecryptedFolderMetadata.Sharing();
+ sharing.signature = "HMACOFRECIPIENTANDNEWESTMETADATAKEY";
+ HashMap recipient = new HashMap<>();
+ recipient.put("blah@schiessle.org", "PUBLIC KEY");
+ recipient.put("bjoern@schiessle.org", "PUBLIC KEY");
+ sharing.recipient = recipient;
+ metadata1.sharing = sharing;
+
+ HashMap files = new HashMap<>();
+
+ DecryptedFolderMetadata.Data data1 = new DecryptedFolderMetadata.Data();
+ data1.key = "jtboLmgGR1OQf2uneqCVHpklQLlIwWL5TXAQ0keK";
+ data1.filename = "test.txt";
+ data1.version = 1;
+
+ DecryptedFolderMetadata.DecryptedFile file1 = new DecryptedFolderMetadata.DecryptedFile();
+ file1.initializationVector = "+mHu52HyZq+pAAIN";
+ file1.encrypted = data1;
+ file1.metadataKey = 0;
+ file1.authenticationTag = "HMAC of file";
+
+ files.put("ia7OEEEyXMoRa1QWQk8r", file1);
+
+ DecryptedFolderMetadata.Data data2 = new DecryptedFolderMetadata.Data();
+ data2.key = "s4k4LPDpxoO53TKwem3Lo1yJnbNUYH2KLrSFT8Ea";
+ data2.filename = "test2.txt";
+ data2.version = 1;
+
+ DecryptedFolderMetadata.DecryptedFile file2 = new DecryptedFolderMetadata.DecryptedFile();
+ file2.initializationVector = "sOFd17hCKWIv0gyB";
+ file2.encrypted = data2;
+ file2.metadataKey = 0;
+ file2.authenticationTag = "HMAC of file";
+
+ files.put("n9WXAIXO2wRY4R8nXwmo", file2);
+
+ DecryptedFolderMetadata metadata = new DecryptedFolderMetadata(metadata1, files);
+
+ // serialize
+ assertEquals(decryptedString, EncryptionUtils.serializeJSON(metadata));
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/owncloud/android/utils/ErrorMessageAdapterUnitTest.java b/src/test/java/com/owncloud/android/utils/ErrorMessageAdapterUnitTest.java
index 9c232f3ea9..b00489dab5 100644
--- a/src/test/java/com/owncloud/android/utils/ErrorMessageAdapterUnitTest.java
+++ b/src/test/java/com/owncloud/android/utils/ErrorMessageAdapterUnitTest.java
@@ -21,8 +21,10 @@
package com.owncloud.android.utils;
+import android.accounts.Account;
import android.content.res.Resources;
+import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.operations.RemoveFileOperation;
@@ -65,10 +67,12 @@ public class ErrorMessageAdapterUnitTest {
when(mMockResources.getString(R.string.forbidden_permissions_delete))
.thenReturn(MOCK_TO_DELETE);
+ Account account = new Account("name", MainApp.getAccountType());
+
// ... when method under test is called ...
String errorMessage = ErrorMessageAdapter.getErrorCauseMessage(
new RemoteOperationResult(RemoteOperationResult.ResultCode.FORBIDDEN),
- new RemoveFileOperation(PATH_TO_DELETE, false),
+ new RemoveFileOperation(PATH_TO_DELETE, false, account, MainApp.getAppContext()),
mMockResources
);