Add BinaryByte and BinaryFile

This commit is contained in:
J-Jamet
2021-03-18 13:20:35 +01:00
parent f080750545
commit 174e562dcb
8 changed files with 479 additions and 238 deletions

View File

@@ -3,7 +3,7 @@ package com.kunzisoft.keepass.tests.stream
import android.content.Context
import androidx.test.platform.app.InstrumentationRegistry
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.database.element.database.BinaryData
import com.kunzisoft.keepass.database.element.database.BinaryFile
import com.kunzisoft.keepass.stream.readAllBytes
import com.kunzisoft.keepass.utils.UriUtil
import junit.framework.TestCase.assertEquals
@@ -25,7 +25,7 @@ class BinaryDataTest {
private val loadedKey = Database.LoadedKey.generateNewCipherKey()
private fun saveBinary(asset: String, binaryData: BinaryData) {
private fun saveBinary(asset: String, binaryData: BinaryFile) {
context.assets.open(asset).use { assetInputStream ->
binaryData.getOutputDataStream(loadedKey).use { binaryOutputStream ->
assetInputStream.readAllBytes(DEFAULT_BUFFER_SIZE) { buffer ->
@@ -37,8 +37,8 @@ class BinaryDataTest {
@Test
fun testSaveTextInCache() {
val binaryA = BinaryData(fileA)
val binaryB = BinaryData(fileB)
val binaryA = BinaryFile(fileA)
val binaryB = BinaryFile(fileB)
saveBinary(TEST_TEXT_ASSET, binaryA)
saveBinary(TEST_TEXT_ASSET, binaryB)
assertEquals("Save text binary length failed.", binaryA.getSize(), binaryB.getSize())
@@ -47,8 +47,8 @@ class BinaryDataTest {
@Test
fun testSaveImageInCache() {
val binaryA = BinaryData(fileA)
val binaryB = BinaryData(fileB)
val binaryA = BinaryFile(fileA)
val binaryB = BinaryFile(fileB)
saveBinary(TEST_IMAGE_ASSET, binaryA)
saveBinary(TEST_IMAGE_ASSET, binaryB)
assertEquals("Save image binary length failed.", binaryA.getSize(), binaryB.getSize())
@@ -57,9 +57,9 @@ class BinaryDataTest {
@Test
fun testCompressText() {
val binaryA = BinaryData(fileA)
val binaryB = BinaryData(fileB)
val binaryC = BinaryData(fileC)
val binaryA = BinaryFile(fileA)
val binaryB = BinaryFile(fileB)
val binaryC = BinaryFile(fileC)
saveBinary(TEST_TEXT_ASSET, binaryA)
saveBinary(TEST_TEXT_ASSET, binaryB)
saveBinary(TEST_TEXT_ASSET, binaryC)
@@ -74,9 +74,9 @@ class BinaryDataTest {
@Test
fun testCompressImage() {
val binaryA = BinaryData(fileA)
var binaryB = BinaryData(fileB)
val binaryC = BinaryData(fileC)
val binaryA = BinaryFile(fileA)
var binaryB = BinaryFile(fileB)
val binaryC = BinaryFile(fileC)
saveBinary(TEST_IMAGE_ASSET, binaryA)
saveBinary(TEST_IMAGE_ASSET, binaryB)
saveBinary(TEST_IMAGE_ASSET, binaryC)
@@ -84,7 +84,7 @@ class BinaryDataTest {
binaryB.compress(loadedKey)
assertEquals("Compress image length failed.", binaryA.getSize(), binaryA.getSize())
assertEquals("Compress image failed.", binaryA.binaryHash(), binaryA.binaryHash())
binaryB = BinaryData(fileB, true)
binaryB = BinaryFile(fileB, true)
binaryB.decompress(loadedKey)
assertEquals("Decompress image length failed.", binaryB.getSize(), binaryC.getSize())
assertEquals("Decompress image failed.", binaryB.binaryHash(), binaryC.binaryHash())
@@ -92,7 +92,7 @@ class BinaryDataTest {
@Test
fun testReadText() {
val binaryA = BinaryData(fileA)
val binaryA = BinaryFile(fileA)
saveBinary(TEST_TEXT_ASSET, binaryA)
assert(streamAreEquals(context.assets.open(TEST_TEXT_ASSET),
binaryA.getInputDataStream(loadedKey)))
@@ -100,7 +100,7 @@ class BinaryDataTest {
@Test
fun testReadImage() {
val binaryA = BinaryData(fileA)
val binaryA = BinaryFile(fileA)
saveBinary(TEST_IMAGE_ASSET, binaryA)
assert(streamAreEquals(context.assets.open(TEST_IMAGE_ASSET),
binaryA.getInputDataStream(loadedKey)))

View File

@@ -21,6 +21,7 @@ package com.kunzisoft.keepass.database.element
import android.os.Parcel
import android.os.Parcelable
import com.kunzisoft.keepass.database.element.database.BinaryByte
import com.kunzisoft.keepass.database.element.database.BinaryData
@@ -29,7 +30,7 @@ data class Attachment(var name: String,
constructor(parcel: Parcel) : this(
parcel.readString() ?: "",
parcel.readParcelable(BinaryData::class.java.classLoader) ?: BinaryData()
parcel.readParcelable(BinaryData::class.java.classLoader) ?: BinaryByte()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {

View File

@@ -0,0 +1,153 @@
/*
* Copyright 2018 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.element.database
import android.os.Parcel
import android.os.Parcelable
import com.kunzisoft.keepass.database.element.Database
import java.io.*
class BinaryByte : BinaryData {
private var mDataByte: ByteArray = ByteArray(0)
/**
* Empty protected binary
*/
constructor() : super()
constructor(byteArray: ByteArray,
compressed: Boolean = false,
protected: Boolean = false) : super(compressed, protected) {
this.mDataByte = byteArray
}
constructor(parcel: Parcel) : super(parcel) {
val byteArray = ByteArray(parcel.readInt())
parcel.readByteArray(byteArray)
mDataByte = byteArray
}
@Throws(IOException::class)
override fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream {
return ByteArrayInputStream(mDataByte)
}
@Throws(IOException::class)
override fun getOutputDataStream(cipherKey: Database.LoadedKey): OutputStream {
return ByteOutputStream()
}
@Throws(IOException::class)
override fun getUnGzipInputDataStream(cipherKey: Database.LoadedKey): InputStream {
return getInputDataStream(cipherKey)
}
@Throws(IOException::class)
override fun getGzipOutputDataStream(cipherKey: Database.LoadedKey): OutputStream {
return getOutputDataStream(cipherKey)
}
@Throws(IOException::class)
override fun compress(cipherKey: Database.LoadedKey) {
// TODO compress
}
@Throws(IOException::class)
override fun decompress(cipherKey: Database.LoadedKey) {
// TODO decompress
}
@Throws(IOException::class)
override fun clear() {
mDataByte = ByteArray(0)
}
override fun dataExists(): Boolean {
return mDataByte.isNotEmpty()
}
override fun getSize(): Long {
return mDataByte.size.toLong()
}
/**
* Hash of the raw encrypted file in temp folder, only to compare binary data
*/
override fun binaryHash(): Int {
return if (dataExists())
mDataByte.contentHashCode()
else
0
}
override fun toString(): String {
return mDataByte.toString()
}
override fun writeToParcel(dest: Parcel, flags: Int) {
super.writeToParcel(dest, flags)
dest.writeInt(mDataByte.size)
dest.writeByteArray(mDataByte)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is BinaryByte) return false
if (!super.equals(other)) return false
if (!mDataByte.contentEquals(other.mDataByte)) return false
return true
}
override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + mDataByte.contentHashCode()
return result
}
/**
* Custom OutputStream to calculate the size and hash of binary file
*/
private inner class ByteOutputStream : ByteArrayOutputStream() {
override fun close() {
mDataByte = this.toByteArray()
super.close()
}
}
companion object {
private val TAG = BinaryByte::class.java.name
@JvmField
val CREATOR: Parcelable.Creator<BinaryByte> = object : Parcelable.Creator<BinaryByte> {
override fun createFromParcel(parcel: Parcel): BinaryByte {
return BinaryByte(parcel)
}
override fun newArray(size: Int): Array<BinaryByte?> {
return arrayOfNulls(size)
}
}
}
}

View File

@@ -21,278 +21,92 @@ package com.kunzisoft.keepass.database.element.database
import android.os.Parcel
import android.os.Parcelable
import android.util.Base64
import android.util.Base64InputStream
import android.util.Base64OutputStream
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.stream.readAllBytes
import org.apache.commons.io.output.CountingOutputStream
import java.io.*
import java.nio.ByteBuffer
import java.security.MessageDigest
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
import javax.crypto.Cipher
import javax.crypto.CipherInputStream
import javax.crypto.CipherOutputStream
import javax.crypto.spec.IvParameterSpec
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
class BinaryData : Parcelable {
abstract class BinaryData : Parcelable {
private var mDataFile: File? = null
private var mLength: Long = 0
private var mBinaryHash = 0
var isCompressed: Boolean = false
private set
protected set
var isProtected: Boolean = false
private set
protected set
var isCorrupted: Boolean = false
// Cipher to encrypt temp file
private var cipherEncryption: Cipher = Cipher.getInstance(Database.LoadedKey.BINARY_CIPHER)
private var cipherDecryption: Cipher = Cipher.getInstance(Database.LoadedKey.BINARY_CIPHER)
/**
* Empty protected binary
*/
constructor()
protected constructor()
constructor(dataFile: File, compressed: Boolean = false, protected: Boolean = false) {
this.mDataFile = dataFile
this.mLength = 0
protected constructor(compressed: Boolean = false, protected: Boolean = false) {
this.isCompressed = compressed
this.isProtected = protected
}
private constructor(parcel: Parcel) {
parcel.readString()?.let {
mDataFile = File(it)
}
mLength = parcel.readLong()
protected constructor(parcel: Parcel) {
isCompressed = parcel.readByte().toInt() != 0
isProtected = parcel.readByte().toInt() != 0
isCorrupted = parcel.readByte().toInt() != 0
}
@Throws(IOException::class)
fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream {
return buildInputStream(mDataFile, cipherKey)
}
abstract fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream
@Throws(IOException::class)
fun getOutputDataStream(cipherKey: Database.LoadedKey): OutputStream {
return buildOutputStream(mDataFile, cipherKey)
}
abstract fun getOutputDataStream(cipherKey: Database.LoadedKey): OutputStream
@Throws(IOException::class)
fun getUnGzipInputDataStream(cipherKey: Database.LoadedKey): InputStream {
return if (isCompressed) {
GZIPInputStream(getInputDataStream(cipherKey))
} else {
getInputDataStream(cipherKey)
}
}
abstract fun getUnGzipInputDataStream(cipherKey: Database.LoadedKey): InputStream
@Throws(IOException::class)
fun getGzipOutputDataStream(cipherKey: Database.LoadedKey): OutputStream {
return if (isCompressed) {
GZIPOutputStream(getOutputDataStream(cipherKey))
} else {
getOutputDataStream(cipherKey)
}
}
abstract fun getGzipOutputDataStream(cipherKey: Database.LoadedKey): OutputStream
@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, IvParameterSpec(cipherKey.iv))
Base64InputStream(CipherInputStream(FileInputStream(file), cipherDecryption), Base64.NO_WRAP)
}
else -> ByteArrayInputStream(ByteArray(0))
}
}
abstract fun compress(cipherKey: Database.LoadedKey)
@Throws(IOException::class)
private fun buildOutputStream(file: File?, cipherKey: Database.LoadedKey): OutputStream {
return when {
file != null -> {
cipherEncryption.init(Cipher.ENCRYPT_MODE, cipherKey.key, IvParameterSpec(cipherKey.iv))
BinaryCountingOutputStream(Base64OutputStream(CipherOutputStream(FileOutputStream(file), cipherEncryption), Base64.NO_WRAP))
}
else -> throw IOException("Unable to write in an unknown file")
}
}
abstract fun decompress(cipherKey: Database.LoadedKey)
@Throws(IOException::class)
fun compress(cipherKey: Database.LoadedKey) {
mDataFile?.let { concreteDataFile ->
// To compress, create a new binary with file
if (!isCompressed) {
// Encrypt the new gzipped temp file
val fileBinaryCompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
getInputDataStream(cipherKey).use { inputStream ->
GZIPOutputStream(buildOutputStream(fileBinaryCompress, cipherKey)).use { outputStream ->
inputStream.readAllBytes { buffer ->
outputStream.write(buffer)
}
}
}
// Remove ungzip file
if (concreteDataFile.delete()) {
if (fileBinaryCompress.renameTo(concreteDataFile)) {
// Harmonize with database compression
isCompressed = true
}
}
}
}
}
abstract fun clear()
@Throws(IOException::class)
fun decompress(cipherKey: Database.LoadedKey) {
mDataFile?.let { concreteDataFile ->
if (isCompressed) {
// Encrypt the new ungzipped temp file
val fileBinaryDecompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
getUnGzipInputDataStream(cipherKey).use { inputStream ->
buildOutputStream(fileBinaryDecompress, cipherKey).use { outputStream ->
inputStream.readAllBytes { buffer ->
outputStream.write(buffer)
}
}
}
// Remove gzip file
if (concreteDataFile.delete()) {
if (fileBinaryDecompress.renameTo(concreteDataFile)) {
// Harmonize with database compression
isCompressed = false
}
}
}
}
}
abstract fun dataExists(): Boolean
@Throws(IOException::class)
fun clear() {
if (mDataFile != null && !mDataFile!!.delete())
throw IOException("Unable to delete temp file " + mDataFile!!.absolutePath)
}
abstract fun getSize(): Long
fun dataExists(): Boolean {
return mDataFile != null && mLength > 0
}
fun getSize(): Long {
return mLength
}
/**
* Hash of the raw encrypted file in temp folder, only to compare binary data
*/
@Throws(FileNotFoundException::class)
fun binaryHash(): Int {
return mBinaryHash
}
override fun equals(other: Any?): Boolean {
if (this === other)
return true
if (other == null || javaClass != other.javaClass)
return false
if (other !is BinaryData)
return false
var sameData = false
if (mDataFile != null && mDataFile == other.mDataFile)
sameData = true
return isCompressed == other.isCompressed
&& isProtected == other.isProtected
&& isCorrupted == other.isCorrupted
&& sameData
}
override fun hashCode(): Int {
var result = 0
result = 31 * result + if (isCompressed) 1 else 0
result = 31 * result + if (isProtected) 1 else 0
result = 31 * result + if (isCorrupted) 1 else 0
result = 31 * result + mDataFile!!.hashCode()
result = 31 * result + mLength.hashCode()
return result
}
override fun toString(): String {
return mDataFile.toString()
}
abstract fun binaryHash(): Int
override fun describeContents(): Int {
return 0
}
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeString(mDataFile?.absolutePath)
dest.writeLong(mLength)
dest.writeByte((if (isCompressed) 1 else 0).toByte())
dest.writeByte((if (isProtected) 1 else 0).toByte())
dest.writeByte((if (isCorrupted) 1 else 0).toByte())
}
/**
* Custom OutputStream to calculate the size and hash of binary file
*/
private inner class BinaryCountingOutputStream(out: OutputStream): CountingOutputStream(out) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is BinaryData) return false
private val mMessageDigest: MessageDigest
init {
mLength = 0
mMessageDigest = MessageDigest.getInstance("MD5")
mBinaryHash = 0
if (isCompressed != other.isCompressed) return false
if (isProtected != other.isProtected) return false
if (isCorrupted != other.isCorrupted) return false
return true
}
override fun beforeWrite(n: Int) {
super.beforeWrite(n)
mLength = byteCount
}
override fun write(idx: Int) {
super.write(idx)
mMessageDigest.update(idx.toByte())
}
override fun write(bts: ByteArray) {
super.write(bts)
mMessageDigest.update(bts)
}
override fun write(bts: ByteArray, st: Int, end: Int) {
super.write(bts, st, end)
mMessageDigest.update(bts, st, end)
}
override fun close() {
super.close()
mLength = byteCount
val bytes = mMessageDigest.digest()
mBinaryHash = ByteBuffer.wrap(bytes).int
}
override fun hashCode(): Int {
var result = isCompressed.hashCode()
result = 31 * result + isProtected.hashCode()
result = 31 * result + isCorrupted.hashCode()
return result
}
companion object {
private val TAG = BinaryData::class.java.name
@JvmField
val CREATOR: Parcelable.Creator<BinaryData> = object : Parcelable.Creator<BinaryData> {
override fun createFromParcel(parcel: Parcel): BinaryData {
return BinaryData(parcel)
}
override fun newArray(size: Int): Array<BinaryData?> {
return arrayOfNulls(size)
}
}
}
}

View File

@@ -0,0 +1,273 @@
/*
* Copyright 2018 Jeremy Jamet / Kunzisoft.
*
* This file is part of KeePassDX.
*
* KeePassDX is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* KeePassDX is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.kunzisoft.keepass.database.element.database
import android.os.Parcel
import android.os.Parcelable
import android.util.Base64
import android.util.Base64InputStream
import android.util.Base64OutputStream
import com.kunzisoft.keepass.database.element.Database
import com.kunzisoft.keepass.stream.readAllBytes
import org.apache.commons.io.output.CountingOutputStream
import java.io.*
import java.nio.ByteBuffer
import java.security.MessageDigest
import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream
import javax.crypto.Cipher
import javax.crypto.CipherInputStream
import javax.crypto.CipherOutputStream
import javax.crypto.spec.IvParameterSpec
class BinaryFile : BinaryData {
private var mDataFile: File? = null
private var mLength: Long = 0
private var mBinaryHash = 0
// Cipher to encrypt temp file
@Transient
private var cipherEncryption: Cipher = Cipher.getInstance(Database.LoadedKey.BINARY_CIPHER)
@Transient
private var cipherDecryption: Cipher = Cipher.getInstance(Database.LoadedKey.BINARY_CIPHER)
constructor() : super()
constructor(dataFile: File,
compressed: Boolean = false,
protected: Boolean = false) : super(compressed, protected) {
this.mDataFile = dataFile
this.mLength = 0
this.mBinaryHash = 0
}
constructor(parcel: Parcel) : super(parcel) {
parcel.readString()?.let {
mDataFile = File(it)
}
mLength = parcel.readLong()
mBinaryHash = parcel.readInt()
}
@Throws(IOException::class)
override fun getInputDataStream(cipherKey: Database.LoadedKey): InputStream {
return buildInputStream(mDataFile, cipherKey)
}
@Throws(IOException::class)
override fun getOutputDataStream(cipherKey: Database.LoadedKey): OutputStream {
return buildOutputStream(mDataFile, cipherKey)
}
@Throws(IOException::class)
override fun getUnGzipInputDataStream(cipherKey: Database.LoadedKey): InputStream {
return if (isCompressed) {
GZIPInputStream(getInputDataStream(cipherKey))
} else {
getInputDataStream(cipherKey)
}
}
@Throws(IOException::class)
override fun getGzipOutputDataStream(cipherKey: Database.LoadedKey): OutputStream {
return if (isCompressed) {
GZIPOutputStream(getOutputDataStream(cipherKey))
} else {
getOutputDataStream(cipherKey)
}
}
@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, IvParameterSpec(cipherKey.iv))
Base64InputStream(CipherInputStream(FileInputStream(file), cipherDecryption), Base64.NO_WRAP)
}
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, IvParameterSpec(cipherKey.iv))
BinaryCountingOutputStream(Base64OutputStream(CipherOutputStream(FileOutputStream(file), cipherEncryption), Base64.NO_WRAP))
}
else -> throw IOException("Unable to write in an unknown file")
}
}
@Throws(IOException::class)
override fun compress(cipherKey: Database.LoadedKey) {
mDataFile?.let { concreteDataFile ->
// To compress, create a new binary with file
if (!isCompressed) {
// Encrypt the new gzipped temp file
val fileBinaryCompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
getInputDataStream(cipherKey).use { inputStream ->
GZIPOutputStream(buildOutputStream(fileBinaryCompress, cipherKey)).use { outputStream ->
inputStream.readAllBytes { buffer ->
outputStream.write(buffer)
}
}
}
// Remove ungzip file
if (concreteDataFile.delete()) {
if (fileBinaryCompress.renameTo(concreteDataFile)) {
// Harmonize with database compression
isCompressed = true
}
}
}
}
}
@Throws(IOException::class)
override fun decompress(cipherKey: Database.LoadedKey) {
mDataFile?.let { concreteDataFile ->
if (isCompressed) {
// Encrypt the new ungzipped temp file
val fileBinaryDecompress = File(concreteDataFile.parent, concreteDataFile.name + "_temp")
getUnGzipInputDataStream(cipherKey).use { inputStream ->
buildOutputStream(fileBinaryDecompress, cipherKey).use { outputStream ->
inputStream.readAllBytes { buffer ->
outputStream.write(buffer)
}
}
}
// Remove gzip file
if (concreteDataFile.delete()) {
if (fileBinaryDecompress.renameTo(concreteDataFile)) {
// Harmonize with database compression
isCompressed = false
}
}
}
}
}
@Throws(IOException::class)
override fun clear() {
if (mDataFile != null && !mDataFile!!.delete())
throw IOException("Unable to delete temp file " + mDataFile!!.absolutePath)
}
override fun dataExists(): Boolean {
return mDataFile != null && mLength > 0
}
override fun getSize(): Long {
return mLength
}
/**
* Hash of the raw encrypted file in temp folder, only to compare binary data
*/
@Throws(FileNotFoundException::class)
override fun binaryHash(): Int {
return mBinaryHash
}
override fun toString(): String {
return mDataFile.toString()
}
override fun writeToParcel(dest: Parcel, flags: Int) {
super.writeToParcel(dest, flags)
dest.writeString(mDataFile?.absolutePath)
dest.writeLong(mLength)
dest.writeInt(mBinaryHash)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is BinaryFile) return false
if (!super.equals(other)) return false
return mDataFile != null && mDataFile == other.mDataFile
}
override fun hashCode(): Int {
var result = super.hashCode()
result = 31 * result + (mDataFile?.hashCode() ?: 0)
result = 31 * result + mLength.hashCode()
result = 31 * result + mBinaryHash
return result
}
/**
* Custom OutputStream to calculate the size and hash of binary file
*/
private inner class BinaryCountingOutputStream(out: OutputStream): CountingOutputStream(out) {
private val mMessageDigest: MessageDigest
init {
mLength = 0
mMessageDigest = MessageDigest.getInstance("MD5")
mBinaryHash = 0
}
override fun beforeWrite(n: Int) {
super.beforeWrite(n)
mLength = byteCount
}
override fun write(idx: Int) {
super.write(idx)
mMessageDigest.update(idx.toByte())
}
override fun write(bts: ByteArray) {
super.write(bts)
mMessageDigest.update(bts)
}
override fun write(bts: ByteArray, st: Int, end: Int) {
super.write(bts, st, end)
mMessageDigest.update(bts, st, end)
}
override fun close() {
super.close()
mLength = byteCount
val bytes = mMessageDigest.digest()
mBinaryHash = ByteBuffer.wrap(bytes).int
}
}
companion object {
private val TAG = BinaryFile::class.java.name
@JvmField
val CREATOR: Parcelable.Creator<BinaryFile> = object : Parcelable.Creator<BinaryFile> {
override fun createFromParcel(parcel: Parcel): BinaryFile {
return BinaryFile(parcel)
}
override fun newArray(size: Int): Array<BinaryFile?> {
return arrayOfNulls(size)
}
}
}
}

View File

@@ -49,7 +49,7 @@ abstract class BinaryPool<T> {
protection: Boolean = false): KeyBinary<T> {
val fileInCache = File(cacheDirectory, "$poolId$creationId$binaryFileIncrement")
binaryFileIncrement++
val newBinaryFile = BinaryData(fileInCache, compression, protection)
val newBinaryFile = BinaryFile(fileInCache, compression, protection)
val newKey = put(key, newBinaryFile)
return KeyBinary(newBinaryFile, newKey)
}

View File

@@ -278,7 +278,7 @@ class DatabaseKDB : DatabaseVersioned<Int, UUID, GroupKDB, EntryKDB>() {
// Generate an unique new file
val fileInCache = File(cacheDirectory, binaryIncrement.toString())
binaryIncrement++
return BinaryData(fileInCache)
return BinaryFile(fileInCache)
}
companion object {

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.model
import android.os.Parcel
import android.os.Parcelable
import com.kunzisoft.keepass.database.element.Attachment
import com.kunzisoft.keepass.database.element.database.BinaryData
import com.kunzisoft.keepass.database.element.database.BinaryByte
import com.kunzisoft.keepass.utils.readEnum
import com.kunzisoft.keepass.utils.writeEnum
@@ -33,7 +33,7 @@ data class EntryAttachmentState(var attachment: Attachment,
var previewState: AttachmentState = AttachmentState.NULL) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readParcelable(Attachment::class.java.classLoader) ?: Attachment("", BinaryData()),
parcel.readParcelable(Attachment::class.java.classLoader) ?: Attachment("", BinaryByte()),
parcel.readEnum<StreamDirection>() ?: StreamDirection.DOWNLOAD,
parcel.readEnum<AttachmentState>() ?: AttachmentState.NULL,
parcel.readInt(),