mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Refactor HMAC methods
This commit is contained in:
@@ -17,17 +17,35 @@
|
|||||||
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.stream
|
package com.kunzisoft.keepass.database.crypto
|
||||||
|
|
||||||
import com.kunzisoft.encrypt.UnsignedLong
|
import com.kunzisoft.encrypt.UnsignedLong
|
||||||
import com.kunzisoft.encrypt.stream.NullOutputStream
|
import com.kunzisoft.encrypt.stream.NullOutputStream
|
||||||
import com.kunzisoft.encrypt.stream.write8BytesLong
|
import com.kunzisoft.encrypt.stream.write8BytesLong
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.security.DigestOutputStream
|
import java.security.DigestOutputStream
|
||||||
|
import java.security.InvalidKeyException
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
|
import javax.crypto.Mac
|
||||||
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
|
||||||
|
object HmacBlock {
|
||||||
|
|
||||||
|
fun getHmacSha256(blockKey: ByteArray): Mac {
|
||||||
|
val hmac: Mac
|
||||||
|
try {
|
||||||
|
hmac = Mac.getInstance("HmacSHA256")
|
||||||
|
val signingKey = SecretKeySpec(blockKey, "HmacSHA256")
|
||||||
|
hmac.init(signingKey)
|
||||||
|
} catch (e: NoSuchAlgorithmException) {
|
||||||
|
throw IOException("No HmacAlogirthm")
|
||||||
|
} catch (e: InvalidKeyException) {
|
||||||
|
throw IOException("Invalid Hmac Key")
|
||||||
|
}
|
||||||
|
return hmac
|
||||||
|
}
|
||||||
|
|
||||||
object HmacBlockStream {
|
|
||||||
fun getHmacKey64(key: ByteArray, blockIndex: UnsignedLong): ByteArray {
|
fun getHmacKey64(key: ByteArray, blockIndex: UnsignedLong): ByteArray {
|
||||||
val hash: MessageDigest
|
val hash: MessageDigest
|
||||||
try {
|
try {
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.database.crypto.kdf
|
package com.kunzisoft.keepass.database.crypto.kdf
|
||||||
|
|
||||||
import com.kunzisoft.encrypt.CryptoUtil
|
import com.kunzisoft.encrypt.HashManager
|
||||||
import com.kunzisoft.encrypt.UnsignedLong
|
import com.kunzisoft.encrypt.UnsignedLong
|
||||||
import com.kunzisoft.encrypt.aes.AESKeyTransformerFactory
|
import com.kunzisoft.encrypt.aes.AESKeyTransformerFactory
|
||||||
import com.kunzisoft.encrypt.stream.bytes16ToUuid
|
import com.kunzisoft.encrypt.stream.bytes16ToUuid
|
||||||
@@ -48,12 +48,12 @@ class AesKdf : KdfEngine() {
|
|||||||
|
|
||||||
var seed = kdfParameters.getByteArray(PARAM_SEED)
|
var seed = kdfParameters.getByteArray(PARAM_SEED)
|
||||||
if (seed != null && seed.size != 32) {
|
if (seed != null && seed.size != 32) {
|
||||||
seed = CryptoUtil.hashSha256(seed)
|
seed = HashManager.hashSha256(seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
var currentMasterKey = masterKey
|
var currentMasterKey = masterKey
|
||||||
if (currentMasterKey.size != 32) {
|
if (currentMasterKey.size != 32) {
|
||||||
currentMasterKey = CryptoUtil.hashSha256(currentMasterKey)
|
currentMasterKey = HashManager.hashSha256(currentMasterKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
val rounds = kdfParameters.getUInt64(PARAM_ROUNDS)?.toKotlinLong()
|
val rounds = kdfParameters.getUInt64(PARAM_ROUNDS)?.toKotlinLong()
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ package com.kunzisoft.keepass.database.element.database
|
|||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.util.Base64
|
import android.util.Base64
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.kunzisoft.encrypt.CryptoUtil
|
import com.kunzisoft.encrypt.HashManager
|
||||||
import com.kunzisoft.encrypt.UnsignedInt
|
import com.kunzisoft.encrypt.UnsignedInt
|
||||||
|
import com.kunzisoft.encrypt.stream.longTo8Bytes
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.database.action.node.NodeHandler
|
import com.kunzisoft.keepass.database.action.node.NodeHandler
|
||||||
import com.kunzisoft.keepass.database.crypto.AesEngine
|
import com.kunzisoft.keepass.database.crypto.AesEngine
|
||||||
@@ -56,9 +57,11 @@ import java.io.InputStream
|
|||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import javax.crypto.Mac
|
||||||
import javax.xml.XMLConstants
|
import javax.xml.XMLConstants
|
||||||
import javax.xml.parsers.DocumentBuilderFactory
|
import javax.xml.parsers.DocumentBuilderFactory
|
||||||
import javax.xml.parsers.ParserConfigurationException
|
import javax.xml.parsers.ParserConfigurationException
|
||||||
|
import kotlin.math.min
|
||||||
|
|
||||||
|
|
||||||
class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
||||||
@@ -362,13 +365,13 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
|
|
||||||
var transformedMasterKey = kdfEngine.transform(masterKey, keyDerivationFunctionParameters)
|
var transformedMasterKey = kdfEngine.transform(masterKey, keyDerivationFunctionParameters)
|
||||||
if (transformedMasterKey.size != 32) {
|
if (transformedMasterKey.size != 32) {
|
||||||
transformedMasterKey = CryptoUtil.hashSha256(transformedMasterKey)
|
transformedMasterKey = HashManager.hashSha256(transformedMasterKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
val cmpKey = ByteArray(65)
|
val cmpKey = ByteArray(65)
|
||||||
System.arraycopy(masterSeed, 0, cmpKey, 0, 32)
|
System.arraycopy(masterSeed, 0, cmpKey, 0, 32)
|
||||||
System.arraycopy(transformedMasterKey, 0, cmpKey, 32, 32)
|
System.arraycopy(transformedMasterKey, 0, cmpKey, 32, 32)
|
||||||
finalKey = CryptoUtil.resizeKey(cmpKey, 0, 64, dataEngine.keyLength())
|
finalKey = resizeKey(cmpKey, dataEngine.keyLength())
|
||||||
|
|
||||||
val messageDigest: MessageDigest
|
val messageDigest: MessageDigest
|
||||||
try {
|
try {
|
||||||
@@ -383,6 +386,49 @@ 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cbOut == hash.size) {
|
||||||
|
return hash
|
||||||
|
}
|
||||||
|
|
||||||
|
val ret = ByteArray(cbOut)
|
||||||
|
if (cbOut < hash.size) {
|
||||||
|
System.arraycopy(hash, 0, ret, 0, cbOut)
|
||||||
|
} else {
|
||||||
|
var pos = 0
|
||||||
|
var r: Long = 0
|
||||||
|
while (pos < cbOut) {
|
||||||
|
val hmac: Mac
|
||||||
|
try {
|
||||||
|
hmac = Mac.getInstance("HmacSHA256")
|
||||||
|
} catch (e: NoSuchAlgorithmException) {
|
||||||
|
throw RuntimeException(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
val pbR = longTo8Bytes(r)
|
||||||
|
val part = hmac.doFinal(pbR)
|
||||||
|
|
||||||
|
val copy = min(cbOut - pos, part.size)
|
||||||
|
System.arraycopy(part, 0, ret, pos, copy)
|
||||||
|
pos += copy
|
||||||
|
r++
|
||||||
|
|
||||||
|
Arrays.fill(part, 0.toByte())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Arrays.fill(hash, 0.toByte())
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
override fun loadXmlKeyFile(keyInputStream: InputStream): ByteArray? {
|
override fun loadXmlKeyFile(keyInputStream: InputStream): ByteArray? {
|
||||||
try {
|
try {
|
||||||
val documentBuilderFactory = DocumentBuilderFactory.newInstance()
|
val documentBuilderFactory = DocumentBuilderFactory.newInstance()
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.kunzisoft.encrypt.UnsignedInt
|
|||||||
import com.kunzisoft.encrypt.UnsignedLong
|
import com.kunzisoft.encrypt.UnsignedLong
|
||||||
import com.kunzisoft.encrypt.stream.*
|
import com.kunzisoft.encrypt.stream.*
|
||||||
import com.kunzisoft.keepass.database.action.node.NodeHandler
|
import com.kunzisoft.keepass.database.action.node.NodeHandler
|
||||||
|
import com.kunzisoft.keepass.database.crypto.HmacBlock
|
||||||
import com.kunzisoft.keepass.database.crypto.VariantDictionary
|
import com.kunzisoft.keepass.database.crypto.VariantDictionary
|
||||||
import com.kunzisoft.keepass.database.crypto.kdf.AesKdf
|
import com.kunzisoft.keepass.database.crypto.kdf.AesKdf
|
||||||
import com.kunzisoft.keepass.database.crypto.kdf.KdfFactory
|
import com.kunzisoft.keepass.database.crypto.kdf.KdfFactory
|
||||||
@@ -35,16 +36,13 @@ import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
|||||||
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
||||||
import com.kunzisoft.keepass.database.exception.VersionDatabaseException
|
import com.kunzisoft.keepass.database.exception.VersionDatabaseException
|
||||||
import com.kunzisoft.keepass.stream.CopyInputStream
|
import com.kunzisoft.keepass.stream.CopyInputStream
|
||||||
import com.kunzisoft.keepass.stream.HmacBlockStream
|
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.DigestInputStream
|
import java.security.DigestInputStream
|
||||||
import java.security.InvalidKeyException
|
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
import javax.crypto.Mac
|
import javax.crypto.Mac
|
||||||
import javax.crypto.spec.SecretKeySpec
|
|
||||||
|
|
||||||
class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader() {
|
class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader() {
|
||||||
var innerRandomStreamKey: ByteArray = ByteArray(32)
|
var innerRandomStreamKey: ByteArray = ByteArray(32)
|
||||||
@@ -327,19 +325,8 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
|||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun computeHeaderHmac(header: ByteArray, key: ByteArray): ByteArray {
|
fun computeHeaderHmac(header: ByteArray, key: ByteArray): ByteArray {
|
||||||
val blockKey = HmacBlockStream.getHmacKey64(key, UnsignedLong.MAX)
|
val blockKey = HmacBlock.getHmacKey64(key, UnsignedLong.MAX)
|
||||||
|
val hmac: Mac = HmacBlock.getHmacSha256(blockKey)
|
||||||
val hmac: Mac
|
|
||||||
try {
|
|
||||||
hmac = Mac.getInstance("HmacSHA256")
|
|
||||||
val signingKey = SecretKeySpec(blockKey, "HmacSHA256")
|
|
||||||
hmac.init(signingKey)
|
|
||||||
} catch (e: NoSuchAlgorithmException) {
|
|
||||||
throw IOException("No HmacAlogirthm")
|
|
||||||
} catch (e: InvalidKeyException) {
|
|
||||||
throw IOException("Invalid Hmac Key")
|
|
||||||
}
|
|
||||||
|
|
||||||
return hmac.doFinal(header)
|
return hmac.doFinal(header)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import com.kunzisoft.encrypt.UnsignedLong
|
|||||||
import com.kunzisoft.encrypt.stream.*
|
import com.kunzisoft.encrypt.stream.*
|
||||||
import com.kunzisoft.keepass.database.crypto.CipherEngine
|
import com.kunzisoft.keepass.database.crypto.CipherEngine
|
||||||
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
|
import com.kunzisoft.keepass.database.crypto.EncryptionAlgorithm
|
||||||
|
import com.kunzisoft.keepass.database.crypto.HmacBlock
|
||||||
import com.kunzisoft.keepass.database.element.Attachment
|
import com.kunzisoft.keepass.database.element.Attachment
|
||||||
import com.kunzisoft.keepass.database.element.DateInstant
|
import com.kunzisoft.keepass.database.element.DateInstant
|
||||||
import com.kunzisoft.keepass.database.element.DeletedObject
|
import com.kunzisoft.keepass.database.element.DeletedObject
|
||||||
@@ -60,6 +61,7 @@ import java.util.*
|
|||||||
import java.util.zip.GZIPInputStream
|
import java.util.zip.GZIPInputStream
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.CipherInputStream
|
import javax.crypto.CipherInputStream
|
||||||
|
import javax.crypto.Mac
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
class DatabaseInputKDBX(cacheDirectory: File,
|
class DatabaseInputKDBX(cacheDirectory: File,
|
||||||
@@ -181,7 +183,11 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
}
|
}
|
||||||
|
|
||||||
val hmacKey = mDatabase.hmacKey ?: throw LoadDatabaseException()
|
val hmacKey = mDatabase.hmacKey ?: throw LoadDatabaseException()
|
||||||
val headerHmac = DatabaseHeaderKDBX.computeHeaderHmac(pbHeader, hmacKey)
|
|
||||||
|
val blockKey = HmacBlock.getHmacKey64(hmacKey, UnsignedLong.MAX)
|
||||||
|
val hmac: Mac = HmacBlock.getHmacSha256(blockKey)
|
||||||
|
val headerHmac = hmac.doFinal(pbHeader)
|
||||||
|
|
||||||
val storedHmac = databaseInputStream.readBytesLength(32)
|
val storedHmac = databaseInputStream.readBytesLength(32)
|
||||||
if (storedHmac.size != 32) {
|
if (storedHmac.size != 32) {
|
||||||
throw InvalidCredentialsDatabaseException()
|
throw InvalidCredentialsDatabaseException()
|
||||||
|
|||||||
@@ -22,25 +22,23 @@ package com.kunzisoft.keepass.database.file.output
|
|||||||
import com.kunzisoft.encrypt.UnsignedInt
|
import com.kunzisoft.encrypt.UnsignedInt
|
||||||
import com.kunzisoft.encrypt.UnsignedLong
|
import com.kunzisoft.encrypt.UnsignedLong
|
||||||
import com.kunzisoft.encrypt.stream.*
|
import com.kunzisoft.encrypt.stream.*
|
||||||
|
import com.kunzisoft.keepass.database.crypto.HmacBlock
|
||||||
import com.kunzisoft.keepass.database.crypto.VariantDictionary
|
import com.kunzisoft.keepass.database.crypto.VariantDictionary
|
||||||
import com.kunzisoft.keepass.database.crypto.kdf.KdfParameters
|
import com.kunzisoft.keepass.database.crypto.kdf.KdfParameters
|
||||||
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
||||||
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
|
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
|
||||||
import com.kunzisoft.keepass.database.file.DatabaseHeader
|
import com.kunzisoft.keepass.database.file.DatabaseHeader
|
||||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX
|
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX
|
||||||
import com.kunzisoft.keepass.stream.HmacBlockStream
|
|
||||||
import com.kunzisoft.keepass.stream.MacOutputStream
|
import com.kunzisoft.keepass.stream.MacOutputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.security.DigestOutputStream
|
import java.security.DigestOutputStream
|
||||||
import java.security.InvalidKeyException
|
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
import javax.crypto.Mac
|
import javax.crypto.Mac
|
||||||
import javax.crypto.spec.SecretKeySpec
|
|
||||||
|
|
||||||
class DatabaseHeaderOutputKDBX @Throws(DatabaseOutputException::class)
|
class DatabaseHeaderOutputKDBX @Throws(IOException::class)
|
||||||
constructor(private val databaseKDBX: DatabaseKDBX,
|
constructor(private val databaseKDBX: DatabaseKDBX,
|
||||||
private val header: DatabaseHeaderKDBX,
|
private val header: DatabaseHeaderKDBX,
|
||||||
outputStream: OutputStream) {
|
outputStream: OutputStream) {
|
||||||
@@ -68,16 +66,7 @@ constructor(private val databaseKDBX: DatabaseKDBX,
|
|||||||
}
|
}
|
||||||
|
|
||||||
val hmacKey = databaseKDBX.hmacKey ?: throw DatabaseOutputException("HmacKey is not defined")
|
val hmacKey = databaseKDBX.hmacKey ?: throw DatabaseOutputException("HmacKey is not defined")
|
||||||
val hmac: Mac
|
val hmac: Mac = HmacBlock.getHmacSha256(HmacBlock.getHmacKey64(hmacKey, UnsignedLong.MAX))
|
||||||
try {
|
|
||||||
hmac = Mac.getInstance("HmacSHA256")
|
|
||||||
val signingKey = SecretKeySpec(HmacBlockStream.getHmacKey64(hmacKey, UnsignedLong.MAX), "HmacSHA256")
|
|
||||||
hmac.init(signingKey)
|
|
||||||
} catch (e: NoSuchAlgorithmException) {
|
|
||||||
throw DatabaseOutputException(e)
|
|
||||||
} catch (e: InvalidKeyException) {
|
|
||||||
throw DatabaseOutputException(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
dos = DigestOutputStream(outputStream, md)
|
dos = DigestOutputStream(outputStream, md)
|
||||||
mos = MacOutputStream(dos, hmac)
|
mos = MacOutputStream(dos, hmac)
|
||||||
|
|||||||
@@ -23,13 +23,11 @@ import com.kunzisoft.encrypt.UnsignedLong
|
|||||||
import com.kunzisoft.encrypt.stream.bytes4ToUInt
|
import com.kunzisoft.encrypt.stream.bytes4ToUInt
|
||||||
import com.kunzisoft.encrypt.stream.readBytesLength
|
import com.kunzisoft.encrypt.stream.readBytesLength
|
||||||
import com.kunzisoft.encrypt.stream.uLongTo8Bytes
|
import com.kunzisoft.encrypt.stream.uLongTo8Bytes
|
||||||
|
import com.kunzisoft.keepass.database.crypto.HmacBlock
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.InvalidKeyException
|
|
||||||
import java.security.NoSuchAlgorithmException
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.crypto.Mac
|
import javax.crypto.Mac
|
||||||
import javax.crypto.spec.SecretKeySpec
|
|
||||||
|
|
||||||
class HmacBlockInputStream(private val baseStream: InputStream, private val verify: Boolean, private val key: ByteArray) : InputStream() {
|
class HmacBlockInputStream(private val baseStream: InputStream, private val verify: Boolean, private val key: ByteArray) : InputStream() {
|
||||||
|
|
||||||
@@ -104,19 +102,8 @@ class HmacBlockInputStream(private val baseStream: InputStream, private val veri
|
|||||||
buffer = baseStream.readBytesLength(blockSize.toKotlinInt())
|
buffer = baseStream.readBytesLength(blockSize.toKotlinInt())
|
||||||
|
|
||||||
if (verify) {
|
if (verify) {
|
||||||
val cmpHmac: ByteArray
|
val blockKey = HmacBlock.getHmacKey64(key, blockIndex)
|
||||||
val blockKey = HmacBlockStream.getHmacKey64(key, blockIndex)
|
val hmac: Mac = HmacBlock.getHmacSha256(blockKey)
|
||||||
val hmac: Mac
|
|
||||||
try {
|
|
||||||
hmac = Mac.getInstance("HmacSHA256")
|
|
||||||
val signingKey = SecretKeySpec(blockKey, "HmacSHA256")
|
|
||||||
hmac.init(signingKey)
|
|
||||||
} catch (e: NoSuchAlgorithmException) {
|
|
||||||
throw IOException("Invalid Hmac")
|
|
||||||
} catch (e: InvalidKeyException) {
|
|
||||||
throw IOException("Invalid Hmac")
|
|
||||||
}
|
|
||||||
|
|
||||||
hmac.update(pbBlockIndex)
|
hmac.update(pbBlockIndex)
|
||||||
hmac.update(pbBlockSize)
|
hmac.update(pbBlockSize)
|
||||||
|
|
||||||
@@ -124,7 +111,7 @@ class HmacBlockInputStream(private val baseStream: InputStream, private val veri
|
|||||||
hmac.update(buffer)
|
hmac.update(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmpHmac = hmac.doFinal()
|
val cmpHmac: ByteArray = hmac.doFinal()
|
||||||
Arrays.fill(blockKey, 0.toByte())
|
Arrays.fill(blockKey, 0.toByte())
|
||||||
|
|
||||||
if (!cmpHmac.contentEquals(storedHmac)) {
|
if (!cmpHmac.contentEquals(storedHmac)) {
|
||||||
|
|||||||
@@ -23,12 +23,10 @@ import com.kunzisoft.encrypt.UnsignedInt
|
|||||||
import com.kunzisoft.encrypt.UnsignedLong
|
import com.kunzisoft.encrypt.UnsignedLong
|
||||||
import com.kunzisoft.encrypt.stream.uIntTo4Bytes
|
import com.kunzisoft.encrypt.stream.uIntTo4Bytes
|
||||||
import com.kunzisoft.encrypt.stream.uLongTo8Bytes
|
import com.kunzisoft.encrypt.stream.uLongTo8Bytes
|
||||||
|
import com.kunzisoft.keepass.database.crypto.HmacBlock
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.security.InvalidKeyException
|
|
||||||
import java.security.NoSuchAlgorithmException
|
|
||||||
import javax.crypto.Mac
|
import javax.crypto.Mac
|
||||||
import javax.crypto.spec.SecretKeySpec
|
|
||||||
|
|
||||||
class HmacBlockOutputStream(private val baseStream: OutputStream,
|
class HmacBlockOutputStream(private val baseStream: OutputStream,
|
||||||
private val key: ByteArray)
|
private val key: ByteArray)
|
||||||
@@ -90,20 +88,8 @@ class HmacBlockOutputStream(private val baseStream: OutputStream,
|
|||||||
val bufBlockIndex = uLongTo8Bytes(blockIndex)
|
val bufBlockIndex = uLongTo8Bytes(blockIndex)
|
||||||
val blockSizeBuf = uIntTo4Bytes(UnsignedInt(bufferPos))
|
val blockSizeBuf = uIntTo4Bytes(UnsignedInt(bufferPos))
|
||||||
|
|
||||||
val blockHmac: ByteArray
|
val blockKey = HmacBlock.getHmacKey64(key, blockIndex)
|
||||||
val blockKey = HmacBlockStream.getHmacKey64(key, blockIndex)
|
val hmac: Mac = HmacBlock.getHmacSha256(blockKey)
|
||||||
|
|
||||||
val hmac: Mac
|
|
||||||
try {
|
|
||||||
hmac = Mac.getInstance("HmacSHA256")
|
|
||||||
val signingKey = SecretKeySpec(blockKey, "HmacSHA256")
|
|
||||||
hmac.init(signingKey)
|
|
||||||
} catch (e: NoSuchAlgorithmException) {
|
|
||||||
throw IOException("Invalid Hmac")
|
|
||||||
} catch (e: InvalidKeyException) {
|
|
||||||
throw IOException("Invalid HMAC")
|
|
||||||
}
|
|
||||||
|
|
||||||
hmac.update(bufBlockIndex)
|
hmac.update(bufBlockIndex)
|
||||||
hmac.update(blockSizeBuf)
|
hmac.update(blockSizeBuf)
|
||||||
|
|
||||||
@@ -111,8 +97,7 @@ class HmacBlockOutputStream(private val baseStream: OutputStream,
|
|||||||
hmac.update(buffer, 0, bufferPos)
|
hmac.update(buffer, 0, bufferPos)
|
||||||
}
|
}
|
||||||
|
|
||||||
blockHmac = hmac.doFinal()
|
val blockHmac: ByteArray = hmac.doFinal()
|
||||||
|
|
||||||
baseStream.write(blockHmac)
|
baseStream.write(blockHmac)
|
||||||
baseStream.write(blockSizeBuf)
|
baseStream.write(blockSizeBuf)
|
||||||
|
|
||||||
|
|||||||
@@ -20,59 +20,12 @@
|
|||||||
package com.kunzisoft.encrypt
|
package com.kunzisoft.encrypt
|
||||||
|
|
||||||
import com.kunzisoft.encrypt.stream.NullOutputStream
|
import com.kunzisoft.encrypt.stream.NullOutputStream
|
||||||
import com.kunzisoft.encrypt.stream.longTo8Bytes
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.security.DigestOutputStream
|
import java.security.DigestOutputStream
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
import java.util.*
|
|
||||||
import javax.crypto.Mac
|
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
object CryptoUtil {
|
object HashManager {
|
||||||
|
|
||||||
fun resizeKey(inBytes: ByteArray, inOffset: Int, cbIn: Int, cbOut: Int): ByteArray {
|
|
||||||
if (cbOut == 0) return ByteArray(0)
|
|
||||||
|
|
||||||
val hash: ByteArray = if (cbOut <= 32) {
|
|
||||||
hashSha256(inBytes, inOffset, cbIn)
|
|
||||||
} else {
|
|
||||||
hashSha512(inBytes, inOffset, cbIn)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cbOut == hash.size) {
|
|
||||||
return hash
|
|
||||||
}
|
|
||||||
|
|
||||||
val ret = ByteArray(cbOut)
|
|
||||||
if (cbOut < hash.size) {
|
|
||||||
System.arraycopy(hash, 0, ret, 0, cbOut)
|
|
||||||
} else {
|
|
||||||
var pos = 0
|
|
||||||
var r: Long = 0
|
|
||||||
while (pos < cbOut) {
|
|
||||||
val hmac: Mac
|
|
||||||
try {
|
|
||||||
hmac = Mac.getInstance("HmacSHA256")
|
|
||||||
} catch (e: NoSuchAlgorithmException) {
|
|
||||||
throw RuntimeException(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
val pbR = longTo8Bytes(r)
|
|
||||||
val part = hmac.doFinal(pbR)
|
|
||||||
|
|
||||||
val copy = min(cbOut - pos, part.size)
|
|
||||||
System.arraycopy(part, 0, ret, pos, copy)
|
|
||||||
pos += copy
|
|
||||||
r++
|
|
||||||
|
|
||||||
Arrays.fill(part, 0.toByte())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Arrays.fill(hash, 0.toByte())
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hashSha256(data: ByteArray, offset: Int = 0, count: Int = data.size): ByteArray {
|
fun hashSha256(data: ByteArray, offset: Int = 0, count: Int = data.size): ByteArray {
|
||||||
return hashGen("SHA-256", data, offset, count)
|
return hashGen("SHA-256", data, offset, count)
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
package com.kunzisoft.encrypt.stream
|
package com.kunzisoft.encrypt.stream
|
||||||
|
|
||||||
import com.kunzisoft.encrypt.CrsAlgorithm
|
import com.kunzisoft.encrypt.CrsAlgorithm
|
||||||
import com.kunzisoft.encrypt.CryptoUtil
|
import com.kunzisoft.encrypt.HashManager
|
||||||
import org.bouncycastle.crypto.engines.ChaCha7539Engine
|
import org.bouncycastle.crypto.engines.ChaCha7539Engine
|
||||||
import org.bouncycastle.crypto.engines.Salsa20Engine
|
import org.bouncycastle.crypto.engines.Salsa20Engine
|
||||||
import org.bouncycastle.crypto.params.KeyParameter
|
import org.bouncycastle.crypto.params.KeyParameter
|
||||||
@@ -41,7 +41,7 @@ object StreamCipherFactory {
|
|||||||
|
|
||||||
private fun getSalsa20(key: ByteArray): StreamCipher {
|
private fun getSalsa20(key: ByteArray): StreamCipher {
|
||||||
// Build stream cipher key
|
// Build stream cipher key
|
||||||
val key32 = CryptoUtil.hashSha256(key)
|
val key32 = HashManager.hashSha256(key)
|
||||||
|
|
||||||
val keyParam = KeyParameter(key32)
|
val keyParam = KeyParameter(key32)
|
||||||
val ivParam = ParametersWithIV(keyParam, SALSA_IV)
|
val ivParam = ParametersWithIV(keyParam, SALSA_IV)
|
||||||
@@ -54,7 +54,7 @@ object StreamCipherFactory {
|
|||||||
|
|
||||||
private fun getChaCha20(key: ByteArray): StreamCipher {
|
private fun getChaCha20(key: ByteArray): StreamCipher {
|
||||||
// Build stream cipher key
|
// Build stream cipher key
|
||||||
val hash = CryptoUtil.hashSha512(key)
|
val hash = HashManager.hashSha512(key)
|
||||||
val key32 = ByteArray(32)
|
val key32 = ByteArray(32)
|
||||||
val iv = ByteArray(12)
|
val iv = ByteArray(12)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user