diff --git a/app/libcryfs b/app/libcryfs index cf822d6..c5be03a 160000 --- a/app/libcryfs +++ b/app/libcryfs @@ -1 +1 @@ -Subproject commit cf822d6a5bb0bb3492ec350d2648f14c859f846f +Subproject commit c5be03ad3abea3aef5b0fcc5aa3af8cba2befdd1 diff --git a/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt index 498090b..aef4bec 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt @@ -9,7 +9,11 @@ import android.view.View import android.widget.Toast import androidx.lifecycle.lifecycleScope import sushi.hardcore.droidfs.databinding.ActivityChangePasswordBinding +import sushi.hardcore.droidfs.filesystems.CryfsVolume +import sushi.hardcore.droidfs.filesystems.EncryptedVolume import sushi.hardcore.droidfs.filesystems.GocryptfsVolume +import sushi.hardcore.droidfs.util.ObjRef +import sushi.hardcore.droidfs.util.WidgetUtil import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder import java.util.* @@ -66,14 +70,12 @@ class ChangePasswordActivity: BaseActivity() { } private fun changeVolumePassword() { - val newPassword = CharArray(binding.editNewPassword.text.length) - binding.editNewPassword.text.getChars(0, newPassword.size, newPassword, 0) - val newPasswordConfirm = CharArray(binding.editPasswordConfirm.text.length) - binding.editPasswordConfirm.text.getChars(0, newPasswordConfirm.size, newPasswordConfirm, 0) + val newPassword = WidgetUtil.encodeEditTextContent(binding.editNewPassword) + val newPasswordConfirm = WidgetUtil.encodeEditTextContent(binding.editPasswordConfirm) @SuppressLint("NewApi") if (!newPassword.contentEquals(newPasswordConfirm)) { Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show() - Arrays.fill(newPassword, 0.toChar()) + Arrays.fill(newPassword, 0) } else { var changeWithCurrentPassword = true volume.encryptedHash?.let { encryptedHash -> @@ -91,7 +93,7 @@ class ChangePasswordActivity: BaseActivity() { } override fun onPasswordHashSaved() {} override fun onFailed(pending: Boolean) { - Arrays.fill(newPassword, 0.toChar()) + Arrays.fill(newPassword, 0) } } it.loadPasswordHash(volume.name, encryptedHash, iv) @@ -102,30 +104,48 @@ class ChangePasswordActivity: BaseActivity() { changeVolumePassword(newPassword) } } - Arrays.fill(newPasswordConfirm, 0.toChar()) + Arrays.fill(newPasswordConfirm, 0) } - private fun changeVolumePassword(newPassword: CharArray, givenHash: ByteArray? = null) { - var returnedHash: ByteArray? = null - if (binding.checkboxSavePassword.isChecked) { - returnedHash = ByteArray(GocryptfsVolume.KeyLen) + private fun changeVolumePassword(newPassword: ByteArray, givenHash: ByteArray? = null) { + val returnedHash: ObjRef? = if (binding.checkboxSavePassword.isChecked) { + ObjRef(null) + } else { + null } - var currentPassword: CharArray? = null - if (givenHash == null) { - currentPassword = CharArray(binding.editCurrentPassword.text.length) - binding.editCurrentPassword.text.getChars(0, currentPassword.size, currentPassword, 0) + val currentPassword = if (givenHash == null) { + WidgetUtil.encodeEditTextContent(binding.editCurrentPassword) + } else { + null } object : LoadingTask(this, themeValue, R.string.loading_msg_change_password) { override suspend fun doTask(): Boolean { - val success = GocryptfsVolume.changePassword(volume.getFullPath(filesDir.path), currentPassword, givenHash, newPassword, returnedHash) + val success = if (volume.type == EncryptedVolume.GOCRYPTFS_VOLUME_TYPE) { + GocryptfsVolume.changePassword( + volume.getFullPath(filesDir.path), + currentPassword, + givenHash, + newPassword, + returnedHash?.apply { value = ByteArray(GocryptfsVolume.KeyLen) }?.value + ) + } else { + CryfsVolume.changePassword( + volume.getFullPath(filesDir.path), + filesDir.path, + currentPassword, + givenHash, + newPassword, + returnedHash + ) + } if (success) { if (volumeDatabase.isHashSaved(volume.name)) { volumeDatabase.removeHash(volume) } } if (currentPassword != null) - Arrays.fill(currentPassword, 0.toChar()) - Arrays.fill(newPassword, 0.toChar()) + Arrays.fill(currentPassword, 0) + Arrays.fill(newPassword, 0) if (givenHash != null) Arrays.fill(givenHash, 0) return success @@ -138,21 +158,21 @@ class ChangePasswordActivity: BaseActivity() { it.listener = object : FingerprintProtector.Listener { override fun onHashStorageReset() { // retry - it.savePasswordHash(volume, returnedHash) + it.savePasswordHash(volume, returnedHash.value!!) } override fun onPasswordHashDecrypted(hash: ByteArray) {} override fun onPasswordHashSaved() { - Arrays.fill(returnedHash, 0) + Arrays.fill(returnedHash.value!!, 0) finish() } override fun onFailed(pending: Boolean) { if (!pending) { - Arrays.fill(returnedHash, 0) + Arrays.fill(returnedHash.value!!, 0) finish() } } } - it.savePasswordHash(volume, returnedHash) + it.savePasswordHash(volume, returnedHash.value!!) } } else { finish() diff --git a/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt index 830abd5..bd23fd3 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt @@ -342,11 +342,7 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { val onlyOneAndWriteable = onlyOneSelected && volumeAdapter.volumes[volumeAdapter.selectedItems.first()].canWrite(filesDir.path) - menu.findItem(R.id.change_password).isVisible = - onlyOneAndWriteable && - // Only gocryptfs volumes support password change - !BuildConfig.GOCRYPTFS_DISABLED && - volumeAdapter.volumes[volumeAdapter.selectedItems.first()].type == EncryptedVolume.GOCRYPTFS_VOLUME_TYPE + menu.findItem(R.id.change_password).isVisible = onlyOneAndWriteable menu.findItem(R.id.remove_default_open).isVisible = onlyOneSelected && volumeAdapter.volumes[volumeAdapter.selectedItems.first()].name == defaultVolumeName diff --git a/app/src/main/java/sushi/hardcore/droidfs/filesystems/CryfsVolume.kt b/app/src/main/java/sushi/hardcore/droidfs/filesystems/CryfsVolume.kt index 45390d1..6f408f2 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/filesystems/CryfsVolume.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/filesystems/CryfsVolume.kt @@ -23,6 +23,14 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() { createBaseDir: Boolean, cipher: String? ): Long + private external fun nativeChangeEncryptionKey( + baseDir: String, + localStateDir: String, + currentPassword: ByteArray?, + givenHash: ByteArray?, + newPassword: ByteArray, + returnedHash: ObjRef? + ): Boolean private external fun nativeCreate(fusePtr: Long, path: String, mode: Int): Long private external fun nativeOpen(fusePtr: Long, path: String, flags: Int): Long private external fun nativeRead(fusePtr: Long, fileHandle: Long, buffer: ByteArray, offset: Long): Int @@ -66,6 +74,15 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() { fun init(baseDir: String, localStateDir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ObjRef?): CryfsVolume? { return init(baseDir, localStateDir, password, givenHash, returnedHash, false, null) } + + fun changePassword( + baseDir: String, filesDir: String, currentPassword: ByteArray?, + givenHash: ByteArray?, + newPassword: ByteArray, + returnedHash: ObjRef? + ): Boolean { + return nativeChangeEncryptionKey(baseDir, getLocalStateDir(filesDir), currentPassword, givenHash, newPassword, returnedHash) + } } constructor(parcel: Parcel) : this(parcel.readLong()) diff --git a/app/src/main/java/sushi/hardcore/droidfs/filesystems/GocryptfsVolume.kt b/app/src/main/java/sushi/hardcore/droidfs/filesystems/GocryptfsVolume.kt index 22d60a8..aa7e67d 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/filesystems/GocryptfsVolume.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/filesystems/GocryptfsVolume.kt @@ -25,7 +25,13 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() { const val CONFIG_FILE_NAME = "gocryptfs.conf" external fun createVolume(root_cipher_dir: String, password: ByteArray, plainTextNames: Boolean, xchacha: Int, logN: Int, creator: String, returnedHash: ByteArray?): Boolean private external fun nativeInit(root_cipher_dir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ByteArray?): Int - external fun changePassword(root_cipher_dir: String, old_password: CharArray?, givenHash: ByteArray?, new_password: CharArray, returnedHash: ByteArray?): Boolean + external fun changePassword( + root_cipher_dir: String, + currentPassword: ByteArray?, + givenHash: ByteArray?, + newPassword: ByteArray, + returnedHash: ByteArray? + ): Boolean fun init(root_cipher_dir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ByteArray?): GocryptfsVolume? { val sessionId = nativeInit(root_cipher_dir, password, givenHash, returnedHash) diff --git a/app/src/main/native/libcryfs.c b/app/src/main/native/libcryfs.c index a671519..9239e81 100644 --- a/app/src/main/native/libcryfs.c +++ b/app/src/main/native/libcryfs.c @@ -12,6 +12,14 @@ Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeInit(JN return cryfs_init(env, base_dir, jlocalStateDir, password, givenHash, returnedHash, createBaseDir, cipher); } +JNIEXPORT jboolean JNICALL +Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeChangeEncryptionKey( + JNIEnv *env, jobject thiz, jstring base_dir, jstring local_state_dir, + jbyteArray current_password, jbyteArray given_hash, jbyteArray new_password, + jobject returned_hash) { + return cryfs_change_encryption_key(env, base_dir, local_state_dir, current_password, given_hash, new_password, returned_hash); +} + JNIEXPORT jlong JNICALL Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeCreate(JNIEnv *env, jobject thiz, jlong fuse_ptr, jstring path,