mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-05-19 00:10:25 +00:00
Add support for turning encryption on/off
This commit is contained in:
parent
2400977629
commit
cd781d3236
10 changed files with 123 additions and 31 deletions
|
@ -23,21 +23,17 @@ public class DatabaseFile {
|
|||
private CryptParameters _cryptParameters;
|
||||
private SlotCollection _slots;
|
||||
|
||||
public DatabaseFile() {
|
||||
_slots = new SlotCollection();
|
||||
}
|
||||
|
||||
public byte[] serialize() throws DatabaseFileException {
|
||||
try {
|
||||
JSONObject cryptObj = null;
|
||||
if (_cryptParameters != null) {
|
||||
if (isEncrypted()) {
|
||||
cryptObj = new JSONObject();
|
||||
cryptObj.put("nonce", Hex.encode(_cryptParameters.Nonce));
|
||||
cryptObj.put("tag", Hex.encode(_cryptParameters.Tag));
|
||||
}
|
||||
|
||||
// don't write the crypt parameters if the content is not encrypted
|
||||
boolean plain = _content instanceof JSONObject || _slots.isEmpty() || cryptObj == null;
|
||||
boolean plain = _content instanceof JSONObject || _slots == null || cryptObj == null;
|
||||
JSONObject headerObj = new JSONObject();
|
||||
headerObj.put("slots", plain ? JSONObject.NULL : SlotCollection.serialize(_slots));
|
||||
headerObj.put("params", plain ? JSONObject.NULL : cryptObj);
|
||||
|
@ -86,7 +82,7 @@ public class DatabaseFile {
|
|||
}
|
||||
|
||||
public boolean isEncrypted() {
|
||||
return !_slots.isEmpty() && _cryptParameters != null;
|
||||
return _slots != null;
|
||||
}
|
||||
|
||||
public JSONObject getContent() {
|
||||
|
@ -106,6 +102,7 @@ public class DatabaseFile {
|
|||
public void setContent(JSONObject dbObj) {
|
||||
_content = dbObj;
|
||||
_cryptParameters = null;
|
||||
_slots = null;
|
||||
}
|
||||
|
||||
public void setContent(JSONObject dbObj, MasterKey key) throws DatabaseFileException {
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.List;
|
|||
|
||||
import me.impy.aegis.BuildConfig;
|
||||
import me.impy.aegis.crypto.MasterKey;
|
||||
import me.impy.aegis.db.slots.SlotCollection;
|
||||
|
||||
public class DatabaseManager {
|
||||
private static final String FILENAME = "aegis.json";
|
||||
|
@ -195,6 +196,18 @@ public class DatabaseManager {
|
|||
return _file;
|
||||
}
|
||||
|
||||
public void enableEncryption(MasterKey key, SlotCollection slots) {
|
||||
assertState(false, true);
|
||||
_key = key;
|
||||
_file.setSlots(slots);
|
||||
}
|
||||
|
||||
public void disableEncryption() {
|
||||
assertState(false, true);
|
||||
_key = null;
|
||||
_file.setSlots(null);
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return _file != null;
|
||||
}
|
||||
|
|
|
@ -89,10 +89,6 @@ public class SlotCollection implements Iterable<Slot>, Serializable {
|
|||
return _slots.size();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return _slots.size() == 0;
|
||||
}
|
||||
|
||||
public <T extends Slot> T find(Class<T> type) {
|
||||
for (Slot slot : this) {
|
||||
if (slot.getClass() == type) {
|
||||
|
|
|
@ -327,6 +327,7 @@ public class MainActivity extends AegisActivity implements KeyProfileView.Listen
|
|||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
updateLockIcon();
|
||||
|
||||
// refresh all codes to prevent showing old ones
|
||||
_keyProfileView.refresh();
|
||||
|
|
|
@ -2,7 +2,12 @@ package me.impy.aegis.ui;
|
|||
|
||||
import android.os.Bundle;
|
||||
|
||||
public class PreferencesActivity extends AegisActivity {
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import me.impy.aegis.db.slots.Slot;
|
||||
import me.impy.aegis.ui.dialogs.PasswordDialogFragment;
|
||||
|
||||
public class PreferencesActivity extends AegisActivity implements PasswordDialogFragment.Listener {
|
||||
private PreferencesFragment _fragment;
|
||||
|
||||
@Override
|
||||
|
@ -36,4 +41,14 @@ public class PreferencesActivity extends AegisActivity {
|
|||
outState.putParcelable("result", _fragment.getResult());
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlotResult(Slot slot, Cipher cipher) {
|
||||
_fragment.onSlotResult(slot, cipher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Exception e) {
|
||||
_fragment.onException(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@ import android.os.Bundle;
|
|||
import android.preference.EditTextPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.SwitchPreference;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Toast;
|
||||
|
@ -22,20 +24,25 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
|
||||
import me.impy.aegis.AegisApplication;
|
||||
import me.impy.aegis.R;
|
||||
import me.impy.aegis.crypto.MasterKey;
|
||||
import me.impy.aegis.db.DatabaseEntry;
|
||||
import me.impy.aegis.db.DatabaseManager;
|
||||
import me.impy.aegis.db.DatabaseManagerException;
|
||||
import me.impy.aegis.db.slots.Slot;
|
||||
import me.impy.aegis.db.slots.SlotCollection;
|
||||
import me.impy.aegis.db.slots.SlotException;
|
||||
import me.impy.aegis.helpers.PermissionHelper;
|
||||
import me.impy.aegis.importers.AegisImporter;
|
||||
import me.impy.aegis.importers.DatabaseImporter;
|
||||
import me.impy.aegis.importers.DatabaseImporterException;
|
||||
import me.impy.aegis.ui.dialogs.PasswordDialogFragment;
|
||||
import me.impy.aegis.util.ByteInputStream;
|
||||
|
||||
public class PreferencesFragment extends PreferenceFragment {
|
||||
public class PreferencesFragment extends PreferenceFragment implements PasswordDialogFragment.Listener {
|
||||
// activity request codes
|
||||
private static final int CODE_IMPORT = 0;
|
||||
private static final int CODE_IMPORT_DECRYPT = 1;
|
||||
|
@ -53,6 +60,9 @@ public class PreferencesFragment extends PreferenceFragment {
|
|||
private DatabaseImporter _importer;
|
||||
private Class<? extends DatabaseImporter> _importerType;
|
||||
|
||||
private SwitchPreference _encryptionPreference;
|
||||
private Preference _slotsPreference;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -92,20 +102,6 @@ public class PreferencesFragment extends PreferenceFragment {
|
|||
}
|
||||
});
|
||||
|
||||
Preference slotsPreference = findPreference("pref_slots");
|
||||
slotsPreference.setEnabled(_db.getFile().isEncrypted());
|
||||
slotsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
MasterKey masterKey = _db.getMasterKey();
|
||||
Intent intent = new Intent(getActivity(), SlotManagerActivity.class);
|
||||
intent.putExtra("masterKey", masterKey);
|
||||
intent.putExtra("slots", _db.getFile().getSlots());
|
||||
startActivityForResult(intent, CODE_SLOTS);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
EditTextPreference timeoutPreference = (EditTextPreference) findPreference("pref_timeout");
|
||||
timeoutPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
|
@ -139,6 +135,45 @@ public class PreferencesFragment extends PreferenceFragment {
|
|||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
_encryptionPreference = (SwitchPreference) findPreference("pref_encryption");
|
||||
_encryptionPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (!_db.getFile().isEncrypted()) {
|
||||
PasswordDialogFragment dialog = new PasswordDialogFragment();
|
||||
// TODO: find a less ugly way to obtain the fragment manager
|
||||
dialog.show(((AppCompatActivity)getActivity()).getSupportFragmentManager(), null);
|
||||
} else {
|
||||
new AlertDialog.Builder(getActivity())
|
||||
.setTitle("Disable encryption")
|
||||
.setMessage("Are you sure you want to disable encryption? This will cause the database to be stored in plain text")
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
_db.disableEncryption();
|
||||
saveDatabase();
|
||||
updateEncryptionPreference();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, null)
|
||||
.show();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
_slotsPreference = findPreference("pref_slots");
|
||||
_slotsPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
MasterKey masterKey = _db.getMasterKey();
|
||||
Intent intent = new Intent(getActivity(), SlotManagerActivity.class);
|
||||
intent.putExtra("masterKey", masterKey);
|
||||
intent.putExtra("slots", _db.getFile().getSlots());
|
||||
startActivityForResult(intent, CODE_SLOTS);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
updateEncryptionPreference();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -195,8 +230,6 @@ public class PreferencesFragment extends PreferenceFragment {
|
|||
.setSingleChoiceItems(names, 0, null)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
|
||||
int i = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
|
||||
_importerType = importers.get(names[i]);
|
||||
|
||||
|
@ -353,4 +386,34 @@ public class PreferencesFragment extends PreferenceFragment {
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlotResult(Slot slot, Cipher cipher) {
|
||||
MasterKey masterKey = MasterKey.generate();
|
||||
|
||||
SlotCollection slots = new SlotCollection();
|
||||
try {
|
||||
slots.encrypt(slot, masterKey, cipher);
|
||||
} catch (SlotException e) {
|
||||
onException(e);
|
||||
return;
|
||||
}
|
||||
slots.add(slot);
|
||||
_db.enableEncryption(masterKey, slots);
|
||||
|
||||
saveDatabase();
|
||||
updateEncryptionPreference();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onException(Exception e) {
|
||||
updateEncryptionPreference();
|
||||
Toast.makeText(getActivity(), "An error occurred while trying to set the password: " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private void updateEncryptionPreference() {
|
||||
boolean encrypted = _db.getFile().isEncrypted();
|
||||
_encryptionPreference.setChecked(encrypted);
|
||||
_slotsPreference.setEnabled(encrypted);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@ package me.impy.aegis.ui.dialogs;
|
|||
import android.app.Dialog;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ public class PasswordDialogFragment extends SlotDialogFragment {
|
|||
|
||||
char[] password = EditTextHelper.getEditTextChars(textPassword);
|
||||
PasswordSlot slot = new PasswordSlot();
|
||||
DerivationTask task = new DerivationTask(getContext(), key -> {
|
||||
DerivationTask task = new DerivationTask(getActivity(), key -> {
|
||||
Cipher cipher;
|
||||
try {
|
||||
cipher = Slot.createCipher(key, Cipher.ENCRYPT_MODE);
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
<string name="pref_export_summary">Export the database</string>
|
||||
<string name="pref_secure_screen_title">Screen security</string>
|
||||
<string name="pref_secure_screen_summary">Block screenshots and other attempts to capture the screen within the app</string>
|
||||
<string name="pref_encryption_title">Encryption</string>
|
||||
<string name="pref_encryption_summary">Encrypt the database and unlock it with a password or fingerprint</string>
|
||||
|
||||
<string name="fingerprint_hint">Touch sensor</string>
|
||||
<string name="fingerprint_not_recognized">Fingerprint not recognized. Try again</string>
|
||||
|
|
|
@ -31,6 +31,11 @@
|
|||
android:inputType="number"
|
||||
android:defaultValue="30"
|
||||
android:dialogTitle="Set number of seconds of inactivity before Aegis locks the database"/>
|
||||
<SwitchPreference
|
||||
android:key="pref_encryption"
|
||||
android:title="@string/pref_encryption_title"
|
||||
android:summary="@string/pref_encryption_summary"
|
||||
android:persistent="false"/>
|
||||
<Preference
|
||||
android:key="pref_slots"
|
||||
android:title="@string/pref_slots_title"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue