Allow opening CryFS volumes with password hash
This commit is contained in:
parent
cf4927a90b
commit
e01932acda
@ -1 +1 @@
|
||||
Subproject commit 356cf8a1604776cb2cc4f4ff873936f7b396bd49
|
||||
Subproject commit cf822d6a5bb0bb3492ec350d2648f14c859f846f
|
@ -31,7 +31,7 @@ import sushi.hardcore.droidfs.explorers.ExplorerActivityDrop
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerActivityPick
|
||||
import sushi.hardcore.droidfs.file_operations.FileOperationService
|
||||
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
||||
import sushi.hardcore.droidfs.filesystems.GocryptfsVolume
|
||||
import sushi.hardcore.droidfs.util.ObjRef
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
||||
@ -535,7 +535,7 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
|
||||
|
||||
private fun askForPassword(volume: SavedVolume, position: Int, savePasswordHash: Boolean = false) {
|
||||
val dialogBinding = DialogOpenVolumeBinding.inflate(layoutInflater)
|
||||
if (!usfFingerprint || fingerprintProtector == null || volume.encryptedHash != null || volume.type == EncryptedVolume.CRYFS_VOLUME_TYPE) {
|
||||
if (!usfFingerprint || fingerprintProtector == null || volume.encryptedHash != null) {
|
||||
dialogBinding.checkboxSavePassword.visibility = View.GONE
|
||||
} else {
|
||||
dialogBinding.checkboxSavePassword.isChecked = savePasswordHash
|
||||
@ -564,10 +564,10 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
|
||||
}
|
||||
|
||||
private fun openVolumeWithPassword(volume: SavedVolume, position: Int, password: ByteArray, savePasswordHash: Boolean) {
|
||||
val usfFingerprint = sharedPrefs.getBoolean("usf_fingerprint", false)
|
||||
var returnedHash: ByteArray? = null
|
||||
if (savePasswordHash && usfFingerprint) {
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
val returnedHash: ObjRef<ByteArray?>? = if (savePasswordHash) {
|
||||
ObjRef(null)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
object : LoadingTask<EncryptedVolume?>(this, themeValue, R.string.loading_msg_open) {
|
||||
override suspend fun doTask(): EncryptedVolume? {
|
||||
@ -594,7 +594,7 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
|
||||
}
|
||||
override fun onPasswordHashDecrypted(hash: ByteArray) {}
|
||||
override fun onPasswordHashSaved() {
|
||||
Arrays.fill(returnedHash, 0)
|
||||
Arrays.fill(returnedHash.value!!, 0)
|
||||
volumeAdapter.onVolumeChanged(position)
|
||||
startExplorer(encryptedVolume, volume.shortName)
|
||||
}
|
||||
@ -604,10 +604,10 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
|
||||
encryptedVolume.close()
|
||||
isClosed = true
|
||||
}
|
||||
Arrays.fill(returnedHash, 0)
|
||||
Arrays.fill(returnedHash.value!!, 0)
|
||||
}
|
||||
}
|
||||
fingerprintProtector.savePasswordHash(volume, returnedHash)
|
||||
fingerprintProtector.savePasswordHash(volume, returnedHash.value!!)
|
||||
} else {
|
||||
startExplorer(encryptedVolume, volume.shortName)
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import sushi.hardcore.droidfs.databinding.FragmentCreateVolumeBinding
|
||||
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.io.File
|
||||
@ -108,12 +109,8 @@ class CreateVolumeFragment: Fragment() {
|
||||
binding.spinnerVolumeType.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
val ciphersArray = if (volumeTypes[position] == resources.getString(R.string.gocryptfs)) {
|
||||
if (usfFingerprint && fingerprintProtector != null) {
|
||||
binding.checkboxSavePassword.visibility = View.VISIBLE
|
||||
}
|
||||
R.array.gocryptfs_encryption_ciphers
|
||||
} else {
|
||||
binding.checkboxSavePassword.visibility = View.GONE
|
||||
R.array.cryfs_encryption_ciphers
|
||||
}
|
||||
with(encryptionCipherAdapter) {
|
||||
@ -167,9 +164,11 @@ class CreateVolumeFragment: Fragment() {
|
||||
Arrays.fill(passwordConfirm, 0)
|
||||
} else {
|
||||
Arrays.fill(passwordConfirm, 0)
|
||||
var returnedHash: ByteArray? = null
|
||||
if (binding.checkboxSavePassword.isChecked)
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
val returnedHash: ObjRef<ByteArray?>? = if (binding.checkboxSavePassword.isChecked) {
|
||||
ObjRef(null)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
object: LoadingTask<SavedVolume?>(requireActivity() as AppCompatActivity, themeValue, R.string.loading_msg_create) {
|
||||
override suspend fun doTask(): SavedVolume? {
|
||||
val volumeFile = File(volumePath)
|
||||
@ -188,13 +187,16 @@ class CreateVolumeFragment: Fragment() {
|
||||
xchacha,
|
||||
GocryptfsVolume.ScryptDefaultLogN,
|
||||
ConstValues.CREATOR,
|
||||
returnedHash
|
||||
returnedHash?.apply {
|
||||
value = ByteArray(GocryptfsVolume.KeyLen)
|
||||
}?.value,
|
||||
), EncryptedVolume.GOCRYPTFS_VOLUME_TYPE)
|
||||
} else {
|
||||
saveVolume(CryfsVolume.create(
|
||||
volumePath,
|
||||
CryfsVolume.getLocalStateDir(activity.filesDir.path),
|
||||
password,
|
||||
returnedHash,
|
||||
resources.getStringArray(R.array.cryfs_encryption_ciphers)[binding.spinnerCipher.selectedItemPosition]
|
||||
), EncryptedVolume.CRYFS_VOLUME_TYPE)
|
||||
}
|
||||
@ -216,21 +218,21 @@ class CreateVolumeFragment: Fragment() {
|
||||
override fun onHashStorageReset() {
|
||||
hashStorageReset = true
|
||||
// retry
|
||||
it.savePasswordHash(volume, returnedHash)
|
||||
it.savePasswordHash(volume, returnedHash.value!!)
|
||||
}
|
||||
override fun onPasswordHashDecrypted(hash: ByteArray) {} // shouldn't happen here
|
||||
override fun onPasswordHashSaved() {
|
||||
Arrays.fill(returnedHash, 0)
|
||||
Arrays.fill(returnedHash.value!!, 0)
|
||||
onVolumeCreated()
|
||||
}
|
||||
override fun onFailed(pending: Boolean) {
|
||||
if (!pending) {
|
||||
Arrays.fill(returnedHash, 0)
|
||||
Arrays.fill(returnedHash.value!!, 0)
|
||||
onVolumeCreated()
|
||||
}
|
||||
}
|
||||
}
|
||||
it.savePasswordHash(volume, returnedHash)
|
||||
it.savePasswordHash(volume, returnedHash.value!!)
|
||||
}
|
||||
} else onVolumeCreated()
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import sushi.hardcore.droidfs.ConstValues
|
||||
import sushi.hardcore.droidfs.R
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
||||
import sushi.hardcore.droidfs.util.ObjRef
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import sushi.hardcore.droidfs.util.Wiper
|
||||
import java.io.File
|
||||
@ -415,8 +416,6 @@ class FileOperationService : Service() {
|
||||
return count
|
||||
}
|
||||
|
||||
internal class ObjRef<T>(var value: T)
|
||||
|
||||
private fun recursiveCopyVolume(
|
||||
src: DocumentFile,
|
||||
dst: DocumentFile,
|
||||
|
@ -3,6 +3,7 @@ package sushi.hardcore.droidfs.filesystems
|
||||
import android.os.Parcel
|
||||
import sushi.hardcore.droidfs.ConstValues
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||
import sushi.hardcore.droidfs.util.ObjRef
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
|
||||
class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
||||
@ -16,7 +17,9 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
||||
private external fun nativeInit(
|
||||
baseDir: String,
|
||||
localStateDir: String,
|
||||
password: ByteArray,
|
||||
password: ByteArray?,
|
||||
givenHash: ByteArray?,
|
||||
returnedHash: ObjRef<ByteArray?>?,
|
||||
createBaseDir: Boolean,
|
||||
cipher: String?
|
||||
): Long
|
||||
@ -39,8 +42,16 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
||||
return PathUtils.pathJoin(filesDir, ConstValues.CRYFS_LOCAL_STATE_DIR)
|
||||
}
|
||||
|
||||
private fun init(baseDir: String, localStateDir: String, password: ByteArray, createBaseDir: Boolean, cipher: String?): CryfsVolume? {
|
||||
val fusePtr = nativeInit(baseDir, localStateDir, password, createBaseDir, cipher)
|
||||
private fun init(
|
||||
baseDir: String,
|
||||
localStateDir: String,
|
||||
password: ByteArray?,
|
||||
givenHash: ByteArray?,
|
||||
returnedHash: ObjRef<ByteArray?>?,
|
||||
createBaseDir: Boolean,
|
||||
cipher: String?
|
||||
): CryfsVolume? {
|
||||
val fusePtr = nativeInit(baseDir, localStateDir, password, givenHash, returnedHash, createBaseDir, cipher)
|
||||
return if (fusePtr == 0L) {
|
||||
null
|
||||
} else {
|
||||
@ -48,12 +59,12 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
||||
}
|
||||
}
|
||||
|
||||
fun create(baseDir: String, localStateDir: String, password: ByteArray, cipher: String?): Boolean {
|
||||
return init(baseDir, localStateDir, password, true, cipher)?.also { it.close() } != null
|
||||
fun create(baseDir: String, localStateDir: String, password: ByteArray, returnedHash: ObjRef<ByteArray?>?, cipher: String?): Boolean {
|
||||
return init(baseDir, localStateDir, password, null, returnedHash, true, cipher)?.also { it.close() } != null
|
||||
}
|
||||
|
||||
fun init(baseDir: String, localStateDir: String, password: ByteArray): CryfsVolume? {
|
||||
return init(baseDir, localStateDir, password, false, null)
|
||||
fun init(baseDir: String, localStateDir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ObjRef<ByteArray?>?): CryfsVolume? {
|
||||
return init(baseDir, localStateDir, password, givenHash, returnedHash, false, null)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import android.os.Parcelable
|
||||
import sushi.hardcore.droidfs.ConstValues
|
||||
import sushi.hardcore.droidfs.SavedVolume
|
||||
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||
import sushi.hardcore.droidfs.util.ObjRef
|
||||
import sushi.hardcore.droidfs.util.PathUtils
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
@ -40,13 +41,26 @@ abstract class EncryptedVolume: Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
fun init(volume: SavedVolume, filesDir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ByteArray?): EncryptedVolume? {
|
||||
fun init(
|
||||
volume: SavedVolume,
|
||||
filesDir: String,
|
||||
password: ByteArray?,
|
||||
givenHash: ByteArray?,
|
||||
returnedHash: ObjRef<ByteArray?>?
|
||||
): EncryptedVolume? {
|
||||
return when (volume.type) {
|
||||
GOCRYPTFS_VOLUME_TYPE -> {
|
||||
GocryptfsVolume.init(volume.getFullPath(filesDir), password, givenHash, returnedHash)
|
||||
GocryptfsVolume.init(
|
||||
volume.getFullPath(filesDir),
|
||||
password,
|
||||
givenHash,
|
||||
returnedHash?.apply {
|
||||
value = ByteArray(GocryptfsVolume.KeyLen)
|
||||
}?.value
|
||||
)
|
||||
}
|
||||
CRYFS_VOLUME_TYPE -> {
|
||||
CryfsVolume.init(volume.getFullPath(filesDir), CryfsVolume.getLocalStateDir(filesDir), password!!)
|
||||
CryfsVolume.init(volume.getFullPath(filesDir), CryfsVolume.getLocalStateDir(filesDir), password, givenHash, returnedHash)
|
||||
}
|
||||
else -> throw invalidVolumeType()
|
||||
}
|
||||
|
3
app/src/main/java/sushi/hardcore/droidfs/util/ObjRef.kt
Normal file
3
app/src/main/java/sushi/hardcore/droidfs/util/ObjRef.kt
Normal file
@ -0,0 +1,3 @@
|
||||
package sushi.hardcore.droidfs.util
|
||||
|
||||
class ObjRef<T>(var value: T)
|
@ -5,9 +5,11 @@
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeInit(JNIEnv *env, jobject thiz,
|
||||
jstring base_dir, jstring jlocalStateDir,
|
||||
jbyteArray password, jboolean createBaseDir,
|
||||
jbyteArray password, jbyteArray givenHash,
|
||||
jobject returnedHash,
|
||||
jboolean createBaseDir,
|
||||
jstring cipher) {
|
||||
return cryfs_init(env, base_dir, jlocalStateDir, password, createBaseDir, cipher);
|
||||
return cryfs_init(env, base_dir, jlocalStateDir, password, givenHash, returnedHash, createBaseDir, cipher);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
|
@ -17,16 +17,16 @@
|
||||
<requestFocus/>
|
||||
</EditText>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox_save_password"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/fingerprint_save_checkbox_text"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox_default_open"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/default_open"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox_save_password"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/fingerprint_save_checkbox_text"/>
|
||||
|
||||
</LinearLayout>
|
Loading…
Reference in New Issue
Block a user