1
0
mirror of https://github.com/etesync/android synced 2025-01-23 14:10:54 +00:00

Implementing changing encryption password.

The way it's done is by changing the password and adding ourselves as
journal members with our public keys. Same way shared journals works.

This should not be used if you believe your encryption password has been
compromised. That would require a much more intrusive action (as the
note there indicates).
This commit is contained in:
Tom Hacohen 2019-01-11 21:04:01 +00:00
parent 6e2ab7d972
commit 5c894e001f
9 changed files with 325 additions and 12 deletions

View File

@ -236,6 +236,7 @@
<activity android:name=".ui.JournalItemActivity"/> <activity android:name=".ui.JournalItemActivity"/>
<activity android:name=".ui.importlocal.ImportActivity"/> <activity android:name=".ui.importlocal.ImportActivity"/>
<activity android:name=".ui.AccountSettingsActivity"/> <activity android:name=".ui.AccountSettingsActivity"/>
<activity android:name=".ui.ChangeEncryptionPasswordActivity"/>
<activity android:name=".ui.CreateCollectionActivity"/> <activity android:name=".ui.CreateCollectionActivity"/>
<activity android:name=".ui.EditCollectionActivity"/> <activity android:name=".ui.EditCollectionActivity"/>

View File

@ -83,6 +83,8 @@ class UserInfoManager(httpClient: OkHttpClient, remote: HttpUrl) : BaseManager()
class UserInfo { class UserInfo {
@Transient @Transient
var owner: String? = null var owner: String? = null
@Transient
val plan: String? = null
val version: Byte? val version: Byte?
val pubkey: ByteArray? val pubkey: ByteArray?
private var content: ByteArray? = null private var content: ByteArray? = null

View File

@ -95,6 +95,13 @@ class AccountSettingsActivity : BaseActivity() {
false false
} }
// Category: encryption
val prefEncryptionPassword = findPreference("encryption_password")
prefEncryptionPassword.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ ->
startActivity(ChangeEncryptionPasswordActivity.newIntent(activity!!, account))
true
}
// category: synchronization // category: synchronization
val prefSyncContacts = findPreference("sync_interval_contacts") as ListPreference val prefSyncContacts = findPreference("sync_interval_contacts") as ListPreference
val syncIntervalContacts = settings.getSyncInterval(App.addressBooksAuthority) val syncIntervalContacts = settings.getSyncInterval(App.addressBooksAuthority)

View File

