diff --git a/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt index 4375c0d..5352fe7 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt @@ -379,11 +379,12 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { private fun getOutputPath(isVideo: Boolean): String { val baseName = if (isVideo) {"VID"} else {"IMG"}+'_'+dateFormat.format(Date())+'_' - var fileName: String + var outputPath: String do { - fileName = baseName+(random.nextInt(fileNameRandomMax-fileNameRandomMin)+fileNameRandomMin)+'.'+ if (isVideo) {"mp4"} else {"jpg"} - } while (encryptedVolume.pathExists(fileName)) - return PathUtils.pathJoin(outputDirectory, fileName) + val fileName = baseName+(random.nextInt(fileNameRandomMax-fileNameRandomMin)+fileNameRandomMin)+'.'+ if (isVideo) {"mp4"} else {"jpg"} + outputPath = PathUtils.pathJoin(outputDirectory, fileName) + } while (encryptedVolume.pathExists(outputPath)) + return outputPath } private fun startTimerThen(action: () -> Unit) { @@ -447,18 +448,18 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { isRecording = false } else if (!isWaitingForTimer) { val path = getOutputPath(true) - /*startTimerThen { - val handleId = encryptedVolume.openWriteMode(path) + startTimerThen { + val fileHandle = encryptedVolume.openFile(path) videoCapture?.startRecording(VideoCapture.OutputFileOptions(object : SeekableWriter { var offset = 0L override fun write(byteArray: ByteArray) { - offset += encryptedVolume.writeFile(handleId, offset, byteArray, byteArray.size) + offset += encryptedVolume.write(fileHandle, offset, byteArray, byteArray.size) } override fun seek(offset: Long) { this.offset = offset } override fun close() { - encryptedVolume.closeFile(handleId) + encryptedVolume.closeFile(fileHandle) } }), executor, object : VideoCapture.OnVideoSavedCallback { override fun onVideoSaved() { @@ -473,7 +474,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener { }) binding.recordVideoButton.setImageResource(R.drawable.stop_recording_video_button) isRecording = true - }*/ + } } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/ConstValues.kt b/app/src/main/java/sushi/hardcore/droidfs/ConstValues.kt index d8f7e55..bbcf554 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/ConstValues.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/ConstValues.kt @@ -6,6 +6,7 @@ import java.io.File object ConstValues { const val CREATOR = "DroidFS" const val VOLUME_DATABASE_NAME = "SavedVolumes" + const val CRYFS_LOCAL_STATE_DIR = "cryfsLocalState" const val SORT_ORDER_KEY = "sort_order" val FAKE_URI: Uri = Uri.parse("fakeuri://droidfs") const val MAX_KERNEL_WRITE = 128*1024 diff --git a/app/src/main/java/sushi/hardcore/droidfs/GocryptfsVolume.kt b/app/src/main/java/sushi/hardcore/droidfs/GocryptfsVolume.kt index 732f9ad..5a60814 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/GocryptfsVolume.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/GocryptfsVolume.kt @@ -26,8 +26,8 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() { const val ScryptDefaultLogN = 16 const val DefaultBS = 4096 const val CONFIG_FILE_NAME = "gocryptfs.conf" - external fun createVolume(root_cipher_dir: String, password: CharArray, plainTextNames: Boolean, xchacha: Int, logN: Int, creator: String, returnedHash: ByteArray?): Boolean - external fun nativeInit(root_cipher_dir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ByteArray?): Int + 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 fun init(root_cipher_dir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ByteArray?): GocryptfsVolume? { diff --git a/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt index 62425ea..39dda28 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt @@ -32,6 +32,7 @@ import sushi.hardcore.droidfs.explorers.ExplorerActivityPick import sushi.hardcore.droidfs.file_operations.FileOperationService import sushi.hardcore.droidfs.filesystems.EncryptedVolume import sushi.hardcore.droidfs.util.PathUtils +import sushi.hardcore.droidfs.util.WidgetUtil import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder import sushi.hardcore.droidfs.widgets.EditTextDialog import java.io.File @@ -342,7 +343,10 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { val onlyOneAndWriteable = onlyOneSelected && volumeAdapter.volumes[volumeAdapter.selectedItems.first()].canWrite(filesDir.path) - menu.findItem(R.id.change_password).isVisible = onlyOneAndWriteable + menu.findItem(R.id.change_password).isVisible = + onlyOneAndWriteable && + // Only gocryptfs volumes support password change + volumeAdapter.volumes[volumeAdapter.selectedItems.first()].type == EncryptedVolume.GOCRYPTFS_VOLUME_TYPE menu.findItem(R.id.remove_default_open).isVisible = onlyOneSelected && volumeAdapter.volumes[volumeAdapter.selectedItems.first()].name == defaultVolumeName @@ -513,20 +517,18 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener { apply() } } - val password = CharArray(dialogBinding.editPassword.text.length) - dialogBinding.editPassword.text.getChars(0, password.size, password, 0) // openVolumeWithPassword is responsible for wiping the password openVolumeWithPassword( volume, position, - StandardCharsets.UTF_8.encode(CharBuffer.wrap(password)).array(), + WidgetUtil.editTextContentEncode(dialogBinding.editPassword), dialogBinding.checkboxSavePassword.isChecked, ) } private fun askForPassword(volume: SavedVolume, position: Int, savePasswordHash: Boolean = false) { val dialogBinding = DialogOpenVolumeBinding.inflate(layoutInflater) - if (!usfFingerprint || fingerprintProtector == null || volume.encryptedHash != null) { + if (!usfFingerprint || fingerprintProtector == null || volume.encryptedHash != null || volume.type == EncryptedVolume.CRYFS_VOLUME_TYPE) { dialogBinding.checkboxSavePassword.visibility = View.GONE } else { dialogBinding.checkboxSavePassword.isChecked = savePasswordHash diff --git a/app/src/main/java/sushi/hardcore/droidfs/add_volume/CreateVolumeFragment.kt b/app/src/main/java/sushi/hardcore/droidfs/add_volume/CreateVolumeFragment.kt index 446db9f..672efb9 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/add_volume/CreateVolumeFragment.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/add_volume/CreateVolumeFragment.kt @@ -15,7 +15,9 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.lifecycleScope import sushi.hardcore.droidfs.* import sushi.hardcore.droidfs.databinding.FragmentCreateVolumeBinding +import sushi.hardcore.droidfs.filesystems.CryfsVolume import sushi.hardcore.droidfs.filesystems.EncryptedVolume +import sushi.hardcore.droidfs.util.WidgetUtil import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder import java.io.File import java.util.* @@ -80,6 +82,37 @@ class CreateVolumeFragment: Fragment() { if (!usfFingerprint || fingerprintProtector == null) { binding.checkboxSavePassword.visibility = View.GONE } + binding.spinnerVolumeType.adapter = ArrayAdapter( + requireContext(), + android.R.layout.simple_spinner_item, + resources.getStringArray(R.array.volume_types) + ).apply { + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + } + val encryptionCipherAdapter = ArrayAdapter( + requireContext(), + android.R.layout.simple_spinner_item, + resources.getStringArray(R.array.gocryptfs_encryption_ciphers).toMutableList() + ).apply { + setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + } + binding.spinnerVolumeType.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + val ciphersArray = if (position == 0) { // Gocryptfs + binding.checkboxSavePassword.visibility = View.VISIBLE + R.array.gocryptfs_encryption_ciphers + } else { + binding.checkboxSavePassword.visibility = View.GONE + R.array.cryfs_encryption_ciphers + } + with(encryptionCipherAdapter) { + clear() + addAll(resources.getStringArray(ciphersArray).asList()) + } + } + override fun onNothingSelected(parent: AdapterView<*>?) {} + } + binding.spinnerCipher.adapter = encryptionCipherAdapter if (pinPasswords) { arrayOf(binding.editPassword, binding.editPasswordConfirm).forEach { it.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD @@ -89,24 +122,6 @@ class CreateVolumeFragment: Fragment() { createVolume() true } - binding.spinnerXchacha.adapter = ArrayAdapter( - requireContext(), - android.R.layout.simple_spinner_item, - resources.getStringArray(R.array.encryption_cipher) - ).apply { - setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) - } - binding.spinnerXchacha.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { - override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { - if (position == 1) - CustomAlertDialogBuilder(requireContext(), themeValue) - .setTitle(R.string.warning) - .setMessage(R.string.xchacha_warning) - .setPositiveButton(R.string.ok, null) - .show() - } - override fun onNothingSelected(parent: AdapterView<*>?) {} - } binding.buttonCreate.setOnClickListener { createVolume() } @@ -117,31 +132,45 @@ class CreateVolumeFragment: Fragment() { (activity as AddVolumeActivity).onFragmentLoaded(false) } + private fun saveVolume(success: Boolean, volumeType: Byte): SavedVolume? { + return if (success) { + val volumeName = if (isHiddenVolume) File(volumePath).name else volumePath + val volume = SavedVolume(volumeName, isHiddenVolume, volumeType) + volumeDatabase.apply { + if (isVolumeSaved(volumeName, isHiddenVolume)) // cleaning old saved path + removeVolume(volumeName) + saveVolume(volume) + } + volume + } else { + null + } + } + private fun createVolume() { - val password = CharArray(binding.editPassword.text.length) - binding.editPassword.text.getChars(0, password.size, password, 0) - val passwordConfirm = CharArray(binding.editPasswordConfirm.text.length) - binding.editPasswordConfirm.text.getChars(0, passwordConfirm.size, passwordConfirm, 0) + val password = WidgetUtil.editTextContentEncode(binding.editPassword) + val passwordConfirm = WidgetUtil.editTextContentEncode(binding.editPasswordConfirm) if (!password.contentEquals(passwordConfirm)) { Toast.makeText(requireContext(), R.string.passwords_mismatch, Toast.LENGTH_SHORT).show() - Arrays.fill(password, 0.toChar()) - Arrays.fill(passwordConfirm, 0.toChar()) + Arrays.fill(password, 0) + Arrays.fill(passwordConfirm, 0) } else { - Arrays.fill(passwordConfirm, 0.toChar()) + Arrays.fill(passwordConfirm, 0) var returnedHash: ByteArray? = null if (binding.checkboxSavePassword.isChecked) returnedHash = ByteArray(GocryptfsVolume.KeyLen) object: LoadingTask(requireActivity() as AppCompatActivity, themeValue, R.string.loading_msg_create) { override suspend fun doTask(): SavedVolume? { - val xchacha = when (binding.spinnerXchacha.selectedItemPosition) { - 0 -> 0 - 1 -> 1 - else -> -1 - } val volumeFile = File(volumePath) if (!volumeFile.exists()) volumeFile.mkdirs() - val volume = if (GocryptfsVolume.createVolume( + val volume = if (binding.spinnerVolumeType.selectedItem == 0) { // Gocryptfs + val xchacha = when (binding.spinnerCipher.selectedItemPosition) { + 0 -> 0 + 1 -> 1 + else -> -1 + } + saveVolume(GocryptfsVolume.createVolume( volumePath, password, false, @@ -149,20 +178,16 @@ class CreateVolumeFragment: Fragment() { GocryptfsVolume.ScryptDefaultLogN, ConstValues.CREATOR, returnedHash - ) - ) { - val volumeName = if (isHiddenVolume) File(volumePath).name else volumePath - val volume = SavedVolume(volumeName, isHiddenVolume, EncryptedVolume.GOCRYPTFS_VOLUME_TYPE) - volumeDatabase.apply { - if (isVolumeSaved(volumeName, isHiddenVolume)) // cleaning old saved path - removeVolume(volumeName) - saveVolume(volume) - } - volume + ), EncryptedVolume.GOCRYPTFS_VOLUME_TYPE) } else { - null + saveVolume(CryfsVolume.create( + volumePath, + CryfsVolume.getLocalStateDir(activity.filesDir.path), + password, + resources.getStringArray(R.array.cryfs_encryption_ciphers)[binding.spinnerCipher.selectedItemPosition] + ), EncryptedVolume.CRYFS_VOLUME_TYPE) } - Arrays.fill(password, 0.toChar()) + Arrays.fill(password, 0) return volume } }.startTask(lifecycleScope) { volume -> diff --git a/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt b/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt index 10fe96e..87011c7 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt @@ -454,7 +454,7 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene items.clear() break } else { - items.add(OperationFile(PathUtils.pathJoin(fileName, currentDirectoryPath), Stat.S_IFREG)) + items.add(OperationFile(PathUtils.pathJoin(currentDirectoryPath, fileName), Stat.S_IFREG)) } } if (items.size > 0) { 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 4e0e853..3e709bf 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/filesystems/CryfsVolume.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/filesystems/CryfsVolume.kt @@ -1,7 +1,10 @@ package sushi.hardcore.droidfs.filesystems import android.os.Parcel +import android.util.Log +import sushi.hardcore.droidfs.ConstValues import sushi.hardcore.droidfs.explorers.ExplorerElement +import sushi.hardcore.droidfs.util.PathUtils class CryfsVolume(private val fusePtr: Long): EncryptedVolume() { companion object { @@ -11,7 +14,13 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() { const val CONFIG_FILE_NAME = "cryfs.config" - private external fun nativeInit(baseDir: String, localStateDir: String, password: ByteArray): Long + private external fun nativeInit( + baseDir: String, + localStateDir: String, + password: ByteArray, + createBaseDir: Boolean, + cipher: String? + ): 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 nativeRead(fusePtr: Long, fileHandle: Long, buffer: ByteArray, offset: Long): Int @@ -27,9 +36,25 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() { private external fun nativeClose(fusePtr: Long) private external fun nativeIsClosed(fusePtr: Long): Boolean - fun init(baseDir: String, localStateDir: String, password: ByteArray): CryfsVolume { - val fusePtr = nativeInit(baseDir, localStateDir, password) - return CryfsVolume(fusePtr) + fun getLocalStateDir(filesDir: String): String { + 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) + return if (fusePtr == 0L) { + null + } else { + CryfsVolume(fusePtr) + } + } + + fun create(baseDir: String, localStateDir: String, password: ByteArray, cipher: String?): Boolean { + return init(baseDir, localStateDir, password, true, cipher)?.also { it.close() } != null + } + + fun init(baseDir: String, localStateDir: String, password: ByteArray): CryfsVolume? { + return init(baseDir, localStateDir, password, false, null) } } diff --git a/app/src/main/java/sushi/hardcore/droidfs/filesystems/EncryptedVolume.kt b/app/src/main/java/sushi/hardcore/droidfs/filesystems/EncryptedVolume.kt index 04b5112..79a5c80 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/filesystems/EncryptedVolume.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/filesystems/EncryptedVolume.kt @@ -4,6 +4,7 @@ import android.content.Context import android.net.Uri import android.os.Parcel import android.os.Parcelable +import sushi.hardcore.droidfs.ConstValues import sushi.hardcore.droidfs.GocryptfsVolume import sushi.hardcore.droidfs.SavedVolume import sushi.hardcore.droidfs.explorers.ExplorerElement @@ -46,7 +47,7 @@ abstract class EncryptedVolume: Parcelable { GocryptfsVolume.init(volume.getFullPath(filesDir), password, givenHash, returnedHash) } CRYFS_VOLUME_TYPE -> { - CryfsVolume.init(volume.getFullPath(filesDir), PathUtils.pathJoin(filesDir, "localState"), password!!) + CryfsVolume.init(volume.getFullPath(filesDir), CryfsVolume.getLocalStateDir(filesDir), password!!) } else -> throw invalidVolumeType() } diff --git a/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt b/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt index 4d98524..edabb98 100644 --- a/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt +++ b/app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt @@ -14,19 +14,20 @@ import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder import java.io.File import java.text.DecimalFormat import kotlin.math.log10 +import kotlin.math.max import kotlin.math.pow object PathUtils { fun getParentPath(path: String): String { return if (path.endsWith("/")) { - val a = path.substring(0, path.length - 2) + val a = path.substring(0, max(1, path.length - 1)) if (a.count { it == '/' } == 1) { "/" } else { a.substring(0, a.lastIndexOf("/")) } } else { - if (path.count { it == '/' } == 1) { + if (path.count { it == '/' } <= 1) { "/" } else { path.substring(0, path.lastIndexOf("/")) @@ -48,17 +49,11 @@ object PathUtils { } fun getRelativePath(parentPath: String, childPath: String): String { - return when { - parentPath.isEmpty() -> { - childPath - } - parentPath.length == childPath.length -> { - "" - } - else -> { - childPath.substring(parentPath.length + 1) - } - } + return childPath.substring(parentPath.length + if (parentPath.endsWith("/")) { + 0 + } else { + 1 + }) } fun isChildOf(childPath: String, parentPath: String): Boolean { diff --git a/app/src/main/java/sushi/hardcore/droidfs/util/WidgetUtil.kt b/app/src/main/java/sushi/hardcore/droidfs/util/WidgetUtil.kt new file mode 100644 index 0000000..ea37e01 --- /dev/null +++ b/app/src/main/java/sushi/hardcore/droidfs/util/WidgetUtil.kt @@ -0,0 +1,18 @@ +package sushi.hardcore.droidfs.util + +import android.widget.EditText +import java.nio.CharBuffer +import java.nio.charset.StandardCharsets +import java.util.* + +object WidgetUtil { + fun editTextContentEncode(editText: EditText): ByteArray { + val charArray = CharArray(editText.text.length) + editText.text.getChars(0, editText.text.length, charArray, 0) + val byteArray = StandardCharsets.UTF_8.encode( + CharBuffer.wrap(charArray) + ).array() + Arrays.fill(charArray, Char.MIN_VALUE) + return byteArray + } +} \ No newline at end of file diff --git a/app/src/main/native/gocryptfs_jni.c b/app/src/main/native/gocryptfs_jni.c index 08526fb..dc38404 100644 --- a/app/src/main/native/gocryptfs_jni.c +++ b/app/src/main/native/gocryptfs_jni.c @@ -31,7 +31,8 @@ void jbyteArray_to_unsignedCharArray(const jbyte* src, unsigned char* dst, const JNIEXPORT jboolean JNICALL Java_sushi_hardcore_droidfs_GocryptfsVolume_00024Companion_createVolume(JNIEnv *env, jclass clazz, - jstring jroot_cipher_dir, jcharArray jpassword, + jstring jroot_cipher_dir, + jbyteArray jpassword, jboolean plainTextNames, jint xchacha, jint logN, @@ -42,9 +43,7 @@ Java_sushi_hardcore_droidfs_GocryptfsVolume_00024Companion_createVolume(JNIEnv * GoString gofilename = {root_cipher_dir, strlen(root_cipher_dir)}, gocreator = {creator, strlen(creator)}; const size_t password_len = (*env)->GetArrayLength(env, jpassword); - jchar* jchar_password = (*env)->GetCharArrayElements(env, jpassword, NULL); - char password[password_len]; - jcharArray_to_charArray(jchar_password, password, password_len); + char* password = (char*)(*env)->GetByteArrayElements(env, jpassword, NULL); GoSlice go_password = {password, password_len, password_len}; size_t returned_hash_len; @@ -65,7 +64,7 @@ Java_sushi_hardcore_droidfs_GocryptfsVolume_00024Companion_createVolume(JNIEnv * (*env)->ReleaseStringUTFChars(env, jroot_cipher_dir, root_cipher_dir); (*env)->ReleaseStringUTFChars(env, jcreator, creator); wipe(password, password_len); - (*env)->ReleaseCharArrayElements(env, jpassword, jchar_password, 0); + (*env)->ReleaseByteArrayElements(env, jpassword, (jbyte*)password, 0); if (!(*env)->IsSameObject(env, jreturned_hash, NULL)) { unsignedCharArray_to_jbyteArray(returned_hash, jbyte_returned_hash, returned_hash_len); @@ -260,15 +259,11 @@ Java_sushi_hardcore_droidfs_GocryptfsVolume_native_1list_1dir(JNIEnv *env, jobje size_t name_len = strlen(name); const char gcf_full_path[plain_dir_len+name_len+2]; - if (plain_dir_len > 0){ - strcpy(gcf_full_path, plain_dir); - if (plain_dir[-2] != '/') { - strcat(gcf_full_path, "/"); - } - strcat(gcf_full_path, name); - } else { - strcpy(gcf_full_path, name); + strcpy(gcf_full_path, plain_dir); + if (plain_dir[-2] != '/') { + strcat(gcf_full_path, "/"); } + strcat(gcf_full_path, name); GoString go_name = {gcf_full_path, strlen(gcf_full_path)}; struct gcf_get_attrs_return attrs = gcf_get_attrs(sessionID, go_name); diff --git a/app/src/main/native/libcryfs.c b/app/src/main/native/libcryfs.c index dcbeceb..f36c351 100644 --- a/app/src/main/native/libcryfs.c +++ b/app/src/main/native/libcryfs.c @@ -1,7 +1,7 @@ #include #include -jlong cryfs_init(JNIEnv* env, jstring jbaseDir, jstring jlocalSateDir, jbyteArray jpassword); +jlong cryfs_init(JNIEnv* env, jstring jbaseDir, jstring jlocalSateDir, jbyteArray jpassword, jboolean createBaseDir, jstring jcipher); jlong cryfs_create(JNIEnv* env, jlong fusePtr, jstring jpath, mode_t mode); jlong cryfs_open(JNIEnv* env, jlong fusePtr, jstring jpath, jint flags); jint cryfs_read(JNIEnv* env, jlong fusePtr, jlong fileHandle, jbyteArray jbuffer, jlong offset); @@ -20,8 +20,9 @@ jboolean cryfs_is_closed(jlong fusePtr); JNIEXPORT jlong JNICALL Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeInit(JNIEnv *env, jobject thiz, jstring base_dir, jstring jlocalStateDir, - jbyteArray password) { - return cryfs_init(env, base_dir, jlocalStateDir, password); + jbyteArray password, jboolean createBaseDir, + jstring cipher) { + return cryfs_init(env, base_dir, jlocalStateDir, password, createBaseDir, cipher); } JNIEXPORT jlong JNICALL diff --git a/app/src/main/res/layout/fragment_create_volume.xml b/app/src/main/res/layout/fragment_create_volume.xml index 62abdc4..d0c73b4 100644 --- a/app/src/main/res/layout/fragment_create_volume.xml +++ b/app/src/main/res/layout/fragment_create_volume.xml @@ -6,6 +6,18 @@ android:gravity="center_vertical" android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap"> + + + + diff --git a/app/src/main/res/values-ar/arrays.xml b/app/src/main/res/values-ar/arrays.xml index 7142577..71f169d 100644 --- a/app/src/main/res/values-ar/arrays.xml +++ b/app/src/main/res/values-ar/arrays.xml @@ -1,10 +1,4 @@  - - AES-GCM - XChaCha20-Poly1305 - @string/auto - - اسم حجم diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 6627024..d0bc625 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -138,7 +138,6 @@ تم حفظ تغييرات الصورة بنجاح. فشل ضغط الصورة النقطية. فشل كتابة الملف. - لم يتم التعرف على مجلد التشفير Gocryptfs. يرجى التحقق من المسار المحدد. إصدار تشفير الخطأ فارغ KeyPermanentlyInvalidatedException @@ -173,7 +172,6 @@ دقة أعلى أداء أفضل تلقائي - XChaCha20-Poly1305 مدعوم فقط منذ إصدار gocryptfs v2.2.0. لن تتمكن الإصدارات الأقدم من فتح وحدة تخزين بناءً على هذا التشفير. خوارزمية التشفير: سمة تخصيص سمة التطبيق diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 7d3a4e3..dfd8b2f 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -138,7 +138,6 @@ Cambios de la imagen guardados con éxito. Fallo al comprimir el mapa de bits. No se ha podido escribir el archivo. - No se reconoce el volumen Gocryptfs. Por favor, comprueba la ruta seleccionada. Versión Error de cifrado núlo KeyPermanentlyInvalidatedException @@ -173,7 +172,6 @@ Maximizar la calidad Minimizar la latencia Automático - XChaCha20-Poly1305 sólo está soportado desde gocryptfs v2.2.0. Las versiones anteriores no podrán abrir un volumen basado en este cifrado. Cifrado de encriptación: Tema Personalizar el tema de la aplicación diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index f5ffe5d..faf99cf 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -135,7 +135,6 @@ Mudanças na imagem salva com sucesso. Falha ao compactar o bitmap. Falha ao salvar o arquivo. - O volume do Gocryptfs não foi reconhecido. Por favor, verifique a localização selecionada. Versão Erro, o cipher é nulo KeyPermanentlyInvalidatedException @@ -170,7 +169,6 @@ Maximizar a qualidade Minimizar a latência Autom - XChaCha20-Poly1305 só tem suporte desde gocryptfs v2.2.0. Versões mais antigas não podem abrir um volume baseado neste cipher. Cipher de criptografia: Tema Personalizar o tema do app diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 2eda505..4849d0b 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -133,7 +133,6 @@ Изменения изображения успешно сохранены. Невозможно сжать растровое изображение. Невозможно записать файл. - Том GocryptFS не распознан. Проверьте выбранный путь. Версия Шифр ошибки нулевой Похоже, вы добавили новый отпечаток пальца. Сохранённый хеш паролей стал непригодным для использования. @@ -167,7 +166,6 @@ Максимальное качество Минимальная задержка Авто - Шифр XChaCha20-Poly1305 поддерживается только с версии GocryptFS 2.2.0. Более старые версии не смогут открыть том, использующий данный шифр. Шифр: Тема Настройка темы приложения diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index f143993..2ca30eb 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,10 +1,29 @@ - + + Gocryptfs + CryFS + + + AES-GCM XChaCha20-Poly1305 @string/auto + + xchacha20-poly1305 + aes-256-gcm + aes-128-gcm + twofish-256-gcm + twofish-128-gcm + serpent-256-gcm + serpent-128-gcm + cast-256-gcm + mars-448-gcm + mars-256-gcm + mars-128-gcm + + Name Size diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f46d1ca..09ed838 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -138,7 +138,7 @@ Image changes successfully saved. Failed to compress the bitmap. Failed to write the file. - Gocryptfs volume not recognized. Please check the selected path. + Encrypted volume not recognized. Please check the selected path. Version Error cipher is null KeyPermanentlyInvalidatedException @@ -173,7 +173,6 @@ Maximize quality Minimize latency Auto - XChaCha20-Poly1305 is only supported since gocryptfs v2.2.0. Older versions won\'t be able to open a volume based on this cipher. Encryption cipher: Theme Customize app theme @@ -242,4 +241,5 @@ %d/%d selected Numeric keypad layout Use a numeric keypad layout when entering volume passwords + Volume type: