diff --git a/app/src/main/java/eu/faircode/email/EditTextCompose.java b/app/src/main/java/eu/faircode/email/EditTextCompose.java
index 5f466deb0a..c830d65811 100644
--- a/app/src/main/java/eu/faircode/email/EditTextCompose.java
+++ b/app/src/main/java/eu/faircode/email/EditTextCompose.java
@@ -37,7 +37,9 @@ import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.QuoteSpan;
import android.text.style.StyleSpan;
+import android.text.style.URLSpan;
import android.util.AttributeSet;
+import android.util.Base64;
import android.view.ActionMode;
import android.view.KeyEvent;
import android.view.Menu;
@@ -56,9 +58,16 @@ import androidx.preference.PreferenceManager;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
+import java.nio.ByteBuffer;
+import java.security.SecureRandom;
import java.util.List;
import java.util.concurrent.ExecutorService;
+import javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.PBEKeySpec;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
@@ -113,6 +122,7 @@ public class EditTextCompose extends FixedEditText {
int order = 1000;
menu.add(Menu.CATEGORY_SECONDARY, R.string.title_insert_brackets, order++, context.getString(R.string.title_insert_brackets));
menu.add(Menu.CATEGORY_SECONDARY, R.string.title_insert_quotes, order++, context.getString(R.string.title_insert_quotes));
+ menu.add(Menu.CATEGORY_SECONDARY, R.string.title_protect_text, order++, context.getString(R.string.title_protect_text));
} catch (Throwable ex) {
Log.e(ex);
}
@@ -137,6 +147,8 @@ public class EditTextCompose extends FixedEditText {
return surround("(", ")");
else if (id == R.string.title_insert_quotes)
return surround("\"", "\"");
+ else if (id == R.string.title_protect_text)
+ return protect();
}
return false;
}
@@ -166,6 +178,81 @@ public class EditTextCompose extends FixedEditText {
}
return selection;
}
+
+ private boolean protect() {
+ Editable edit = getText();
+ int start = getSelectionStart();
+ int end = getSelectionEnd();
+ boolean selection = (edit != null && start >= 0 && start < end);
+ if (selection)
+ executor.submit(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ String password = "FairEmail";
+ String text = HtmlHelper.toHtml((Spanned) edit.subSequence(start, end), context);
+
+ SecureRandom random = new SecureRandom();
+
+ byte[] salt = new byte[16]; // 128 bits
+ random.nextBytes(salt);
+
+ byte[] iv = new byte[12]; // 96 bites
+ random.nextBytes(iv);
+
+ // Iterations = 120,000; Keylength = 256 bits = 32 bytes
+ PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 120000, 256);
+
+ SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
+ SecretKey key = skf.generateSecret(spec);
+
+ // Authentication tag length = 128 bits = 16 bytes
+ GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
+
+ final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, key, parameterSpec);
+
+ byte[] cipherText = cipher.doFinal(text.getBytes());
+
+ ByteBuffer out = ByteBuffer.allocate(1 + salt.length + iv.length + cipherText.length);
+ out.put((byte) 1); //version
+ out.put(salt);
+ out.put(iv);
+ out.put(cipherText);
+ String fragment = Base64.encodeToString(out.array(), Base64.URL_SAFE | Base64.NO_WRAP);
+
+ post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ if (getSelectionStart() != start || getSelectionEnd() != end)
+ return;
+ String title = context.getString(R.string.title_decrypt);
+ String url = "https://email.faircode.eu/decrypt/#" + fragment;
+ edit.delete(start, end);
+ edit.insert(start, title);
+ edit.setSpan(new URLSpan(url), start, start + title.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ setSelection(start + title.length());
+ } catch (Throwable ex) {
+ Log.e(ex);
+ }
+ }
+ });
+
+ } catch (Throwable ex) {
+ Log.e(ex);
+ post(new Runnable() {
+ @Override
+ public void run() {
+ ToastEx.makeText(context, ex.toString(), Toast.LENGTH_LONG).show();
+ }
+ });
+ }
+ }
+ });
+
+ return selection;
+ }
});
setCustomInsertionActionModeCallback(new ActionMode.Callback() {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b17e745446..4e68b48da8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1954,6 +1954,7 @@
Select block
Bracket
Quote
+ Protect
Add
Open with
Info