@ -0,0 +1,194 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package com.etesync.syncadapter.ui
import android.accounts.Account
import android.app.ProgressDialog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.support.design.widget.TextInputLayout
import android.support.v7.app.AlertDialog
import android.view.View
import com.etesync.syncadapter.AccountSettings
import com.etesync.syncadapter.App
import com.etesync.syncadapter.HttpClient
import com.etesync.syncadapter.R
import com.etesync.syncadapter.journalmanager.Crypto
import com.etesync.syncadapter.journalmanager.JournalManager
import com.etesync.syncadapter.journalmanager.UserInfoManager
import okhttp3.HttpUrl
import org.jetbrains.anko.doAsync
import org.jetbrains.anko.uiThread
import java.util.*
open class ChangeEncryptionPasswordActivity : BaseActivity() {
protected lateinit var account: Account
lateinit var progress: ProgressDialog
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
account = intent.extras!!.getParcelable(EXTRA_ACCOUNT)!!
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
setContentView(R.layout.change_encryption_password)
}
fun onCancelClicked(v: View) {
finish()
}
fun changePasswordError(e: Exception) {
progress.dismiss()
AlertDialog.Builder(this)
.setTitle(R.string.wrong_encryption_password)
.setIcon(R.drawable.ic_error_dark)
.setMessage(getString(R.string.wrong_encryption_password_content, e.localizedMessage))
.setPositiveButton(android.R.string.ok) { _, _ ->
// dismiss
}.show()
}
fun changePasswordDo(old_password: String, new_password: String) {
val settings = AccountSettings(this, account)
val httpClient = HttpClient.create(this, settings)
doAsync {
App.log.info("Started deriving old key")
val old_key = Crypto.deriveKey(account.name, old_password)
App.log.info("Finished deriving old key")
var cryptoManager: Crypto.CryptoManager
val principal = HttpUrl.get(settings.uri!!)!!
try {
val userInfoManager = UserInfoManager(httpClient, principal)
val userInfo = userInfoManager.fetch(account.name)!!
App.log.info("Fetched userInfo for " + account.name)
cryptoManager = Crypto.CryptoManager(userInfo.version!!.toInt(), old_key, "userInfo")
userInfo.verify(cryptoManager)
App.log.info("Started deriving new key")
val new_key = Crypto.deriveKey(account.name, new_password)
App.log.info("Finished deriving new key")
val userInfoContent = userInfo.getContent(cryptoManager)!!
cryptoManager = Crypto.CryptoManager(userInfo.version.toInt(), new_key, "userInfo")
userInfo.setContent(cryptoManager, userInfoContent)
App.log.info("Fetching journal list")
val membersToAdd = LinkedList<Pair<JournalManager.Journal, ByteArray?>>()
val journalManager = JournalManager(httpClient, principal)
val journals = journalManager.list()
for (journal in journals) {
if (journal.owner != account.name) {
continue
}
if (journal.key != null) {
// We don't need to handle those cases, as they are already encrypted using pubkey
continue
} else {
cryptoManager = Crypto.CryptoManager(journal.version, old_key, journal.uid!!)
}
App.log.info("Converting journal ${journal.uid}")
journal.verify(cryptoManager)
membersToAdd.add(Pair(journal, cryptoManager.getEncryptedKey(settings.keyPair!!, userInfo.pubkey!!)))
}
App.log.info("Finished converting account. Uploading changes")
userInfoManager.update(userInfo)
for ((journal, encryptedKey) in membersToAdd) {
if (journal.owner != account.name) {
continue
}
App.log.info("Uploading journal ${journal.uid}")
val member = JournalManager.Member(account.name, encryptedKey!!)
journalManager.addMember(journal, member)
}
settings.password(new_key)
App.log.info("Finished uploading changes. Encryption password changed successfully.")
uiThread {
progress.dismiss()
AlertDialog.Builder(this@ChangeEncryptionPasswordActivity)
.setTitle(R.string.change_encryption_password_success_title)
.setMessage(R.string.change_encryption_password_success_body)
.setPositiveButton(android.R.string.ok) { _, _ ->
this@ChangeEncryptionPasswordActivity.finish()
}.show()
}
} catch (e: Exception) {
uiThread {
changePasswordError(e)
}
return@doAsync
}
}
}
fun changePasswordClicked(v: View) {
val old_password_view = findViewById<TextInputLayout>(R.id.encryption_password)
val new_password_view = findViewById<TextInputLayout>(R.id.new_encryption_password)
var valid = true
val old_password = old_password_view.editText?.text.toString()
if (old_password.isEmpty()) {
old_password_view.error = getString(R.string.login_password_required)
valid = false
} else {
old_password_view.error = null
}
val new_password = new_password_view.editText?.text.toString()
if (new_password.isEmpty()) {
new_password_view.error = getString(R.string.login_password_required)
valid = false
} else {
new_password_view.error = null
}
if (!valid) {
return
}
AlertDialog.Builder(this)
.setTitle(R.string.delete_collection_confirm_title)
.setMessage(R.string.change_encryption_password_are_you_sure)
.setPositiveButton(android.R.string.yes) { _, _ ->
changePasswordDo(old_password, new_password)
progress = ProgressDialog(this)
progress.setTitle(R.string.login_encryption_setup_title)
progress.setMessage(getString(R.string.login_encryption_setup))
progress.isIndeterminate = true
progress.setCanceledOnTouchOutside(false)
progress.setCancelable(false)
progress.show()
}
.setNegativeButton(android.R.string.no) { _, _ -> }
.create().show()
}
companion object {
internal val EXTRA_ACCOUNT = "account"
fun newIntent(context: Context, account: Account): Intent {
val intent = Intent(context, ChangeEncryptionPasswordActivity::class.java)
intent.putExtra(CreateCollectionActivity.EXTRA_ACCOUNT, account)
return intent
}
}
}

