forked from hardcoresushi/DroidFS
CryFS volume creation & bug fixes
This commit is contained in:
parent
b5a8b02c5c
commit
b2ab69c8f2
@ -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
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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? {
|
||||
|
@ -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
|
||||
|
@ -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,42 +132,10 @@ class CreateVolumeFragment: Fragment() {
|
||||
(activity as AddVolumeActivity).onFragmentLoaded(false)
|
||||
}
|
||||
|
||||
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)
|
||||
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())
|
||||
} else {
|
||||
Arrays.fill(passwordConfirm, 0.toChar())
|
||||
var returnedHash: ByteArray? = null
|
||||
if (binding.checkboxSavePassword.isChecked)
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
object: LoadingTask<SavedVolume?>(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(
|
||||
volumePath,
|
||||
password,
|
||||
false,
|
||||
xchacha,
|
||||
GocryptfsVolume.ScryptDefaultLogN,
|
||||
ConstValues.CREATOR,
|
||||
returnedHash
|
||||
)
|
||||
) {
|
||||
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, EncryptedVolume.GOCRYPTFS_VOLUME_TYPE)
|
||||
val volume = SavedVolume(volumeName, isHiddenVolume, volumeType)
|
||||
volumeDatabase.apply {
|
||||
if (isVolumeSaved(volumeName, isHiddenVolume)) // cleaning old saved path
|
||||
removeVolume(volumeName)
|
||||
@ -162,7 +145,49 @@ class CreateVolumeFragment: Fragment() {
|
||||
} else {
|
||||
null
|
||||
}
|
||||
Arrays.fill(password, 0.toChar())
|
||||
}
|
||||
|
||||
private fun createVolume() {
|
||||
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)
|
||||
Arrays.fill(passwordConfirm, 0)
|
||||
} else {
|
||||
Arrays.fill(passwordConfirm, 0)
|
||||
var returnedHash: ByteArray? = null
|
||||
if (binding.checkboxSavePassword.isChecked)
|
||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||
object: LoadingTask<SavedVolume?>(requireActivity() as AppCompatActivity, themeValue, R.string.loading_msg_create) {
|
||||
override suspend fun doTask(): SavedVolume? {
|
||||
val volumeFile = File(volumePath)
|
||||
if (!volumeFile.exists())
|
||||
volumeFile.mkdirs()
|
||||
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,
|
||||
xchacha,
|
||||
GocryptfsVolume.ScryptDefaultLogN,
|
||||
ConstValues.CREATOR,
|
||||
returnedHash
|
||||
), EncryptedVolume.GOCRYPTFS_VOLUME_TYPE)
|
||||
} else {
|
||||
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)
|
||||
return volume
|
||||
}
|
||||
}.startTask(lifecycleScope) { volume ->
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 {
|
||||
|
18
app/src/main/java/sushi/hardcore/droidfs/util/WidgetUtil.kt
Normal file
18
app/src/main/java/sushi/hardcore/droidfs/util/WidgetUtil.kt
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
GoString go_name = {gcf_full_path, strlen(gcf_full_path)};
|
||||
struct gcf_get_attrs_return attrs = gcf_get_attrs(sessionID, go_name);
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <jni.h>
|
||||
|
||||
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
|
||||
|
@ -6,6 +6,18 @@
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/volume_type_label"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_volume_type"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginVertical="@dimen/volume_operation_vertical_gap"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
@ -44,11 +56,11 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/encryption_cipher_label"
|
||||
android:layout_toStartOf="@id/spinner_xchacha"
|
||||
android:layout_toStartOf="@id/spinner_cipher"
|
||||
android:layout_alignParentStart="true"/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_xchacha"
|
||||
android:id="@+id/spinner_cipher"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true" />
|
||||
|
@ -1,10 +1,4 @@
|
||||
<resources>
|
||||
<string-array name="encryption_cipher">
|
||||
<item>AES-GCM</item>
|
||||
<item>XChaCha20-Poly1305</item>
|
||||
<item>@string/auto</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="sort_orders_entries">
|
||||
<item>اسم</item>
|
||||
<item>حجم</item>
|
||||
|
@ -138,7 +138,6 @@
|
||||
<string name="image_saved_successfully">تم حفظ تغييرات الصورة بنجاح.</string>
|
||||
<string name="bitmap_compress_failed">فشل ضغط الصورة النقطية.</string>
|
||||
<string name="file_write_failed">فشل كتابة الملف.</string>
|
||||
<string name="error_not_a_volume">لم يتم التعرف على مجلد التشفير Gocryptfs. يرجى التحقق من المسار المحدد.</string>
|
||||
<string name="version">إصدار</string>
|
||||
<string name="error_cipher_null">تشفير الخطأ فارغ</string>
|
||||
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
||||
@ -173,7 +172,6 @@
|
||||
<string name="maximize_quality">دقة أعلى</string>
|
||||
<string name="minimize_latency">أداء أفضل</string>
|
||||
<string name="auto">تلقائي</string>
|
||||
<string name="xchacha_warning">XChaCha20-Poly1305 مدعوم فقط منذ إصدار gocryptfs v2.2.0. لن تتمكن الإصدارات الأقدم من فتح وحدة تخزين بناءً على هذا التشفير.</string>
|
||||
<string name="encryption_cipher_label">خوارزمية التشفير:</string>
|
||||
<string name="theme">سمة</string>
|
||||
<string name="theme_summary">تخصيص سمة التطبيق</string>
|
||||
|
@ -138,7 +138,6 @@
|
||||
<string name="image_saved_successfully">Cambios de la imagen guardados con éxito.</string>
|
||||
<string name="bitmap_compress_failed">Fallo al comprimir el mapa de bits.</string>
|
||||
<string name="file_write_failed">No se ha podido escribir el archivo.</string>
|
||||
<string name="error_not_a_volume">No se reconoce el volumen Gocryptfs. Por favor, comprueba la ruta seleccionada.</string>
|
||||
<string name="version">Versión</string>
|
||||
<string name="error_cipher_null">Error de cifrado núlo</string>
|
||||
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
||||
@ -173,7 +172,6 @@
|
||||
<string name="maximize_quality">Maximizar la calidad</string>
|
||||
<string name="minimize_latency">Minimizar la latencia</string>
|
||||
<string name="auto">Automático</string>
|
||||
<string name="xchacha_warning">XChaCha20-Poly1305 sólo está soportado desde gocryptfs v2.2.0. Las versiones anteriores no podrán abrir un volumen basado en este cifrado.</string>
|
||||
<string name="encryption_cipher_label">Cifrado de encriptación:</string>
|
||||
<string name="theme">Tema</string>
|
||||
<string name="theme_summary">Personalizar el tema de la aplicación</string>
|
||||
|
@ -135,7 +135,6 @@
|
||||
<string name="image_saved_successfully">Mudanças na imagem salva com sucesso.</string>
|
||||
<string name="bitmap_compress_failed">Falha ao compactar o bitmap.</string>
|
||||
<string name="file_write_failed">Falha ao salvar o arquivo.</string>
|
||||
<string name="error_not_a_volume">O volume do Gocryptfs não foi reconhecido. Por favor, verifique a localização selecionada.</string>
|
||||
<string name="version">Versão</string>
|
||||
<string name="error_cipher_null">Erro, o cipher é nulo</string>
|
||||
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
||||
@ -170,7 +169,6 @@
|
||||
<string name="maximize_quality">Maximizar a qualidade</string>
|
||||
<string name="minimize_latency">Minimizar a latência</string>
|
||||
<string name="auto">Autom</string>
|
||||
<string name="xchacha_warning">XChaCha20-Poly1305 só tem suporte desde gocryptfs v2.2.0. Versões mais antigas não podem abrir um volume baseado neste cipher.</string>
|
||||
<string name="encryption_cipher_label">Cipher de criptografia:</string>
|
||||
<string name="theme">Tema</string>
|
||||
<string name="theme_summary">Personalizar o tema do app</string>
|
||||
|
@ -133,7 +133,6 @@
|
||||
<string name="image_saved_successfully">Изменения изображения успешно сохранены.</string>
|
||||
<string name="bitmap_compress_failed">Невозможно сжать растровое изображение.</string>
|
||||
<string name="file_write_failed">Невозможно записать файл.</string>
|
||||
<string name="error_not_a_volume">Том GocryptFS не распознан. Проверьте выбранный путь.</string>
|
||||
<string name="version">Версия</string>
|
||||
<string name="error_cipher_null">Шифр ошибки нулевой</string>
|
||||
<string name="key_permanently_invalidated_exception_msg">Похоже, вы добавили новый отпечаток пальца. Сохранённый хеш паролей стал непригодным для использования.</string>
|
||||
@ -167,7 +166,6 @@
|
||||
<string name="maximize_quality">Максимальное качество</string>
|
||||
<string name="minimize_latency">Минимальная задержка</string>
|
||||
<string name="auto">Авто</string>
|
||||
<string name="xchacha_warning">Шифр XChaCha20-Poly1305 поддерживается только с версии GocryptFS 2.2.0. Более старые версии не смогут открыть том, использующий данный шифр.</string>
|
||||
<string name="encryption_cipher_label">Шифр:</string>
|
||||
<string name="theme">Тема</string>
|
||||
<string name="theme_summary">Настройка темы приложения</string>
|
||||
|
@ -1,10 +1,29 @@
|
||||
<resources>
|
||||
<string-array name="encryption_cipher">
|
||||
<string-array name="volume_types">
|
||||
<item>Gocryptfs</item>
|
||||
<item>CryFS</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="gocryptfs_encryption_ciphers">
|
||||
<item>AES-GCM</item>
|
||||
<item>XChaCha20-Poly1305</item>
|
||||
<item>@string/auto</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="cryfs_encryption_ciphers">
|
||||
<item>xchacha20-poly1305</item>
|
||||
<item>aes-256-gcm</item>
|
||||
<item>aes-128-gcm</item>
|
||||
<item>twofish-256-gcm</item>
|
||||
<item>twofish-128-gcm</item>
|
||||
<item>serpent-256-gcm</item>
|
||||
<item>serpent-128-gcm</item>
|
||||
<item>cast-256-gcm</item>
|
||||
<item>mars-448-gcm</item>
|
||||
<item>mars-256-gcm</item>
|
||||
<item>mars-128-gcm</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="sort_orders_entries">
|
||||
<item>Name</item>
|
||||
<item>Size</item>
|
||||
|
@ -138,7 +138,7 @@
|
||||
<string name="image_saved_successfully">Image changes successfully saved.</string>
|
||||
<string name="bitmap_compress_failed">Failed to compress the bitmap.</string>
|
||||
<string name="file_write_failed">Failed to write the file.</string>
|
||||
<string name="error_not_a_volume">Gocryptfs volume not recognized. Please check the selected path.</string>
|
||||
<string name="error_not_a_volume">Encrypted volume not recognized. Please check the selected path.</string>
|
||||
<string name="version">Version</string>
|
||||
<string name="error_cipher_null">Error cipher is null</string>
|
||||
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
||||
@ -173,7 +173,6 @@
|
||||
<string name="maximize_quality">Maximize quality</string>
|
||||
<string name="minimize_latency">Minimize latency</string>
|
||||
<string name="auto">Auto</string>
|
||||
<string name="xchacha_warning">XChaCha20-Poly1305 is only supported since gocryptfs v2.2.0. Older versions won\'t be able to open a volume based on this cipher.</string>
|
||||
<string name="encryption_cipher_label">Encryption cipher:</string>
|
||||
<string name="theme">Theme</string>
|
||||
<string name="theme_summary">Customize app theme</string>
|
||||
@ -242,4 +241,5 @@
|
||||
<string name="elements_selected">%d/%d selected</string>
|
||||
<string name="pin_passwords_title">Numeric keypad layout</string>
|
||||
<string name="pin_passwords_summary">Use a numeric keypad layout when entering volume passwords</string>
|
||||
<string name="volume_type_label">Volume type:</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user