From 3f6a9c3af513c7f0d9b8d3c549e83e3850817a58 Mon Sep 17 00:00:00 2001 From: J-Jamet Date: Tue, 9 Feb 2021 14:15:18 +0100 Subject: [PATCH] Rollback readBytes method and default buffer to fix argon2 database --- .../database/element/database/DatabaseKDB.kt | 2 - .../database/element/database/DatabaseKDBX.kt | 6 +-- .../database/file/input/DatabaseInputKDB.kt | 4 +- .../database/file/input/DatabaseInputKDBX.kt | 5 ++- .../file/output/DatabaseOutputKDBX.kt | 7 ++-- .../database/file/output/EntryOutputKDB.kt | 3 +- .../keepass/stream/StreamBytesUtils.kt | 38 +++++++++++++------ 7 files changed, 39 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDB.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDB.kt index 8678e84ce..a72875753 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDB.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDB.kt @@ -281,7 +281,5 @@ class DatabaseKDB : DatabaseVersioned() { const val BACKUP_FOLDER_TITLE = "Backup" private const val BACKUP_FOLDER_UNDEFINED_ID = -1 - - const val BUFFER_SIZE_BYTES = 3 * 128 } } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDBX.kt b/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDBX.kt index fc0a8e802..d2ebabd20 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDBX.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/element/database/DatabaseKDBX.kt @@ -216,7 +216,7 @@ class DatabaseKDBX : DatabaseVersioned { val cipherKey = loadedCipherKey ?: throw IOException("Unable to retrieve cipher key to compress binaries") // To compress, create a new binary with file - binary.compress(cipherKey, BUFFER_SIZE_BYTES) + binary.compress(cipherKey) } catch (e: Exception) { Log.e(TAG, "Unable to compress $binary", e) } @@ -228,7 +228,7 @@ class DatabaseKDBX : DatabaseVersioned { try { val cipherKey = loadedCipherKey ?: throw IOException("Unable to retrieve cipher key to decompress binaries") - binary.decompress(cipherKey, BUFFER_SIZE_BYTES) + binary.decompress(cipherKey) } catch (e: Exception) { Log.e(TAG, "Unable to decompress $binary", e) } @@ -713,7 +713,5 @@ class DatabaseKDBX : DatabaseVersioned { private const val XML_ATTRIBUTE_DATA_HASH = "Hash" const val BASE_64_FLAG = Base64.NO_WRAP - - const val BUFFER_SIZE_BYTES = 3 * 128 } } \ No newline at end of file diff --git a/app/src/main/java/com/kunzisoft/keepass/database/file/input/DatabaseInputKDB.kt b/app/src/main/java/com/kunzisoft/keepass/database/file/input/DatabaseInputKDB.kt index ce9a950e0..e5ccf7131 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/file/input/DatabaseInputKDB.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/file/input/DatabaseInputKDB.kt @@ -332,7 +332,9 @@ class DatabaseInputKDB(cacheDirectory: File) val cipherKey = mDatabase.loadedCipherKey ?: throw IOException("Unable to retrieve cipher key to load binaries") BufferedOutputStream(binaryAttachment.getOutputDataStream(cipherKey)).use { outputStream -> - cipherInputStream.copyPartTo(outputStream, fieldSize) + cipherInputStream.readBytes(fieldSize) { buffer -> + outputStream.write(buffer) + } } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/file/input/DatabaseInputKDBX.kt b/app/src/main/java/com/kunzisoft/keepass/database/file/input/DatabaseInputKDBX.kt index a230d742f..b5ecdc904 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/file/input/DatabaseInputKDBX.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/file/input/DatabaseInputKDBX.kt @@ -33,7 +33,6 @@ import com.kunzisoft.keepass.database.element.database.BinaryAttachment import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm import com.kunzisoft.keepass.database.element.database.DatabaseKDBX import com.kunzisoft.keepass.database.element.database.DatabaseKDBX.Companion.BASE_64_FLAG -import com.kunzisoft.keepass.database.element.database.DatabaseKDBX.Companion.BUFFER_SIZE_BYTES import com.kunzisoft.keepass.database.element.database.DatabaseVersioned import com.kunzisoft.keepass.database.element.entry.EntryKDBX import com.kunzisoft.keepass.database.element.group.GroupKDBX @@ -303,7 +302,9 @@ class DatabaseInputKDBX(cacheDirectory: File) val cipherKey = mDatabase.loadedCipherKey ?: throw IOException("Unable to retrieve cipher key to load binaries") protectedBinary.getOutputDataStream(cipherKey).use { outputStream -> - dataInputStream.copyPartTo(outputStream, byteLength) + dataInputStream.readBytes(byteLength) { buffer -> + outputStream.write(buffer) + } } } } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/file/output/DatabaseOutputKDBX.kt b/app/src/main/java/com/kunzisoft/keepass/database/file/output/DatabaseOutputKDBX.kt index 334d4fd16..4ca77a42a 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/file/output/DatabaseOutputKDBX.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/file/output/DatabaseOutputKDBX.kt @@ -32,7 +32,6 @@ import com.kunzisoft.keepass.database.element.DeletedObject import com.kunzisoft.keepass.database.element.database.CompressionAlgorithm import com.kunzisoft.keepass.database.element.database.DatabaseKDBX import com.kunzisoft.keepass.database.element.database.DatabaseKDBX.Companion.BASE_64_FLAG -import com.kunzisoft.keepass.database.element.database.DatabaseKDBX.Companion.BUFFER_SIZE_BYTES import com.kunzisoft.keepass.database.element.entry.AutoType import com.kunzisoft.keepass.database.element.entry.EntryKDBX import com.kunzisoft.keepass.database.element.group.GroupKDBX @@ -473,7 +472,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX, if (binary.isProtected) { xml.attribute(null, DatabaseKDBXXML.AttrProtected, DatabaseKDBXXML.ValTrue) binary.getInputDataStream().use { inputStream -> - inputStream.readBytes(BUFFER_SIZE_BYTES) { buffer -> + inputStream.readBytes { buffer -> val encoded = ByteArray(buffer.size) randomStream!!.processBytes(buffer, 0, encoded.size, encoded, 0) xml.text(String(Base64.encode(encoded, BASE_64_FLAG))) @@ -482,7 +481,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX, } else { // Write the XML binary.getInputDataStream().use { inputStream -> - inputStream.readBytes(BUFFER_SIZE_BYTES) { buffer -> + inputStream.readBytes { buffer -> xml.text(String(Base64.encode(buffer, BASE_64_FLAG))) } } @@ -510,7 +509,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX, val binaryCipherKey = mDatabaseKDBX.loadedCipherKey ?: throw IOException("Unable to retrieve cipher key to write binaries") binary.getInputDataStream(binaryCipherKey).use { inputStream -> - inputStream.readAllBytes(BUFFER_SIZE_BYTES) { buffer -> + inputStream.readAllBytes { buffer -> xml.text(String(Base64.encode(buffer, BASE_64_FLAG))) } } diff --git a/app/src/main/java/com/kunzisoft/keepass/database/file/output/EntryOutputKDB.kt b/app/src/main/java/com/kunzisoft/keepass/database/file/output/EntryOutputKDB.kt index b42cda4ce..5e6777664 100644 --- a/app/src/main/java/com/kunzisoft/keepass/database/file/output/EntryOutputKDB.kt +++ b/app/src/main/java/com/kunzisoft/keepass/database/file/output/EntryOutputKDB.kt @@ -20,7 +20,6 @@ package com.kunzisoft.keepass.database.file.output import com.kunzisoft.keepass.database.element.Database -import com.kunzisoft.keepass.database.element.database.DatabaseKDB import com.kunzisoft.keepass.database.element.entry.EntryKDB import com.kunzisoft.keepass.database.exception.DatabaseOutputException import com.kunzisoft.keepass.stream.* @@ -103,7 +102,7 @@ class EntryOutputKDB { // Write data if (binaryDataLength > 0) { binaryData?.getInputDataStream(binaryCipherKey).use { inputStream -> - inputStream?.readAllBytes(DatabaseKDB.BUFFER_SIZE_BYTES) { buffer -> + inputStream?.readAllBytes { buffer -> mOutputStream.write(buffer) } inputStream?.close() diff --git a/app/src/main/java/com/kunzisoft/keepass/stream/StreamBytesUtils.kt b/app/src/main/java/com/kunzisoft/keepass/stream/StreamBytesUtils.kt index add6c2cf5..4b88e00ee 100644 --- a/app/src/main/java/com/kunzisoft/keepass/stream/StreamBytesUtils.kt +++ b/app/src/main/java/com/kunzisoft/keepass/stream/StreamBytesUtils.kt @@ -24,14 +24,14 @@ import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils.bytesToString import com.kunzisoft.keepass.utils.UnsignedInt import java.io.IOException import java.io.InputStream -import java.io.OutputStream import java.util.* /** * Read all data of stream and invoke [readBytes] each time the buffer is full or no more data to read. */ @Throws(IOException::class) -fun InputStream.readAllBytes(bufferSize: Int, readBytes: (bytesRead: ByteArray) -> Unit) { +fun InputStream.readAllBytes(bufferSize: Int = DEFAULT_BUFFER_SIZE, + readBytes: (bytesRead: ByteArray) -> Unit) { val buffer = ByteArray(bufferSize) var read = 0 while (read != -1) { @@ -48,17 +48,33 @@ fun InputStream.readAllBytes(bufferSize: Int, readBytes: (bytesRead: ByteArray) } /** - * Read number of bytes defined by [length] and copy the content in [outputStream] + * Read number of bytes defined by [length] and invoke [readBytes] each time the buffer is full or no more data to read. */ @Throws(IOException::class) -fun InputStream.copyPartTo(outputStream: OutputStream, length: Int, bufferSize: Int = DEFAULT_BUFFER_SIZE) { - var bytesCopied: Long = 0 - val buffer = ByteArray(bufferSize) - var bytesRead = read(buffer) - while (bytesRead >= 0 && bytesCopied <= length) { - outputStream.write(buffer, 0, bytesRead) - bytesCopied += bytesRead - bytesRead = read(buffer) +fun InputStream.readBytes(length: Int, bufferSize: Int = DEFAULT_BUFFER_SIZE, + readBytes: (bytesRead: ByteArray) -> Unit) { + var bufferLength = bufferSize + var buffer = ByteArray(bufferLength) + + var offset = 0 + var read = 0 + while (offset < length && read != -1) { + + // To reduce the buffer for the last bytes reads + if (length - offset < bufferLength) { + bufferLength = length - offset + buffer = ByteArray(bufferLength) + } + read = this.read(buffer, 0, bufferLength) + + // To get only the bytes read + val optimizedBuffer: ByteArray = if (read >= 0 && buffer.size > read) { + buffer.copyOf(read) + } else { + buffer + } + readBytes.invoke(optimizedBuffer) + offset += read } }