View File

@ -0,0 +1,104 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
~ All rights reserved. This program and the accompanying materials
~ are made available under the terms of the GNU Public License v3.0
~ which accompanies this distribution, and is available at
~ http://www.gnu.org/licenses/gpl.html
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="@dimen/activity_margin">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/login_type_headline"
android:text="@string/change_encryption_password_title"
android:layout_marginBottom="14dp"/>
<TextView
android:id="@+id/account_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.design.widget.TextInputLayout
android:id="@+id/encryption_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:inputType="textPassword"
android:hint="@string/login_encryption_password"/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:id="@+id/new_encryption_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:passwordToggleEnabled="true">
<android.support.design.widget.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="monospace"
android:inputType="textPassword"
android:hint="@string/change_encryption_password_new_password"/>
</android.support.design.widget.TextInputLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="@string/login_encryption_check_password"/>
<TextView
android:id="@+id/encryption_extra_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:autoLink="web"
android:text="@string/change_encryption_password_extra_info"/>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/stepper_nav_bar">
<Button
android:id="@+id/back"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_gravity="center"
android:text="@android:string/cancel"
android:onClick="onCancelClicked"
style="@style/stepper_nav_button"/>
<Button
android:id="@+id/set_password"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_gravity="center"
android:text="@string/login_finish"
android:onClick="changePasswordClicked"
style="@style/stepper_nav_button"/>
</LinearLayout>
</LinearLayout>

View File

@ -126,7 +126,7 @@
<string name="settings_password_summary">Ihr Anmelde-Passwort</string> <string name="settings_password_summary">Ihr Anmelde-Passwort</string>
<string name="settings_enter_password">Passwort eingeben:</string> <string name="settings_enter_password">Passwort eingeben:</string>
<string name="settings_encryption_password">Verschlüsselungs-Passwort</string> <string name="settings_encryption_password">Verschlüsselungs-Passwort</string>
<string name="settings_encryption_password_summary">Verschlüsselungs-Passwort ändern (nicht implementiert)</string> <string name="settings_encryption_password_summary">Verschlüsselungs-Passwort ändern</string>
<string name="settings_enter_encryption_password">Verschlüsselungs-Passwort eingeben:</string> <string name="settings_enter_encryption_password">Verschlüsselungs-Passwort eingeben:</string>
<string name="settings_sync">Synchronisation</string> <string name="settings_sync">Synchronisation</string>
<string name="settings_sync_interval_contacts">Häufigkeit der Kontakte-Synchronisation</string> <string name="settings_sync_interval_contacts">Häufigkeit der Kontakte-Synchronisation</string>

View File

@ -205,7 +205,7 @@
<string name="settings_password_summary">Zmień hasło weryfikacji</string> <string name="settings_password_summary">Zmień hasło weryfikacji</string>
<string name="settings_enter_password">Wprowadź obecne hasło:</string> <string name="settings_enter_password">Wprowadź obecne hasło:</string>
<string name="settings_encryption_password">Hasło szyfrowania</string> <string name="settings_encryption_password">Hasło szyfrowania</string>
<string name="settings_encryption_password_summary">Zmień swoje hasło szyfrowania (niezaimpletowane)</string> <string name="settings_encryption_password_summary">Zmień swoje hasło szyfrowania</string>
<string name="settings_enter_encryption_password">Wprowadź obecne hasło szyfrowania:</string> <string name="settings_enter_encryption_password">Wprowadź obecne hasło szyfrowania:</string>
<string name="settings_sync">Synchronizacja</string> <string name="settings_sync">Synchronizacja</string>
<string name="settings_sync_interval_contacts">Okres synchronizacji kontaktów</string> <string name="settings_sync_interval_contacts">Okres synchronizacji kontaktów</string>

View File

