Allow changing password of CryFS volumes
This commit is contained in:
parent
1a21a43f05
commit
d1ca164934
@ -1 +1 @@
|
|||||||
Subproject commit cf822d6a5bb0bb3492ec350d2648f14c859f846f
|
Subproject commit c5be03ad3abea3aef5b0fcc5aa3af8cba2befdd1
|
@ -9,7 +9,11 @@ import android.view.View
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import sushi.hardcore.droidfs.databinding.ActivityChangePasswordBinding
|
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.filesystems.GocryptfsVolume
|
||||||
|
import sushi.hardcore.droidfs.util.ObjRef
|
||||||
|
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||||
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@ -66,14 +70,12 @@ class ChangePasswordActivity: BaseActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun changeVolumePassword() {
|
private fun changeVolumePassword() {
|
||||||
val newPassword = CharArray(binding.editNewPassword.text.length)
|
val newPassword = WidgetUtil.encodeEditTextContent(binding.editNewPassword)
|
||||||
binding.editNewPassword.text.getChars(0, newPassword.size, newPassword, 0)
|
val newPasswordConfirm = WidgetUtil.encodeEditTextContent(binding.editPasswordConfirm)
|
||||||
val newPasswordConfirm = CharArray(binding.editPasswordConfirm.text.length)
|
|
||||||
binding.editPasswordConfirm.text.getChars(0, newPasswordConfirm.size, newPasswordConfirm, 0)
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
if (!newPassword.contentEquals(newPasswordConfirm)) {
|
if (!newPassword.contentEquals(newPasswordConfirm)) {
|
||||||
Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
|
||||||
Arrays.fill(newPassword, 0.toChar())
|
Arrays.fill(newPassword, 0)
|
||||||
} else {
|
} else {
|
||||||
var changeWithCurrentPassword = true
|
var changeWithCurrentPassword = true
|
||||||
volume.encryptedHash?.let { encryptedHash ->
|
volume.encryptedHash?.let { encryptedHash ->
|
||||||
@ -91,7 +93,7 @@ class ChangePasswordActivity: BaseActivity() {
|
|||||||
}
|
}
|
||||||
override fun onPasswordHashSaved() {}
|
override fun onPasswordHashSaved() {}
|
||||||
override fun onFailed(pending: Boolean) {
|
override fun onFailed(pending: Boolean) {
|
||||||
Arrays.fill(newPassword, 0.toChar())
|
Arrays.fill(newPassword, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it.loadPasswordHash(volume.name, encryptedHash, iv)
|
it.loadPasswordHash(volume.name, encryptedHash, iv)
|
||||||
@ -102,30 +104,48 @@ class ChangePasswordActivity: BaseActivity() {
|
|||||||
changeVolumePassword(newPassword)
|
changeVolumePassword(newPassword)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Arrays.fill(newPasswordConfirm, 0.toChar())
|
Arrays.fill(newPasswordConfirm, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun changeVolumePassword(newPassword: CharArray, givenHash: ByteArray? = null) {
|
private fun changeVolumePassword(newPassword: ByteArray, givenHash: ByteArray? = null) {
|
||||||
var returnedHash: ByteArray? = null
|
val returnedHash: ObjRef<ByteArray?>? = if (binding.checkboxSavePassword.isChecked) {
|
||||||
if (binding.checkboxSavePassword.isChecked) {
|
ObjRef(null)
|
||||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
} else {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
var currentPassword: CharArray? = null
|
val currentPassword = if (givenHash == null) {
|
||||||
if (givenHash == null) {
|
WidgetUtil.encodeEditTextContent(binding.editCurrentPassword)
|
||||||
currentPassword = CharArray(binding.editCurrentPassword.text.length)
|
} else {
|
||||||
binding.editCurrentPassword.text.getChars(0, currentPassword.size, currentPassword, 0)
|
null
|
||||||
}
|
}
|
||||||
object : LoadingTask<Boolean>(this, themeValue, R.string.loading_msg_change_password) {
|
object : LoadingTask<Boolean>(this, themeValue, R.string.loading_msg_change_password) {
|
||||||
override suspend fun doTask(): Boolean {
|
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 (success) {
|
||||||
if (volumeDatabase.isHashSaved(volume.name)) {
|
if (volumeDatabase.isHashSaved(volume.name)) {
|
||||||
volumeDatabase.removeHash(volume)
|
volumeDatabase.removeHash(volume)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (currentPassword != null)
|
if (currentPassword != null)
|
||||||
Arrays.fill(currentPassword, 0.toChar())
|
Arrays.fill(currentPassword, 0)
|
||||||
Arrays.fill(newPassword, 0.toChar())
|
Arrays.fill(newPassword, 0)
|
||||||
if (givenHash != null)
|
if (givenHash != null)
|
||||||
Arrays.fill(givenHash, 0)
|
Arrays.fill(givenHash, 0)
|
||||||
return success
|
return success
|
||||||
@ -138,21 +158,21 @@ class ChangePasswordActivity: BaseActivity() {
|
|||||||
it.listener = object : FingerprintProtector.Listener {
|
it.listener = object : FingerprintProtector.Listener {
|
||||||
override fun onHashStorageReset() {
|
override fun onHashStorageReset() {
|
||||||
// retry
|
// retry
|
||||||
it.savePasswordHash(volume, returnedHash)
|
it.savePasswordHash(volume, returnedHash.value!!)
|
||||||
}
|
}
|
||||||
override fun onPasswordHashDecrypted(hash: ByteArray) {}
|
override fun onPasswordHashDecrypted(hash: ByteArray) {}
|
||||||
override fun onPasswordHashSaved() {
|
override fun onPasswordHashSaved() {
|
||||||
Arrays.fill(returnedHash, 0)
|
Arrays.fill(returnedHash.value!!, 0)
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
override fun onFailed(pending: Boolean) {
|
override fun onFailed(pending: Boolean) {
|
||||||
if (!pending) {
|
if (!pending) {
|
||||||
Arrays.fill(returnedHash, 0)
|
Arrays.fill(returnedHash.value!!, 0)
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it.savePasswordHash(volume, returnedHash)
|
it.savePasswordHash(volume, returnedHash.value!!)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
finish()
|
finish()
|
||||||
|
@ -342,11 +342,7 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
|
|||||||
val onlyOneAndWriteable =
|
val onlyOneAndWriteable =
|
||||||
onlyOneSelected &&
|
onlyOneSelected &&
|
||||||
volumeAdapter.volumes[volumeAdapter.selectedItems.first()].canWrite(filesDir.path)
|
volumeAdapter.volumes[volumeAdapter.selectedItems.first()].canWrite(filesDir.path)
|
||||||
menu.findItem(R.id.change_password).isVisible =
|
menu.findItem(R.id.change_password).isVisible = onlyOneAndWriteable
|
||||||
onlyOneAndWriteable &&
|
|
||||||
// Only gocryptfs volumes support password change
|
|
||||||
!BuildConfig.GOCRYPTFS_DISABLED &&
|
|
||||||
volumeAdapter.volumes[volumeAdapter.selectedItems.first()].type == EncryptedVolume.GOCRYPTFS_VOLUME_TYPE
|
|
||||||
menu.findItem(R.id.remove_default_open).isVisible =
|
menu.findItem(R.id.remove_default_open).isVisible =
|
||||||
onlyOneSelected &&
|
onlyOneSelected &&
|
||||||
volumeAdapter.volumes[volumeAdapter.selectedItems.first()].name == defaultVolumeName
|
volumeAdapter.volumes[volumeAdapter.selectedItems.first()].name == defaultVolumeName
|
||||||
|
@ -23,6 +23,14 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
|||||||
createBaseDir: Boolean,
|
createBaseDir: Boolean,
|
||||||
cipher: String?
|
cipher: String?
|
||||||
): Long
|
): Long
|
||||||
|
private external fun nativeChangeEncryptionKey(
|
||||||
|
baseDir: String,
|
||||||
|
localStateDir: String,
|
||||||
|
currentPassword: ByteArray?,
|
||||||
|
givenHash: ByteArray?,
|
||||||
|
newPassword: ByteArray,
|
||||||
|
returnedHash: ObjRef<ByteArray?>?
|
||||||
|
): Boolean
|
||||||
private external fun nativeCreate(fusePtr: Long, path: String, mode: Int): Long
|
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 nativeOpen(fusePtr: Long, path: String, flags: Int): Long
|
||||||
private external fun nativeRead(fusePtr: Long, fileHandle: Long, buffer: ByteArray, offset: Long): Int
|
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<ByteArray?>?): CryfsVolume? {
|
fun init(baseDir: String, localStateDir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ObjRef<ByteArray?>?): CryfsVolume? {
|
||||||
return init(baseDir, localStateDir, password, givenHash, returnedHash, false, null)
|
return init(baseDir, localStateDir, password, givenHash, returnedHash, false, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun changePassword(
|
||||||
|
baseDir: String, filesDir: String, currentPassword: ByteArray?,
|
||||||
|
givenHash: ByteArray?,
|
||||||
|
newPassword: ByteArray,
|
||||||
|
returnedHash: ObjRef<ByteArray?>?
|
||||||
|
): Boolean {
|
||||||
|
return nativeChangeEncryptionKey(baseDir, getLocalStateDir(filesDir), currentPassword, givenHash, newPassword, returnedHash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(parcel: Parcel) : this(parcel.readLong())
|
constructor(parcel: Parcel) : this(parcel.readLong())
|
||||||
|
@ -25,7 +25,13 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() {
|
|||||||
const val CONFIG_FILE_NAME = "gocryptfs.conf"
|
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
|
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
|
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? {
|
fun init(root_cipher_dir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ByteArray?): GocryptfsVolume? {
|
||||||
val sessionId = nativeInit(root_cipher_dir, password, givenHash, returnedHash)
|
val sessionId = nativeInit(root_cipher_dir, password, givenHash, returnedHash)
|
||||||
|
@ -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);
|
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
|
JNIEXPORT jlong JNICALL
|
||||||
Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeCreate(JNIEnv *env, jobject thiz,
|
Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeCreate(JNIEnv *env, jobject thiz,
|
||||||
jlong fuse_ptr, jstring path,
|
jlong fuse_ptr, jstring path,
|
||||||
|
Loading…
Reference in New Issue
Block a user