Direct encrypted files read/write & More compliant EncryptedVolumeDataSource

This commit is contained in:
Matéo Duparc 2022-09-23 20:58:16 +02:00
parent 8f5afca823
commit 7cdfc32c31
Signed by untrusted user: hardcoresushi
GPG Key ID: AFE384344A45E13A
11 changed files with 73 additions and 82 deletions

@ -1 +1 @@
Subproject commit c0600c262480f6fb3d31e2b500ba04714f1ff342
Subproject commit dc82772e5eb8063bace8415193eebc52cedcec64

View File

@ -459,7 +459,7 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
videoCapture?.startRecording(VideoCapture.OutputFileOptions(object : SeekableWriter {
var offset = 0L
override fun write(byteArray: ByteArray) {
offset += encryptedVolume.write(fileHandle, offset, byteArray, byteArray.size)
offset += encryptedVolume.write(fileHandle, offset, byteArray, 0, byteArray.size.toLong())
}
override fun seek(offset: Long) {
this.offset = offset

View File

@ -9,7 +9,6 @@ object ConstValues {
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
const val WIPE_PASSES = 2
const val IO_BUFF_SIZE = 16384
const val SLIDESHOW_DELAY: Long = 4000

View File

@ -131,10 +131,10 @@ class FileOperationService : Service() {
if (dstFileHandle != -1L) {
var offset: Long = 0
val ioBuffer = ByteArray(ConstValues.IO_BUFF_SIZE)
var length: Int
while (remoteEncryptedVolume.read(srcFileHandle, ioBuffer, offset).also { length = it } > 0) {
val written = encryptedVolume.write(dstFileHandle, offset, ioBuffer, length).toLong()
if (written == length.toLong()) {
var length: Long
while (remoteEncryptedVolume.read(srcFileHandle, offset, ioBuffer, 0, ioBuffer.size.toLong()).also { length = it.toLong() } > 0) {
val written = encryptedVolume.write(dstFileHandle, offset, ioBuffer, 0, length).toLong()
if (written == length) {
offset += written
} else {
success = false

View File

@ -1,23 +1,29 @@
package sushi.hardcore.droidfs.file_viewers
import android.net.Uri
import com.google.android.exoplayer2.C
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DataSpec
import com.google.android.exoplayer2.upstream.TransferListener
import sushi.hardcore.droidfs.ConstValues
import sushi.hardcore.droidfs.filesystems.EncryptedVolume
import kotlin.math.ceil
import kotlin.math.min
class EncryptedVolumeDataSource(private val encryptedVolume: EncryptedVolume, private val filePath: String): DataSource {
private var fileHandle = -1L
private var fileSize: Long = -1
private var fileOffset: Long = 0
private var bytesRemaining: Long = -1
override fun open(dataSpec: DataSpec): Long {
fileOffset = dataSpec.position
fileHandle = encryptedVolume.openFile(filePath)
fileSize = encryptedVolume.getAttr(filePath)!!.size
return fileSize
fileOffset = dataSpec.position
val fileSize = encryptedVolume.getAttr(filePath)!!.size
bytesRemaining = if (dataSpec.length == C.LENGTH_UNSET.toLong()) {
fileSize - fileOffset
} else {
min(fileSize, dataSpec.length)
}
return bytesRemaining
}
override fun getUri(): Uri {
@ -33,23 +39,18 @@ class EncryptedVolumeDataSource(private val encryptedVolume: EncryptedVolume, pr
}
override fun read(buffer: ByteArray, offset: Int, readLength: Int): Int {
if (fileOffset >= fileSize){
return -1
}
var totalRead = 0
for (i in 0 until ceil(readLength.toDouble()/ConstValues.MAX_KERNEL_WRITE).toInt()){
val tmpReadLength = min(readLength-totalRead, ConstValues.MAX_KERNEL_WRITE)
val tmpBuff = if (fileOffset+tmpReadLength > fileSize){
ByteArray((fileSize-fileOffset).toInt())
} else {
ByteArray(tmpReadLength)
}
val read = encryptedVolume.read(fileHandle, tmpBuff, fileOffset)
System.arraycopy(tmpBuff, 0, buffer, offset+totalRead, read)
fileOffset += read
totalRead += read
}
return totalRead
val originalOffset = fileOffset
while (fileOffset < originalOffset+readLength && encryptedVolume.read(
fileHandle,
fileOffset,
buffer,
offset+(fileOffset-originalOffset),
(originalOffset+readLength)-fileOffset
).also { fileOffset += it } > 0
) {}
val totalRead = fileOffset-originalOffset
bytesRemaining -= totalRead
return totalRead.toInt()
}
class Factory(private val encryptedVolume: EncryptedVolume, private val filePath: String): DataSource.Factory {

View File

@ -70,23 +70,12 @@ class TextEditor: FileViewerActivity() {
val content = editor.text.toString().toByteArray()
val fileHandle = encryptedVolume.openFile(filePath)
if (fileHandle != -1L) {
val buff = ByteArrayInputStream(content)
var offset: Long = 0
val ioBuffer = ByteArray(ConstValues.IO_BUFF_SIZE)
var length: Int
while (buff.read(ioBuffer).also { length = it } > 0) {
val written = encryptedVolume.write(fileHandle, offset, ioBuffer, length).toLong()
if (written == length.toLong()) {
offset += written
} else {
break
}
}
while (offset < content.size && encryptedVolume.write(fileHandle, offset, content, offset, content.size.toLong()).also { offset += it } > 0) {}
if (offset == content.size.toLong()){
success = encryptedVolume.truncate(filePath, offset)
}
encryptedVolume.closeFile(fileHandle)
buff.close()
}
if (success){
Toast.makeText(this, getString(R.string.file_saved), Toast.LENGTH_SHORT).show()

View File

@ -33,8 +33,8 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
): Boolean
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
private external fun nativeWrite(fusePtr: Long, fileHandle: Long, offset: Long, buffer: ByteArray, size: Int): Int
private external fun nativeRead(fusePtr: Long, fileHandle: Long, fileOffset: Long, buffer: ByteArray, dstOffset: Long, length: Long): Int
private external fun nativeWrite(fusePtr: Long, fileHandle: Long, fileOffset: Long, buffer: ByteArray, srcOffset: Long, length: Long): Int
private external fun nativeTruncate(fusePtr: Long, path: String, size: Long): Boolean
private external fun nativeDeleteFile(fusePtr: Long, path: String): Boolean
private external fun nativeCloseFile(fusePtr: Long, fileHandle: Long): Boolean
@ -101,12 +101,12 @@ class CryfsVolume(private val fusePtr: Long): EncryptedVolume() {
}
}
override fun read(fileHandle: Long, buffer: ByteArray, offset: Long): Int {
return nativeRead(fusePtr, fileHandle, buffer, offset)
override fun read(fileHandle: Long, fileOffset: Long, buffer: ByteArray, dstOffset: Long, length: Long): Int {
return nativeRead(fusePtr, fileHandle, fileOffset, buffer, dstOffset, length)
}
override fun write(fileHandle: Long, offset: Long, buffer: ByteArray, size: Int): Int {
return nativeWrite(fusePtr, fileHandle, offset, buffer, size)
override fun write(fileHandle: Long, fileOffset: Long, buffer: ByteArray, srcOffset: Long, length: Long): Int {
return nativeWrite(fusePtr, fileHandle, fileOffset, buffer, srcOffset, length)
}
override fun truncate(path: String, size: Long): Boolean {

View File

@ -74,8 +74,8 @@ abstract class EncryptedVolume: Parcelable {
override fun describeContents() = 0
abstract fun openFile(path: String): Long
abstract fun read(fileHandle: Long, buffer: ByteArray, offset: Long): Int
abstract fun write(fileHandle: Long, offset: Long, buffer: ByteArray, size: Int): Int
abstract fun read(fileHandle: Long, fileOffset: Long, buffer: ByteArray, dstOffset: Long, length: Long): Int
abstract fun write(fileHandle: Long, fileOffset: Long, buffer: ByteArray, srcOffset: Long, length: Long): Int
abstract fun closeFile(fileHandle: Long): Boolean
// Due to gocryptfs internals, truncate requires the file to be open before it is called
abstract fun truncate(path: String, size: Long): Boolean
@ -96,7 +96,7 @@ abstract class EncryptedVolume: Parcelable {
var offset: Long = 0
val ioBuffer = ByteArray(ConstValues.IO_BUFF_SIZE)
var length: Int
while (read(fileHandle, ioBuffer, offset).also { length = it } > 0) {
while (read(fileHandle, offset, ioBuffer, 0, ioBuffer.size.toLong()).also { length = it } > 0) {
os.write(ioBuffer, 0, length)
offset += length.toLong()
}
@ -132,10 +132,10 @@ abstract class EncryptedVolume: Parcelable {
var success = true
var offset: Long = 0
val ioBuffer = ByteArray(ConstValues.IO_BUFF_SIZE)
var length: Int
while (inputStream.read(ioBuffer).also { length = it } > 0) {
val written = write(dstfileHandle, offset, ioBuffer, length).toLong()
if (written == length.toLong()) {
var length: Long
while (inputStream.read(ioBuffer).also { length = it.toLong() } > 0) {
val written = write(dstfileHandle, offset, ioBuffer, 0, length).toLong()
if (written == length) {
offset += written
} else {
inputStream.close()
@ -174,12 +174,7 @@ abstract class EncryptedVolume: Parcelable {
Pair(null, 3)
} else {
var offset: Long = 0
val ioBuffer = ByteArray(ConstValues.IO_BUFF_SIZE)
var length: Int
while (read(fileHandle, ioBuffer, offset).also { length = it } > 0) {
System.arraycopy(ioBuffer, 0, fileBuff, offset.toInt(), length)
offset += length.toLong()
}
while (offset < fileSize && read(fileHandle, offset, fileBuff, offset, fileSize-offset).also { offset += it } > 0) {}
closeFile(fileHandle)
if (offset == fileBuff.size.toLong()) {
Pair(fileBuff, 0)

View File

@ -2,6 +2,7 @@ package sushi.hardcore.droidfs.filesystems
import android.os.Parcel
import sushi.hardcore.droidfs.explorers.ExplorerElement
import kotlin.math.min
class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() {
private external fun native_close(sessionID: Int)
@ -9,8 +10,8 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() {
private external fun native_list_dir(sessionID: Int, dir_path: String): MutableList<ExplorerElement>?
private external fun native_open_read_mode(sessionID: Int, file_path: String): Int
private external fun native_open_write_mode(sessionID: Int, file_path: String, mode: Int): Int
private external fun native_read_file(sessionID: Int, handleID: Int, offset: Long, buff: ByteArray): Int
private external fun native_write_file(sessionID: Int, handleID: Int, offset: Long, buff: ByteArray, buff_size: Int): Int
private external fun native_read_file(sessionID: Int, handleID: Int, fileOffset: Long, buff: ByteArray, dstOffset: Long, length: Int): Int
private external fun native_write_file(sessionID: Int, handleID: Int, fileOffset: Long, buff: ByteArray, srcOffset: Long, length: Int): Int
private external fun native_truncate(sessionID: Int, path: String, offset: Long): Boolean
private external fun native_close_file(sessionID: Int, handleID: Int)
private external fun native_remove_file(sessionID: Int, file_path: String): Boolean
@ -22,6 +23,7 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() {
companion object {
const val KeyLen = 32
const val ScryptDefaultLogN = 16
const val MAX_KERNEL_WRITE = 128*1024
const val CONFIG_FILE_NAME = "gocryptfs.conf"
external fun createVolume(root_cipher_dir: String, password: ByteArray, plainTextNames: Boolean, xchacha: Int, logN: Int, creator: String, returnedHash: ByteArray?): Boolean
private external fun nativeInit(root_cipher_dir: String, password: ByteArray?, givenHash: ByteArray?, returnedHash: ByteArray?): Int
@ -53,8 +55,8 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() {
return native_open_write_mode(sessionID, path, 0).toLong()
}
override fun read(fileHandle: Long, buffer: ByteArray, offset: Long): Int {
return native_read_file(sessionID, fileHandle.toInt(), offset, buffer)
override fun read(fileHandle: Long, fileOffset: Long, buffer: ByteArray, dstOffset: Long, length: Long): Int {
return native_read_file(sessionID, fileHandle.toInt(), fileOffset, buffer, dstOffset, min(length.toInt(), MAX_KERNEL_WRITE))
}
override fun readDir(path: String): MutableList<ExplorerElement>? {
@ -91,8 +93,8 @@ class GocryptfsVolume(private val sessionID: Int): EncryptedVolume() {
return true
}
override fun write(fileHandle: Long, offset: Long, buffer: ByteArray, size: Int): Int {
return native_write_file(sessionID, fileHandle.toInt(), offset, buffer, size)
override fun write(fileHandle: Long, fileOffset: Long, buffer: ByteArray, srcOffset: Long, length: Long): Int {
return native_write_file(sessionID, fileHandle.toInt(), fileOffset, buffer, srcOffset, min(length.toInt(), MAX_KERNEL_WRITE))
}
override fun truncate(path: String, size: Long): Boolean {

View File

@ -293,12 +293,12 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1open_1write_1mod
JNIEXPORT jint JNICALL
Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1write_1file(JNIEnv *env, jobject thiz,
jint sessionID, jint handleID, jlong offset,
jbyteArray jbuff, jint buff_size) {
jint sessionID, jint handleID, jlong file_offset,
jbyteArray jbuff, jlong src_offset, jint length) {
jbyte* buff = (*env)->GetByteArrayElements(env, jbuff, NULL);
GoSlice go_buff = {buff, buff_size, buff_size};
GoSlice go_buff = {buff+src_offset, length, length};
int written = gcf_write_file(sessionID, handleID, offset, go_buff);
int written = gcf_write_file(sessionID, handleID, file_offset, go_buff);
(*env)->ReleaseByteArrayElements(env, jbuff, buff, 0);
@ -307,13 +307,12 @@ Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1write_1file(JNIE
JNIEXPORT jint JNICALL
Java_sushi_hardcore_droidfs_filesystems_GocryptfsVolume_native_1read_1file(JNIEnv *env, jobject thiz,
jint sessionID, jint handleID, jlong offset,
jbyteArray jbuff) {
const size_t buff_size = (*env)->GetArrayLength(env, jbuff);
jint sessionID, jint handleID, jlong file_offset,
jbyteArray jbuff, jlong dst_offset, jint length) {
jbyte* buff = (*env)->GetByteArrayElements(env, jbuff, NULL);
GoSlice go_buff = {buff, buff_size, buff_size};
GoSlice go_buff = {buff+dst_offset, length, length};
int read = gcf_read_file(sessionID, handleID, offset, go_buff);
int read = gcf_read_file(sessionID, handleID, file_offset, go_buff);
(*env)->ReleaseByteArrayElements(env, jbuff, buff, 0);
return read;

View File

@ -35,10 +35,15 @@ Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeOpen(JN
}
JNIEXPORT jint JNICALL
Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeRead(JNIEnv *env, jobject thiz,
jlong fuse_ptr, jlong file_handle,
jbyteArray buffer, jlong offset) {
return cryfs_read(env, fuse_ptr, file_handle, buffer, offset);
Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeRead(JNIEnv *env,
jobject thiz,
jlong fuse_ptr,
jlong file_handle,
jlong file_offset,
jbyteArray buffer,
jlong dst_offset,
jlong length) {
return cryfs_read(env, fuse_ptr, file_handle, file_offset, buffer, dst_offset, length);
}
JNIEXPORT jint JNICALL
@ -46,10 +51,11 @@ Java_sushi_hardcore_droidfs_filesystems_CryfsVolume_00024Companion_nativeWrite(J
jobject thiz,
jlong fuse_ptr,
jlong file_handle,
jlong offset,
jlong file_offset,
jbyteArray buffer,
jint size) {
return cryfs_write(env, fuse_ptr, file_handle, offset, buffer, size);
jlong src_offset,
jlong length) {
return cryfs_write(env, fuse_ptr, file_handle, file_offset, buffer, src_offset, length);
}
JNIEXPORT jboolean JNICALL