@ -184,7 +184,7 @@
<string name="login_custom_server_error">Invalid URL found, did you forget to include https://?</string> <string name="login_custom_server_error">Invalid URL found, did you forget to include https://?</string>
<string name="login_toggle_advanced">Show advanced settings</string> <string name="login_toggle_advanced">Show advanced settings</string>
<string name="login_encryption_password">Encryption Password</string> <string name="login_encryption_password">Encryption Password</string>
<string name="login_encryption_check_password">* Please double-check the password, as it can\'t be changed if wrong.</string> <string name="login_encryption_check_password">* Please double-check the password, as it can\'t be recovered if wrong!</string>
<string name="login_encryption_extra_info">This password is used to encrypt your data, unlike the previous one, which is used to log into the service.\nYou are asked to choose a separate encryption password for security reasons. For more information, plesae refer to the FAQ at: %s</string> <string name="login_encryption_extra_info">This password is used to encrypt your data, unlike the previous one, which is used to log into the service.\nYou are asked to choose a separate encryption password for security reasons. For more information, plesae refer to the FAQ at: %s</string>
<string name="login_password_required">Password required</string> <string name="login_password_required">Password required</string>
<string name="login_login">Log In</string> <string name="login_login">Log In</string>
@ -207,12 +207,19 @@
<string name="account_creation_failed">Account creation failed</string> <string name="account_creation_failed">Account creation failed</string>
<string name="wrong_encryption_password">Wrong encryption password</string> <string name="wrong_encryption_password">Wrong encryption password</string>
<string name="wrong_encryption_password_content">Got an integrity error while accessing your account, which most likely means you put in the wrong encryption password.\n\n%s</string> <string name="wrong_encryption_password_content">Got an integrity error while accessing your account, which most likely means you put in the wrong encryption password.\n\nError: %s</string>
<!-- ChangeEncryptionPasswordActivity -->
<string name="change_encryption_password_title">Change Encryption Password</string>
<string name="change_encryption_password_extra_info">Please don\'t use this tool if you believe your encryption password has been comporomised. Contact support instead.</string>
<string name="change_encryption_password_new_password">New encryption Password</string>
<string name="change_encryption_password_are_you_sure">Are you sure you would like to continue? The process can not be stopped half way or be undone, and may take a while to complete.</string>
<string name="change_encryption_password_success_title">Encryption Password Change</string>
<string name="change_encryption_password_success_body">Encryption password has been successfully changed!</string>
<!-- SetupUserInfoFragment --> <!-- SetupUserInfoFragment -->
<string name="login_user_info_error_title">Error Setting User Info</string> <string name="login_user_info_error_title">Error Setting User Info</string>
<!-- ImportFragment --> <!-- ImportFragment -->
<string name="import_dialog_title">Import</string> <string name="import_dialog_title">Import</string>
<string name="import_dialog_failed_title">Import Failed</string> <string name="import_dialog_failed_title">Import Failed</string>
@ -230,7 +237,7 @@
<string name="settings_password_summary">Change your authentication password</string> <string name="settings_password_summary">Change your authentication password</string>
<string name="settings_enter_password">Enter your password:</string> <string name="settings_enter_password">Enter your password:</string>
<string name="settings_encryption_password">Encryption Password</string> <string name="settings_encryption_password">Encryption Password</string>
<string name="settings_encryption_password_summary">Change your encryption password (not implemented)</string> <string name="settings_encryption_password_summary">Change your encryption password</string>
<string name="settings_enter_encryption_password">Enter your encryption password:</string> <string name="settings_enter_encryption_password">Enter your encryption password:</string>
<string name="settings_sync">Synchronization</string> <string name="settings_sync">Synchronization</string>
<string name="settings_sync_interval_contacts">Contacts sync. interval</string> <string name="settings_sync_interval_contacts">Contacts sync. interval</string>

View File

@ -23,14 +23,12 @@
<PreferenceCategory android:title="@string/settings_encryption"> <PreferenceCategory android:title="@string/settings_encryption">
<EditTextPreference <Preference
android:key="encryption_password"
android:title="@string/settings_encryption_password" android:title="@string/settings_encryption_password"
android:persistent="false" android:key="encryption_password"
android:inputType="textPassword"
android:enabled="false"
android:summary="@string/settings_encryption_password_summary" android:summary="@string/settings_encryption_password_summary"
android:dialogTitle="@string/settings_enter_encryption_password" /> android:persistent="false"
/>
</PreferenceCategory> </PreferenceCategory>