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 {
|
private fun getOutputPath(isVideo: Boolean): String {
|
||||||
val baseName = if (isVideo) {"VID"} else {"IMG"}+'_'+dateFormat.format(Date())+'_'
|
val baseName = if (isVideo) {"VID"} else {"IMG"}+'_'+dateFormat.format(Date())+'_'
|
||||||
var fileName: String
|
var outputPath: String
|
||||||
do {
|
do {
|
||||||
fileName = baseName+(random.nextInt(fileNameRandomMax-fileNameRandomMin)+fileNameRandomMin)+'.'+ if (isVideo) {"mp4"} else {"jpg"}
|
val fileName = baseName+(random.nextInt(fileNameRandomMax-fileNameRandomMin)+fileNameRandomMin)+'.'+ if (isVideo) {"mp4"} else {"jpg"}
|
||||||
} while (encryptedVolume.pathExists(fileName))
|
outputPath = PathUtils.pathJoin(outputDirectory, fileName)
|
||||||
return PathUtils.pathJoin(outputDirectory, fileName)
|
} while (encryptedVolume.pathExists(outputPath))
|
||||||
|
return outputPath
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startTimerThen(action: () -> Unit) {
|
private fun startTimerThen(action: () -> Unit) {
|
||||||
@ -447,18 +448,18 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
|||||||
isRecording = false
|
isRecording = false
|
||||||
} else if (!isWaitingForTimer) {
|
} else if (!isWaitingForTimer) {
|
||||||
val path = getOutputPath(true)
|
val path = getOutputPath(true)
|
||||||
/*startTimerThen {
|
startTimerThen {
|
||||||
val handleId = encryptedVolume.openWriteMode(path)
|
val fileHandle = encryptedVolume.openFile(path)
|
||||||
videoCapture?.startRecording(VideoCapture.OutputFileOptions(object : SeekableWriter {
|
videoCapture?.startRecording(VideoCapture.OutputFileOptions(object : SeekableWriter {
|
||||||
var offset = 0L
|
var offset = 0L
|
||||||
override fun write(byteArray: ByteArray) {
|
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) {
|
override fun seek(offset: Long) {
|
||||||
this.offset = offset
|
this.offset = offset
|
||||||
}
|
}
|
||||||
override fun close() {
|
override fun close() {
|
||||||
encryptedVolume.closeFile(handleId)
|
encryptedVolume.closeFile(fileHandle)
|
||||||
}
|
}
|
||||||
}), executor, object : VideoCapture.OnVideoSavedCallback {
|
}), executor, object : VideoCapture.OnVideoSavedCallback {
|
||||||
override fun onVideoSaved() {
|
override fun onVideoSaved() {
|
||||||
@ -473,7 +474,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
|
|||||||
})
|
})
|
||||||
binding.recordVideoButton.setImageResource(R.drawable.stop_recording_video_button)
|
binding.recordVideoButton.setImageResource(R.drawable.stop_recording_video_button)
|
||||||
isRecording = true
|
isRecording = true
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import java.io.File
|
|||||||
object ConstValues {
|
object ConstValues {
|
||||||
const val CREATOR = "DroidFS"
|
const val CREATOR = "DroidFS"
|
||||||
const val VOLUME_DATABASE_NAME = "SavedVolumes"
|
const val VOLUME_DATABASE_NAME = "SavedVolumes"
|
||||||
|
const val CRYFS_LOCAL_STATE_DIR = "cryfsLocalState"
|
||||||
const val SORT_ORDER_KEY = "sort_order"
|
const val SORT_ORDER_KEY = "sort_order"
|
||||||
val FAKE_URI: Uri = Uri.parse("fakeuri://droidfs")
|
val FAKE_URI: Uri = Uri.parse("fakeuri://droidfs")
|
||||||
const val MAX_KERNEL_WRITE = 128*1024
|
const val MAX_KERNEL_WRITE = 128*1024
|
||||||
|
@ -26,8 +26,8 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() {
|
|||||||
const val ScryptDefaultLogN = 16
|
const val ScryptDefaultLogN = 16
|
||||||
const val DefaultBS = 4096
|
const val DefaultBS = 4096
|
||||||
const val CONFIG_FILE_NAME = "gocryptfs.conf"
|
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 createVolume(root_cipher_dir: String, password: ByteArray, 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
|
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, old_password: CharArray?, givenHash: ByteArray?, new_password: CharArray, 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? {
|
||||||
|
@ -32,6 +32,7 @@ import sushi.hardcore.droidfs.explorers.ExplorerActivityPick
|
|||||||
import sushi.hardcore.droidfs.file_operations.FileOperationService
|
import sushi.hardcore.droidfs.file_operations.FileOperationService
|
||||||
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
||||||
import sushi.hardcore.droidfs.util.PathUtils
|
import sushi.hardcore.droidfs.util.PathUtils
|
||||||
|
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||||
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
||||||
import sushi.hardcore.droidfs.widgets.EditTextDialog
|
import sushi.hardcore.droidfs.widgets.EditTextDialog
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@ -342,7 +343,10 @@ 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 = 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 =
|
menu.findItem(R.id.remove_default_open).isVisible =
|
||||||
onlyOneSelected &&
|
onlyOneSelected &&
|
||||||
volumeAdapter.volumes[volumeAdapter.selectedItems.first()].name == defaultVolumeName
|
volumeAdapter.volumes[volumeAdapter.selectedItems.first()].name == defaultVolumeName
|
||||||
@ -513,20 +517,18 @@ class MainActivity : BaseActivity(), VolumeAdapter.Listener {
|
|||||||
apply()
|
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 is responsible for wiping the password
|
||||||
openVolumeWithPassword(
|
openVolumeWithPassword(
|
||||||
volume,
|
volume,
|
||||||
position,
|
position,
|
||||||
StandardCharsets.UTF_8.encode(CharBuffer.wrap(password)).array(),
|
WidgetUtil.editTextContentEncode(dialogBinding.editPassword),
|
||||||
dialogBinding.checkboxSavePassword.isChecked,
|
dialogBinding.checkboxSavePassword.isChecked,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun askForPassword(volume: SavedVolume, position: Int, savePasswordHash: Boolean = false) {
|
private fun askForPassword(volume: SavedVolume, position: Int, savePasswordHash: Boolean = false) {
|
||||||
val dialogBinding = DialogOpenVolumeBinding.inflate(layoutInflater)
|
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
|
dialogBinding.checkboxSavePassword.visibility = View.GONE
|
||||||
} else {
|
} else {
|
||||||
dialogBinding.checkboxSavePassword.isChecked = savePasswordHash
|
dialogBinding.checkboxSavePassword.isChecked = savePasswordHash
|
||||||
|
@ -15,7 +15,9 @@ import androidx.fragment.app.Fragment
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import sushi.hardcore.droidfs.*
|
import sushi.hardcore.droidfs.*
|
||||||
import sushi.hardcore.droidfs.databinding.FragmentCreateVolumeBinding
|
import sushi.hardcore.droidfs.databinding.FragmentCreateVolumeBinding
|
||||||
|
import sushi.hardcore.droidfs.filesystems.CryfsVolume
|
||||||
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
|
||||||
|
import sushi.hardcore.droidfs.util.WidgetUtil
|
||||||
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -80,6 +82,37 @@ class CreateVolumeFragment: Fragment() {
|
|||||||
if (!usfFingerprint || fingerprintProtector == null) {
|
if (!usfFingerprint || fingerprintProtector == null) {
|
||||||
binding.checkboxSavePassword.visibility = View.GONE
|
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) {
|
if (pinPasswords) {
|
||||||
arrayOf(binding.editPassword, binding.editPasswordConfirm).forEach {
|
arrayOf(binding.editPassword, binding.editPasswordConfirm).forEach {
|
||||||
it.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD
|
it.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD
|
||||||
@ -89,24 +122,6 @@ class CreateVolumeFragment: Fragment() {
|
|||||||
createVolume()
|
createVolume()
|
||||||
true
|
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 {
|
binding.buttonCreate.setOnClickListener {
|
||||||
createVolume()
|
createVolume()
|
||||||
}
|
}
|
||||||
@ -117,31 +132,45 @@ class CreateVolumeFragment: Fragment() {
|
|||||||
(activity as AddVolumeActivity).onFragmentLoaded(false)
|
(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() {
|
private fun createVolume() {
|
||||||
val password = CharArray(binding.editPassword.text.length)
|
val password = WidgetUtil.editTextContentEncode(binding.editPassword)
|
||||||
binding.editPassword.text.getChars(0, password.size, password, 0)
|
val passwordConfirm = WidgetUtil.editTextContentEncode(binding.editPasswordConfirm)
|
||||||
val passwordConfirm = CharArray(binding.editPasswordConfirm.text.length)
|
|
||||||
binding.editPasswordConfirm.text.getChars(0, passwordConfirm.size, passwordConfirm, 0)
|
|
||||||
if (!password.contentEquals(passwordConfirm)) {
|
if (!password.contentEquals(passwordConfirm)) {
|
||||||
Toast.makeText(requireContext(), R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
|
Toast.makeText(requireContext(), R.string.passwords_mismatch, Toast.LENGTH_SHORT).show()
|
||||||
Arrays.fill(password, 0.toChar())
|
Arrays.fill(password, 0)
|
||||||
Arrays.fill(passwordConfirm, 0.toChar())
|
Arrays.fill(passwordConfirm, 0)
|
||||||
} else {
|
} else {
|
||||||
Arrays.fill(passwordConfirm, 0.toChar())
|
Arrays.fill(passwordConfirm, 0)
|
||||||
var returnedHash: ByteArray? = null
|
var returnedHash: ByteArray? = null
|
||||||
if (binding.checkboxSavePassword.isChecked)
|
if (binding.checkboxSavePassword.isChecked)
|
||||||
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
returnedHash = ByteArray(GocryptfsVolume.KeyLen)
|
||||||
object: LoadingTask<SavedVolume?>(requireActivity() as AppCompatActivity, themeValue, R.string.loading_msg_create) {
|
object: LoadingTask<SavedVolume?>(requireActivity() as AppCompatActivity, themeValue, R.string.loading_msg_create) {
|
||||||
override suspend fun doTask(): SavedVolume? {
|
override suspend fun doTask(): SavedVolume? {
|
||||||
val xchacha = when (binding.spinnerXchacha.selectedItemPosition) {
|
|
||||||
0 -> 0
|
|
||||||
1 -> 1
|
|
||||||
else -> -1
|
|
||||||
}
|
|
||||||
val volumeFile = File(volumePath)
|
val volumeFile = File(volumePath)
|
||||||
if (!volumeFile.exists())
|
if (!volumeFile.exists())
|
||||||
volumeFile.mkdirs()
|
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,
|
volumePath,
|
||||||
password,
|
password,
|
||||||
false,
|
false,
|
||||||
@ -149,20 +178,16 @@ class CreateVolumeFragment: Fragment() {
|
|||||||
GocryptfsVolume.ScryptDefaultLogN,
|
GocryptfsVolume.ScryptDefaultLogN,
|
||||||
ConstValues.CREATOR,
|
ConstValues.CREATOR,
|
||||||
returnedHash
|
returnedHash
|
||||||
)
|
), EncryptedVolume.GOCRYPTFS_VOLUME_TYPE)
|
||||||
) {
|
|
||||||
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
|
|
||||||
} else {
|
} 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
|
return volume
|
||||||
}
|
}
|
||||||
}.startTask(lifecycleScope) { volume ->
|
}.startTask(lifecycleScope) { volume ->
|
||||||
|
@ -454,7 +454,7 @@ open class BaseExplorerActivity : BaseActivity(), ExplorerElementAdapter.Listene
|
|||||||
items.clear()
|
items.clear()
|
||||||
break
|
break
|
||||||
} else {
|
} 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) {
|
if (items.size > 0) {
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
package sushi.hardcore.droidfs.filesystems
|
package sushi.hardcore.droidfs.filesystems
|
||||||
|
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
|
import android.util.Log
|
||||||
|
import sushi.hardcore.droidfs.ConstValues
|
||||||
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||||
|
import sushi.hardcore.droidfs.util.PathUtils
|
||||||
|
|
||||||
class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
||||||
companion object {
|
companion object {
|
||||||
@ -11,7 +14,13 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
|||||||
|
|
||||||
const val CONFIG_FILE_NAME = "cryfs.config"
|
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 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
|
||||||
@ -27,9 +36,25 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
|
|||||||
private external fun nativeClose(fusePtr: Long)
|
private external fun nativeClose(fusePtr: Long)
|
||||||
private external fun nativeIsClosed(fusePtr: Long): Boolean
|
private external fun nativeIsClosed(fusePtr: Long): Boolean
|
||||||
|
|
||||||
fun init(baseDir: String, localStateDir: String, password: ByteArray): CryfsVolume {
|
fun getLocalStateDir(filesDir: String): String {
|
||||||
val fusePtr = nativeInit(baseDir, localStateDir, password)
|
return PathUtils.pathJoin(filesDir, ConstValues.CRYFS_LOCAL_STATE_DIR)
|
||||||
return CryfsVolume(fusePtr)
|
}
|
||||||
|
|
||||||
|
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.net.Uri
|
||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import sushi.hardcore.droidfs.ConstValues
|
||||||
import sushi.hardcore.droidfs.GocryptfsVolume
|
import sushi.hardcore.droidfs.GocryptfsVolume
|
||||||
import sushi.hardcore.droidfs.SavedVolume
|
import sushi.hardcore.droidfs.SavedVolume
|
||||||
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
import sushi.hardcore.droidfs.explorers.ExplorerElement
|
||||||
@ -46,7 +47,7 @@ abstract class EncryptedVolume: Parcelable {
|
|||||||
GocryptfsVolume.init(volume.getFullPath(filesDir), password, givenHash, returnedHash)
|
GocryptfsVolume.init(volume.getFullPath(filesDir), password, givenHash, returnedHash)
|
||||||
}
|
}
|
||||||
CRYFS_VOLUME_TYPE -> {
|
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()
|
else -> throw invalidVolumeType()
|
||||||
}
|
}
|
||||||
|
@ -14,19 +14,20 @@ import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.text.DecimalFormat
|
import java.text.DecimalFormat
|
||||||
import kotlin.math.log10
|
import kotlin.math.log10
|
||||||
|
import kotlin.math.max
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
|
|
||||||
object PathUtils {
|
object PathUtils {
|
||||||
fun getParentPath(path: String): String {
|
fun getParentPath(path: String): String {
|
||||||
return if (path.endsWith("/")) {
|
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) {
|
if (a.count { it == '/' } == 1) {
|
||||||
"/"
|
"/"
|
||||||
} else {
|
} else {
|
||||||
a.substring(0, a.lastIndexOf("/"))
|
a.substring(0, a.lastIndexOf("/"))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (path.count { it == '/' } == 1) {
|
if (path.count { it == '/' } <= 1) {
|
||||||
"/"
|
"/"
|
||||||
} else {
|
} else {
|
||||||
path.substring(0, path.lastIndexOf("/"))
|
path.substring(0, path.lastIndexOf("/"))
|
||||||
@ -48,17 +49,11 @@ object PathUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getRelativePath(parentPath: String, childPath: String): String {
|
fun getRelativePath(parentPath: String, childPath: String): String {
|
||||||
return when {
|
return childPath.substring(parentPath.length + if (parentPath.endsWith("/")) {
|
||||||
parentPath.isEmpty() -> {
|
0
|
||||||
childPath
|
} else {
|
||||||
}
|
1
|
||||||
parentPath.length == childPath.length -> {
|
})
|
||||||
""
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
childPath.substring(parentPath.length + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isChildOf(childPath: String, parentPath: String): Boolean {
|
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
|
JNIEXPORT jboolean JNICALL
|
||||||
Java_sushi_hardcore_droidfs_GocryptfsVolume_00024Companion_createVolume(JNIEnv *env, jclass clazz,
|
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,
|
jboolean plainTextNames,
|
||||||
jint xchacha,
|
jint xchacha,
|
||||||
jint logN,
|
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)};
|
GoString gofilename = {root_cipher_dir, strlen(root_cipher_dir)}, gocreator = {creator, strlen(creator)};
|
||||||
|
|
||||||
const size_t password_len = (*env)->GetArrayLength(env, jpassword);
|
const size_t password_len = (*env)->GetArrayLength(env, jpassword);
|
||||||
jchar* jchar_password = (*env)->GetCharArrayElements(env, jpassword, NULL);
|
char* password = (char*)(*env)->GetByteArrayElements(env, jpassword, NULL);
|
||||||
char password[password_len];
|
|
||||||
jcharArray_to_charArray(jchar_password, password, password_len);
|
|
||||||
GoSlice go_password = {password, password_len, password_len};
|
GoSlice go_password = {password, password_len, password_len};
|
||||||
|
|
||||||
size_t returned_hash_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, jroot_cipher_dir, root_cipher_dir);
|
||||||
(*env)->ReleaseStringUTFChars(env, jcreator, creator);
|
(*env)->ReleaseStringUTFChars(env, jcreator, creator);
|
||||||
wipe(password, password_len);
|
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)) {
|
if (!(*env)->IsSameObject(env, jreturned_hash, NULL)) {
|
||||||
unsignedCharArray_to_jbyteArray(returned_hash, jbyte_returned_hash, returned_hash_len);
|
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);
|
size_t name_len = strlen(name);
|
||||||
|
|
||||||
const char gcf_full_path[plain_dir_len+name_len+2];
|
const char gcf_full_path[plain_dir_len+name_len+2];
|
||||||
if (plain_dir_len > 0){
|
strcpy(gcf_full_path, plain_dir);
|
||||||
strcpy(gcf_full_path, plain_dir);
|
if (plain_dir[-2] != '/') {
|
||||||
if (plain_dir[-2] != '/') {
|
strcat(gcf_full_path, "/");
|
||||||
strcat(gcf_full_path, "/");
|
|
||||||
}
|
|
||||||
strcat(gcf_full_path, name);
|
|
||||||
} else {
|
|
||||||
strcpy(gcf_full_path, name);
|
|
||||||
}
|
}
|
||||||
|
strcat(gcf_full_path, name);
|
||||||
|
|
||||||
GoString go_name = {gcf_full_path, strlen(gcf_full_path)};
|
GoString go_name = {gcf_full_path, strlen(gcf_full_path)};
|
||||||
struct gcf_get_attrs_return attrs = gcf_get_attrs(sessionID, go_name);
|
struct gcf_get_attrs_return attrs = gcf_get_attrs(sessionID, go_name);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <jni.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_create(JNIEnv* env, jlong fusePtr, jstring jpath, mode_t mode);
|
||||||
jlong cryfs_open(JNIEnv* env, jlong fusePtr, jstring jpath, jint flags);
|
jlong cryfs_open(JNIEnv* env, jlong fusePtr, jstring jpath, jint flags);
|
||||||
jint cryfs_read(JNIEnv* env, jlong fusePtr, jlong fileHandle, jbyteArray jbuffer, jlong offset);
|
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
|
JNIEXPORT jlong JNICALL
|
||||||
Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeInit(JNIEnv *env, jobject thiz,
|
Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeInit(JNIEnv *env, jobject thiz,
|
||||||
jstring base_dir, jstring jlocalStateDir,
|
jstring base_dir, jstring jlocalStateDir,
|
||||||
jbyteArray password) {
|
jbyteArray password, jboolean createBaseDir,
|
||||||
return cryfs_init(env, base_dir, jlocalStateDir, password);
|
jstring cipher) {
|
||||||
|
return cryfs_init(env, base_dir, jlocalStateDir, password, createBaseDir, cipher);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL
|
JNIEXPORT jlong JNICALL
|
||||||
|
@ -6,6 +6,18 @@
|
|||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:layout_marginHorizontal="@dimen/volume_operation_horizontal_gap">
|
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
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@ -44,11 +56,11 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/encryption_cipher_label"
|
android:text="@string/encryption_cipher_label"
|
||||||
android:layout_toStartOf="@id/spinner_xchacha"
|
android:layout_toStartOf="@id/spinner_cipher"
|
||||||
android:layout_alignParentStart="true"/>
|
android:layout_alignParentStart="true"/>
|
||||||
|
|
||||||
<Spinner
|
<Spinner
|
||||||
android:id="@+id/spinner_xchacha"
|
android:id="@+id/spinner_cipher"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentEnd="true" />
|
android:layout_alignParentEnd="true" />
|
||||||
|
@ -1,10 +1,4 @@
|
|||||||
<resources>
|
<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">
|
<string-array name="sort_orders_entries">
|
||||||
<item>اسم</item>
|
<item>اسم</item>
|
||||||
<item>حجم</item>
|
<item>حجم</item>
|
||||||
|
@ -138,7 +138,6 @@
|
|||||||
<string name="image_saved_successfully">تم حفظ تغييرات الصورة بنجاح.</string>
|
<string name="image_saved_successfully">تم حفظ تغييرات الصورة بنجاح.</string>
|
||||||
<string name="bitmap_compress_failed">فشل ضغط الصورة النقطية.</string>
|
<string name="bitmap_compress_failed">فشل ضغط الصورة النقطية.</string>
|
||||||
<string name="file_write_failed">فشل كتابة الملف.</string>
|
<string name="file_write_failed">فشل كتابة الملف.</string>
|
||||||
<string name="error_not_a_volume">لم يتم التعرف على مجلد التشفير Gocryptfs. يرجى التحقق من المسار المحدد.</string>
|
|
||||||
<string name="version">إصدار</string>
|
<string name="version">إصدار</string>
|
||||||
<string name="error_cipher_null">تشفير الخطأ فارغ</string>
|
<string name="error_cipher_null">تشفير الخطأ فارغ</string>
|
||||||
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
||||||
@ -173,7 +172,6 @@
|
|||||||
<string name="maximize_quality">دقة أعلى</string>
|
<string name="maximize_quality">دقة أعلى</string>
|
||||||
<string name="minimize_latency">أداء أفضل</string>
|
<string name="minimize_latency">أداء أفضل</string>
|
||||||
<string name="auto">تلقائي</string>
|
<string name="auto">تلقائي</string>
|
||||||
<string name="xchacha_warning">XChaCha20-Poly1305 مدعوم فقط منذ إصدار gocryptfs v2.2.0. لن تتمكن الإصدارات الأقدم من فتح وحدة تخزين بناءً على هذا التشفير.</string>
|
|
||||||
<string name="encryption_cipher_label">خوارزمية التشفير:</string>
|
<string name="encryption_cipher_label">خوارزمية التشفير:</string>
|
||||||
<string name="theme">سمة</string>
|
<string name="theme">سمة</string>
|
||||||
<string name="theme_summary">تخصيص سمة التطبيق</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="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="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="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="version">Versión</string>
|
||||||
<string name="error_cipher_null">Error de cifrado núlo</string>
|
<string name="error_cipher_null">Error de cifrado núlo</string>
|
||||||
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
||||||
@ -173,7 +172,6 @@
|
|||||||
<string name="maximize_quality">Maximizar la calidad</string>
|
<string name="maximize_quality">Maximizar la calidad</string>
|
||||||
<string name="minimize_latency">Minimizar la latencia</string>
|
<string name="minimize_latency">Minimizar la latencia</string>
|
||||||
<string name="auto">Automático</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="encryption_cipher_label">Cifrado de encriptación:</string>
|
||||||
<string name="theme">Tema</string>
|
<string name="theme">Tema</string>
|
||||||
<string name="theme_summary">Personalizar el tema de la aplicación</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="image_saved_successfully">Mudanças na imagem salva com sucesso.</string>
|
||||||
<string name="bitmap_compress_failed">Falha ao compactar o bitmap.</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="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="version">Versão</string>
|
||||||
<string name="error_cipher_null">Erro, o cipher é nulo</string>
|
<string name="error_cipher_null">Erro, o cipher é nulo</string>
|
||||||
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
||||||
@ -170,7 +169,6 @@
|
|||||||
<string name="maximize_quality">Maximizar a qualidade</string>
|
<string name="maximize_quality">Maximizar a qualidade</string>
|
||||||
<string name="minimize_latency">Minimizar a latência</string>
|
<string name="minimize_latency">Minimizar a latência</string>
|
||||||
<string name="auto">Autom</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="encryption_cipher_label">Cipher de criptografia:</string>
|
||||||
<string name="theme">Tema</string>
|
<string name="theme">Tema</string>
|
||||||
<string name="theme_summary">Personalizar o tema do app</string>
|
<string name="theme_summary">Personalizar o tema do app</string>
|
||||||
|
@ -133,7 +133,6 @@
|
|||||||
<string name="image_saved_successfully">Изменения изображения успешно сохранены.</string>
|
<string name="image_saved_successfully">Изменения изображения успешно сохранены.</string>
|
||||||
<string name="bitmap_compress_failed">Невозможно сжать растровое изображение.</string>
|
<string name="bitmap_compress_failed">Невозможно сжать растровое изображение.</string>
|
||||||
<string name="file_write_failed">Невозможно записать файл.</string>
|
<string name="file_write_failed">Невозможно записать файл.</string>
|
||||||
<string name="error_not_a_volume">Том GocryptFS не распознан. Проверьте выбранный путь.</string>
|
|
||||||
<string name="version">Версия</string>
|
<string name="version">Версия</string>
|
||||||
<string name="error_cipher_null">Шифр ошибки нулевой</string>
|
<string name="error_cipher_null">Шифр ошибки нулевой</string>
|
||||||
<string name="key_permanently_invalidated_exception_msg">Похоже, вы добавили новый отпечаток пальца. Сохранённый хеш паролей стал непригодным для использования.</string>
|
<string name="key_permanently_invalidated_exception_msg">Похоже, вы добавили новый отпечаток пальца. Сохранённый хеш паролей стал непригодным для использования.</string>
|
||||||
@ -167,7 +166,6 @@
|
|||||||
<string name="maximize_quality">Максимальное качество</string>
|
<string name="maximize_quality">Максимальное качество</string>
|
||||||
<string name="minimize_latency">Минимальная задержка</string>
|
<string name="minimize_latency">Минимальная задержка</string>
|
||||||
<string name="auto">Авто</string>
|
<string name="auto">Авто</string>
|
||||||
<string name="xchacha_warning">Шифр XChaCha20-Poly1305 поддерживается только с версии GocryptFS 2.2.0. Более старые версии не смогут открыть том, использующий данный шифр.</string>
|
|
||||||
<string name="encryption_cipher_label">Шифр:</string>
|
<string name="encryption_cipher_label">Шифр:</string>
|
||||||
<string name="theme">Тема</string>
|
<string name="theme">Тема</string>
|
||||||
<string name="theme_summary">Настройка темы приложения</string>
|
<string name="theme_summary">Настройка темы приложения</string>
|
||||||
|
@ -1,10 +1,29 @@
|
|||||||
<resources>
|
<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>AES-GCM</item>
|
||||||
<item>XChaCha20-Poly1305</item>
|
<item>XChaCha20-Poly1305</item>
|
||||||
<item>@string/auto</item>
|
<item>@string/auto</item>
|
||||||
</string-array>
|
</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">
|
<string-array name="sort_orders_entries">
|
||||||
<item>Name</item>
|
<item>Name</item>
|
||||||
<item>Size</item>
|
<item>Size</item>
|
||||||
|
@ -138,7 +138,7 @@
|
|||||||
<string name="image_saved_successfully">Image changes successfully saved.</string>
|
<string name="image_saved_successfully">Image changes successfully saved.</string>
|
||||||
<string name="bitmap_compress_failed">Failed to compress the bitmap.</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="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="version">Version</string>
|
||||||
<string name="error_cipher_null">Error cipher is null</string>
|
<string name="error_cipher_null">Error cipher is null</string>
|
||||||
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
<string name="key_permanently_invalidated_exception">KeyPermanentlyInvalidatedException</string>
|
||||||
@ -173,7 +173,6 @@
|
|||||||
<string name="maximize_quality">Maximize quality</string>
|
<string name="maximize_quality">Maximize quality</string>
|
||||||
<string name="minimize_latency">Minimize latency</string>
|
<string name="minimize_latency">Minimize latency</string>
|
||||||
<string name="auto">Auto</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="encryption_cipher_label">Encryption cipher:</string>
|
||||||
<string name="theme">Theme</string>
|
<string name="theme">Theme</string>
|
||||||
<string name="theme_summary">Customize app theme</string>
|
<string name="theme_summary">Customize app theme</string>
|
||||||
@ -242,4 +241,5 @@
|
|||||||
<string name="elements_selected">%d/%d selected</string>
|
<string name="elements_selected">%d/%d selected</string>
|
||||||
<string name="pin_passwords_title">Numeric keypad layout</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="pin_passwords_summary">Use a numeric keypad layout when entering volume passwords</string>
|
||||||
|
<string name="volume_type_label">Volume type:</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user