Better binary hash implementation

This commit is contained in:
J-Jamet
2021-03-17 22:17:14 +01:00
parent 3508f47842
commit 5aa1c70999
3 changed files with 41 additions and 26 deletions

View File

@@ -42,7 +42,7 @@ class BinaryFileTest {
saveBinary(TEST_TEXT_ASSET, binaryA)
saveBinary(TEST_TEXT_ASSET, binaryB)
assertEquals("Save text binary length failed.", binaryA.length, binaryB.length)
assertEquals("Save text binary MD5 failed.", binaryA.md5(), binaryB.md5())
assertEquals("Save text binary MD5 failed.", binaryA.binaryHash(), binaryB.binaryHash())
}
@Test
@@ -52,7 +52,7 @@ class BinaryFileTest {
saveBinary(TEST_IMAGE_ASSET, binaryA)
saveBinary(TEST_IMAGE_ASSET, binaryB)
assertEquals("Save image binary length failed.", binaryA.length, binaryB.length)
assertEquals("Save image binary failed.", binaryA.md5(), binaryB.md5())
assertEquals("Save image binary failed.", binaryA.binaryHash(), binaryB.binaryHash())
}
@Test
@@ -66,10 +66,10 @@ class BinaryFileTest {
binaryA.compress(loadedKey)
binaryB.compress(loadedKey)
assertEquals("Compress text length failed.", binaryA.length, binaryB.length)
assertEquals("Compress text MD5 failed.", binaryA.md5(), binaryB.md5())
assertEquals("Compress text MD5 failed.", binaryA.binaryHash(), binaryB.binaryHash())
binaryB.decompress(loadedKey)
assertEquals("Decompress text length failed.", binaryB.length, binaryC.length)
assertEquals("Decompress text MD5 failed.", binaryB.md5(), binaryC.md5())
assertEquals("Decompress text MD5 failed.", binaryB.binaryHash(), binaryC.binaryHash())
}
@Test
@@ -83,11 +83,11 @@ class BinaryFileTest {
binaryA.compress(loadedKey)
binaryB.compress(loadedKey)
assertEquals("Compress image length failed.", binaryA.length, binaryA.length)
assertEquals("Compress image failed.", binaryA.md5(), binaryA.md5())
assertEquals("Compress image failed.", binaryA.binaryHash(), binaryA.binaryHash())
binaryB = BinaryFile(fileB, true)
binaryB.decompress(loadedKey)
assertEquals("Decompress image length failed.", binaryB.length, binaryC.length)
assertEquals("Decompress image failed.", binaryB.md5(), binaryC.md5())
assertEquals("Decompress image failed.", binaryB.binaryHash(), binaryC.binaryHash())
}
@Test

View File

@@ -28,6 +28,7 @@ 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
@@ -41,6 +42,7 @@ class BinaryFile : Parcelable {
private var dataFile: File? = null
var length: Long = 0
private set
private var mBinaryHash = 0
var isCompressed: Boolean = false
private set
var isProtected: Boolean = false
@@ -182,23 +184,11 @@ class BinaryFile : Parcelable {
}
/**
* MD5 of the raw encrypted file in temp folder, only to compare binary data
* Hash of the raw encrypted file in temp folder, only to compare binary data
*/
@Throws(FileNotFoundException::class)
fun md5(): String {
val md = MessageDigest.getInstance("MD5")
if (dataFile == null)
return ""
return FileInputStream(dataFile).use { fis ->
val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
generateSequence {
when (val bytesRead = fis.read(buffer)) {
-1 -> null
else -> bytesRead
}
}.forEach { bytesRead -> md.update(buffer, 0, bytesRead) }
md.digest().joinToString("") { "%02x".format(it) }
}
fun binaryHash(): Int {
return mBinaryHash
}
override fun equals(other: Any?): Boolean {
@@ -247,11 +237,15 @@ class BinaryFile : Parcelable {
}
/**
* Custom OutputStream to calculate the size of binary file
* Custom OutputStream to calculate the size and hash of binary file
*/
private inner class BinaryCountingOutputStream(out: OutputStream): CountingOutputStream(out) {
private val mMessageDigest: MessageDigest
init {
length = 0
mMessageDigest = MessageDigest.getInstance("MD5")
mBinaryHash = 0
}
override fun beforeWrite(n: Int) {
@@ -259,9 +253,26 @@ class BinaryFile : Parcelable {
length = 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()
length = byteCount
val bytes = mMessageDigest.digest()
mBinaryHash = ByteBuffer.wrap(bytes).int
}
}

View File

@@ -125,10 +125,10 @@ abstract class BinaryPool<T> {
try {
binaryFile?.let {
if (it.length > 0) {
val searchBinaryMD5 = it.md5()
val searchBinaryMD5 = it.binaryHash()
var i = 0
for ((_, binary) in pool) {
if (binary.md5() == searchBinaryMD5) {
if (binary.binaryHash() == searchBinaryMD5) {
i++
if (i > 1)
return true
@@ -169,12 +169,16 @@ abstract class BinaryPool<T> {
val existentBinary =
try {
if (binary.length > 0) {
keyBinaryList.find { it.binary.md5() == binary.md5() }
keyBinaryList.find {
val hash0 = it.binary.binaryHash()
val hash1 = binary.binaryHash()
hash0 != 0 && hash1 != 0 && hash0 == hash1
}
} else {
null
}
} catch (e: Exception) {
Log.e(TAG, "Unable to check binary MD5", e)
Log.e(TAG, "Unable to check binary hash", e)
null
}
if (existentBinary == null) {