mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Fix length and better streams implementation
This commit is contained in:
@@ -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')
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 ->
|
||||||
|
|||||||
Reference in New Issue
Block a user