Fix length and better streams implementation

This commit is contained in:
J-Jamet
2021-02-06 20:24:07 +01:00
parent 7590d18c67
commit d13aa047d5
7 changed files with 64 additions and 38 deletions

View File

@@ -124,9 +124,9 @@ dependencies {
implementation 'com.github.Kunzisoft:AndroidClearChroma:2.4' implementation 'com.github.Kunzisoft:AndroidClearChroma:2.4'
// Education // Education
implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.0' implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.0'
// Apache Commons Collections // Apache Commons
implementation 'commons-collections:commons-collections:3.2.2' implementation 'commons-collections:commons-collections:3.2.2'
// Apache Commons Codec implementation 'commons-io:commons-io:2.8.0'
implementation 'commons-codec:commons-codec:1.15' implementation 'commons-codec:commons-codec:1.15'
// Icon pack // Icon pack
implementation project(path: ':icon-pack-classic') implementation project(path: ':icon-pack-classic')

View File

@@ -77,7 +77,7 @@ class EntryAttachmentsItemsAdapter(context: Context)
holder.binaryFileTitle.setTextColor(mTitleColor) holder.binaryFileTitle.setTextColor(mTitleColor)
} }
holder.binaryFileSize.text = Formatter.formatFileSize(context, holder.binaryFileSize.text = Formatter.formatFileSize(context,
entryAttachmentState.attachment.binaryAttachment.length()) entryAttachmentState.attachment.binaryAttachment.length)
holder.binaryFileCompression.apply { holder.binaryFileCompression.apply {
if (entryAttachmentState.attachment.binaryAttachment.isCompressed) { if (entryAttachmentState.attachment.binaryAttachment.isCompressed) {
text = CompressionAlgorithm.GZip.getName(context.resources) text = CompressionAlgorithm.GZip.getName(context.resources)

View File

@@ -23,6 +23,7 @@ import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import com.kunzisoft.keepass.database.element.Database import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.stream.readAllBytes import com.kunzisoft.keepass.stream.readAllBytes
import org.apache.commons.io.output.CountingOutputStream
import java.io.* import java.io.*
import java.util.zip.GZIPInputStream import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
@@ -33,6 +34,8 @@ import javax.crypto.CipherOutputStream
class BinaryAttachment : Parcelable { class BinaryAttachment : Parcelable {
private var dataFile: File? = null private var dataFile: File? = null
var length: Long = 0
private set
var isCompressed: Boolean = false var isCompressed: Boolean = false
private set private set
var isProtected: Boolean = false var isProtected: Boolean = false
@@ -42,10 +45,6 @@ class BinaryAttachment : Parcelable {
private var cipherEncryption: Cipher = Cipher.getInstance(Database.LoadedKey.BINARY_CIPHER) private var cipherEncryption: Cipher = Cipher.getInstance(Database.LoadedKey.BINARY_CIPHER)
private var cipherDecryption: Cipher = Cipher.getInstance(Database.LoadedKey.BINARY_CIPHER) private var cipherDecryption: Cipher = Cipher.getInstance(Database.LoadedKey.BINARY_CIPHER)
fun length(): Long {
return dataFile?.length() ?: 0
}
/** /**
* Empty protected binary * Empty protected binary
*/ */
@@ -53,6 +52,7 @@ class BinaryAttachment : Parcelable {
constructor(dataFile: File, compressed: Boolean = false, protected: Boolean = false) { constructor(dataFile: File, compressed: Boolean = false, protected: Boolean = false) {
this.dataFile = dataFile this.dataFile = dataFile
this.length = 0
this.isCompressed = compressed this.isCompressed = compressed
this.isProtected = protected this.isProtected = protected
} }
@@ -61,6 +61,7 @@ class BinaryAttachment : Parcelable {
parcel.readString()?.let { parcel.readString()?.let {
dataFile = File(it) dataFile = File(it)
} }
length = parcel.readLong()
isCompressed = parcel.readByte().toInt() != 0 isCompressed = parcel.readByte().toInt() != 0
isProtected = parcel.readByte().toInt() != 0 isProtected = parcel.readByte().toInt() != 0
isCorrupted = parcel.readByte().toInt() != 0 isCorrupted = parcel.readByte().toInt() != 0
@@ -68,31 +69,20 @@ class BinaryAttachment : Parcelable {
@Throws(IOException::class) @Throws(IOException::class)
fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream { fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream {
return when { return buildInputStream(dataFile!!, cipherKey)
length() > 0 -> {
cipherDecryption.init(Cipher.DECRYPT_MODE, cipherKey.key, cipherKey.iv)
CipherInputStream(FileInputStream(dataFile!!), cipherDecryption)
}
else -> ByteArrayInputStream(ByteArray(0))
}
}
@Throws(IOException::class)
fun getUnGzipInputDataStream(cipherKey: Database.LoadedKey): InputStream {
return if (isCompressed)
GZIPInputStream(getInputDataStream(cipherKey))
else
getInputDataStream(cipherKey)
} }
@Throws(IOException::class) @Throws(IOException::class)
fun getOutputDataStream(cipherKey: Database.LoadedKey): OutputStream { fun getOutputDataStream(cipherKey: Database.LoadedKey): OutputStream {
return when { return buildOutputStream(dataFile!!, cipherKey)
dataFile != null -> { }
cipherEncryption.init(Cipher.ENCRYPT_MODE, cipherKey.key, cipherKey.iv)
CipherOutputStream(FileOutputStream(dataFile!!), cipherEncryption) @Throws(IOException::class)
} fun getUnGzipInputDataStream(cipherKey: Database.LoadedKey): InputStream {
else -> throw IOException("Unable to write in an unknown file") return if (isCompressed) {
GZIPInputStream(getInputDataStream(cipherKey))
} else {
getInputDataStream(cipherKey)
} }
} }
@@ -105,6 +95,28 @@ class BinaryAttachment : Parcelable {
} }
} }
@Throws(IOException::class)
private fun buildInputStream(file: File?, cipherKey: Database.LoadedKey): InputStream {
return when {
file != null && file.length() > 0 -> {
cipherDecryption.init(Cipher.DECRYPT_MODE, cipherKey.key, cipherKey.iv)
CipherInputStream(FileInputStream(file), cipherDecryption)
}
else -> ByteArrayInputStream(ByteArray(0))
}
}
@Throws(IOException::class)
private fun buildOutputStream(file: File?, cipherKey: Database.LoadedKey): OutputStream {
return when {
file != null -> {
cipherEncryption.init(Cipher.ENCRYPT_MODE, cipherKey.key, cipherKey.iv)
BinaryCountingOutputStream(CipherOutputStream(FileOutputStream(file), cipherEncryption))
}
else -> throw IOException("Unable to write in an unknown file")
}
}
@Throws(IOException::class) @Throws(IOException::class)
fun compress(cipherKey: Database.LoadedKey, bufferSize: Int = DEFAULT_BUFFER_SIZE) { fun compress(cipherKey: Database.LoadedKey, bufferSize: Int = DEFAULT_BUFFER_SIZE) {
dataFile?.let { concreteDataFile -> dataFile?.let { concreteDataFile ->
@@ -112,8 +124,7 @@ class BinaryAttachment : Parcelable {
if (!isCompressed) { if (!isCompressed) {
// Encrypt the new gzipped temp file // Encrypt the new gzipped temp file
val fileBinaryCompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp") val fileBinaryCompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
cipherEncryption.init(Cipher.ENCRYPT_MODE, cipherKey.key, cipherKey.iv) GZIPOutputStream(buildOutputStream(fileBinaryCompress, cipherKey)).use { outputStream ->
GZIPOutputStream(CipherOutputStream(FileOutputStream(fileBinaryCompress), cipherEncryption)).use { outputStream ->
getInputDataStream(cipherKey).use { inputStream -> getInputDataStream(cipherKey).use { inputStream ->
inputStream.readAllBytes(bufferSize) { buffer -> inputStream.readAllBytes(bufferSize) { buffer ->
outputStream.write(buffer) outputStream.write(buffer)
@@ -137,8 +148,7 @@ class BinaryAttachment : Parcelable {
if (isCompressed) { if (isCompressed) {
// Encrypt the new ungzipped temp file // Encrypt the new ungzipped temp file
val fileBinaryDecompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp") val fileBinaryDecompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
cipherEncryption.init(Cipher.ENCRYPT_MODE, cipherKey.key, cipherKey.iv) buildOutputStream(fileBinaryDecompress, cipherKey).use { outputStream ->
CipherOutputStream(FileOutputStream(fileBinaryDecompress), cipherEncryption).use { outputStream ->
getUnGzipInputDataStream(cipherKey).use { inputStream -> getUnGzipInputDataStream(cipherKey).use { inputStream ->
inputStream.readAllBytes(bufferSize) { buffer -> inputStream.readAllBytes(bufferSize) { buffer ->
outputStream.write(buffer) outputStream.write(buffer)
@@ -171,7 +181,8 @@ class BinaryAttachment : Parcelable {
return false return false
var sameData = false var sameData = false
if (dataFile != null && dataFile == other.dataFile) if (dataFile != null && dataFile == other.dataFile
&& length == other.length)
sameData = true sameData = true
return isCompressed == other.isCompressed return isCompressed == other.isCompressed
@@ -187,6 +198,7 @@ class BinaryAttachment : Parcelable {
result = 31 * result + if (isProtected) 1 else 0 result = 31 * result + if (isProtected) 1 else 0
result = 31 * result + if (isCorrupted) 1 else 0 result = 31 * result + if (isCorrupted) 1 else 0
result = 31 * result + dataFile!!.hashCode() result = 31 * result + dataFile!!.hashCode()
result = 31 * result + length.hashCode()
return result return result
} }
@@ -200,11 +212,25 @@ class BinaryAttachment : Parcelable {
override fun writeToParcel(dest: Parcel, flags: Int) { override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeString(dataFile?.absolutePath) dest.writeString(dataFile?.absolutePath)
dest.writeLong(length)
dest.writeByte((if (isCompressed) 1 else 0).toByte()) dest.writeByte((if (isCompressed) 1 else 0).toByte())
dest.writeByte((if (isProtected) 1 else 0).toByte()) dest.writeByte((if (isProtected) 1 else 0).toByte())
dest.writeByte((if (isCorrupted) 1 else 0).toByte()) dest.writeByte((if (isCorrupted) 1 else 0).toByte())
} }
/**
* Custom OutputStream to calculate the size of binary file
*/
private inner class BinaryCountingOutputStream(out: OutputStream): CountingOutputStream(out) {
init {
length = 0
}
override fun close() {
super.close()
length = byteCount
}
}
companion object { companion object {
private val TAG = BinaryAttachment::class.java.name private val TAG = BinaryAttachment::class.java.name

View File

@@ -316,7 +316,7 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
var size = 0L var size = 0L
for ((label, poolId) in binaries) { for ((label, poolId) in binaries) {
size += label.length.toLong() size += label.length.toLong()
size += binaryPool[poolId]?.length() ?: 0 size += binaryPool[poolId]?.length ?: 0
} }
return size return size
} }

View File

@@ -147,7 +147,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
// Write type binary // Write type binary
dataOutputStream.writeByte(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary) dataOutputStream.writeByte(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary)
// Write size // Write size
dataOutputStream.writeUInt(UnsignedInt.fromKotlinLong(protectedBinary.length() + 1)) dataOutputStream.writeUInt(UnsignedInt.fromKotlinLong(protectedBinary.length + 1))
// Write protected flag // Write protected flag
var flag = DatabaseHeaderKDBX.KdbxBinaryFlags.None var flag = DatabaseHeaderKDBX.KdbxBinaryFlags.None
if (protectedBinary.isProtected) { if (protectedBinary.isProtected) {
@@ -502,7 +502,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
xml.startTag(null, DatabaseKDBXXML.ElemBinary) xml.startTag(null, DatabaseKDBXXML.ElemBinary)
xml.attribute(null, DatabaseKDBXXML.AttrId, index.toString()) xml.attribute(null, DatabaseKDBXXML.AttrId, index.toString())
val binary = keyBinary.binary val binary = keyBinary.binary
if (binary.length() > 0) { if (binary.length > 0) {
if (binary.isCompressed) { if (binary.isCompressed) {
xml.attribute(null, DatabaseKDBXXML.AttrCompressed, DatabaseKDBXXML.ValTrue) xml.attribute(null, DatabaseKDBXXML.AttrCompressed, DatabaseKDBXXML.ValTrue)
} }

View File

@@ -97,7 +97,7 @@ class EntryOutputKDB {
// Binary // Binary
mOutputStream.write(BINARY_DATA_FIELD_TYPE) mOutputStream.write(BINARY_DATA_FIELD_TYPE)
val binaryData = mEntry.binaryData val binaryData = mEntry.binaryData
val binaryDataLength = binaryData?.length() ?: 0L val binaryDataLength = binaryData?.length ?: 0L
// Write data length // Write data length
mOutputStream.write(uIntTo4Bytes(UnsignedInt.fromKotlinLong(binaryDataLength))) mOutputStream.write(uIntTo4Bytes(UnsignedInt.fromKotlinLong(binaryDataLength)))
// Write data // Write data

View File

@@ -373,7 +373,7 @@ class AttachmentFileNotificationService: LockNotificationService() {
bufferSize: Int = DEFAULT_BUFFER_SIZE, bufferSize: Int = DEFAULT_BUFFER_SIZE,
update: ((percent: Int)->Unit)? = null) { update: ((percent: Int)->Unit)? = null) {
var dataDownloaded = 0L var dataDownloaded = 0L
val fileSize = binaryAttachment.length() val fileSize = binaryAttachment.length
UriUtil.getUriOutputStream(contentResolver, attachmentToUploadUri)?.use { outputStream -> UriUtil.getUriOutputStream(contentResolver, attachmentToUploadUri)?.use { outputStream ->
Database.getInstance().loadedCipherKey?.let { binaryCipherKey -> Database.getInstance().loadedCipherKey?.let { binaryCipherKey ->
binaryAttachment.getUnGzipInputDataStream(binaryCipherKey).use { inputStream -> binaryAttachment.getUnGzipInputDataStream(binaryCipherKey).use { inputStream ->