mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Refactor bytes utility methods
This commit is contained in:
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
package com.kunzisoft.keepass.tests
|
||||
|
||||
import junit.framework.TestCase
|
||||
|
||||
import com.kunzisoft.keepass.database.element.DateInstant
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import org.junit.Assert
|
||||
|
||||
class PwDateTest : TestCase() {
|
||||
|
||||
fun testDate() {
|
||||
val jDate = DateInstant(System.currentTimeMillis())
|
||||
val intermediate = DateInstant(jDate)
|
||||
val cDate = DatabaseInputOutputUtils.bytes5ToDate(DatabaseInputOutputUtils.dateToBytes(intermediate.date)!!, 0)
|
||||
|
||||
Assert.assertTrue("jDate and intermediate not equal", jDate == intermediate)
|
||||
Assert.assertTrue("jDate $jDate and cDate $cDate not equal", cDate == jDate)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
@@ -19,18 +19,15 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.tests
|
||||
|
||||
import com.kunzisoft.keepass.database.element.DateInstant
|
||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX.Companion.ULONG_MAX_VALUE
|
||||
import com.kunzisoft.keepass.stream.*
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.util.Calendar
|
||||
import java.util.Random
|
||||
|
||||
import junit.framework.TestCase
|
||||
import org.junit.Assert.assertArrayEquals
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.util.*
|
||||
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
|
||||
class DatabaseInputOutputUtilsTest : TestCase() {
|
||||
class StringDatabaseKDBUtilsTest : TestCase() {
|
||||
|
||||
fun testReadWriteLongZero() {
|
||||
testReadWriteLong(0.toByte())
|
||||
@@ -54,15 +51,9 @@ class DatabaseInputOutputUtilsTest : TestCase() {
|
||||
|
||||
private fun testReadWriteLong(value: Byte) {
|
||||
val orig = ByteArray(8)
|
||||
val dest = ByteArray(8)
|
||||
|
||||
setArray(orig, value, 0, 8)
|
||||
|
||||
val one = bytes64ToLong(orig, 0)
|
||||
writeLong(one, dest, 0)
|
||||
|
||||
assertArrayEquals(orig, dest)
|
||||
setArray(orig, value, 8)
|
||||
|
||||
assertArrayEquals(orig, longTo8Bytes(bytes64ToLong(orig)))
|
||||
}
|
||||
|
||||
fun testReadWriteIntZero() {
|
||||
@@ -79,24 +70,22 @@ class DatabaseInputOutputUtilsTest : TestCase() {
|
||||
|
||||
private fun testReadWriteInt(value: Byte) {
|
||||
val orig = ByteArray(4)
|
||||
val dest = ByteArray(4)
|
||||
|
||||
for (i in 0..3) {
|
||||
orig[i] = 0
|
||||
}
|
||||
|
||||
setArray(orig, value, 0, 4)
|
||||
setArray(orig, value, 4)
|
||||
|
||||
val one = bytes4ToInt(orig, 0)
|
||||
|
||||
writeInt(one, dest, 0)
|
||||
val one = bytes4ToInt(orig)
|
||||
val dest = intTo4Bytes(one)
|
||||
|
||||
assertArrayEquals(orig, dest)
|
||||
|
||||
}
|
||||
|
||||
private fun setArray(buf: ByteArray, value: Byte, offset: Int, size: Int) {
|
||||
for (i in offset until offset + size) {
|
||||
private fun setArray(buf: ByteArray, value: Byte, size: Int) {
|
||||
for (i in 0 until size) {
|
||||
buf[i] = value
|
||||
}
|
||||
}
|
||||
@@ -107,11 +96,10 @@ class DatabaseInputOutputUtilsTest : TestCase() {
|
||||
orig[0] = 0
|
||||
orig[1] = 1
|
||||
|
||||
val one = bytes2ToUShort(orig, 0)
|
||||
val dest = writeUShortBuf(one)
|
||||
val one = bytes2ToUShort(orig)
|
||||
val dest = uShortTo2Bytes(one)
|
||||
|
||||
assertArrayEquals(orig, dest)
|
||||
|
||||
}
|
||||
|
||||
fun testReadWriteShortMin() {
|
||||
@@ -124,15 +112,12 @@ class DatabaseInputOutputUtilsTest : TestCase() {
|
||||
|
||||
private fun testReadWriteShort(value: Byte) {
|
||||
val orig = ByteArray(2)
|
||||
val dest = ByteArray(2)
|
||||
setArray(orig, value, 2)
|
||||
|
||||
setArray(orig, value, 0, 2)
|
||||
|
||||
val one = bytes2ToUShort(orig, 0)
|
||||
writeUShort(one, dest, 0)
|
||||
val one = bytes2ToUShort(orig)
|
||||
val dest = uShortTo2Bytes(one)
|
||||
|
||||
assertArrayEquals(orig, dest)
|
||||
|
||||
}
|
||||
|
||||
fun testReadWriteByteZero() {
|
||||
@@ -148,16 +133,8 @@ class DatabaseInputOutputUtilsTest : TestCase() {
|
||||
}
|
||||
|
||||
private fun testReadWriteByte(value: Byte) {
|
||||
val orig = ByteArray(1)
|
||||
val dest = ByteArray(1)
|
||||
|
||||
setArray(orig, value, 0, 1)
|
||||
|
||||
val one = DatabaseInputOutputUtils.readUByte(orig, 0)
|
||||
DatabaseInputOutputUtils.writeUByte(one, dest, 0)
|
||||
|
||||
assertArrayEquals(orig, dest)
|
||||
|
||||
val dest: Byte = uIntToByte(byteToUInt(value))
|
||||
assert(value == dest)
|
||||
}
|
||||
|
||||
fun testDate() {
|
||||
@@ -167,27 +144,33 @@ class DatabaseInputOutputUtilsTest : TestCase() {
|
||||
expected.set(2008, 1, 2, 3, 4, 5)
|
||||
|
||||
val actual = Calendar.getInstance()
|
||||
DatabaseInputOutputUtils.dateToBytes(expected.time, cal)?.let { buf ->
|
||||
actual.time = DatabaseInputOutputUtils.bytes5ToDate(buf, 0, cal).date
|
||||
dateTo5Bytes(expected.time, cal)?.let { buf ->
|
||||
actual.time = bytes5ToDate(buf, cal).date
|
||||
}
|
||||
|
||||
val jDate = DateInstant(System.currentTimeMillis())
|
||||
val intermediate = DateInstant(jDate)
|
||||
val cDate = bytes5ToDate(dateTo5Bytes(intermediate.date)!!)
|
||||
|
||||
assertEquals("Year mismatch: ", 2008, actual.get(Calendar.YEAR))
|
||||
assertEquals("Month mismatch: ", 1, actual.get(Calendar.MONTH))
|
||||
assertEquals("Day mismatch: ", 2, actual.get(Calendar.DAY_OF_MONTH))
|
||||
assertEquals("Hour mismatch: ", 3, actual.get(Calendar.HOUR_OF_DAY))
|
||||
assertEquals("Minute mismatch: ", 4, actual.get(Calendar.MINUTE))
|
||||
assertEquals("Second mismatch: ", 5, actual.get(Calendar.SECOND))
|
||||
assertTrue("jDate and intermediate not equal", jDate == intermediate)
|
||||
assertTrue("jDate $jDate and cDate $cDate not equal", cDate == jDate)
|
||||
}
|
||||
|
||||
fun testUUID() {
|
||||
val bUUID = ByteArray(16)
|
||||
Random().nextBytes(bUUID)
|
||||
|
||||
val uuid = DatabaseInputOutputUtils.bytesToUuid(bUUID)
|
||||
val eUUID = DatabaseInputOutputUtils.uuidToBytes(uuid)
|
||||
val uuid = bytes16ToUuid(bUUID)
|
||||
val eUUID = uuidTo16Bytes(uuid)
|
||||
|
||||
val lUUID = bytes16ToUuid(bUUID, 0)
|
||||
val leUUID = DatabaseInputOutputUtils.uuidToBytes(lUUID)
|
||||
val lUUID = bytes16ToUuid(bUUID)
|
||||
val leUUID = uuidTo16Bytes(lUUID)
|
||||
|
||||
assertArrayEquals("UUID match failed", bUUID, eUUID)
|
||||
assertArrayEquals("UUID match failed", bUUID, leUUID)
|
||||
@@ -202,7 +185,7 @@ class DatabaseInputOutputUtilsTest : TestCase() {
|
||||
|
||||
val bos = ByteArrayOutputStream()
|
||||
val leos = LittleEndianDataOutputStream(bos)
|
||||
leos.writeLong(DatabaseInputOutputUtils.ULONG_MAX_VALUE)
|
||||
leos.writeLong(ULONG_MAX_VALUE)
|
||||
leos.close()
|
||||
|
||||
val uLongMax = bos.toByteArray()
|
||||
@@ -20,7 +20,7 @@
|
||||
package com.kunzisoft.keepass.crypto
|
||||
|
||||
import com.kunzisoft.keepass.stream.NullOutputStream
|
||||
import com.kunzisoft.keepass.stream.writeLongBuf
|
||||
import com.kunzisoft.keepass.stream.longTo8Bytes
|
||||
import java.io.IOException
|
||||
import java.security.DigestOutputStream
|
||||
import java.security.MessageDigest
|
||||
@@ -58,7 +58,7 @@ object CryptoUtil {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
|
||||
val pbR = writeLongBuf(r)
|
||||
val pbR = longTo8Bytes(r)
|
||||
val part = hmac.doFinal(pbR)
|
||||
|
||||
val copy = min(cbOut - pos, part.size)
|
||||
|
||||
@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.crypto.engine
|
||||
|
||||
import com.kunzisoft.keepass.crypto.CipherFactory
|
||||
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
||||
import java.security.InvalidAlgorithmParameterException
|
||||
import java.security.InvalidKeyException
|
||||
import java.security.NoSuchAlgorithmException
|
||||
@@ -47,7 +47,22 @@ class AesEngine : CipherEngine() {
|
||||
|
||||
companion object {
|
||||
|
||||
val CIPHER_UUID: UUID = DatabaseInputOutputUtils.bytesToUuid(
|
||||
byteArrayOf(0x31.toByte(), 0xC1.toByte(), 0xF2.toByte(), 0xE6.toByte(), 0xBF.toByte(), 0x71.toByte(), 0x43.toByte(), 0x50.toByte(), 0xBE.toByte(), 0x58.toByte(), 0x05.toByte(), 0x21.toByte(), 0x6A.toByte(), 0xFC.toByte(), 0x5A.toByte(), 0xFF.toByte()))
|
||||
val CIPHER_UUID: UUID = bytes16ToUuid(
|
||||
byteArrayOf(0x31.toByte(),
|
||||
0xC1.toByte(),
|
||||
0xF2.toByte(),
|
||||
0xE6.toByte(),
|
||||
0xBF.toByte(),
|
||||
0x71.toByte(),
|
||||
0x43.toByte(),
|
||||
0x50.toByte(),
|
||||
0xBE.toByte(),
|
||||
0x58.toByte(),
|
||||
0x05.toByte(),
|
||||
0x21.toByte(),
|
||||
0x6A.toByte(),
|
||||
0xFC.toByte(),
|
||||
0x5A.toByte(),
|
||||
0xFF.toByte()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
package com.kunzisoft.keepass.crypto.engine
|
||||
|
||||
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
||||
import org.spongycastle.jce.provider.BouncyCastleProvider
|
||||
import java.security.InvalidAlgorithmParameterException
|
||||
import java.security.InvalidKeyException
|
||||
@@ -50,7 +50,22 @@ class ChaCha20Engine : CipherEngine() {
|
||||
|
||||
companion object {
|
||||
|
||||
val CIPHER_UUID: UUID = DatabaseInputOutputUtils.bytesToUuid(
|
||||
byteArrayOf(0xD6.toByte(), 0x03.toByte(), 0x8A.toByte(), 0x2B.toByte(), 0x8B.toByte(), 0x6F.toByte(), 0x4C.toByte(), 0xB5.toByte(), 0xA5.toByte(), 0x24.toByte(), 0x33.toByte(), 0x9A.toByte(), 0x31.toByte(), 0xDB.toByte(), 0xB5.toByte(), 0x9A.toByte()))
|
||||
val CIPHER_UUID: UUID = bytes16ToUuid(
|
||||
byteArrayOf(0xD6.toByte(),
|
||||
0x03.toByte(),
|
||||
0x8A.toByte(),
|
||||
0x2B.toByte(),
|
||||
0x8B.toByte(),
|
||||
0x6F.toByte(),
|
||||
0x4C.toByte(),
|
||||
0xB5.toByte(),
|
||||
0xA5.toByte(),
|
||||
0x24.toByte(),
|
||||
0x33.toByte(),
|
||||
0x9A.toByte(),
|
||||
0x31.toByte(),
|
||||
0xDB.toByte(),
|
||||
0xB5.toByte(),
|
||||
0x9A.toByte()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,13 +21,11 @@ package com.kunzisoft.keepass.crypto.engine
|
||||
|
||||
import com.kunzisoft.keepass.crypto.CipherFactory
|
||||
import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
|
||||
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
||||
import java.security.InvalidAlgorithmParameterException
|
||||
import java.security.InvalidKeyException
|
||||
import java.security.NoSuchAlgorithmException
|
||||
import java.util.UUID
|
||||
|
||||
import java.util.*
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.NoSuchPaddingException
|
||||
import javax.crypto.spec.IvParameterSpec
|
||||
@@ -53,7 +51,22 @@ class TwofishEngine : CipherEngine() {
|
||||
|
||||
companion object {
|
||||
|
||||
val CIPHER_UUID: UUID = DatabaseInputOutputUtils.bytesToUuid(
|
||||
byteArrayOf(0xAD.toByte(), 0x68.toByte(), 0xF2.toByte(), 0x9F.toByte(), 0x57.toByte(), 0x6F.toByte(), 0x4B.toByte(), 0xB9.toByte(), 0xA3.toByte(), 0x6A.toByte(), 0xD4.toByte(), 0x7A.toByte(), 0xF9.toByte(), 0x65.toByte(), 0x34.toByte(), 0x6C.toByte()))
|
||||
val CIPHER_UUID: UUID = bytes16ToUuid(
|
||||
byteArrayOf(0xAD.toByte(),
|
||||
0x68.toByte(),
|
||||
0xF2.toByte(),
|
||||
0x9F.toByte(),
|
||||
0x57.toByte(),
|
||||
0x6F.toByte(),
|
||||
0x4B.toByte(),
|
||||
0xB9.toByte(),
|
||||
0xA3.toByte(),
|
||||
0x6A.toByte(),
|
||||
0xD4.toByte(),
|
||||
0x7A.toByte(),
|
||||
0xF9.toByte(),
|
||||
0x65.toByte(),
|
||||
0x34.toByte(),
|
||||
0x6C.toByte()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.content.res.Resources
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.crypto.CryptoUtil
|
||||
import com.kunzisoft.keepass.crypto.finalkey.FinalKeyFactory
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
||||
import java.io.IOException
|
||||
import java.security.SecureRandom
|
||||
import java.util.*
|
||||
@@ -88,7 +88,7 @@ class AesKdf internal constructor() : KdfEngine() {
|
||||
|
||||
private const val DEFAULT_ROUNDS = 6000
|
||||
|
||||
val CIPHER_UUID: UUID = DatabaseInputOutputUtils.bytesToUuid(
|
||||
val CIPHER_UUID: UUID = bytes16ToUuid(
|
||||
byteArrayOf(0xC9.toByte(),
|
||||
0xD9.toByte(),
|
||||
0xF3.toByte(),
|
||||
|
||||
@@ -21,7 +21,7 @@ package com.kunzisoft.keepass.crypto.keyDerivation
|
||||
|
||||
import android.content.res.Resources
|
||||
import com.kunzisoft.keepass.R
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
||||
import java.io.IOException
|
||||
import java.security.SecureRandom
|
||||
import java.util.*
|
||||
@@ -126,7 +126,7 @@ class Argon2Kdf internal constructor() : KdfEngine() {
|
||||
|
||||
companion object {
|
||||
|
||||
val CIPHER_UUID: UUID = DatabaseInputOutputUtils.bytesToUuid(
|
||||
val CIPHER_UUID: UUID = bytes16ToUuid(
|
||||
byteArrayOf(0xEF.toByte(),
|
||||
0x63.toByte(),
|
||||
0x6D.toByte(),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
@@ -19,20 +19,20 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.crypto.keyDerivation
|
||||
|
||||
import com.kunzisoft.keepass.utils.VariantDictionary
|
||||
import com.kunzisoft.keepass.stream.LittleEndianDataInputStream
|
||||
import com.kunzisoft.keepass.stream.LittleEndianDataOutputStream
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
|
||||
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
||||
import com.kunzisoft.keepass.stream.uuidTo16Bytes
|
||||
import com.kunzisoft.keepass.utils.VariantDictionary
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.IOException
|
||||
import java.util.UUID
|
||||
import java.util.*
|
||||
|
||||
class KdfParameters internal constructor(val uuid: UUID) : VariantDictionary() {
|
||||
|
||||
fun setParamUUID() {
|
||||
setByteArray(PARAM_UUID, DatabaseInputOutputUtils.uuidToBytes(uuid))
|
||||
setByteArray(PARAM_UUID, uuidTo16Bytes(uuid))
|
||||
}
|
||||
|
||||
companion object {
|
||||
@@ -46,7 +46,7 @@ class KdfParameters internal constructor(val uuid: UUID) : VariantDictionary() {
|
||||
|
||||
val d = deserialize(lis) ?: return null
|
||||
|
||||
val uuid = DatabaseInputOutputUtils.bytesToUuid(d.getByteArray(PARAM_UUID))
|
||||
val uuid = bytes16ToUuid(d.getByteArray(PARAM_UUID))
|
||||
|
||||
val kdfP = KdfParameters(uuid)
|
||||
kdfP.copyTo(d)
|
||||
|
||||
@@ -31,7 +31,6 @@ import com.kunzisoft.keepass.database.element.group.GroupKDBX
|
||||
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
||||
import com.kunzisoft.keepass.database.exception.VersionDatabaseException
|
||||
import com.kunzisoft.keepass.stream.*
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
@@ -241,12 +240,12 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
throw IOException("Invalid cipher ID.")
|
||||
}
|
||||
|
||||
databaseV4.dataCipher = DatabaseInputOutputUtils.bytesToUuid(pbId)
|
||||
databaseV4.dataCipher = bytes16ToUuid(pbId)
|
||||
}
|
||||
|
||||
private fun setTransformRound(roundsByte: ByteArray?) {
|
||||
private fun setTransformRound(roundsByte: ByteArray) {
|
||||
assignAesKdfEngineIfNotExists()
|
||||
val rounds = bytes64ToLong(roundsByte!!, 0)
|
||||
val rounds = bytes64ToLong(roundsByte)
|
||||
databaseV4.kdfParameters?.setUInt64(AesKdf.PARAM_ROUNDS, rounds)
|
||||
databaseV4.numberKeyEncryptionRounds = rounds
|
||||
}
|
||||
@@ -257,7 +256,7 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
throw IOException("Invalid compression flags.")
|
||||
}
|
||||
|
||||
val flag = bytes4ToInt(pbFlags, 0)
|
||||
val flag = bytes4ToInt(pbFlags)
|
||||
if (flag < 0 || flag >= CompressionAlgorithm.values().size) {
|
||||
throw IOException("Unrecognized compression flag.")
|
||||
}
|
||||
@@ -273,7 +272,7 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
throw IOException("Invalid stream id.")
|
||||
}
|
||||
|
||||
val id = bytes4ToInt(streamID, 0)
|
||||
val id = bytes4ToInt(streamID)
|
||||
if (id < 0 || id >= CrsAlgorithm.values().size) {
|
||||
throw IOException("Invalid stream id.")
|
||||
}
|
||||
@@ -293,6 +292,9 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
var ULONG_MAX_VALUE: Long = -1
|
||||
|
||||
const val DBSIG_PRE2 = -0x4ab4049a
|
||||
const val DBSIG_2 = -0x4ab40499
|
||||
|
||||
@@ -321,7 +323,7 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun computeHeaderHmac(header: ByteArray, key: ByteArray): ByteArray {
|
||||
val blockKey = HmacBlockStream.GetHmacKey64(key, DatabaseInputOutputUtils.ULONG_MAX_VALUE)
|
||||
val blockKey = HmacBlockStream.GetHmacKey64(key, ULONG_MAX_VALUE)
|
||||
|
||||
val hmac: Mac
|
||||
try {
|
||||
|
||||
@@ -43,7 +43,6 @@ import com.kunzisoft.keepass.database.file.DatabaseKDBXXML
|
||||
import com.kunzisoft.keepass.database.file.DateKDBXUtil
|
||||
import com.kunzisoft.keepass.stream.*
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import org.spongycastle.crypto.StreamCipher
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
import org.xmlpull.v1.XmlPullParserException
|
||||
@@ -823,7 +822,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
||||
buf = buf8
|
||||
}
|
||||
|
||||
val seconds = bytes64ToLong(buf, 0)
|
||||
val seconds = bytes64ToLong(buf)
|
||||
utcDate = DateKDBXUtil.convertKDBX4Time(seconds)
|
||||
|
||||
} else {
|
||||
@@ -883,7 +882,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
||||
}
|
||||
val buf = Base64.decode(encoded, BASE_64_FLAG)
|
||||
|
||||
return DatabaseInputOutputUtils.bytesToUuid(buf)
|
||||
return bytes16ToUuid(buf)
|
||||
}
|
||||
|
||||
@Throws(IOException::class, XmlPullParserException::class)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
package com.kunzisoft.keepass.database.file.output
|
||||
|
||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDB
|
||||
import com.kunzisoft.keepass.stream.writeIntBuf
|
||||
import com.kunzisoft.keepass.stream.intTo4Bytes
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
|
||||
@@ -29,14 +29,14 @@ class DatabaseHeaderOutputKDB(private val mHeader: DatabaseHeaderKDB,
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun outputStart() {
|
||||
mOutputStream.write(writeIntBuf(mHeader.signature1))
|
||||
mOutputStream.write(writeIntBuf(mHeader.signature2))
|
||||
mOutputStream.write(writeIntBuf(mHeader.flags))
|
||||
mOutputStream.write(writeIntBuf(mHeader.version))
|
||||
mOutputStream.write(intTo4Bytes(mHeader.signature1))
|
||||
mOutputStream.write(intTo4Bytes(mHeader.signature2))
|
||||
mOutputStream.write(intTo4Bytes(mHeader.flags))
|
||||
mOutputStream.write(intTo4Bytes(mHeader.version))
|
||||
mOutputStream.write(mHeader.masterSeed)
|
||||
mOutputStream.write(mHeader.encryptionIV)
|
||||
mOutputStream.write(writeIntBuf(mHeader.numGroups))
|
||||
mOutputStream.write(writeIntBuf(mHeader.numEntries))
|
||||
mOutputStream.write(intTo4Bytes(mHeader.numGroups))
|
||||
mOutputStream.write(intTo4Bytes(mHeader.numEntries))
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
@@ -47,7 +47,7 @@ class DatabaseHeaderOutputKDB(private val mHeader: DatabaseHeaderKDB,
|
||||
@Throws(IOException::class)
|
||||
fun outputEnd() {
|
||||
mOutputStream.write(mHeader.transformSeed)
|
||||
mOutputStream.write(writeIntBuf(mHeader.numKeyEncRounds))
|
||||
mOutputStream.write(intTo4Bytes(mHeader.numKeyEncRounds))
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
|
||||
@@ -24,8 +24,8 @@ import com.kunzisoft.keepass.database.element.database.DatabaseKDBX
|
||||
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
|
||||
import com.kunzisoft.keepass.database.file.DatabaseHeader
|
||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX
|
||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX.Companion.ULONG_MAX_VALUE
|
||||
import com.kunzisoft.keepass.stream.*
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import com.kunzisoft.keepass.utils.VariantDictionary
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.IOException
|
||||
@@ -62,7 +62,7 @@ constructor(private val db: DatabaseKDBX, private val header: DatabaseHeaderKDBX
|
||||
val hmac: Mac
|
||||
try {
|
||||
hmac = Mac.getInstance("HmacSHA256")
|
||||
val signingKey = SecretKeySpec(HmacBlockStream.GetHmacKey64(db.hmacKey, DatabaseInputOutputUtils.ULONG_MAX_VALUE), "HmacSHA256")
|
||||
val signingKey = SecretKeySpec(HmacBlockStream.GetHmacKey64(db.hmacKey, ULONG_MAX_VALUE), "HmacSHA256")
|
||||
hmac.init(signingKey)
|
||||
} catch (e: NoSuchAlgorithmException) {
|
||||
throw DatabaseOutputException(e)
|
||||
@@ -82,13 +82,13 @@ constructor(private val db: DatabaseKDBX, private val header: DatabaseHeaderKDBX
|
||||
los.writeUInt(DatabaseHeaderKDBX.DBSIG_2.toLong())
|
||||
los.writeUInt(header.version)
|
||||
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CipherID, DatabaseInputOutputUtils.uuidToBytes(db.dataCipher))
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CompressionFlags, writeIntBuf(DatabaseHeaderKDBX.getFlagFromCompression(db.compressionAlgorithm)))
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CipherID, uuidTo16Bytes(db.dataCipher))
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CompressionFlags, intTo4Bytes(DatabaseHeaderKDBX.getFlagFromCompression(db.compressionAlgorithm)))
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.MasterSeed, header.masterSeed)
|
||||
|
||||
if (header.version < DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.TransformSeed, header.transformSeed)
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.TransformRounds, writeLongBuf(db.numberKeyEncryptionRounds))
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.TransformRounds, longTo8Bytes(db.numberKeyEncryptionRounds))
|
||||
} else {
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.KdfParameters, KdfParameters.serialize(db.kdfParameters!!))
|
||||
}
|
||||
@@ -100,7 +100,7 @@ constructor(private val db: DatabaseKDBX, private val header: DatabaseHeaderKDBX
|
||||
if (header.version < DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.InnerRandomstreamKey, header.innerRandomStreamKey)
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.StreamStartBytes, header.streamStartBytes)
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.InnerRandomStreamID, writeIntBuf(header.innerRandomStream!!.id))
|
||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.InnerRandomStreamID, intTo4Bytes(header.innerRandomStream!!.id))
|
||||
}
|
||||
|
||||
if (db.containsPublicCustomData()) {
|
||||
|
||||
@@ -46,11 +46,7 @@ import com.kunzisoft.keepass.database.exception.UnknownKDF
|
||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX
|
||||
import com.kunzisoft.keepass.database.file.DatabaseKDBXXML
|
||||
import com.kunzisoft.keepass.database.file.DateKDBXUtil
|
||||
import com.kunzisoft.keepass.stream.HashedBlockOutputStream
|
||||
import com.kunzisoft.keepass.stream.HmacBlockOutputStream
|
||||
import com.kunzisoft.keepass.stream.readBytes
|
||||
import com.kunzisoft.keepass.stream.writeLongBuf
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import com.kunzisoft.keepass.stream.*
|
||||
import org.joda.time.DateTime
|
||||
import org.spongycastle.crypto.StreamCipher
|
||||
import org.xmlpull.v1.XmlSerializer
|
||||
@@ -393,7 +389,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
} else {
|
||||
val dt = DateTime(value)
|
||||
val seconds = DateKDBXUtil.convertDateToKDBX4Time(dt)
|
||||
val buf = writeLongBuf(seconds)
|
||||
val buf = longTo8Bytes(seconds)
|
||||
val b64 = String(Base64.encode(buf, BASE_64_FLAG))
|
||||
writeObject(name, b64)
|
||||
}
|
||||
@@ -417,7 +413,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
||||
|
||||
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
||||
private fun writeUuid(name: String, uuid: UUID) {
|
||||
val data = DatabaseInputOutputUtils.uuidToBytes(uuid)
|
||||
val data = uuidTo16Bytes(uuid)
|
||||
writeObject(name, String(Base64.encode(data, BASE_64_FLAG)))
|
||||
}
|
||||
|
||||
|
||||
@@ -21,12 +21,11 @@ package com.kunzisoft.keepass.database.file.output
|
||||
|
||||
import com.kunzisoft.keepass.database.element.database.DatabaseKDB
|
||||
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
||||
import com.kunzisoft.keepass.stream.readBytes
|
||||
import com.kunzisoft.keepass.stream.writeIntBuf
|
||||
import com.kunzisoft.keepass.stream.writeUShortBuf
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import com.kunzisoft.keepass.stream.*
|
||||
import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import java.nio.charset.Charset
|
||||
|
||||
class EntryOutputKDB
|
||||
/**
|
||||
@@ -49,54 +48,54 @@ class EntryOutputKDB
|
||||
// UUID
|
||||
mOutputStream.write(UUID_FIELD_TYPE)
|
||||
mOutputStream.write(UUID_FIELD_SIZE)
|
||||
mOutputStream.write(DatabaseInputOutputUtils.uuidToBytes(mEntry.id))
|
||||
mOutputStream.write(uuidTo16Bytes(mEntry.id))
|
||||
|
||||
// Group ID
|
||||
mOutputStream.write(GROUPID_FIELD_TYPE)
|
||||
mOutputStream.write(LONG_FOUR)
|
||||
mOutputStream.write(writeIntBuf(mEntry.parent!!.id))
|
||||
mOutputStream.write(intTo4Bytes(mEntry.parent!!.id))
|
||||
|
||||
// Image ID
|
||||
mOutputStream.write(IMAGEID_FIELD_TYPE)
|
||||
mOutputStream.write(LONG_FOUR)
|
||||
mOutputStream.write(writeIntBuf(mEntry.icon.iconId))
|
||||
mOutputStream.write(intTo4Bytes(mEntry.icon.iconId))
|
||||
|
||||
// Title
|
||||
//byte[] title = mEntry.title.getBytes("UTF-8");
|
||||
mOutputStream.write(TITLE_FIELD_TYPE)
|
||||
length += DatabaseInputOutputUtils.writeCString(mEntry.title, mOutputStream).toLong()
|
||||
length += StringDatabaseKDBUtils.writeStringToBytes(mEntry.title, mOutputStream).toLong()
|
||||
|
||||
// URL
|
||||
mOutputStream.write(URL_FIELD_TYPE)
|
||||
length += DatabaseInputOutputUtils.writeCString(mEntry.url, mOutputStream).toLong()
|
||||
length += StringDatabaseKDBUtils.writeStringToBytes(mEntry.url, mOutputStream).toLong()
|
||||
|
||||
// Username
|
||||
mOutputStream.write(USERNAME_FIELD_TYPE)
|
||||
length += DatabaseInputOutputUtils.writeCString(mEntry.username, mOutputStream).toLong()
|
||||
length += StringDatabaseKDBUtils.writeStringToBytes(mEntry.username, mOutputStream).toLong()
|
||||
|
||||
// Password
|
||||
mOutputStream.write(PASSWORD_FIELD_TYPE)
|
||||
length += DatabaseInputOutputUtils.writePassword(mEntry.password, mOutputStream).toLong()
|
||||
length += writePassword(mEntry.password, mOutputStream).toLong()
|
||||
|
||||
// Additional
|
||||
mOutputStream.write(ADDITIONAL_FIELD_TYPE)
|
||||
length += DatabaseInputOutputUtils.writeCString(mEntry.notes, mOutputStream).toLong()
|
||||
length += StringDatabaseKDBUtils.writeStringToBytes(mEntry.notes, mOutputStream).toLong()
|
||||
|
||||
// Create date
|
||||
writeDate(CREATE_FIELD_TYPE, DatabaseInputOutputUtils.dateToBytes(mEntry.creationTime.date))
|
||||
writeDate(CREATE_FIELD_TYPE, dateTo5Bytes(mEntry.creationTime.date))
|
||||
|
||||
// Modification date
|
||||
writeDate(MOD_FIELD_TYPE, DatabaseInputOutputUtils.dateToBytes(mEntry.lastModificationTime.date))
|
||||
writeDate(MOD_FIELD_TYPE, dateTo5Bytes(mEntry.lastModificationTime.date))
|
||||
|
||||
// Access date
|
||||
writeDate(ACCESS_FIELD_TYPE, DatabaseInputOutputUtils.dateToBytes(mEntry.lastAccessTime.date))
|
||||
writeDate(ACCESS_FIELD_TYPE, dateTo5Bytes(mEntry.lastAccessTime.date))
|
||||
|
||||
// Expiration date
|
||||
writeDate(EXPIRE_FIELD_TYPE, DatabaseInputOutputUtils.dateToBytes(mEntry.expiryTime.date))
|
||||
writeDate(EXPIRE_FIELD_TYPE, dateTo5Bytes(mEntry.expiryTime.date))
|
||||
|
||||
// Binary description
|
||||
mOutputStream.write(BINARY_DESC_FIELD_TYPE)
|
||||
length += DatabaseInputOutputUtils.writeCString(mEntry.binaryDescription, mOutputStream).toLong()
|
||||
length += StringDatabaseKDBUtils.writeStringToBytes(mEntry.binaryDescription, mOutputStream).toLong()
|
||||
|
||||
// Binary
|
||||
mOutputStream.write(BINARY_DATA_FIELD_TYPE)
|
||||
@@ -108,7 +107,7 @@ class EntryOutputKDB
|
||||
0 // TODO if length > UInt.maxvalue show exception
|
||||
}
|
||||
// Write data length
|
||||
mOutputStream.write(writeIntBuf(binaryDataLengthRightSize))
|
||||
mOutputStream.write(intTo4Bytes(binaryDataLengthRightSize))
|
||||
// Write data
|
||||
if (binaryDataLength > 0) {
|
||||
binaryData?.getInputDataStream().use { inputStream ->
|
||||
@@ -136,30 +135,40 @@ class EntryOutputKDB
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
private fun writePassword(str: String, os: OutputStream): Int {
|
||||
val initial = str.toByteArray(Charset.forName("UTF-8"))
|
||||
val length = initial.size + 1
|
||||
os.write(intTo4Bytes(length))
|
||||
os.write(initial)
|
||||
os.write(0x00)
|
||||
return length
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Constants
|
||||
val UUID_FIELD_TYPE:ByteArray = writeUShortBuf(1)
|
||||
val GROUPID_FIELD_TYPE:ByteArray = writeUShortBuf(2)
|
||||
val IMAGEID_FIELD_TYPE:ByteArray = writeUShortBuf(3)
|
||||
val TITLE_FIELD_TYPE:ByteArray = writeUShortBuf(4)
|
||||
val URL_FIELD_TYPE:ByteArray = writeUShortBuf(5)
|
||||
val USERNAME_FIELD_TYPE:ByteArray = writeUShortBuf(6)
|
||||
val PASSWORD_FIELD_TYPE:ByteArray = writeUShortBuf(7)
|
||||
val ADDITIONAL_FIELD_TYPE:ByteArray = writeUShortBuf(8)
|
||||
val CREATE_FIELD_TYPE:ByteArray = writeUShortBuf(9)
|
||||
val MOD_FIELD_TYPE:ByteArray = writeUShortBuf(10)
|
||||
val ACCESS_FIELD_TYPE:ByteArray = writeUShortBuf(11)
|
||||
val EXPIRE_FIELD_TYPE:ByteArray = writeUShortBuf(12)
|
||||
val BINARY_DESC_FIELD_TYPE:ByteArray = writeUShortBuf(13)
|
||||
val BINARY_DATA_FIELD_TYPE:ByteArray = writeUShortBuf(14)
|
||||
val END_FIELD_TYPE:ByteArray = writeUShortBuf(0xFFFF)
|
||||
val LONG_FOUR:ByteArray = writeIntBuf(4)
|
||||
val UUID_FIELD_SIZE:ByteArray = writeIntBuf(16)
|
||||
val DATE_FIELD_SIZE:ByteArray = writeIntBuf(5)
|
||||
val UUID_FIELD_TYPE:ByteArray = uShortTo2Bytes(1)
|
||||
val GROUPID_FIELD_TYPE:ByteArray = uShortTo2Bytes(2)
|
||||
val IMAGEID_FIELD_TYPE:ByteArray = uShortTo2Bytes(3)
|
||||
val TITLE_FIELD_TYPE:ByteArray = uShortTo2Bytes(4)
|
||||
val URL_FIELD_TYPE:ByteArray = uShortTo2Bytes(5)
|
||||
val USERNAME_FIELD_TYPE:ByteArray = uShortTo2Bytes(6)
|
||||
val PASSWORD_FIELD_TYPE:ByteArray = uShortTo2Bytes(7)
|
||||
val ADDITIONAL_FIELD_TYPE:ByteArray = uShortTo2Bytes(8)
|
||||
val CREATE_FIELD_TYPE:ByteArray = uShortTo2Bytes(9)
|
||||
val MOD_FIELD_TYPE:ByteArray = uShortTo2Bytes(10)
|
||||
val ACCESS_FIELD_TYPE:ByteArray = uShortTo2Bytes(11)
|
||||
val EXPIRE_FIELD_TYPE:ByteArray = uShortTo2Bytes(12)
|
||||
val BINARY_DESC_FIELD_TYPE:ByteArray = uShortTo2Bytes(13)
|
||||
val BINARY_DATA_FIELD_TYPE:ByteArray = uShortTo2Bytes(14)
|
||||
val END_FIELD_TYPE:ByteArray = uShortTo2Bytes(0xFFFF)
|
||||
val LONG_FOUR:ByteArray = intTo4Bytes(4)
|
||||
val UUID_FIELD_SIZE:ByteArray = intTo4Bytes(16)
|
||||
val DATE_FIELD_SIZE:ByteArray = intTo4Bytes(5)
|
||||
val IMAGEID_FIELD_SIZE:ByteArray = LONG_FOUR
|
||||
val LEVEL_FIELD_SIZE:ByteArray = LONG_FOUR
|
||||
val FLAGS_FIELD_SIZE:ByteArray = LONG_FOUR
|
||||
val ZERO_FIELD_SIZE:ByteArray = writeIntBuf(0)
|
||||
val ZERO_FIELD_SIZE:ByteArray = intTo4Bytes(0)
|
||||
val ZERO_FIVE:ByteArray = byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,10 @@
|
||||
package com.kunzisoft.keepass.database.file.output
|
||||
|
||||
import com.kunzisoft.keepass.database.element.group.GroupKDB
|
||||
import com.kunzisoft.keepass.stream.writeIntBuf
|
||||
import com.kunzisoft.keepass.stream.writeUShortBuf
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import com.kunzisoft.keepass.stream.dateTo5Bytes
|
||||
import com.kunzisoft.keepass.stream.intTo4Bytes
|
||||
import com.kunzisoft.keepass.stream.uShortTo2Bytes
|
||||
import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
|
||||
@@ -38,46 +39,46 @@ class GroupOutputKDB (private val mGroup: GroupKDB, private val mOutputStream: O
|
||||
// Group ID
|
||||
mOutputStream.write(GROUPID_FIELD_TYPE)
|
||||
mOutputStream.write(GROUPID_FIELD_SIZE)
|
||||
mOutputStream.write(writeIntBuf(mGroup.id))
|
||||
mOutputStream.write(intTo4Bytes(mGroup.id))
|
||||
|
||||
// Name
|
||||
mOutputStream.write(NAME_FIELD_TYPE)
|
||||
DatabaseInputOutputUtils.writeCString(mGroup.title, mOutputStream)
|
||||
StringDatabaseKDBUtils.writeStringToBytes(mGroup.title, mOutputStream)
|
||||
|
||||
// Create date
|
||||
mOutputStream.write(CREATE_FIELD_TYPE)
|
||||
mOutputStream.write(DATE_FIELD_SIZE)
|
||||
mOutputStream.write(DatabaseInputOutputUtils.dateToBytes(mGroup.creationTime.date))
|
||||
mOutputStream.write(dateTo5Bytes(mGroup.creationTime.date))
|
||||
|
||||
// Modification date
|
||||
mOutputStream.write(MOD_FIELD_TYPE)
|
||||
mOutputStream.write(DATE_FIELD_SIZE)
|
||||
mOutputStream.write(DatabaseInputOutputUtils.dateToBytes(mGroup.lastModificationTime.date))
|
||||
mOutputStream.write(dateTo5Bytes(mGroup.lastModificationTime.date))
|
||||
|
||||
// Access date
|
||||
mOutputStream.write(ACCESS_FIELD_TYPE)
|
||||
mOutputStream.write(DATE_FIELD_SIZE)
|
||||
mOutputStream.write(DatabaseInputOutputUtils.dateToBytes(mGroup.lastAccessTime.date))
|
||||
mOutputStream.write(dateTo5Bytes(mGroup.lastAccessTime.date))
|
||||
|
||||
// Expiration date
|
||||
mOutputStream.write(EXPIRE_FIELD_TYPE)
|
||||
mOutputStream.write(DATE_FIELD_SIZE)
|
||||
mOutputStream.write(DatabaseInputOutputUtils.dateToBytes(mGroup.expiryTime.date))
|
||||
mOutputStream.write(dateTo5Bytes(mGroup.expiryTime.date))
|
||||
|
||||
// Image ID
|
||||
mOutputStream.write(IMAGEID_FIELD_TYPE)
|
||||
mOutputStream.write(IMAGEID_FIELD_SIZE)
|
||||
mOutputStream.write(writeIntBuf(mGroup.icon.iconId))
|
||||
mOutputStream.write(intTo4Bytes(mGroup.icon.iconId))
|
||||
|
||||
// Level
|
||||
mOutputStream.write(LEVEL_FIELD_TYPE)
|
||||
mOutputStream.write(LEVEL_FIELD_SIZE)
|
||||
mOutputStream.write(writeUShortBuf(mGroup.level))
|
||||
mOutputStream.write(uShortTo2Bytes(mGroup.level))
|
||||
|
||||
// Flags
|
||||
mOutputStream.write(FLAGS_FIELD_TYPE)
|
||||
mOutputStream.write(FLAGS_FIELD_SIZE)
|
||||
mOutputStream.write(writeIntBuf(mGroup.flags))
|
||||
mOutputStream.write(intTo4Bytes(mGroup.flags))
|
||||
|
||||
// End
|
||||
mOutputStream.write(END_FIELD_TYPE)
|
||||
@@ -86,23 +87,23 @@ class GroupOutputKDB (private val mGroup: GroupKDB, private val mOutputStream: O
|
||||
|
||||
companion object {
|
||||
// Constants
|
||||
val GROUPID_FIELD_TYPE: ByteArray = writeUShortBuf(1)
|
||||
val NAME_FIELD_TYPE:ByteArray = writeUShortBuf(2)
|
||||
val CREATE_FIELD_TYPE:ByteArray = writeUShortBuf(3)
|
||||
val MOD_FIELD_TYPE:ByteArray = writeUShortBuf(4)
|
||||
val ACCESS_FIELD_TYPE:ByteArray = writeUShortBuf(5)
|
||||
val EXPIRE_FIELD_TYPE:ByteArray = writeUShortBuf(6)
|
||||
val IMAGEID_FIELD_TYPE:ByteArray = writeUShortBuf(7)
|
||||
val LEVEL_FIELD_TYPE:ByteArray = writeUShortBuf(8)
|
||||
val FLAGS_FIELD_TYPE:ByteArray = writeUShortBuf(9)
|
||||
val END_FIELD_TYPE:ByteArray = writeUShortBuf(0xFFFF)
|
||||
val LONG_FOUR:ByteArray = writeIntBuf(4)
|
||||
val GROUPID_FIELD_TYPE: ByteArray = uShortTo2Bytes(1)
|
||||
val NAME_FIELD_TYPE:ByteArray = uShortTo2Bytes(2)
|
||||
val CREATE_FIELD_TYPE:ByteArray = uShortTo2Bytes(3)
|
||||
val MOD_FIELD_TYPE:ByteArray = uShortTo2Bytes(4)
|
||||
val ACCESS_FIELD_TYPE:ByteArray = uShortTo2Bytes(5)
|
||||
val EXPIRE_FIELD_TYPE:ByteArray = uShortTo2Bytes(6)
|
||||
val IMAGEID_FIELD_TYPE:ByteArray = uShortTo2Bytes(7)
|
||||
val LEVEL_FIELD_TYPE:ByteArray = uShortTo2Bytes(8)
|
||||
val FLAGS_FIELD_TYPE:ByteArray = uShortTo2Bytes(9)
|
||||
val END_FIELD_TYPE:ByteArray = uShortTo2Bytes(0xFFFF)
|
||||
val LONG_FOUR:ByteArray = intTo4Bytes(4)
|
||||
val GROUPID_FIELD_SIZE:ByteArray = LONG_FOUR
|
||||
val DATE_FIELD_SIZE:ByteArray = writeIntBuf(5)
|
||||
val DATE_FIELD_SIZE:ByteArray = intTo4Bytes(5)
|
||||
val IMAGEID_FIELD_SIZE:ByteArray = LONG_FOUR
|
||||
val LEVEL_FIELD_SIZE:ByteArray = writeIntBuf(2)
|
||||
val LEVEL_FIELD_SIZE:ByteArray = intTo4Bytes(2)
|
||||
val FLAGS_FIELD_SIZE:ByteArray = LONG_FOUR
|
||||
val ZERO_FIELD_SIZE:ByteArray = writeIntBuf(0)
|
||||
val ZERO_FIELD_SIZE:ByteArray = intTo4Bytes(0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
@@ -19,16 +19,16 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.database.search;
|
||||
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.kunzisoft.keepass.stream.StreamBytesUtilsKt.uuidTo16Bytes;
|
||||
|
||||
public class UuidUtil {
|
||||
|
||||
public static String toHexString(UUID uuid) {
|
||||
if (uuid == null) { return null; }
|
||||
|
||||
byte[] buf = DatabaseInputOutputUtils.INSTANCE.uuidToBytes(uuid);
|
||||
byte[] buf = uuidTo16Bytes(uuid);
|
||||
|
||||
int len = buf.length;
|
||||
if (len == 0) { return ""; }
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.stream
|
||||
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.security.MessageDigest
|
||||
@@ -145,7 +144,7 @@ class HashedBlockInputStream(inputStream: InputStream) : InputStream() {
|
||||
if (!readHashedBlock()) return -1
|
||||
}
|
||||
|
||||
val output = DatabaseInputOutputUtils.readUByte(buffer, bufferPos)
|
||||
val output = byteToUInt(buffer[bufferPos])
|
||||
bufferPos++
|
||||
|
||||
return output
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
package com.kunzisoft.keepass.stream
|
||||
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.security.InvalidKeyException
|
||||
@@ -44,7 +43,7 @@ class HmacBlockInputStream(baseStream: InputStream, private val verify: Boolean,
|
||||
if (!readSafeBlock()) return -1
|
||||
}
|
||||
|
||||
val output = DatabaseInputOutputUtils.readUByte(buffer, bufferPos)
|
||||
val output = byteToUInt(buffer[bufferPos])
|
||||
bufferPos++
|
||||
|
||||
return output
|
||||
@@ -93,12 +92,12 @@ class HmacBlockInputStream(baseStream: InputStream, private val verify: Boolean,
|
||||
throw IOException("File corrupted")
|
||||
}
|
||||
|
||||
val pbBlockIndex = writeLongBuf(blockIndex)
|
||||
val pbBlockIndex = longTo8Bytes(blockIndex)
|
||||
val pbBlockSize = baseStream.readBytes(4)
|
||||
if (pbBlockSize.size != 4) {
|
||||
throw IOException("File corrupted")
|
||||
}
|
||||
val blockSize = bytes4ToInt(pbBlockSize, 0)
|
||||
val blockSize = bytes4ToInt(pbBlockSize)
|
||||
bufferPos = 0
|
||||
|
||||
buffer = baseStream.readBytes(blockSize)
|
||||
|
||||
@@ -27,8 +27,8 @@ import java.security.NoSuchAlgorithmException;
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import static com.kunzisoft.keepass.stream.StreamBytesUtilsKt.writeIntBuf;
|
||||
import static com.kunzisoft.keepass.stream.StreamBytesUtilsKt.writeLongBuf;
|
||||
import static com.kunzisoft.keepass.stream.StreamBytesUtilsKt.intTo4Bytes;
|
||||
import static com.kunzisoft.keepass.stream.StreamBytesUtilsKt.longTo8Bytes;
|
||||
|
||||
public class HmacBlockOutputStream extends OutputStream {
|
||||
private static final int DEFAULT_BUFFER_SIZE = 1024 * 1024;
|
||||
@@ -92,8 +92,8 @@ public class HmacBlockOutputStream extends OutputStream {
|
||||
}
|
||||
|
||||
private void WriteSafeBlock() throws IOException {
|
||||
byte[] bufBlockIndex = writeLongBuf(blockIndex);
|
||||
byte[] blockSizeBuf = writeIntBuf(bufferPos);
|
||||
byte[] bufBlockIndex = longTo8Bytes(blockIndex);
|
||||
byte[] blockSizeBuf = intTo4Bytes(bufferPos);
|
||||
|
||||
byte[] blockHmac;
|
||||
byte[] blockKey = HmacBlockStream.GetHmacKey64(key, blockIndex);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
@@ -24,7 +24,6 @@ import java.io.InputStream
|
||||
|
||||
/**
|
||||
* Little endian version of the DataInputStream
|
||||
* @author bpellin
|
||||
*/
|
||||
class LittleEndianDataInputStream(private val baseStream: InputStream) : InputStream() {
|
||||
|
||||
@@ -42,18 +41,12 @@ class LittleEndianDataInputStream(private val baseStream: InputStream) : InputSt
|
||||
return baseStream.readBytes4ToInt()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun readLong(): Long {
|
||||
val buf = readBytes(8)
|
||||
return bytes64ToLong(buf, 0)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun readUShort(): Int {
|
||||
val buf = ByteArray(2)
|
||||
if (baseStream.read(buf, 0, 2) != 2)
|
||||
throw IOException("Unable to read UShort value")
|
||||
return bytes2ToUShort(buf, 0)
|
||||
return bytes2ToUShort(buf)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
|
||||
@@ -22,8 +22,6 @@ package com.kunzisoft.keepass.stream
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
|
||||
import com.kunzisoft.keepass.stream.writeIntBuf
|
||||
|
||||
|
||||
/**
|
||||
* Little Endian version of the DataOutputStream
|
||||
@@ -32,8 +30,8 @@ import com.kunzisoft.keepass.stream.writeIntBuf
|
||||
class LittleEndianDataOutputStream(private val baseStream: OutputStream) : OutputStream() {
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun writeUInt(uint: Long) {
|
||||
baseStream.write(writeIntBuf(uint.toInt()))
|
||||
fun writeUInt(uint: Long) { // TODO UInt
|
||||
baseStream.write(intTo4Bytes(uint.toInt()))
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
@@ -63,24 +61,16 @@ class LittleEndianDataOutputStream(private val baseStream: OutputStream) : Outpu
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun writeLong(value: Long) {
|
||||
val buf = ByteArray(8)
|
||||
|
||||
writeLong(value, buf, 0)
|
||||
baseStream.write(buf)
|
||||
baseStream.write(longTo8Bytes(value))
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun writeInt(value: Int) {
|
||||
val buf = ByteArray(4)
|
||||
writeInt(value, buf, 0)
|
||||
|
||||
baseStream.write(buf)
|
||||
baseStream.write(intTo4Bytes(value))
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun writeUShort(value: Int) {
|
||||
val buf = ByteArray(2)
|
||||
writeUShort(value, buf, 0)
|
||||
baseStream.write(buf)
|
||||
baseStream.write(uShortTo2Bytes(value))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
package com.kunzisoft.keepass.stream
|
||||
|
||||
import com.kunzisoft.keepass.database.element.DateInstant
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils.bytes5ToDate
|
||||
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils.bytesToString
|
||||
import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils.bytesToString
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.util.*
|
||||
@@ -87,27 +86,27 @@ fun InputStream.readBytes4ToUInt(): Long {
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun InputStream.readBytes4ToInt(): Int {
|
||||
return bytes4ToInt(readBytesLength(4), 0)
|
||||
return bytes4ToInt(readBytesLength(4))
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun InputStream.readBytes2ToUShort(): Int {
|
||||
return bytes2ToUShort(readBytesLength(2), 0)
|
||||
return bytes2ToUShort(readBytesLength(2))
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun InputStream.readBytes5ToDate(): DateInstant {
|
||||
return bytes5ToDate(readBytesLength(5), 0)
|
||||
return bytes5ToDate(readBytesLength(5))
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun InputStream.readBytes16ToUuid(): UUID {
|
||||
return bytes16ToUuid(readBytesLength(16), 0)
|
||||
return bytes16ToUuid(readBytesLength(16))
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun InputStream.readBytesToString(length: Int, replaceCRLF: Boolean = true): String {
|
||||
return bytesToString(this.readBytesLength(length), 0, replaceCRLF)
|
||||
return bytesToString(this.readBytesLength(length), replaceCRLF)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
@@ -123,99 +122,164 @@ fun InputStream.readBytesLength(length: Int): ByteArray {
|
||||
/**
|
||||
* Read an unsigned 16-bit value.
|
||||
*/
|
||||
fun bytes2ToUShort(buf: ByteArray, offset: Int): Int {
|
||||
return ((buf[offset].toInt() and 0xFF)
|
||||
+ (buf[offset + 1].toInt() and 0xFF shl 8))
|
||||
fun bytes2ToUShort(buf: ByteArray): Int {
|
||||
return ((buf[0].toInt() and 0xFF)
|
||||
+ (buf[1].toInt() and 0xFF shl 8))
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 64 bit long
|
||||
*/
|
||||
fun bytes64ToLong(buf: ByteArray, offset: Int): Long {
|
||||
return ((buf[offset].toLong() and 0xFF)
|
||||
+ (buf[offset + 1].toLong() and 0xFF shl 8)
|
||||
+ (buf[offset + 2].toLong() and 0xFF shl 16)
|
||||
+ (buf[offset + 3].toLong() and 0xFF shl 24)
|
||||
+ (buf[offset + 4].toLong() and 0xFF shl 32)
|
||||
+ (buf[offset + 5].toLong() and 0xFF shl 40)
|
||||
+ (buf[offset + 6].toLong() and 0xFF shl 48)
|
||||
+ (buf[offset + 7].toLong() and 0xFF shl 56))
|
||||
fun bytes64ToLong(buf: ByteArray): Long {
|
||||
return ((buf[0].toLong() and 0xFF)
|
||||
+ (buf[1].toLong() and 0xFF shl 8)
|
||||
+ (buf[2].toLong() and 0xFF shl 16)
|
||||
+ (buf[3].toLong() and 0xFF shl 24)
|
||||
+ (buf[4].toLong() and 0xFF shl 32)
|
||||
+ (buf[5].toLong() and 0xFF shl 40)
|
||||
+ (buf[6].toLong() and 0xFF shl 48)
|
||||
+ (buf[7].toLong() and 0xFF shl 56))
|
||||
}
|
||||
|
||||
|
||||
private const val INT_TO_LONG_MASK: Long = 0xffffffffL
|
||||
|
||||
fun bytes4ToUInt(buf: ByteArray, offset: Int): Long {
|
||||
return bytes4ToInt(buf, offset).toLong() and INT_TO_LONG_MASK
|
||||
fun bytes4ToUInt(buf: ByteArray): Long {
|
||||
return bytes4ToInt(buf).toLong() and INT_TO_LONG_MASK
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a 32-bit value.
|
||||
*/
|
||||
fun bytes4ToInt(buf: ByteArray, offset: Int): Int {
|
||||
return ((buf[offset].toInt() and 0xFF)
|
||||
+ (buf[offset + 1].toInt() and 0xFF shl 8)
|
||||
+ (buf[offset + 2].toInt() and 0xFF shl 16)
|
||||
+ (buf[offset + 3].toInt() and 0xFF shl 24))
|
||||
fun bytes4ToInt(buf: ByteArray): Int {
|
||||
return ((buf[0].toInt() and 0xFF)
|
||||
+ (buf[1].toInt() and 0xFF shl 8)
|
||||
+ (buf[2].toInt() and 0xFF shl 16)
|
||||
+ (buf[3].toInt() and 0xFF shl 24))
|
||||
}
|
||||
|
||||
fun bytes16ToUuid(buf: ByteArray, offset: Int): UUID {
|
||||
fun bytes16ToUuid(buf: ByteArray): UUID {
|
||||
var lsb: Long = 0
|
||||
for (i in 15 downTo 8) {
|
||||
lsb = lsb shl 8 or (buf[i + offset].toLong() and 0xff)
|
||||
lsb = lsb shl 8 or (buf[i].toLong() and 0xff)
|
||||
}
|
||||
|
||||
var msb: Long = 0
|
||||
for (i in 7 downTo 0) {
|
||||
msb = msb shl 8 or (buf[i + offset].toLong() and 0xff)
|
||||
msb = msb shl 8 or (buf[i].toLong() and 0xff)
|
||||
}
|
||||
|
||||
return UUID(msb, lsb)
|
||||
}
|
||||
|
||||
fun writeIntBuf(value: Int): ByteArray {
|
||||
val buf = ByteArray(4)
|
||||
writeInt(value, buf, 0)
|
||||
return buf
|
||||
/**
|
||||
* Unpack date from 5 byte format. The five bytes at 'offset' are unpacked
|
||||
* to a java.util.Date instance.
|
||||
*/
|
||||
fun bytes5ToDate(buf: ByteArray, calendar: Calendar = Calendar.getInstance()): DateInstant {
|
||||
val dateSize = 5
|
||||
val cDate = ByteArray(dateSize)
|
||||
System.arraycopy(buf, 0, cDate, 0, dateSize)
|
||||
|
||||
val readOffset = 0
|
||||
val dw1 = byteToUInt(cDate[readOffset])
|
||||
val dw2 = byteToUInt(cDate[readOffset + 1])
|
||||
val dw3 = byteToUInt(cDate[readOffset + 2])
|
||||
val dw4 = byteToUInt(cDate[readOffset + 3])
|
||||
val dw5 = byteToUInt(cDate[readOffset + 4])
|
||||
|
||||
// Unpack 5 byte structure to date and time
|
||||
val year = dw1 shl 6 or (dw2 shr 2)
|
||||
val month = dw2 and 0x00000003 shl 2 or (dw3 shr 6)
|
||||
|
||||
val day = dw3 shr 1 and 0x0000001F
|
||||
val hour = dw3 and 0x00000001 shl 4 or (dw4 shr 4)
|
||||
val minute = dw4 and 0x0000000F shl 2 or (dw5 shr 6)
|
||||
val second = dw5 and 0x0000003F
|
||||
|
||||
// File format is a 1 based month, java Calendar uses a zero based month
|
||||
// File format is a 1 based day, java Calendar uses a 1 based day
|
||||
calendar.set(year, month - 1, day, hour, minute, second)
|
||||
|
||||
return DateInstant(calendar.time)
|
||||
}
|
||||
|
||||
fun writeUShortBuf(value: Int): ByteArray {
|
||||
val buf = ByteArray(2)
|
||||
writeUShort(value, buf, 0)
|
||||
/**
|
||||
* Convert an unsigned Integer to byte
|
||||
*/
|
||||
fun uIntToByte(value: Int): Byte {
|
||||
return (value and 0xFF).toByte()
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 32-bit value.
|
||||
*/
|
||||
fun intTo4Bytes(value: Int): ByteArray {
|
||||
val buf = ByteArray(4)
|
||||
for (i in 0 until 4) {
|
||||
buf[i] = (value.ushr(8 * i) and 0xFF).toByte()
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an unsigned 16-bit value
|
||||
*/
|
||||
fun writeUShort(value: Int, buf: ByteArray, offset: Int) {
|
||||
buf[offset + 0] = (value and 0x00FF).toByte()
|
||||
buf[offset + 1] = (value and 0xFF00 shr 8).toByte()
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a 32-bit value.
|
||||
*/
|
||||
fun writeInt(value: Int, buf: ByteArray, offset: Int) {
|
||||
buf[offset + 0] = (value and 0xFF).toByte()
|
||||
buf[offset + 1] = (value.ushr(8) and 0xFF).toByte()
|
||||
buf[offset + 2] = (value.ushr(16) and 0xFF).toByte()
|
||||
buf[offset + 3] = (value.ushr(24) and 0xFF).toByte()
|
||||
}
|
||||
|
||||
fun writeLongBuf(value: Long): ByteArray {
|
||||
val buf = ByteArray(8)
|
||||
writeLong(value, buf, 0)
|
||||
fun uShortTo2Bytes(value: Int): ByteArray {
|
||||
val buf = ByteArray(2)
|
||||
buf[0] = (value and 0x00FF).toByte()
|
||||
buf[1] = (value and 0xFF00 shr 8).toByte()
|
||||
return buf
|
||||
}
|
||||
|
||||
fun writeLong(value: Long, buf: ByteArray, offset: Int) {
|
||||
buf[offset + 0] = (value and 0xFF).toByte()
|
||||
buf[offset + 1] = (value.ushr(8) and 0xFF).toByte()
|
||||
buf[offset + 2] = (value.ushr(16) and 0xFF).toByte()
|
||||
buf[offset + 3] = (value.ushr(24) and 0xFF).toByte()
|
||||
buf[offset + 4] = (value.ushr(32) and 0xFF).toByte()
|
||||
buf[offset + 5] = (value.ushr(40) and 0xFF).toByte()
|
||||
buf[offset + 6] = (value.ushr(48) and 0xFF).toByte()
|
||||
buf[offset + 7] = (value.ushr(56) and 0xFF).toByte()
|
||||
fun longTo8Bytes(value: Long): ByteArray {
|
||||
val buf = ByteArray(8)
|
||||
for (i in 0 until 8) {
|
||||
buf[i] = (value.ushr(8 * i) and 0xFF).toByte()
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
fun uuidTo16Bytes(uuid: UUID): ByteArray {
|
||||
val buf = ByteArray(16)
|
||||
for (i in 0 until 8) {
|
||||
buf[i] = (uuid.mostSignificantBits.ushr(8 * i) and 0xFF).toByte()
|
||||
}
|
||||
for (i in 8 until 16) {
|
||||
buf[i] = (uuid.leastSignificantBits.ushr(8 * i) and 0xFF).toByte()
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
fun dateTo5Bytes(date: Date?, calendar: Calendar = Calendar.getInstance()): ByteArray? {
|
||||
if (date == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val buf = ByteArray(5)
|
||||
calendar.time = date
|
||||
|
||||
val year = calendar.get(Calendar.YEAR)
|
||||
// File format is a 1 based month, java Calendar uses a zero based month
|
||||
val month = calendar.get(Calendar.MONTH) + 1
|
||||
// File format is a 1 based day, java Calendar uses a 1 based day
|
||||
val day = calendar.get(Calendar.DAY_OF_MONTH)
|
||||
val hour = calendar.get(Calendar.HOUR_OF_DAY)
|
||||
val minute = calendar.get(Calendar.MINUTE)
|
||||
val second = calendar.get(Calendar.SECOND)
|
||||
|
||||
buf[0] = uIntToByte(year shr 6 and 0x0000003F)
|
||||
buf[1] = uIntToByte(year and 0x0000003F shl 2 or (month shr 2 and 0x00000003))
|
||||
buf[2] = (month and 0x00000003 shl 6
|
||||
or (day and 0x0000001F shl 1) or (hour shr 4 and 0x00000001)).toByte()
|
||||
buf[3] = (hour and 0x0000000F shl 4 or (minute shr 2 and 0x0000000F)).toByte()
|
||||
buf[4] = (minute and 0x00000003 shl 6 or (second and 0x0000003F)).toByte()
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
|
||||
/** Convert a byte to an unsigned byte */
|
||||
fun byteToUInt(byte: Byte): Int {
|
||||
return byte.toInt() and 0xFF
|
||||
}
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Brian Pellin, Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
KeePass for J2ME
|
||||
|
||||
Copyright 2007 Naomaru Itoi <nao@phoneid.org>
|
||||
|
||||
This file was derived from
|
||||
|
||||
Java clone of KeePass - A KeePass file viewer for Java
|
||||
Copyright 2006 Bill Zwicky <billzwicky@users.sourceforge.net>
|
||||
|
||||
This program 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; version 2
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
package com.kunzisoft.keepass.utils
|
||||
|
||||
import com.kunzisoft.keepass.database.element.DateInstant
|
||||
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
||||
import com.kunzisoft.keepass.stream.writeIntBuf
|
||||
import com.kunzisoft.keepass.stream.writeLong
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import java.nio.charset.Charset
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* Tools for slicing and dicing Java and KeePass data types.
|
||||
*
|
||||
* @author Bill Zwicky <wrzwicky></wrzwicky>@pobox.com>
|
||||
*/
|
||||
object DatabaseInputOutputUtils {
|
||||
|
||||
var ULONG_MAX_VALUE: Long = -1
|
||||
|
||||
private val defaultCharset = Charset.forName("UTF-8")
|
||||
|
||||
private val CRLFbuf = byteArrayOf(0x0D, 0x0A)
|
||||
private val CRLF = String(CRLFbuf)
|
||||
private val SEP = System.getProperty("line.separator")
|
||||
private val REPLACE = SEP != CRLF
|
||||
|
||||
/** Read an unsigned byte */
|
||||
fun readUByte(buf: ByteArray, offset: Int): Int {
|
||||
return buf[offset].toInt() and 0xFF
|
||||
}
|
||||
|
||||
/**
|
||||
* Write an unsigned byte
|
||||
*/
|
||||
fun writeUByte(value: Int, buf: ByteArray, offset: Int) {
|
||||
buf[offset] = (value and 0xFF).toByte()
|
||||
}
|
||||
|
||||
fun writeUByte(value: Int): Byte {
|
||||
val buf = ByteArray(1)
|
||||
|
||||
writeUByte(value, buf, 0)
|
||||
|
||||
return buf[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Return len of null-terminated string (i.e. distance to null)
|
||||
* within a byte buffer.
|
||||
*/
|
||||
fun bytesStringLength(buf: ByteArray, offset: Int): Int {
|
||||
var len = 0
|
||||
while (buf[offset + len].toInt() != 0)
|
||||
len++
|
||||
return len
|
||||
}
|
||||
|
||||
fun bytesToString(buf: ByteArray, offset: Int, replaceCRLF: Boolean = true): String {
|
||||
var jstring = String(buf, offset, bytesStringLength(buf, offset), defaultCharset)
|
||||
if (replaceCRLF && REPLACE) {
|
||||
jstring = jstring.replace(CRLF, SEP!!)
|
||||
}
|
||||
return jstring
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun writeCString(string: String?, os: OutputStream): Int {
|
||||
var str = string
|
||||
if (str == null) {
|
||||
// Write out a null character
|
||||
os.write(writeIntBuf(1))
|
||||
os.write(0x00)
|
||||
return 0
|
||||
}
|
||||
|
||||
if (REPLACE) {
|
||||
str = str.replace(SEP!!, CRLF)
|
||||
}
|
||||
|
||||
val initial = str.toByteArray(defaultCharset)
|
||||
|
||||
val length = initial.size + 1
|
||||
os.write(writeIntBuf(length))
|
||||
os.write(initial)
|
||||
os.write(0x00)
|
||||
|
||||
return length
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpack date from 5 byte format. The five bytes at 'offset' are unpacked
|
||||
* to a java.util.Date instance.
|
||||
*/
|
||||
fun bytes5ToDate(buf: ByteArray, offset: Int, calendar: Calendar = Calendar.getInstance()): DateInstant {
|
||||
val dateSize = 5
|
||||
val cDate = ByteArray(dateSize)
|
||||
System.arraycopy(buf, offset, cDate, 0, dateSize)
|
||||
|
||||
val readOffset = 0
|
||||
val dw1 = readUByte(cDate, readOffset)
|
||||
val dw2 = readUByte(cDate, readOffset + 1)
|
||||
val dw3 = readUByte(cDate, readOffset + 2)
|
||||
val dw4 = readUByte(cDate, readOffset + 3)
|
||||
val dw5 = readUByte(cDate, readOffset + 4)
|
||||
|
||||
// Unpack 5 byte structure to date and time
|
||||
val year = dw1 shl 6 or (dw2 shr 2)
|
||||
val month = dw2 and 0x00000003 shl 2 or (dw3 shr 6)
|
||||
|
||||
val day = dw3 shr 1 and 0x0000001F
|
||||
val hour = dw3 and 0x00000001 shl 4 or (dw4 shr 4)
|
||||
val minute = dw4 and 0x0000000F shl 2 or (dw5 shr 6)
|
||||
val second = dw5 and 0x0000003F
|
||||
|
||||
// File format is a 1 based month, java Calendar uses a zero based month
|
||||
// File format is a 1 based day, java Calendar uses a 1 based day
|
||||
calendar.set(year, month - 1, day, hour, minute, second)
|
||||
|
||||
return DateInstant(calendar.time)
|
||||
}
|
||||
|
||||
fun dateToBytes(date: Date?, calendar: Calendar = Calendar.getInstance()): ByteArray? {
|
||||
if (date == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val buf = ByteArray(5)
|
||||
calendar.time = date
|
||||
|
||||
val year = calendar.get(Calendar.YEAR)
|
||||
// File format is a 1 based month, java Calendar uses a zero based month
|
||||
val month = calendar.get(Calendar.MONTH) + 1
|
||||
// File format is a 1 based day, java Calendar uses a 1 based day
|
||||
val day = calendar.get(Calendar.DAY_OF_MONTH)
|
||||
val hour = calendar.get(Calendar.HOUR_OF_DAY)
|
||||
val minute = calendar.get(Calendar.MINUTE)
|
||||
val second = calendar.get(Calendar.SECOND)
|
||||
|
||||
buf[0] = writeUByte(year shr 6 and 0x0000003F)
|
||||
buf[1] = writeUByte(year and 0x0000003F shl 2 or (month shr 2 and 0x00000003))
|
||||
buf[2] = (month and 0x00000003 shl 6
|
||||
or (day and 0x0000001F shl 1) or (hour shr 4 and 0x00000001)).toByte()
|
||||
buf[3] = (hour and 0x0000000F shl 4 or (minute shr 2 and 0x0000000F)).toByte()
|
||||
buf[4] = (minute and 0x00000003 shl 6 or (second and 0x0000003F)).toByte()
|
||||
|
||||
return buf
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun writePassword(str: String, os: OutputStream): Int {
|
||||
val initial = str.toByteArray(defaultCharset)
|
||||
val length = initial.size + 1
|
||||
os.write(writeIntBuf(length))
|
||||
os.write(initial)
|
||||
os.write(0x00)
|
||||
return length
|
||||
}
|
||||
|
||||
fun readBytes(buf: ByteArray, offset: Int, len: Int): ByteArray {
|
||||
val binaryData = ByteArray(len)
|
||||
System.arraycopy(buf, offset, binaryData, 0, len)
|
||||
return binaryData
|
||||
}
|
||||
|
||||
fun bytesToUuid(buf: ByteArray): UUID {
|
||||
return bytes16ToUuid(buf, 0)
|
||||
}
|
||||
|
||||
fun uuidToBytes(uuid: UUID): ByteArray {
|
||||
val buf = ByteArray(16)
|
||||
writeLong(uuid.mostSignificantBits, buf, 0)
|
||||
writeLong(uuid.leastSignificantBits, buf, 8)
|
||||
return buf
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
||||
*
|
||||
* This file is part of KeePass DX.
|
||||
*
|
||||
* KeePass DX 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.
|
||||
*
|
||||
* KeePass DX 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 KeePass DX. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.kunzisoft.keepass.utils
|
||||
|
||||
import com.kunzisoft.keepass.stream.intTo4Bytes
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
import java.nio.charset.Charset
|
||||
|
||||
|
||||
/**
|
||||
* Tools for slicing and dicing Java and KeePass data types.
|
||||
*/
|
||||
object StringDatabaseKDBUtils {
|
||||
|
||||
private val defaultCharset = Charset.forName("UTF-8")
|
||||
|
||||
private val CRLFbuf = byteArrayOf(0x0D, 0x0A)
|
||||
private val CRLF = String(CRLFbuf)
|
||||
private val SEP = System.getProperty("line.separator")
|
||||
private val REPLACE = SEP != CRLF
|
||||
|
||||
fun bytesToString(buf: ByteArray, replaceCRLF: Boolean = true): String {
|
||||
// length of null-terminated string (i.e. distance to null) within a byte buffer.
|
||||
var len = 0
|
||||
while (buf[len].toInt() != 0) {
|
||||
len++
|
||||
}
|
||||
// Get string
|
||||
var jstring = String(buf, 0, len, defaultCharset)
|
||||
if (replaceCRLF && REPLACE) {
|
||||
jstring = jstring.replace(CRLF, SEP!!)
|
||||
}
|
||||
return jstring
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun writeStringToBytes(string: String?, os: OutputStream): Int {
|
||||
var str = string
|
||||
if (str == null) {
|
||||
// Write out a null character
|
||||
os.write(intTo4Bytes(1))
|
||||
os.write(0x00)
|
||||
return 0
|
||||
}
|
||||
|
||||
if (REPLACE) {
|
||||
str = str.replace(SEP!!, CRLF)
|
||||
}
|
||||
|
||||
val initial = str.toByteArray(defaultCharset)
|
||||
|
||||
val length = initial.size + 1
|
||||
os.write(intTo4Bytes(length))
|
||||
os.write(initial)
|
||||
os.write(0x00)
|
||||
|
||||
return length
|
||||
}
|
||||
}
|
||||
@@ -21,13 +21,14 @@ package com.kunzisoft.keepass.utils;
|
||||
|
||||
import com.kunzisoft.keepass.stream.LittleEndianDataInputStream;
|
||||
import com.kunzisoft.keepass.stream.LittleEndianDataOutputStream;
|
||||
import com.kunzisoft.keepass.stream.StreamBytesUtilsKt;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.kunzisoft.keepass.stream.StreamBytesUtilsKt.bytes4ToInt;
|
||||
import static com.kunzisoft.keepass.stream.StreamBytesUtilsKt.bytes4ToUInt;
|
||||
import static com.kunzisoft.keepass.stream.StreamBytesUtilsKt.bytes64ToLong;
|
||||
|
||||
public class VariantDictionary {
|
||||
@@ -124,12 +125,12 @@ public class VariantDictionary {
|
||||
switch (bType) {
|
||||
case VdType.UInt32:
|
||||
if (valueLen == 4) {
|
||||
d.setUInt32(name, StreamBytesUtilsKt.bytes4ToUInt(valueBuf, 0));
|
||||
d.setUInt32(name, bytes4ToUInt(valueBuf));
|
||||
}
|
||||
break;
|
||||
case VdType.UInt64:
|
||||
if (valueLen == 8) {
|
||||
d.setUInt64(name, bytes64ToLong(valueBuf, 0));
|
||||
d.setUInt64(name, bytes64ToLong(valueBuf));
|
||||
}
|
||||
break;
|
||||
case VdType.Bool:
|
||||
@@ -139,12 +140,12 @@ public class VariantDictionary {
|
||||
break;
|
||||
case VdType.Int32:
|
||||
if (valueLen == 4) {
|
||||
d.setInt32(name, StreamBytesUtilsKt.bytes4ToInt(valueBuf, 0));
|
||||
d.setInt32(name, bytes4ToInt(valueBuf));
|
||||
}
|
||||
break;
|
||||
case VdType.Int64:
|
||||
if (valueLen == 8) {
|
||||
d.setInt64(name, bytes64ToLong(valueBuf, 0));
|
||||
d.setInt64(name, bytes64ToLong(valueBuf));
|
||||
}
|
||||
break;
|
||||
case VdType.String:
|
||||
@@ -161,7 +162,8 @@ public class VariantDictionary {
|
||||
return d;
|
||||
}
|
||||
|
||||
public static void serialize(VariantDictionary d, LittleEndianDataOutputStream los) throws IOException{
|
||||
public static void serialize(VariantDictionary d,
|
||||
LittleEndianDataOutputStream los) throws IOException{
|
||||
if (los == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user