Better hash implementation

This commit is contained in:
J-Jamet
2021-03-24 22:17:15 +01:00
parent a69d57a4f4
commit 6b17502694
6 changed files with 38 additions and 55 deletions

View File

@@ -33,7 +33,6 @@ import com.kunzisoft.keepass.database.element.node.NodeIdUUID
import com.kunzisoft.keepass.database.element.node.NodeVersioned
import java.io.IOException
import java.io.InputStream
import java.security.MessageDigest
import java.util.*
import kotlin.collections.ArrayList
@@ -141,16 +140,11 @@ class DatabaseKDB : DatabaseVersioned<Int, UUID, GroupKDB, EntryKDB>() {
}
@Throws(IOException::class)
fun makeFinalKey(masterSeed: ByteArray, masterSeed2: ByteArray, numRounds: Long) {
// Write checksum Checksum
val messageDigest: MessageDigest = HashManager.getHash256()
messageDigest.update(masterSeed)
fun makeFinalKey(masterSeed: ByteArray, transformSeed: ByteArray, numRounds: Long) {
// Encrypt the master key a few times to make brute-force key-search harder
val transformedKey = AESKeyTransformerFactory.transformMasterKey(masterSeed2, masterKey, numRounds) ?: ByteArray(0)
messageDigest.update(transformedKey)
finalKey = messageDigest.digest()
val transformedKey = AESKeyTransformerFactory.transformMasterKey(transformSeed, masterKey, numRounds) ?: ByteArray(0)
// Write checksum Checksum
finalKey = HashManager.hashSha256(masterSeed, transformedKey)
}
override fun createGroup(): GroupKDB {

View File

@@ -347,8 +347,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
masterKey = getFileKey(keyInputStream)
}
val messageDigest: MessageDigest = HashManager.getHash256()
return messageDigest.digest(masterKey)
return HashManager.hashSha256(masterKey)
}
@Throws(IOException::class)
@@ -383,11 +382,9 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
private fun resizeKey(inBytes: ByteArray, cbOut: Int): ByteArray {
if (cbOut == 0) return ByteArray(0)
val hash: ByteArray = if (cbOut <= 32) {
HashManager.hashSha256(inBytes, 0, 64)
} else {
HashManager.hashSha512(inBytes, 0, 64)
}
val messageDigest = if (cbOut <= 32) HashManager.getHash256() else HashManager.getHash512()
messageDigest.update(inBytes, 0, 64)
val hash: ByteArray = messageDigest.digest()
if (cbOut == hash.size) {
return hash
@@ -522,12 +519,9 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
private fun checkKeyFileHash(data: String, hash: String): Boolean {
var success = false
try {
val digest: MessageDigest = HashManager.getHash256()
digest.reset()
// hexadecimal encoding of the first 4 bytes of the SHA-256 hash of the key.
val dataDigest = digest.digest(Hex.decodeHex(data.toCharArray()))
.copyOfRange(0, 4)
.toHexString()
val dataDigest = HashManager.hashSha256(Hex.decodeHex(data.toCharArray()))
.copyOfRange(0, 4).toHexString()
success = dataDigest == hash
} catch (e: Exception) {
e.printStackTrace()

View File

@@ -100,10 +100,7 @@ abstract class DatabaseVersioned<
protected fun getCompositeKey(key: String, keyfileInputStream: InputStream): ByteArray {
val fileKey = getFileKey(keyfileInputStream)
val passwordKey = getPasswordKey(key)
val messageDigest: MessageDigest = HashManager.getHash256()
messageDigest.update(passwordKey)
return messageDigest.digest(fileKey)
return HashManager.hashSha256(passwordKey, fileKey)
}
@Throws(IOException::class)
@@ -113,10 +110,7 @@ abstract class DatabaseVersioned<
} catch (e: UnsupportedEncodingException) {
key.toByteArray()
}
val messageDigest: MessageDigest = HashManager.getHash256()
messageDigest.update(bKey)
return messageDigest.digest()
return HashManager.hashSha256(bKey)
}
@Throws(IOException::class)
@@ -138,10 +132,8 @@ abstract class DatabaseVersioned<
// Key is not base 64, treat it as binary data
}
}
// Hash file as binary data
val messageDigest = HashManager.getHash256()
return messageDigest.digest(keyData)
return HashManager.hashSha256(keyData)
}
protected open fun loadXmlKeyFile(keyInputStream: InputStream): ByteArray? {

View File

@@ -53,7 +53,6 @@ class HashedBlockInputStream(private val baseStream: InputStream) : InputStream(
if (!readHashedBlock()) {
return length - remaining
}
}
// Copy from buffer out
@@ -109,13 +108,12 @@ class HashedBlockInputStream(private val baseStream: InputStream) : InputStream(
throw IOException("Invalid data format")
}
val messageDigest: MessageDigest = HashManager.getHash256()
val computedHash = messageDigest.digest(buffer)
val computedHash = HashManager.hashSha256(buffer)
if (computedHash.size != HASH_SIZE) {
throw IOException("Hash wrong size")
}
if (!Arrays.equals(storedHash, computedHash)) {
if (!storedHash.contentEquals(computedHash)) {
throw IOException("Hashes didn't match.")
}

View File

@@ -39,22 +39,29 @@ object HashManager {
return messageDigest
}
fun hashSha256(data: ByteArray, offset: Int = 0, count: Int = data.size): ByteArray {
return hashGen("SHA-256", data, offset, count)
}
fun hashSha512(data: ByteArray, offset: Int = 0, count: Int = data.size): ByteArray {
return hashGen("SHA-512", data, offset, count)
}
private fun hashGen(transform: String, data: ByteArray, offset: Int, count: Int): ByteArray {
val hash: MessageDigest
try {
hash = MessageDigest.getInstance(transform)
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException(e)
fun hashSha256(vararg data: ByteArray): ByteArray {
val hash: MessageDigest = getHash256()
for (byteArray in data) {
hash.update(byteArray)
}
return hash.digest()
}
fun getHash512(): MessageDigest {
val messageDigest: MessageDigest
try {
messageDigest = MessageDigest.getInstance("SHA-256")
} catch (e: NoSuchAlgorithmException) {
throw IOException("SHA-256 not implemented here.", e)
}
return messageDigest
}
private fun hashSha512(vararg data: ByteArray): ByteArray {
val hash: MessageDigest = getHash512()
for (byteArray in data) {
hash.update(byteArray)
}
hash.update(data, offset, count)
return hash.digest()
}

View File

@@ -62,8 +62,6 @@ class AndroidAESKeyTransformer : KeyTransformer() {
}
// Hash the key
val messageDigest: MessageDigest = HashManager.getHash256()
messageDigest.update(newKey)
return messageDigest.digest()
return HashManager.hashSha256(newKey)
}
}