mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Add UnsignedInt and UnsignedLong
This commit is contained in:
@@ -118,4 +118,7 @@ dependencies {
|
|||||||
// Icon pack
|
// Icon pack
|
||||||
implementation project(path: ':icon-pack-classic')
|
implementation project(path: ':icon-pack-classic')
|
||||||
implementation project(path: ':icon-pack-material')
|
implementation project(path: ':icon-pack-material')
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
androidTestImplementation 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,9 @@
|
|||||||
package com.kunzisoft.keepass.tests
|
package com.kunzisoft.keepass.tests
|
||||||
|
|
||||||
import com.kunzisoft.keepass.database.element.DateInstant
|
import com.kunzisoft.keepass.database.element.DateInstant
|
||||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX.Companion.ULONG_MAX_VALUE
|
|
||||||
import com.kunzisoft.keepass.stream.*
|
import com.kunzisoft.keepass.stream.*
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedLong
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.junit.Assert.assertArrayEquals
|
import org.junit.Assert.assertArrayEquals
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
@@ -77,8 +78,8 @@ class StringDatabaseKDBUtilsTest : TestCase() {
|
|||||||
|
|
||||||
setArray(orig, value, 4)
|
setArray(orig, value, 4)
|
||||||
|
|
||||||
val one = bytes4ToInt(orig)
|
val one = bytes4ToUInt(orig)
|
||||||
val dest = intTo4Bytes(one)
|
val dest = uIntTo4Bytes(one)
|
||||||
|
|
||||||
assertArrayEquals(orig, dest)
|
assertArrayEquals(orig, dest)
|
||||||
|
|
||||||
@@ -133,7 +134,7 @@ class StringDatabaseKDBUtilsTest : TestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun testReadWriteByte(value: Byte) {
|
private fun testReadWriteByte(value: Byte) {
|
||||||
val dest: Byte = uIntToByte(byteToUInt(value))
|
val dest: Byte = UnsignedInt(UnsignedInt.fromByte(value)).toByte()
|
||||||
assert(value == dest)
|
assert(value == dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +186,7 @@ class StringDatabaseKDBUtilsTest : TestCase() {
|
|||||||
|
|
||||||
val bos = ByteArrayOutputStream()
|
val bos = ByteArrayOutputStream()
|
||||||
val leos = LittleEndianDataOutputStream(bos)
|
val leos = LittleEndianDataOutputStream(bos)
|
||||||
leos.writeLong(ULONG_MAX_VALUE)
|
leos.writeLong(UnsignedLong.ULONG_MAX_VALUE)
|
||||||
leos.close()
|
leos.close()
|
||||||
|
|
||||||
val uLongMax = bos.toByteArray()
|
val uLongMax = bos.toByteArray()
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ import java.util.Random
|
|||||||
|
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
|
|
||||||
import com.kunzisoft.keepass.crypto.finalkey.AndroidFinalKey
|
import com.kunzisoft.keepass.crypto.finalkey.AndroidAESKeyTransformer
|
||||||
import com.kunzisoft.keepass.crypto.finalkey.NativeFinalKey
|
import com.kunzisoft.keepass.crypto.finalkey.NativeAESKeyTransformer
|
||||||
|
|
||||||
class FinalKeyTest : TestCase() {
|
class FinalKeyTest : TestCase() {
|
||||||
private var mRand: Random? = null
|
private var mRand: Random? = null
|
||||||
@@ -56,10 +56,10 @@ class FinalKeyTest : TestCase() {
|
|||||||
mRand!!.nextBytes(seed)
|
mRand!!.nextBytes(seed)
|
||||||
mRand!!.nextBytes(key)
|
mRand!!.nextBytes(key)
|
||||||
|
|
||||||
val aKey = AndroidFinalKey()
|
val aKey = AndroidAESKeyTransformer()
|
||||||
androidKey = aKey.transformMasterKey(seed, key, rounds.toLong())
|
androidKey = aKey.transformMasterKey(seed, key, rounds.toLong())
|
||||||
|
|
||||||
val nKey = NativeFinalKey()
|
val nKey = NativeAESKeyTransformer()
|
||||||
nativeKey = nKey.transformMasterKey(seed, key, rounds.toLong())
|
nativeKey = nKey.transformMasterKey(seed, key, rounds.toLong())
|
||||||
|
|
||||||
assertArrayEquals("Does not match", androidKey, nativeKey)
|
assertArrayEquals("Does not match", androidKey, nativeKey)
|
||||||
|
|||||||
@@ -19,16 +19,18 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.crypto
|
package com.kunzisoft.keepass.crypto
|
||||||
|
|
||||||
enum class CrsAlgorithm constructor(val id: Int) {
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
|
|
||||||
Null(0),
|
enum class CrsAlgorithm constructor(val id: UnsignedInt) {
|
||||||
ArcFourVariant(1),
|
|
||||||
Salsa20(2),
|
Null(UnsignedInt(0)),
|
||||||
ChaCha20(3);
|
ArcFourVariant(UnsignedInt(1)),
|
||||||
|
Salsa20(UnsignedInt(2)),
|
||||||
|
ChaCha20(UnsignedInt(3));
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun fromId(num: Int): CrsAlgorithm? {
|
fun fromId(num: UnsignedInt): CrsAlgorithm? {
|
||||||
for (e in values()) {
|
for (e in values()) {
|
||||||
if (e.id == num) {
|
if (e.id == num) {
|
||||||
return e
|
return e
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ object NativeLib {
|
|||||||
fun init(): Boolean {
|
fun init(): Boolean {
|
||||||
if (!isLoaded) {
|
if (!isLoaded) {
|
||||||
try {
|
try {
|
||||||
System.loadLibrary("final-key")
|
System.loadLibrary("final-key") // TODO Rename
|
||||||
System.loadLibrary("argon2")
|
System.loadLibrary("argon2")
|
||||||
} catch (e: UnsatisfiedLinkError) {
|
} catch (e: UnsatisfiedLinkError) {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -21,14 +21,17 @@ package com.kunzisoft.keepass.crypto.finalkey;
|
|||||||
|
|
||||||
import com.kunzisoft.keepass.crypto.CipherFactory;
|
import com.kunzisoft.keepass.crypto.CipherFactory;
|
||||||
|
|
||||||
public class FinalKeyFactory {
|
public class AESFactory {
|
||||||
public static FinalKey createFinalKey() {
|
|
||||||
|
// TODO Encaspulate
|
||||||
|
public static KeyTransformer createFinalKey() {
|
||||||
// Prefer the native final key implementation
|
// Prefer the native final key implementation
|
||||||
if ( !CipherFactory.INSTANCE.deviceBlacklisted() && NativeFinalKey.available() ) {
|
if ( !CipherFactory.INSTANCE.deviceBlacklisted()
|
||||||
return new NativeFinalKey();
|
&& NativeAESKeyTransformer.available() ) {
|
||||||
|
return new NativeAESKeyTransformer();
|
||||||
} else {
|
} else {
|
||||||
// Fall back on the android crypto implementation
|
// Fall back on the android crypto implementation
|
||||||
return new AndroidFinalKey();
|
return new AndroidAESKeyTransformer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ import javax.crypto.NoSuchPaddingException;
|
|||||||
import javax.crypto.ShortBufferException;
|
import javax.crypto.ShortBufferException;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
public class AndroidFinalKey extends FinalKey {
|
public class AndroidAESKeyTransformer extends KeyTransformer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] transformMasterKey(byte[] pKeySeed, byte[] pKey, long rounds) throws IOException {
|
public byte[] transformMasterKey(byte[] pKeySeed, byte[] pKey, long rounds) throws IOException {
|
||||||
@@ -21,6 +21,6 @@ package com.kunzisoft.keepass.crypto.finalkey;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public abstract class FinalKey {
|
public abstract class KeyTransformer {
|
||||||
public abstract byte[] transformMasterKey(byte[] seed, byte[] key, long rounds) throws IOException;
|
public abstract byte[] transformMasterKey(byte[] seed, byte[] key, long rounds) throws IOException;
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ import com.kunzisoft.keepass.crypto.NativeLib;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
public class NativeFinalKey extends FinalKey {
|
public class NativeAESKeyTransformer extends KeyTransformer {
|
||||||
|
|
||||||
public static boolean available() {
|
public static boolean available() {
|
||||||
return NativeLib.INSTANCE.init();
|
return NativeLib.INSTANCE.init();
|
||||||
@@ -22,8 +22,9 @@ package com.kunzisoft.keepass.crypto.keyDerivation
|
|||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.crypto.CryptoUtil
|
import com.kunzisoft.keepass.crypto.CryptoUtil
|
||||||
import com.kunzisoft.keepass.crypto.finalkey.FinalKeyFactory
|
import com.kunzisoft.keepass.crypto.finalkey.AESFactory
|
||||||
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -34,12 +35,11 @@ class AesKdf internal constructor() : KdfEngine() {
|
|||||||
get() {
|
get() {
|
||||||
return KdfParameters(uuid!!).apply {
|
return KdfParameters(uuid!!).apply {
|
||||||
setParamUUID()
|
setParamUUID()
|
||||||
setUInt32(PARAM_ROUNDS, DEFAULT_ROUNDS.toLong())
|
setUInt32(PARAM_ROUNDS, UnsignedInt.fromLong(defaultKeyRounds))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val defaultKeyRounds: Long
|
override val defaultKeyRounds: Long = 6000L
|
||||||
get() = DEFAULT_ROUNDS.toLong()
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
uuid = CIPHER_UUID
|
uuid = CIPHER_UUID
|
||||||
@@ -63,8 +63,7 @@ class AesKdf internal constructor() : KdfEngine() {
|
|||||||
seed = CryptoUtil.hashSha256(seed)
|
seed = CryptoUtil.hashSha256(seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
val key = FinalKeyFactory.createFinalKey()
|
return AESFactory.createFinalKey().transformMasterKey(seed, currentMasterKey, rounds)
|
||||||
return key.transformMasterKey(seed, currentMasterKey, rounds)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun randomize(p: KdfParameters) {
|
override fun randomize(p: KdfParameters) {
|
||||||
@@ -86,8 +85,6 @@ class AesKdf internal constructor() : KdfEngine() {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val DEFAULT_ROUNDS = 6000
|
|
||||||
|
|
||||||
val CIPHER_UUID: UUID = bytes16ToUuid(
|
val CIPHER_UUID: UUID = bytes16ToUuid(
|
||||||
byteArrayOf(0xC9.toByte(),
|
byteArrayOf(0xC9.toByte(),
|
||||||
0xD9.toByte(),
|
0xD9.toByte(),
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ package com.kunzisoft.keepass.crypto.keyDerivation
|
|||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import com.kunzisoft.keepass.R
|
import com.kunzisoft.keepass.R
|
||||||
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
import com.kunzisoft.keepass.stream.bytes16ToUuid
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -56,15 +57,21 @@ class Argon2Kdf internal constructor() : KdfEngine() {
|
|||||||
override fun transform(masterKey: ByteArray, p: KdfParameters): ByteArray {
|
override fun transform(masterKey: ByteArray, p: KdfParameters): ByteArray {
|
||||||
|
|
||||||
val salt = p.getByteArray(PARAM_SALT)
|
val salt = p.getByteArray(PARAM_SALT)
|
||||||
val parallelism = p.getUInt32(PARAM_PARALLELISM).toInt()
|
val parallelism = UnsignedInt(p.getUInt32(PARAM_PARALLELISM))
|
||||||
val memory = p.getUInt64(PARAM_MEMORY)
|
val memory = UnsignedInt.fromLong(p.getUInt64(PARAM_MEMORY) / MEMORY_BLOCK_SIZE)
|
||||||
val iterations = p.getUInt64(PARAM_ITERATIONS)
|
val iterations = UnsignedInt.fromLong(p.getUInt64(PARAM_ITERATIONS))
|
||||||
val version = p.getUInt32(PARAM_VERSION)
|
val version = UnsignedInt(p.getUInt32(PARAM_VERSION))
|
||||||
val secretKey = p.getByteArray(PARAM_SECRET_KEY)
|
val secretKey = p.getByteArray(PARAM_SECRET_KEY)
|
||||||
val assocData = p.getByteArray(PARAM_ASSOC_DATA)
|
val assocData = p.getByteArray(PARAM_ASSOC_DATA)
|
||||||
|
|
||||||
return Argon2Native.transformKey(masterKey, salt, parallelism, memory, iterations,
|
return Argon2Native.transformKey(masterKey,
|
||||||
secretKey, assocData, version)
|
salt,
|
||||||
|
parallelism,
|
||||||
|
memory,
|
||||||
|
iterations,
|
||||||
|
secretKey,
|
||||||
|
assocData,
|
||||||
|
version)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun randomize(p: KdfParameters) {
|
override fun randomize(p: KdfParameters) {
|
||||||
@@ -107,21 +114,21 @@ class Argon2Kdf internal constructor() : KdfEngine() {
|
|||||||
override val maxMemoryUsage: Long
|
override val maxMemoryUsage: Long
|
||||||
get() = MAX_MEMORY
|
get() = MAX_MEMORY
|
||||||
|
|
||||||
override fun getParallelism(p: KdfParameters): Int {
|
override fun getParallelism(p: KdfParameters): Long {
|
||||||
return p.getUInt32(PARAM_PARALLELISM).toInt() // TODO Verify #443
|
return UnsignedInt(p.getUInt32(PARAM_PARALLELISM)).toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setParallelism(p: KdfParameters, parallelism: Int) {
|
override fun setParallelism(p: KdfParameters, parallelism: Long) {
|
||||||
p.setUInt32(PARAM_PARALLELISM, parallelism.toLong())
|
p.setUInt32(PARAM_PARALLELISM, UnsignedInt.fromLong(parallelism))
|
||||||
}
|
}
|
||||||
|
|
||||||
override val defaultParallelism: Int
|
override val defaultParallelism: Long
|
||||||
get() = DEFAULT_PARALLELISM.toInt()
|
get() = DEFAULT_PARALLELISM.toLong()
|
||||||
|
|
||||||
override val minParallelism: Int
|
override val minParallelism: Long
|
||||||
get() = MIN_PARALLELISM
|
get() = MIN_PARALLELISM
|
||||||
|
|
||||||
override val maxParallelism: Int
|
override val maxParallelism: Long
|
||||||
get() = MAX_PARALLELISM
|
get() = MAX_PARALLELISM
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -152,23 +159,24 @@ class Argon2Kdf internal constructor() : KdfEngine() {
|
|||||||
private const val PARAM_SECRET_KEY = "K" // byte[]
|
private const val PARAM_SECRET_KEY = "K" // byte[]
|
||||||
private const val PARAM_ASSOC_DATA = "A" // byte[]
|
private const val PARAM_ASSOC_DATA = "A" // byte[]
|
||||||
|
|
||||||
private const val MIN_VERSION: Long = 0x10
|
private val MIN_VERSION = UnsignedInt(0x10)
|
||||||
private const val MAX_VERSION: Long = 0x13
|
private val MAX_VERSION = UnsignedInt(0x13)
|
||||||
|
|
||||||
private const val MIN_SALT = 8
|
private const val MIN_SALT = 8
|
||||||
private const val MAX_SALT = Integer.MAX_VALUE
|
private val MAX_SALT = UnsignedInt.MAX_VALUE.toLong()
|
||||||
|
|
||||||
private const val MIN_ITERATIONS: Long = 1
|
private const val MIN_ITERATIONS: Long = 1L
|
||||||
private const val MAX_ITERATIONS = 4294967295L
|
private const val MAX_ITERATIONS = 4294967295L
|
||||||
|
|
||||||
private const val MIN_MEMORY = (1024 * 8).toLong()
|
private const val MIN_MEMORY = (1024 * 8).toLong()
|
||||||
private const val MAX_MEMORY = Integer.MAX_VALUE.toLong()
|
private val MAX_MEMORY = UnsignedInt.MAX_VALUE.toLong()
|
||||||
|
private const val MEMORY_BLOCK_SIZE: Long = 1024L
|
||||||
|
|
||||||
private const val MIN_PARALLELISM = 1
|
private const val MIN_PARALLELISM: Long = 1L
|
||||||
private const val MAX_PARALLELISM = (1 shl 24) - 1
|
private const val MAX_PARALLELISM: Long = ((1 shl 24) - 1).toLong()
|
||||||
|
|
||||||
private const val DEFAULT_ITERATIONS: Long = 2
|
private const val DEFAULT_ITERATIONS: Long = 2L
|
||||||
private const val DEFAULT_MEMORY = (1024 * 1024).toLong()
|
private const val DEFAULT_MEMORY = (1024 * 1024).toLong()
|
||||||
private const val DEFAULT_PARALLELISM: Long = 2
|
private val DEFAULT_PARALLELISM = UnsignedInt(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,20 +20,29 @@
|
|||||||
package com.kunzisoft.keepass.crypto.keyDerivation;
|
package com.kunzisoft.keepass.crypto.keyDerivation;
|
||||||
|
|
||||||
import com.kunzisoft.keepass.crypto.NativeLib;
|
import com.kunzisoft.keepass.crypto.NativeLib;
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
public class Argon2Native {
|
public class Argon2Native {
|
||||||
|
|
||||||
public static byte[] transformKey(byte[] password, byte[] salt, int parallelism,
|
public static byte[] transformKey(byte[] password, byte[] salt, UnsignedInt parallelism,
|
||||||
long memory, long iterations, byte[] secretKey,
|
UnsignedInt memory, UnsignedInt iterations, byte[] secretKey,
|
||||||
byte[] associatedData, long version) throws IOException {
|
byte[] associatedData, UnsignedInt version) throws IOException {
|
||||||
NativeLib.INSTANCE.init();
|
NativeLib.INSTANCE.init();
|
||||||
|
|
||||||
return nTransformMasterKey(password, salt, parallelism, memory, iterations, secretKey, associatedData, version);
|
return nTransformMasterKey(
|
||||||
|
password,
|
||||||
|
salt,
|
||||||
|
parallelism.toInt(),
|
||||||
|
memory.toInt(),
|
||||||
|
iterations.toInt(),
|
||||||
|
secretKey,
|
||||||
|
associatedData,
|
||||||
|
version.toInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native byte[] nTransformMasterKey(byte[] password, byte[] salt, int parallelism,
|
private static native byte[] nTransformMasterKey(byte[] password, byte[] salt, int parallelism,
|
||||||
long memory, long iterations, byte[] secretKey,
|
int memory, int iterations, byte[] secretKey,
|
||||||
byte[] associatedData, long version) throws IOException;
|
byte[] associatedData, int version) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
package com.kunzisoft.keepass.crypto.keyDerivation
|
package com.kunzisoft.keepass.crypto.keyDerivation
|
||||||
|
|
||||||
import com.kunzisoft.keepass.utils.ObjectNameResource
|
import com.kunzisoft.keepass.utils.ObjectNameResource
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
@@ -51,14 +52,14 @@ abstract class KdfEngine : ObjectNameResource, Serializable {
|
|||||||
get() = 1
|
get() = 1
|
||||||
|
|
||||||
open val maxKeyRounds: Long
|
open val maxKeyRounds: Long
|
||||||
get() = Int.MAX_VALUE.toLong()
|
get() = UnsignedInt.MAX_VALUE.toLong()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MEMORY
|
* MEMORY
|
||||||
*/
|
*/
|
||||||
|
|
||||||
open fun getMemoryUsage(p: KdfParameters): Long {
|
open fun getMemoryUsage(p: KdfParameters): Long {
|
||||||
return UNKNOWN_VALUE.toLong()
|
return UNKNOWN_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun setMemoryUsage(p: KdfParameters, memory: Long) {
|
open fun setMemoryUsage(p: KdfParameters, memory: Long) {
|
||||||
@@ -66,36 +67,36 @@ abstract class KdfEngine : ObjectNameResource, Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open val defaultMemoryUsage: Long
|
open val defaultMemoryUsage: Long
|
||||||
get() = UNKNOWN_VALUE.toLong()
|
get() = UNKNOWN_VALUE
|
||||||
|
|
||||||
open val minMemoryUsage: Long
|
open val minMemoryUsage: Long
|
||||||
get() = 1
|
get() = 1
|
||||||
|
|
||||||
open val maxMemoryUsage: Long
|
open val maxMemoryUsage: Long
|
||||||
get() = Int.MAX_VALUE.toLong()
|
get() = UnsignedInt.MAX_VALUE.toLong()
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PARALLELISM
|
* PARALLELISM
|
||||||
*/
|
*/
|
||||||
|
|
||||||
open fun getParallelism(p: KdfParameters): Int {
|
open fun getParallelism(p: KdfParameters): Long {
|
||||||
return UNKNOWN_VALUE
|
return UNKNOWN_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun setParallelism(p: KdfParameters, parallelism: Int) {
|
open fun setParallelism(p: KdfParameters, parallelism: Long) {
|
||||||
// Do nothing by default
|
// Do nothing by default
|
||||||
}
|
}
|
||||||
|
|
||||||
open val defaultParallelism: Int
|
open val defaultParallelism: Long
|
||||||
get() = UNKNOWN_VALUE
|
get() = UNKNOWN_VALUE
|
||||||
|
|
||||||
open val minParallelism: Int
|
open val minParallelism: Long
|
||||||
get() = 1
|
get() = 1L
|
||||||
|
|
||||||
open val maxParallelism: Int
|
open val maxParallelism: Long
|
||||||
get() = Int.MAX_VALUE
|
get() = UnsignedInt.MAX_VALUE.toLong()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val UNKNOWN_VALUE = -1
|
const val UNKNOWN_VALUE: Long = -1L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -552,12 +552,12 @@ class ProgressDialogThread(private val activity: FragmentActivity) {
|
|||||||
, ACTION_DATABASE_UPDATE_MEMORY_USAGE_TASK)
|
, ACTION_DATABASE_UPDATE_MEMORY_USAGE_TASK)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startDatabaseSaveParallelism(oldParallelism: Int,
|
fun startDatabaseSaveParallelism(oldParallelism: Long,
|
||||||
newParallelism: Int,
|
newParallelism: Long,
|
||||||
save: Boolean) {
|
save: Boolean) {
|
||||||
start(Bundle().apply {
|
start(Bundle().apply {
|
||||||
putInt(DatabaseTaskNotificationService.OLD_ELEMENT_KEY, oldParallelism)
|
putLong(DatabaseTaskNotificationService.OLD_ELEMENT_KEY, oldParallelism)
|
||||||
putInt(DatabaseTaskNotificationService.NEW_ELEMENT_KEY, newParallelism)
|
putLong(DatabaseTaskNotificationService.NEW_ELEMENT_KEY, newParallelism)
|
||||||
putBoolean(DatabaseTaskNotificationService.SAVE_DATABASE_KEY, save)
|
putBoolean(DatabaseTaskNotificationService.SAVE_DATABASE_KEY, save)
|
||||||
}
|
}
|
||||||
, ACTION_DATABASE_UPDATE_PARALLELISM_TASK)
|
, ACTION_DATABASE_UPDATE_PARALLELISM_TASK)
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ import com.kunzisoft.keepass.database.search.SearchHelper
|
|||||||
import com.kunzisoft.keepass.database.search.SearchParameters
|
import com.kunzisoft.keepass.database.search.SearchParameters
|
||||||
import com.kunzisoft.keepass.icons.IconDrawableFactory
|
import com.kunzisoft.keepass.icons.IconDrawableFactory
|
||||||
import com.kunzisoft.keepass.model.SearchInfo
|
import com.kunzisoft.keepass.model.SearchInfo
|
||||||
import com.kunzisoft.keepass.stream.readBytes4ToInt
|
import com.kunzisoft.keepass.stream.readBytes4ToUInt
|
||||||
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
||||||
import com.kunzisoft.keepass.utils.SingletonHolder
|
import com.kunzisoft.keepass.utils.SingletonHolder
|
||||||
import com.kunzisoft.keepass.utils.UriUtil
|
import com.kunzisoft.keepass.utils.UriUtil
|
||||||
@@ -206,7 +206,6 @@ class Database {
|
|||||||
|
|
||||||
var numberKeyEncryptionRounds: Long
|
var numberKeyEncryptionRounds: Long
|
||||||
get() = mDatabaseKDB?.numberKeyEncryptionRounds ?: mDatabaseKDBX?.numberKeyEncryptionRounds ?: 0
|
get() = mDatabaseKDB?.numberKeyEncryptionRounds ?: mDatabaseKDBX?.numberKeyEncryptionRounds ?: 0
|
||||||
@Throws(NumberFormatException::class)
|
|
||||||
set(numberRounds) {
|
set(numberRounds) {
|
||||||
mDatabaseKDB?.numberKeyEncryptionRounds = numberRounds
|
mDatabaseKDB?.numberKeyEncryptionRounds = numberRounds
|
||||||
mDatabaseKDBX?.numberKeyEncryptionRounds = numberRounds
|
mDatabaseKDBX?.numberKeyEncryptionRounds = numberRounds
|
||||||
@@ -214,13 +213,13 @@ class Database {
|
|||||||
|
|
||||||
var memoryUsage: Long
|
var memoryUsage: Long
|
||||||
get() {
|
get() {
|
||||||
return mDatabaseKDBX?.memoryUsage ?: return KdfEngine.UNKNOWN_VALUE.toLong()
|
return mDatabaseKDBX?.memoryUsage ?: return KdfEngine.UNKNOWN_VALUE
|
||||||
}
|
}
|
||||||
set(memory) {
|
set(memory) {
|
||||||
mDatabaseKDBX?.memoryUsage = memory
|
mDatabaseKDBX?.memoryUsage = memory
|
||||||
}
|
}
|
||||||
|
|
||||||
var parallelism: Int
|
var parallelism: Long
|
||||||
get() = mDatabaseKDBX?.parallelism ?: KdfEngine.UNKNOWN_VALUE
|
get() = mDatabaseKDBX?.parallelism ?: KdfEngine.UNKNOWN_VALUE
|
||||||
set(parallelism) {
|
set(parallelism) {
|
||||||
mDatabaseKDBX?.parallelism = parallelism
|
mDatabaseKDBX?.parallelism = parallelism
|
||||||
@@ -348,8 +347,8 @@ class Database {
|
|||||||
databaseInputStream.mark(10)
|
databaseInputStream.mark(10)
|
||||||
|
|
||||||
// Get the file directory to save the attachments
|
// Get the file directory to save the attachments
|
||||||
val sig1 = databaseInputStream.readBytes4ToInt()
|
val sig1 = databaseInputStream.readBytes4ToUInt()
|
||||||
val sig2 = databaseInputStream.readBytes4ToInt()
|
val sig2 = databaseInputStream.readBytes4ToUInt()
|
||||||
|
|
||||||
// Return to the start
|
// Return to the start
|
||||||
databaseInputStream.reset()
|
databaseInputStream.reset()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
package com.kunzisoft.keepass.database.element.database
|
package com.kunzisoft.keepass.database.element.database
|
||||||
|
|
||||||
import com.kunzisoft.keepass.crypto.finalkey.FinalKeyFactory
|
import com.kunzisoft.keepass.crypto.finalkey.AESFactory
|
||||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
|
import com.kunzisoft.keepass.crypto.keyDerivation.KdfEngine
|
||||||
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
|
import com.kunzisoft.keepass.crypto.keyDerivation.KdfFactory
|
||||||
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
||||||
@@ -38,8 +38,6 @@ import kotlin.collections.ArrayList
|
|||||||
|
|
||||||
class DatabaseKDB : DatabaseVersioned<Int, UUID, GroupKDB, EntryKDB>() {
|
class DatabaseKDB : DatabaseVersioned<Int, UUID, GroupKDB, EntryKDB>() {
|
||||||
|
|
||||||
private var numKeyEncRounds: Int = 0
|
|
||||||
|
|
||||||
var backupGroupId: Int = BACKUP_FOLDER_UNDEFINED_ID
|
var backupGroupId: Int = BACKUP_FOLDER_UNDEFINED_ID
|
||||||
|
|
||||||
private var kdfListV3: MutableList<KdfEngine> = ArrayList()
|
private var kdfListV3: MutableList<KdfEngine> = ArrayList()
|
||||||
@@ -87,19 +85,10 @@ class DatabaseKDB : DatabaseVersioned<Int, UUID, GroupKDB, EntryKDB>() {
|
|||||||
override val passwordEncoding: String
|
override val passwordEncoding: String
|
||||||
get() = "ISO-8859-1"
|
get() = "ISO-8859-1"
|
||||||
|
|
||||||
override var numberKeyEncryptionRounds: Long
|
override var numberKeyEncryptionRounds = 300L
|
||||||
get() = numKeyEncRounds.toLong()
|
|
||||||
@Throws(NumberFormatException::class)
|
|
||||||
set(rounds) {
|
|
||||||
if (rounds > Integer.MAX_VALUE || rounds < Integer.MIN_VALUE) {
|
|
||||||
throw NumberFormatException()
|
|
||||||
}
|
|
||||||
numKeyEncRounds = rounds.toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
algorithm = EncryptionAlgorithm.AESRijndael
|
algorithm = EncryptionAlgorithm.AESRijndael
|
||||||
numKeyEncRounds = DEFAULT_ENCRYPTION_ROUNDS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -158,9 +147,9 @@ class DatabaseKDB : DatabaseVersioned<Int, UUID, GroupKDB, EntryKDB>() {
|
|||||||
val nos = NullOutputStream()
|
val nos = NullOutputStream()
|
||||||
val dos = DigestOutputStream(nos, messageDigest)
|
val dos = DigestOutputStream(nos, messageDigest)
|
||||||
|
|
||||||
val transformedMasterKey = transformMasterKey(masterSeed2, masterKey, numRounds)
|
// Encrypt the master key a few times to make brute-force key-search harder
|
||||||
dos.write(masterSeed)
|
dos.write(masterSeed)
|
||||||
dos.write(transformedMasterKey)
|
dos.write(AESFactory.createFinalKey().transformMasterKey(masterSeed2, masterKey, numRounds))
|
||||||
|
|
||||||
finalKey = messageDigest.digest()
|
finalKey = messageDigest.digest()
|
||||||
}
|
}
|
||||||
@@ -266,19 +255,6 @@ class DatabaseKDB : DatabaseVersioned<Int, UUID, GroupKDB, EntryKDB>() {
|
|||||||
const val BACKUP_FOLDER_TITLE = "Backup"
|
const val BACKUP_FOLDER_TITLE = "Backup"
|
||||||
private const val BACKUP_FOLDER_UNDEFINED_ID = -1
|
private const val BACKUP_FOLDER_UNDEFINED_ID = -1
|
||||||
|
|
||||||
private const val DEFAULT_ENCRYPTION_ROUNDS = 300
|
|
||||||
|
|
||||||
const val BUFFER_SIZE_BYTES = 3 * 128
|
const val BUFFER_SIZE_BYTES = 3 * 128
|
||||||
|
|
||||||
/**
|
|
||||||
* Encrypt the master key a few times to make brute-force key-search harder
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
@Throws(IOException::class)
|
|
||||||
private fun transformMasterKey(pKeySeed: ByteArray, pKey: ByteArray, rounds: Long): ByteArray {
|
|
||||||
val key = FinalKeyFactory.createFinalKey()
|
|
||||||
|
|
||||||
return key.transformMasterKey(pKeySeed, pKey, rounds)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ import com.kunzisoft.keepass.database.element.security.MemoryProtectionConfig
|
|||||||
import com.kunzisoft.keepass.database.exception.UnknownKDF
|
import com.kunzisoft.keepass.database.exception.UnknownKDF
|
||||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX.Companion.FILE_VERSION_32_3
|
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX.Companion.FILE_VERSION_32_3
|
||||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX.Companion.FILE_VERSION_32_4
|
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX.Companion.FILE_VERSION_32_4
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import com.kunzisoft.keepass.utils.VariantDictionary
|
import com.kunzisoft.keepass.utils.VariantDictionary
|
||||||
import org.w3c.dom.Node
|
import org.w3c.dom.Node
|
||||||
import org.w3c.dom.Text
|
import org.w3c.dom.Text
|
||||||
@@ -67,7 +68,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
private var numKeyEncRounds: Long = 0
|
private var numKeyEncRounds: Long = 0
|
||||||
var publicCustomData = VariantDictionary()
|
var publicCustomData = VariantDictionary()
|
||||||
|
|
||||||
var kdbxVersion: Long = 0
|
var kdbxVersion = UnsignedInt(0)
|
||||||
var name = ""
|
var name = ""
|
||||||
var nameChanged = DateInstant()
|
var nameChanged = DateInstant()
|
||||||
// TODO change setting date
|
// TODO change setting date
|
||||||
@@ -83,7 +84,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
var keyChangeForceDays: Long = 1
|
var keyChangeForceDays: Long = 1
|
||||||
var isKeyChangeForceOnce = false
|
var isKeyChangeForceOnce = false
|
||||||
|
|
||||||
var maintenanceHistoryDays: Long = 365
|
var maintenanceHistoryDays = UnsignedInt(365)
|
||||||
var color = ""
|
var color = ""
|
||||||
/**
|
/**
|
||||||
* Determine if RecycleBin is enable or not
|
* Determine if RecycleBin is enable or not
|
||||||
@@ -219,7 +220,6 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
numKeyEncRounds = kdfEngine.getKeyRounds(kdfParameters!!)
|
numKeyEncRounds = kdfEngine.getKeyRounds(kdfParameters!!)
|
||||||
return numKeyEncRounds
|
return numKeyEncRounds
|
||||||
}
|
}
|
||||||
@Throws(NumberFormatException::class)
|
|
||||||
set(rounds) {
|
set(rounds) {
|
||||||
val kdfEngine = kdfEngine
|
val kdfEngine = kdfEngine
|
||||||
if (kdfEngine != null && kdfParameters != null)
|
if (kdfEngine != null && kdfParameters != null)
|
||||||
@@ -232,7 +232,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
val kdfEngine = kdfEngine
|
val kdfEngine = kdfEngine
|
||||||
return if (kdfEngine != null && kdfParameters != null) {
|
return if (kdfEngine != null && kdfParameters != null) {
|
||||||
kdfEngine.getMemoryUsage(kdfParameters!!)
|
kdfEngine.getMemoryUsage(kdfParameters!!)
|
||||||
} else KdfEngine.UNKNOWN_VALUE.toLong()
|
} else KdfEngine.UNKNOWN_VALUE
|
||||||
}
|
}
|
||||||
set(memory) {
|
set(memory) {
|
||||||
val kdfEngine = kdfEngine
|
val kdfEngine = kdfEngine
|
||||||
@@ -240,7 +240,7 @@ class DatabaseKDBX : DatabaseVersioned<UUID, UUID, GroupKDBX, EntryKDBX> {
|
|||||||
kdfEngine.setMemoryUsage(kdfParameters!!, memory)
|
kdfEngine.setMemoryUsage(kdfParameters!!, memory)
|
||||||
}
|
}
|
||||||
|
|
||||||
var parallelism: Int
|
var parallelism: Long
|
||||||
get() {
|
get() {
|
||||||
val kdfEngine = kdfEngine
|
val kdfEngine = kdfEngine
|
||||||
return if (kdfEngine != null && kdfParameters != null) {
|
return if (kdfEngine != null && kdfParameters != null) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import android.os.Parcel
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
|
||||||
import com.kunzisoft.keepass.utils.ParcelableUtil
|
import com.kunzisoft.keepass.utils.ParcelableUtil
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
|
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ class AutoType : Parcelable {
|
|||||||
|
|
||||||
constructor(parcel: Parcel) {
|
constructor(parcel: Parcel) {
|
||||||
this.enabled = parcel.readByte().toInt() != 0
|
this.enabled = parcel.readByte().toInt() != 0
|
||||||
this.obfuscationOptions = parcel.readLong()
|
this.obfuscationOptions = UnsignedInt(parcel.readInt())
|
||||||
this.defaultSequence = parcel.readString() ?: defaultSequence
|
this.defaultSequence = parcel.readString() ?: defaultSequence
|
||||||
this.windowSeqPairs = ParcelableUtil.readStringParcelableMap(parcel)
|
this.windowSeqPairs = ParcelableUtil.readStringParcelableMap(parcel)
|
||||||
}
|
}
|
||||||
@@ -57,7 +58,7 @@ class AutoType : Parcelable {
|
|||||||
|
|
||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
dest.writeByte((if (enabled) 1 else 0).toByte())
|
dest.writeByte((if (enabled) 1 else 0).toByte())
|
||||||
dest.writeLong(obfuscationOptions)
|
dest.writeInt(obfuscationOptions.toInt())
|
||||||
dest.writeString(defaultSequence)
|
dest.writeString(defaultSequence)
|
||||||
ParcelableUtil.writeStringParcelableMap(dest, windowSeqPairs)
|
ParcelableUtil.writeStringParcelableMap(dest, windowSeqPairs)
|
||||||
}
|
}
|
||||||
@@ -71,7 +72,7 @@ class AutoType : Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val OBF_OPT_NONE: Long = 0
|
private val OBF_OPT_NONE = UnsignedInt(0)
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val CREATOR: Parcelable.Creator<AutoType> = object : Parcelable.Creator<AutoType> {
|
val CREATOR: Parcelable.Creator<AutoType> = object : Parcelable.Creator<AutoType> {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import com.kunzisoft.keepass.database.element.node.Type
|
|||||||
import com.kunzisoft.keepass.database.element.security.BinaryAttachment
|
import com.kunzisoft.keepass.database.element.security.BinaryAttachment
|
||||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||||
import com.kunzisoft.keepass.utils.ParcelableUtil
|
import com.kunzisoft.keepass.utils.ParcelableUtil
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedLong
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInterface {
|
class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInterface {
|
||||||
@@ -104,7 +105,7 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
|
|
||||||
constructor(parcel: Parcel) : super(parcel) {
|
constructor(parcel: Parcel) : super(parcel) {
|
||||||
iconCustom = parcel.readParcelable(IconImageCustom::class.java.classLoader) ?: iconCustom
|
iconCustom = parcel.readParcelable(IconImageCustom::class.java.classLoader) ?: iconCustom
|
||||||
usageCount = parcel.readLong()
|
usageCount = UnsignedLong(parcel.readLong())
|
||||||
locationChanged = parcel.readParcelable(DateInstant::class.java.classLoader) ?: locationChanged
|
locationChanged = parcel.readParcelable(DateInstant::class.java.classLoader) ?: locationChanged
|
||||||
customData = ParcelableUtil.readStringParcelableMap(parcel)
|
customData = ParcelableUtil.readStringParcelableMap(parcel)
|
||||||
fields = ParcelableUtil.readStringParcelableMap(parcel, ProtectedString::class.java)
|
fields = ParcelableUtil.readStringParcelableMap(parcel, ProtectedString::class.java)
|
||||||
@@ -122,7 +123,7 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
super.writeToParcel(dest, flags)
|
super.writeToParcel(dest, flags)
|
||||||
dest.writeParcelable(iconCustom, flags)
|
dest.writeParcelable(iconCustom, flags)
|
||||||
dest.writeLong(usageCount)
|
dest.writeLong(usageCount.toLong())
|
||||||
dest.writeParcelable(locationChanged, flags)
|
dest.writeParcelable(locationChanged, flags)
|
||||||
ParcelableUtil.writeStringParcelableMap(dest, customData)
|
ParcelableUtil.writeStringParcelableMap(dest, customData)
|
||||||
ParcelableUtil.writeStringParcelableMap(dest, flags, fields)
|
ParcelableUtil.writeStringParcelableMap(dest, flags, fields)
|
||||||
@@ -243,7 +244,7 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
fields[STR_NOTES] = ProtectedString(protect, value)
|
fields[STR_NOTES] = ProtectedString(protect, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
override var usageCount: Long = 0
|
override var usageCount = UnsignedLong(0)
|
||||||
|
|
||||||
override var locationChanged = DateInstant()
|
override var locationChanged = DateInstant()
|
||||||
|
|
||||||
@@ -332,7 +333,8 @@ class EntryKDBX : EntryVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
|
|
||||||
override fun touch(modified: Boolean, touchParents: Boolean) {
|
override fun touch(modified: Boolean, touchParents: Boolean) {
|
||||||
super.touch(modified, touchParents)
|
super.touch(modified, touchParents)
|
||||||
++usageCount
|
// TODO unsigned long
|
||||||
|
usageCount = UnsignedLong(usageCount.toLong() + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -32,14 +32,14 @@ import java.util.*
|
|||||||
class GroupKDB : GroupVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface {
|
class GroupKDB : GroupVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface {
|
||||||
|
|
||||||
var level = 0 // short
|
var level = 0 // short
|
||||||
/** Used by KeePass internally, don't use */
|
// Used by KeePass internally, don't use
|
||||||
var flags: Int = 0
|
var groupFlags = 0
|
||||||
|
|
||||||
constructor() : super()
|
constructor() : super()
|
||||||
|
|
||||||
constructor(parcel: Parcel) : super(parcel) {
|
constructor(parcel: Parcel) : super(parcel) {
|
||||||
level = parcel.readInt()
|
level = parcel.readInt()
|
||||||
flags = parcel.readInt()
|
groupFlags = parcel.readInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readParentParcelable(parcel: Parcel): GroupKDB? {
|
override fun readParentParcelable(parcel: Parcel): GroupKDB? {
|
||||||
@@ -53,13 +53,13 @@ class GroupKDB : GroupVersioned<Int, UUID, GroupKDB, EntryKDB>, NodeKDBInterface
|
|||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
super.writeToParcel(dest, flags)
|
super.writeToParcel(dest, flags)
|
||||||
dest.writeInt(level)
|
dest.writeInt(level)
|
||||||
dest.writeInt(flags)
|
dest.writeInt(groupFlags)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateWith(source: GroupKDB) {
|
fun updateWith(source: GroupKDB) {
|
||||||
super.updateWith(source)
|
super.updateWith(source)
|
||||||
level = source.level
|
level = source.level
|
||||||
flags = source.flags
|
groupFlags = source.groupFlags
|
||||||
}
|
}
|
||||||
|
|
||||||
override val type: Type
|
override val type: Type
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import com.kunzisoft.keepass.database.element.node.NodeId
|
|||||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||||
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
import com.kunzisoft.keepass.database.element.node.NodeKDBXInterface
|
||||||
import com.kunzisoft.keepass.database.element.node.Type
|
import com.kunzisoft.keepass.database.element.node.Type
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedLong
|
||||||
|
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -77,7 +78,7 @@ class GroupKDBX : GroupVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
|
|
||||||
constructor(parcel: Parcel) : super(parcel) {
|
constructor(parcel: Parcel) : super(parcel) {
|
||||||
iconCustom = parcel.readParcelable(IconImageCustom::class.java.classLoader) ?: iconCustom
|
iconCustom = parcel.readParcelable(IconImageCustom::class.java.classLoader) ?: iconCustom
|
||||||
usageCount = parcel.readLong()
|
usageCount = UnsignedLong(parcel.readLong())
|
||||||
locationChanged = parcel.readParcelable(DateInstant::class.java.classLoader) ?: locationChanged
|
locationChanged = parcel.readParcelable(DateInstant::class.java.classLoader) ?: locationChanged
|
||||||
// TODO customData = ParcelableUtil.readStringParcelableMap(parcel);
|
// TODO customData = ParcelableUtil.readStringParcelableMap(parcel);
|
||||||
notes = parcel.readString() ?: notes
|
notes = parcel.readString() ?: notes
|
||||||
@@ -101,7 +102,7 @@ class GroupKDBX : GroupVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||||
super.writeToParcel(dest, flags)
|
super.writeToParcel(dest, flags)
|
||||||
dest.writeParcelable(iconCustom, flags)
|
dest.writeParcelable(iconCustom, flags)
|
||||||
dest.writeLong(usageCount)
|
dest.writeLong(usageCount.toLong())
|
||||||
dest.writeParcelable(locationChanged, flags)
|
dest.writeParcelable(locationChanged, flags)
|
||||||
// TODO ParcelableUtil.writeStringParcelableMap(dest, customData);
|
// TODO ParcelableUtil.writeStringParcelableMap(dest, customData);
|
||||||
dest.writeString(notes)
|
dest.writeString(notes)
|
||||||
@@ -130,7 +131,7 @@ class GroupKDBX : GroupVersioned<UUID, UUID, GroupKDBX, EntryKDBX>, NodeKDBXInte
|
|||||||
lastTopVisibleEntry = source.lastTopVisibleEntry
|
lastTopVisibleEntry = source.lastTopVisibleEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
override var usageCount: Long = 0
|
override var usageCount = UnsignedLong(0)
|
||||||
|
|
||||||
override var locationChanged = DateInstant()
|
override var locationChanged = DateInstant()
|
||||||
|
|
||||||
|
|||||||
@@ -20,10 +20,11 @@
|
|||||||
package com.kunzisoft.keepass.database.element.node
|
package com.kunzisoft.keepass.database.element.node
|
||||||
|
|
||||||
import com.kunzisoft.keepass.database.element.DateInstant
|
import com.kunzisoft.keepass.database.element.DateInstant
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedLong
|
||||||
|
|
||||||
interface NodeKDBXInterface : NodeTimeInterface {
|
interface NodeKDBXInterface : NodeTimeInterface {
|
||||||
|
|
||||||
var usageCount: Long
|
var usageCount: UnsignedLong
|
||||||
|
|
||||||
var locationChanged: DateInstant
|
var locationChanged: DateInstant
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.database.file
|
package com.kunzisoft.keepass.database.file
|
||||||
|
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
|
|
||||||
abstract class DatabaseHeader {
|
abstract class DatabaseHeader {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,7 +34,7 @@ abstract class DatabaseHeader {
|
|||||||
var encryptionIV = ByteArray(16)
|
var encryptionIV = ByteArray(16)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val PWM_DBSIG_1 = -0x655d26fd
|
val PWM_DBSIG_1 = UnsignedInt(-0x655d26fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,9 @@
|
|||||||
|
|
||||||
package com.kunzisoft.keepass.database.file
|
package com.kunzisoft.keepass.database.file
|
||||||
|
|
||||||
import com.kunzisoft.keepass.stream.bytes4ToInt
|
|
||||||
import com.kunzisoft.keepass.stream.readBytesLength
|
import com.kunzisoft.keepass.stream.readBytesLength
|
||||||
import com.kunzisoft.keepass.stream.readBytes4ToInt
|
import com.kunzisoft.keepass.stream.readBytes4ToUInt
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
@@ -34,15 +34,15 @@ class DatabaseHeaderKDB : DatabaseHeader() {
|
|||||||
*/
|
*/
|
||||||
var transformSeed = ByteArray(32)
|
var transformSeed = ByteArray(32)
|
||||||
|
|
||||||
var signature1: Int = 0 // = PWM_DBSIG_1
|
var signature1 = UnsignedInt(0) // = PWM_DBSIG_1
|
||||||
var signature2: Int = 0 // = DBSIG_2
|
var signature2 = UnsignedInt(0) // = DBSIG_2
|
||||||
var flags: Int = 0
|
var flags= UnsignedInt(0)
|
||||||
var version: Int = 0
|
var version= UnsignedInt(0)
|
||||||
|
|
||||||
/** Number of groups in the database */
|
/** Number of groups in the database */
|
||||||
var numGroups: Int = 0
|
var numGroups = UnsignedInt(0)
|
||||||
/** Number of entries in the database */
|
/** Number of entries in the database */
|
||||||
var numEntries: Int = 0
|
var numEntries = UnsignedInt(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SHA-256 hash of the database, used for integrity check
|
* SHA-256 hash of the database, used for integrity check
|
||||||
@@ -50,28 +50,24 @@ class DatabaseHeaderKDB : DatabaseHeader() {
|
|||||||
var contentsHash = ByteArray(32)
|
var contentsHash = ByteArray(32)
|
||||||
|
|
||||||
// As UInt
|
// As UInt
|
||||||
var numKeyEncRounds: Int = 0
|
var numKeyEncRounds = UnsignedInt(0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse given buf, as read from file.
|
* Parse given buf, as read from file.
|
||||||
*/
|
*/
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun loadFromFile(inputStream: InputStream) {
|
fun loadFromFile(inputStream: InputStream) {
|
||||||
signature1 = inputStream.readBytes4ToInt() // 4 bytes
|
signature1 = inputStream.readBytes4ToUInt() // 4 bytes
|
||||||
signature2 = inputStream.readBytes4ToInt() // 4 bytes
|
signature2 = inputStream.readBytes4ToUInt() // 4 bytes
|
||||||
flags = inputStream.readBytes4ToInt() // 4 bytes
|
flags = inputStream.readBytes4ToUInt() // 4 bytes
|
||||||
version = inputStream.readBytes4ToInt() // 4 bytes
|
version = inputStream.readBytes4ToUInt() // 4 bytes
|
||||||
masterSeed = inputStream.readBytesLength(16) // 16 bytes
|
masterSeed = inputStream.readBytesLength(16) // 16 bytes
|
||||||
encryptionIV = inputStream.readBytesLength(16) // 16 bytes
|
encryptionIV = inputStream.readBytesLength(16) // 16 bytes
|
||||||
numGroups = inputStream.readBytes4ToInt() // 4 bytes
|
numGroups = inputStream.readBytes4ToUInt() // 4 bytes
|
||||||
numEntries = inputStream.readBytes4ToInt() // 4 bytes
|
numEntries = inputStream.readBytes4ToUInt() // 4 bytes
|
||||||
contentsHash = inputStream.readBytesLength(32) // 32 bytes
|
contentsHash = inputStream.readBytesLength(32) // 32 bytes
|
||||||
transformSeed = inputStream.readBytesLength(32) // 32 bytes
|
transformSeed = inputStream.readBytesLength(32) // 32 bytes
|
||||||
numKeyEncRounds = inputStream.readBytes4ToInt()
|
numKeyEncRounds = inputStream.readBytes4ToUInt()
|
||||||
if (numKeyEncRounds < 0) {
|
|
||||||
// TODO: Really treat this like an unsigned integer #443
|
|
||||||
throw IOException("Does not support more than " + Integer.MAX_VALUE + " rounds.")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -88,24 +84,24 @@ class DatabaseHeaderKDB : DatabaseHeader() {
|
|||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
// DB sig from KeePass 1.03
|
// DB sig from KeePass 1.03
|
||||||
const val DBSIG_2 = -0x4ab4049b
|
val DBSIG_2 = UnsignedInt(-0x4ab4049b)
|
||||||
// DB sig from KeePass 1.03
|
// DB sig from KeePass 1.03
|
||||||
const val DBVER_DW = 0x00030003
|
val DBVER_DW = UnsignedInt(0x00030003)
|
||||||
|
|
||||||
const val FLAG_SHA2 = 1
|
val FLAG_SHA2 = UnsignedInt(1)
|
||||||
const val FLAG_RIJNDAEL = 2
|
val FLAG_RIJNDAEL = UnsignedInt(2)
|
||||||
const val FLAG_ARCFOUR = 4
|
val FLAG_ARCFOUR = UnsignedInt(4)
|
||||||
const val FLAG_TWOFISH = 8
|
val FLAG_TWOFISH = UnsignedInt(8)
|
||||||
|
|
||||||
/** Size of byte buffer needed to hold this struct. */
|
/** Size of byte buffer needed to hold this struct. */
|
||||||
const val BUF_SIZE = 124
|
const val BUF_SIZE = 124
|
||||||
|
|
||||||
fun matchesHeader(sig1: Int, sig2: Int): Boolean {
|
fun matchesHeader(sig1: UnsignedInt, sig2: UnsignedInt): Boolean {
|
||||||
return sig1 == PWM_DBSIG_1 && sig2 == DBSIG_2
|
return sig1.toInt() == PWM_DBSIG_1.toInt() && sig2.toInt() == DBSIG_2.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compatibleHeaders(one: Int, two: Int): Boolean {
|
fun compatibleHeaders(one: UnsignedInt, two: UnsignedInt): Boolean {
|
||||||
return one and -0x100 == two and -0x100
|
return one.toInt() and -0x100 == two.toInt() and -0x100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019 Jeremy Jamet / Kunzisoft.
|
* Copyright 2020 Jeremy Jamet / Kunzisoft.
|
||||||
*
|
*
|
||||||
* This file is part of KeePassDX.
|
* This file is part of KeePassDX.
|
||||||
*
|
*
|
||||||
@@ -31,6 +31,8 @@ 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.*
|
import com.kunzisoft.keepass.stream.*
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedLong
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
@@ -45,7 +47,7 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
|||||||
var innerRandomStreamKey: ByteArray = ByteArray(32)
|
var innerRandomStreamKey: ByteArray = ByteArray(32)
|
||||||
var streamStartBytes: ByteArray = ByteArray(32)
|
var streamStartBytes: ByteArray = ByteArray(32)
|
||||||
var innerRandomStream: CrsAlgorithm? = null
|
var innerRandomStream: CrsAlgorithm? = null
|
||||||
var version: Long = 0
|
var version: UnsignedInt = UnsignedInt(0)
|
||||||
|
|
||||||
// version < FILE_VERSION_32_4)
|
// version < FILE_VERSION_32_4)
|
||||||
var transformSeed: ByteArray?
|
var transformSeed: ByteArray?
|
||||||
@@ -103,7 +105,7 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMinKdbxVersion(databaseV4: DatabaseKDBX): Long {
|
private fun getMinKdbxVersion(databaseV4: DatabaseKDBX): UnsignedInt {
|
||||||
// https://keepass.info/help/kb/kdbx_4.html
|
// https://keepass.info/help/kb/kdbx_4.html
|
||||||
|
|
||||||
// Return v4 if AES is not use
|
// Return v4 if AES is not use
|
||||||
@@ -147,8 +149,8 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
|||||||
val digestInputStream = DigestInputStream(copyInputStream, messageDigest)
|
val digestInputStream = DigestInputStream(copyInputStream, messageDigest)
|
||||||
val littleEndianDataInputStream = LittleEndianDataInputStream(digestInputStream)
|
val littleEndianDataInputStream = LittleEndianDataInputStream(digestInputStream)
|
||||||
|
|
||||||
val sig1 = littleEndianDataInputStream.readInt()
|
val sig1 = littleEndianDataInputStream.readUInt()
|
||||||
val sig2 = littleEndianDataInputStream.readInt()
|
val sig2 = littleEndianDataInputStream.readUInt()
|
||||||
|
|
||||||
if (!matchesHeader(sig1, sig2)) {
|
if (!matchesHeader(sig1, sig2)) {
|
||||||
throw VersionDatabaseException()
|
throw VersionDatabaseException()
|
||||||
@@ -172,10 +174,10 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
|||||||
private fun readHeaderField(dis: LittleEndianDataInputStream): Boolean {
|
private fun readHeaderField(dis: LittleEndianDataInputStream): Boolean {
|
||||||
val fieldID = dis.read().toByte()
|
val fieldID = dis.read().toByte()
|
||||||
|
|
||||||
val fieldSize: Int = if (version < FILE_VERSION_32_4) {
|
val fieldSize: Int = if (version.toLong() < FILE_VERSION_32_4.toLong()) {
|
||||||
dis.readUShort()
|
dis.readUShort()
|
||||||
} else {
|
} else {
|
||||||
dis.readInt()
|
dis.readUInt().toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
var fieldData: ByteArray? = null
|
var fieldData: ByteArray? = null
|
||||||
@@ -198,20 +200,20 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
|||||||
|
|
||||||
PwDbHeaderV4Fields.MasterSeed -> masterSeed = fieldData
|
PwDbHeaderV4Fields.MasterSeed -> masterSeed = fieldData
|
||||||
|
|
||||||
PwDbHeaderV4Fields.TransformSeed -> if (version < FILE_VERSION_32_4)
|
PwDbHeaderV4Fields.TransformSeed -> if (version.toLong() < FILE_VERSION_32_4.toLong())
|
||||||
transformSeed = fieldData
|
transformSeed = fieldData
|
||||||
|
|
||||||
PwDbHeaderV4Fields.TransformRounds -> if (version < FILE_VERSION_32_4)
|
PwDbHeaderV4Fields.TransformRounds -> if (version.toLong() < FILE_VERSION_32_4.toLong())
|
||||||
setTransformRound(fieldData)
|
setTransformRound(fieldData)
|
||||||
|
|
||||||
PwDbHeaderV4Fields.EncryptionIV -> encryptionIV = fieldData
|
PwDbHeaderV4Fields.EncryptionIV -> encryptionIV = fieldData
|
||||||
|
|
||||||
PwDbHeaderV4Fields.InnerRandomstreamKey -> if (version < FILE_VERSION_32_4)
|
PwDbHeaderV4Fields.InnerRandomstreamKey -> if (version.toLong() < FILE_VERSION_32_4.toLong())
|
||||||
innerRandomStreamKey = fieldData
|
innerRandomStreamKey = fieldData
|
||||||
|
|
||||||
PwDbHeaderV4Fields.StreamStartBytes -> streamStartBytes = fieldData
|
PwDbHeaderV4Fields.StreamStartBytes -> streamStartBytes = fieldData
|
||||||
|
|
||||||
PwDbHeaderV4Fields.InnerRandomStreamID -> if (version < FILE_VERSION_32_4)
|
PwDbHeaderV4Fields.InnerRandomStreamID -> if (version.toLong() < FILE_VERSION_32_4.toLong())
|
||||||
setRandomStreamID(fieldData)
|
setRandomStreamID(fieldData)
|
||||||
|
|
||||||
PwDbHeaderV4Fields.KdfParameters -> databaseV4.kdfParameters = KdfParameters.deserialize(fieldData)
|
PwDbHeaderV4Fields.KdfParameters -> databaseV4.kdfParameters = KdfParameters.deserialize(fieldData)
|
||||||
@@ -256,8 +258,8 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
|||||||
throw IOException("Invalid compression flags.")
|
throw IOException("Invalid compression flags.")
|
||||||
}
|
}
|
||||||
|
|
||||||
val flag = bytes4ToInt(pbFlags)
|
val flag = bytes4ToUInt(pbFlags)
|
||||||
if (flag < 0 || flag >= CompressionAlgorithm.values().size) {
|
if (flag.toLong() < 0 || flag.toLong() >= CompressionAlgorithm.values().size) {
|
||||||
throw IOException("Unrecognized compression flag.")
|
throw IOException("Unrecognized compression flag.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,8 +274,8 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
|||||||
throw IOException("Invalid stream id.")
|
throw IOException("Invalid stream id.")
|
||||||
}
|
}
|
||||||
|
|
||||||
val id = bytes4ToInt(streamID)
|
val id = bytes4ToUInt(streamID)
|
||||||
if (id < 0 || id >= CrsAlgorithm.values().size) {
|
if (id.toInt() < 0 || id.toInt() >= CrsAlgorithm.values().size) {
|
||||||
throw IOException("Invalid stream id.")
|
throw IOException("Invalid stream id.")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,43 +289,42 @@ class DatabaseHeaderKDBX(private val databaseV4: DatabaseKDBX) : DatabaseHeader(
|
|||||||
* @param version Database version
|
* @param version Database version
|
||||||
* @return true if it's a supported version
|
* @return true if it's a supported version
|
||||||
*/
|
*/
|
||||||
private fun validVersion(version: Long): Boolean {
|
private fun validVersion(version: UnsignedInt): Boolean {
|
||||||
return version and FILE_VERSION_CRITICAL_MASK <= FILE_VERSION_32_4 and FILE_VERSION_CRITICAL_MASK
|
return version.toInt() and FILE_VERSION_CRITICAL_MASK.toInt() <=
|
||||||
|
FILE_VERSION_32_4.toInt() and FILE_VERSION_CRITICAL_MASK.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
var ULONG_MAX_VALUE: Long = -1
|
val DBSIG_PRE2 = UnsignedInt(-0x4ab4049a)
|
||||||
|
val DBSIG_2 = UnsignedInt(-0x4ab40499)
|
||||||
|
|
||||||
const val DBSIG_PRE2 = -0x4ab4049a
|
private val FILE_VERSION_CRITICAL_MASK = UnsignedInt(-0x10000)
|
||||||
const val DBSIG_2 = -0x4ab40499
|
val FILE_VERSION_32_3 = UnsignedInt(0x00030001)
|
||||||
|
val FILE_VERSION_32_4 = UnsignedInt(0x00040000)
|
||||||
|
|
||||||
private const val FILE_VERSION_CRITICAL_MASK: Long = -0x10000
|
fun getCompressionFromFlag(flag: UnsignedInt): CompressionAlgorithm? {
|
||||||
const val FILE_VERSION_32_3: Long = 0x00030001
|
return when (flag.toInt()) {
|
||||||
const val FILE_VERSION_32_4: Long = 0x00040000
|
|
||||||
|
|
||||||
fun getCompressionFromFlag(flag: Int): CompressionAlgorithm? {
|
|
||||||
return when (flag) {
|
|
||||||
0 -> CompressionAlgorithm.None
|
0 -> CompressionAlgorithm.None
|
||||||
1 -> CompressionAlgorithm.GZip
|
1 -> CompressionAlgorithm.GZip
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFlagFromCompression(compression: CompressionAlgorithm): Int {
|
fun getFlagFromCompression(compression: CompressionAlgorithm): UnsignedInt {
|
||||||
return when (compression) {
|
return when (compression) {
|
||||||
CompressionAlgorithm.GZip -> 1
|
CompressionAlgorithm.GZip -> UnsignedInt(1)
|
||||||
else -> 0
|
else -> UnsignedInt(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun matchesHeader(sig1: Int, sig2: Int): Boolean {
|
fun matchesHeader(sig1: UnsignedInt, sig2: UnsignedInt): Boolean {
|
||||||
return sig1 == PWM_DBSIG_1 && (sig2 == DBSIG_PRE2 || sig2 == DBSIG_2)
|
return sig1 == PWM_DBSIG_1 && (sig2 == DBSIG_PRE2 || sig2 == DBSIG_2)
|
||||||
}
|
}
|
||||||
|
|
||||||
@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, ULONG_MAX_VALUE)
|
val blockKey = HmacBlockStream.getHmacKey64(key, UnsignedLong.ULONG_MAX_VALUE)
|
||||||
|
|
||||||
val hmac: Mac
|
val hmac: Mac
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -90,10 +90,10 @@ class DatabaseInputKDB(cacheDirectory: File,
|
|||||||
|
|
||||||
// Select algorithm
|
// Select algorithm
|
||||||
when {
|
when {
|
||||||
header.flags and DatabaseHeaderKDB.FLAG_RIJNDAEL != 0 -> {
|
header.flags.toInt() and DatabaseHeaderKDB.FLAG_RIJNDAEL.toInt() != 0 -> {
|
||||||
mDatabaseToOpen.encryptionAlgorithm = EncryptionAlgorithm.AESRijndael
|
mDatabaseToOpen.encryptionAlgorithm = EncryptionAlgorithm.AESRijndael
|
||||||
}
|
}
|
||||||
header.flags and DatabaseHeaderKDB.FLAG_TWOFISH != 0 -> {
|
header.flags.toInt() and DatabaseHeaderKDB.FLAG_TWOFISH.toInt() != 0 -> {
|
||||||
mDatabaseToOpen.encryptionAlgorithm = EncryptionAlgorithm.Twofish
|
mDatabaseToOpen.encryptionAlgorithm = EncryptionAlgorithm.Twofish
|
||||||
}
|
}
|
||||||
else -> throw InvalidAlgorithmDatabaseException()
|
else -> throw InvalidAlgorithmDatabaseException()
|
||||||
@@ -160,8 +160,8 @@ class DatabaseInputKDB(cacheDirectory: File,
|
|||||||
var newEntry: EntryKDB? = null
|
var newEntry: EntryKDB? = null
|
||||||
var currentGroupNumber = 0
|
var currentGroupNumber = 0
|
||||||
var currentEntryNumber = 0
|
var currentEntryNumber = 0
|
||||||
while (currentGroupNumber < header.numGroups
|
while (currentGroupNumber < header.numGroups.toLong()
|
||||||
|| currentEntryNumber < header.numEntries) {
|
|| currentEntryNumber < header.numEntries.toLong()) {
|
||||||
|
|
||||||
val fieldType = cipherInputStream.readBytes2ToUShort()
|
val fieldType = cipherInputStream.readBytes2ToUShort()
|
||||||
val fieldSize = cipherInputStream.readBytes4ToUInt().toInt()
|
val fieldSize = cipherInputStream.readBytes4ToUInt().toInt()
|
||||||
@@ -175,7 +175,7 @@ class DatabaseInputKDB(cacheDirectory: File,
|
|||||||
when (fieldSize) {
|
when (fieldSize) {
|
||||||
4 -> {
|
4 -> {
|
||||||
newGroup = mDatabaseToOpen.createGroup().apply {
|
newGroup = mDatabaseToOpen.createGroup().apply {
|
||||||
setGroupId(cipherInputStream.readBytes4ToInt())
|
setGroupId(cipherInputStream.readBytes4ToUInt().toInt())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
16 -> {
|
16 -> {
|
||||||
@@ -194,7 +194,7 @@ class DatabaseInputKDB(cacheDirectory: File,
|
|||||||
} ?:
|
} ?:
|
||||||
newEntry?.let { entry ->
|
newEntry?.let { entry ->
|
||||||
val groupKDB = mDatabaseToOpen.createGroup()
|
val groupKDB = mDatabaseToOpen.createGroup()
|
||||||
groupKDB.nodeId = NodeIdInt(cipherInputStream.readBytes4ToInt())
|
groupKDB.nodeId = NodeIdInt(cipherInputStream.readBytes4ToUInt().toInt())
|
||||||
entry.parent = groupKDB
|
entry.parent = groupKDB
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,7 +203,7 @@ class DatabaseInputKDB(cacheDirectory: File,
|
|||||||
group.creationTime = cipherInputStream.readBytes5ToDate()
|
group.creationTime = cipherInputStream.readBytes5ToDate()
|
||||||
} ?:
|
} ?:
|
||||||
newEntry?.let { entry ->
|
newEntry?.let { entry ->
|
||||||
var iconId = cipherInputStream.readBytes4ToInt()
|
var iconId = cipherInputStream.readBytes4ToUInt().toInt()
|
||||||
// Clean up after bug that set icon ids to -1
|
// Clean up after bug that set icon ids to -1
|
||||||
if (iconId == -1) {
|
if (iconId == -1) {
|
||||||
iconId = 0
|
iconId = 0
|
||||||
@@ -237,7 +237,7 @@ class DatabaseInputKDB(cacheDirectory: File,
|
|||||||
}
|
}
|
||||||
0x0007 -> {
|
0x0007 -> {
|
||||||
newGroup?.let { group ->
|
newGroup?.let { group ->
|
||||||
group.icon = mDatabaseToOpen.iconFactory.getIcon(cipherInputStream.readBytes4ToInt())
|
group.icon = mDatabaseToOpen.iconFactory.getIcon(cipherInputStream.readBytes4ToUInt().toInt())
|
||||||
} ?:
|
} ?:
|
||||||
newEntry?.let { entry ->
|
newEntry?.let { entry ->
|
||||||
entry.password = cipherInputStream.readBytesToString(fieldSize,false)
|
entry.password = cipherInputStream.readBytesToString(fieldSize,false)
|
||||||
@@ -253,7 +253,7 @@ class DatabaseInputKDB(cacheDirectory: File,
|
|||||||
}
|
}
|
||||||
0x0009 -> {
|
0x0009 -> {
|
||||||
newGroup?.let { group ->
|
newGroup?.let { group ->
|
||||||
group.flags = cipherInputStream.readBytes4ToInt()
|
group.groupFlags = cipherInputStream.readBytes4ToUInt().toInt()
|
||||||
} ?:
|
} ?:
|
||||||
newEntry?.let { entry ->
|
newEntry?.let { entry ->
|
||||||
entry.creationTime = cipherInputStream.readBytes5ToDate()
|
entry.creationTime = cipherInputStream.readBytes5ToDate()
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ import com.kunzisoft.keepass.database.file.DatabaseKDBXXML
|
|||||||
import com.kunzisoft.keepass.database.file.DateKDBXUtil
|
import com.kunzisoft.keepass.database.file.DateKDBXUtil
|
||||||
import com.kunzisoft.keepass.stream.*
|
import com.kunzisoft.keepass.stream.*
|
||||||
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedLong
|
||||||
import org.bouncycastle.crypto.StreamCipher
|
import org.bouncycastle.crypto.StreamCipher
|
||||||
import org.xmlpull.v1.XmlPullParser
|
import org.xmlpull.v1.XmlPullParser
|
||||||
import org.xmlpull.v1.XmlPullParserException
|
import org.xmlpull.v1.XmlPullParserException
|
||||||
@@ -130,7 +132,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
}
|
}
|
||||||
|
|
||||||
val isPlain: InputStream
|
val isPlain: InputStream
|
||||||
if (mDatabase.kdbxVersion < DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
if (mDatabase.kdbxVersion.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
|
|
||||||
val decrypted = attachCipherStream(databaseInputStream, cipher)
|
val decrypted = attachCipherStream(databaseInputStream, cipher)
|
||||||
val dataDecrypted = LittleEndianDataInputStream(decrypted)
|
val dataDecrypted = LittleEndianDataInputStream(decrypted)
|
||||||
@@ -178,7 +180,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
else -> isPlain
|
else -> isPlain
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mDatabase.kdbxVersion >= DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
if (mDatabase.kdbxVersion.toLong() >= DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
loadInnerHeader(inputStreamXml, header)
|
loadInnerHeader(inputStreamXml, header)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +228,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
header: DatabaseHeaderKDBX): Boolean {
|
header: DatabaseHeaderKDBX): Boolean {
|
||||||
val fieldId = dataInputStream.read().toByte()
|
val fieldId = dataInputStream.read().toByte()
|
||||||
|
|
||||||
val size = dataInputStream.readInt()
|
val size = dataInputStream.readUInt().toInt()
|
||||||
if (size < 0) throw IOException("Corrupted file")
|
if (size < 0) throw IOException("Corrupted file")
|
||||||
|
|
||||||
when (fieldId) {
|
when (fieldId) {
|
||||||
@@ -488,7 +490,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
} else if (name.equals(DatabaseKDBXXML.ElemNotes, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemNotes, ignoreCase = true)) {
|
||||||
ctxGroup?.notes = readString(xpp)
|
ctxGroup?.notes = readString(xpp)
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemIcon, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemIcon, ignoreCase = true)) {
|
||||||
ctxGroup?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, 0).toInt())
|
ctxGroup?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, UnsignedInt(0)).toInt())
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemCustomIconID, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemCustomIconID, ignoreCase = true)) {
|
||||||
ctxGroup?.iconCustom = mDatabase.iconFactory.getIcon(readUuid(xpp))
|
ctxGroup?.iconCustom = mDatabase.iconFactory.getIcon(readUuid(xpp))
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemTimes, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemTimes, ignoreCase = true)) {
|
||||||
@@ -542,7 +544,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
KdbContext.Entry -> if (name.equals(DatabaseKDBXXML.ElemUuid, ignoreCase = true)) {
|
KdbContext.Entry -> if (name.equals(DatabaseKDBXXML.ElemUuid, ignoreCase = true)) {
|
||||||
ctxEntry?.nodeId = NodeIdUUID(readUuid(xpp))
|
ctxEntry?.nodeId = NodeIdUUID(readUuid(xpp))
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemIcon, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemIcon, ignoreCase = true)) {
|
||||||
ctxEntry?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, 0).toInt())
|
ctxEntry?.icon = mDatabase.iconFactory.getIcon(readUInt(xpp, UnsignedInt(0)).toInt())
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemCustomIconID, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemCustomIconID, ignoreCase = true)) {
|
||||||
ctxEntry?.iconCustom = mDatabase.iconFactory.getIcon(readUuid(xpp))
|
ctxEntry?.iconCustom = mDatabase.iconFactory.getIcon(readUuid(xpp))
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemFgColor, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemFgColor, ignoreCase = true)) {
|
||||||
@@ -598,7 +600,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
name.equals(DatabaseKDBXXML.ElemLastAccessTime, ignoreCase = true) -> tl?.lastAccessTime = readPwTime(xpp)
|
name.equals(DatabaseKDBXXML.ElemLastAccessTime, ignoreCase = true) -> tl?.lastAccessTime = readPwTime(xpp)
|
||||||
name.equals(DatabaseKDBXXML.ElemExpiryTime, ignoreCase = true) -> tl?.expiryTime = readPwTime(xpp)
|
name.equals(DatabaseKDBXXML.ElemExpiryTime, ignoreCase = true) -> tl?.expiryTime = readPwTime(xpp)
|
||||||
name.equals(DatabaseKDBXXML.ElemExpires, ignoreCase = true) -> tl?.expires = readBool(xpp, false)
|
name.equals(DatabaseKDBXXML.ElemExpires, ignoreCase = true) -> tl?.expires = readBool(xpp, false)
|
||||||
name.equals(DatabaseKDBXXML.ElemUsageCount, ignoreCase = true) -> tl?.usageCount = readULong(xpp, 0)
|
name.equals(DatabaseKDBXXML.ElemUsageCount, ignoreCase = true) -> tl?.usageCount = readULong(xpp, UnsignedLong(0))
|
||||||
name.equals(DatabaseKDBXXML.ElemLocationChanged, ignoreCase = true) -> tl?.locationChanged = readPwTime(xpp)
|
name.equals(DatabaseKDBXXML.ElemLocationChanged, ignoreCase = true) -> tl?.locationChanged = readPwTime(xpp)
|
||||||
else -> readUnknown(xpp)
|
else -> readUnknown(xpp)
|
||||||
}
|
}
|
||||||
@@ -621,7 +623,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
KdbContext.EntryAutoType -> if (name.equals(DatabaseKDBXXML.ElemAutoTypeEnabled, ignoreCase = true)) {
|
KdbContext.EntryAutoType -> if (name.equals(DatabaseKDBXXML.ElemAutoTypeEnabled, ignoreCase = true)) {
|
||||||
ctxEntry?.autoType?.enabled = readBool(xpp, true)
|
ctxEntry?.autoType?.enabled = readBool(xpp, true)
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemAutoTypeObfuscation, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemAutoTypeObfuscation, ignoreCase = true)) {
|
||||||
ctxEntry?.autoType?.obfuscationOptions = readUInt(xpp, 0)
|
ctxEntry?.autoType?.obfuscationOptions = readUInt(xpp, UnsignedInt(0))
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemAutoTypeDefaultSeq, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemAutoTypeDefaultSeq, ignoreCase = true)) {
|
||||||
ctxEntry?.autoType?.defaultSequence = readString(xpp)
|
ctxEntry?.autoType?.defaultSequence = readString(xpp)
|
||||||
} else if (name.equals(DatabaseKDBXXML.ElemAutoTypeItem, ignoreCase = true)) {
|
} else if (name.equals(DatabaseKDBXXML.ElemAutoTypeItem, ignoreCase = true)) {
|
||||||
@@ -815,7 +817,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
val sDate = readString(xpp)
|
val sDate = readString(xpp)
|
||||||
var utcDate: Date? = null
|
var utcDate: Date? = null
|
||||||
|
|
||||||
if (mDatabase.kdbxVersion >= DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
if (mDatabase.kdbxVersion.toLong() >= DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
var buf = Base64.decode(sDate, BASE_64_FLAG)
|
var buf = Base64.decode(sDate, BASE_64_FLAG)
|
||||||
if (buf.size != 8) {
|
if (buf.size != 8) {
|
||||||
val buf8 = ByteArray(8)
|
val buf8 = ByteArray(8)
|
||||||
@@ -887,48 +889,39 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class, XmlPullParserException::class)
|
@Throws(IOException::class, XmlPullParserException::class)
|
||||||
private fun readInt(xpp: XmlPullParser, def: Int): Int {
|
private fun readInt(xpp: XmlPullParser, default: Int): Int {
|
||||||
val str = readString(xpp)
|
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
Integer.parseInt(str)
|
readString(xpp).toInt()
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: Exception) {
|
||||||
def
|
default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class, XmlPullParserException::class)
|
@Throws(IOException::class, XmlPullParserException::class)
|
||||||
private fun readUInt(xpp: XmlPullParser, uDefault: Long): Long {
|
private fun readUInt(xpp: XmlPullParser, default: UnsignedInt): UnsignedInt {
|
||||||
val u: Long = readULong(xpp, uDefault)
|
|
||||||
|
|
||||||
if (u < 0 || u > MAX_UINT) {
|
|
||||||
throw NumberFormatException("Outside of the uint size")
|
|
||||||
}
|
|
||||||
|
|
||||||
return u
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class, XmlPullParserException::class)
|
|
||||||
private fun readLong(xpp: XmlPullParser, def: Long): Long {
|
|
||||||
val str = readString(xpp)
|
|
||||||
|
|
||||||
return try {
|
return try {
|
||||||
java.lang.Long.parseLong(str)
|
UnsignedInt(readString(xpp).toInt())
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: Exception) {
|
||||||
def
|
default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class, XmlPullParserException::class)
|
@Throws(IOException::class, XmlPullParserException::class)
|
||||||
private fun readULong(xpp: XmlPullParser, uDefault: Long): Long {
|
private fun readLong(xpp: XmlPullParser, default: Long): Long {
|
||||||
var u = readLong(xpp, uDefault)
|
return try {
|
||||||
|
readString(xpp).toLong()
|
||||||
if (u < 0) {
|
} catch (e: Exception) {
|
||||||
u = uDefault
|
default
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return u
|
@Throws(IOException::class, XmlPullParserException::class)
|
||||||
|
private fun readULong(xpp: XmlPullParser, default: UnsignedLong): UnsignedLong {
|
||||||
|
return try {
|
||||||
|
UnsignedLong(readString(xpp).toLong())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
default
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(XmlPullParserException::class, IOException::class)
|
@Throws(XmlPullParserException::class, IOException::class)
|
||||||
@@ -1050,7 +1043,7 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
private const val DEFAULT_HISTORY_DAYS: Long = 365
|
private val DEFAULT_HISTORY_DAYS = UnsignedInt(365)
|
||||||
|
|
||||||
@Throws(XmlPullParserException::class)
|
@Throws(XmlPullParserException::class)
|
||||||
private fun createPullParser(readerStream: InputStream): XmlPullParser {
|
private fun createPullParser(readerStream: InputStream): XmlPullParser {
|
||||||
@@ -1062,8 +1055,6 @@ class DatabaseInputKDBX(cacheDirectory: File,
|
|||||||
|
|
||||||
return xpp
|
return xpp
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val MAX_UINT = 4294967296L // 2^32
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
package com.kunzisoft.keepass.database.file.output
|
package com.kunzisoft.keepass.database.file.output
|
||||||
|
|
||||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDB
|
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDB
|
||||||
import com.kunzisoft.keepass.stream.intTo4Bytes
|
import com.kunzisoft.keepass.stream.uIntTo4Bytes
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
@@ -29,14 +29,14 @@ class DatabaseHeaderOutputKDB(private val mHeader: DatabaseHeaderKDB,
|
|||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun outputStart() {
|
fun outputStart() {
|
||||||
mOutputStream.write(intTo4Bytes(mHeader.signature1))
|
mOutputStream.write(uIntTo4Bytes(mHeader.signature1))
|
||||||
mOutputStream.write(intTo4Bytes(mHeader.signature2))
|
mOutputStream.write(uIntTo4Bytes(mHeader.signature2))
|
||||||
mOutputStream.write(intTo4Bytes(mHeader.flags))
|
mOutputStream.write(uIntTo4Bytes(mHeader.flags))
|
||||||
mOutputStream.write(intTo4Bytes(mHeader.version))
|
mOutputStream.write(uIntTo4Bytes(mHeader.version))
|
||||||
mOutputStream.write(mHeader.masterSeed)
|
mOutputStream.write(mHeader.masterSeed)
|
||||||
mOutputStream.write(mHeader.encryptionIV)
|
mOutputStream.write(mHeader.encryptionIV)
|
||||||
mOutputStream.write(intTo4Bytes(mHeader.numGroups))
|
mOutputStream.write(uIntTo4Bytes(mHeader.numGroups))
|
||||||
mOutputStream.write(intTo4Bytes(mHeader.numEntries))
|
mOutputStream.write(uIntTo4Bytes(mHeader.numEntries))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
@@ -47,7 +47,7 @@ class DatabaseHeaderOutputKDB(private val mHeader: DatabaseHeaderKDB,
|
|||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun outputEnd() {
|
fun outputEnd() {
|
||||||
mOutputStream.write(mHeader.transformSeed)
|
mOutputStream.write(mHeader.transformSeed)
|
||||||
mOutputStream.write(intTo4Bytes(mHeader.numKeyEncRounds))
|
mOutputStream.write(uIntTo4Bytes(mHeader.numKeyEncRounds))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@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.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.database.file.DatabaseHeaderKDBX.Companion.ULONG_MAX_VALUE
|
|
||||||
import com.kunzisoft.keepass.stream.*
|
import com.kunzisoft.keepass.stream.*
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedLong
|
||||||
import com.kunzisoft.keepass.utils.VariantDictionary
|
import com.kunzisoft.keepass.utils.VariantDictionary
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@@ -66,7 +66,7 @@ constructor(private val databaseKDBX: DatabaseKDBX,
|
|||||||
val hmac: Mac
|
val hmac: Mac
|
||||||
try {
|
try {
|
||||||
hmac = Mac.getInstance("HmacSHA256")
|
hmac = Mac.getInstance("HmacSHA256")
|
||||||
val signingKey = SecretKeySpec(HmacBlockStream.getHmacKey64(hmacKey, ULONG_MAX_VALUE), "HmacSHA256")
|
val signingKey = SecretKeySpec(HmacBlockStream.getHmacKey64(hmacKey, UnsignedLong.ULONG_MAX_VALUE), "HmacSHA256")
|
||||||
hmac.init(signingKey)
|
hmac.init(signingKey)
|
||||||
} catch (e: NoSuchAlgorithmException) {
|
} catch (e: NoSuchAlgorithmException) {
|
||||||
throw DatabaseOutputException(e)
|
throw DatabaseOutputException(e)
|
||||||
@@ -82,15 +82,15 @@ constructor(private val databaseKDBX: DatabaseKDBX,
|
|||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun output() {
|
fun output() {
|
||||||
|
|
||||||
los.writeUInt(DatabaseHeader.PWM_DBSIG_1.toLong())
|
los.writeUInt(DatabaseHeader.PWM_DBSIG_1)
|
||||||
los.writeUInt(DatabaseHeaderKDBX.DBSIG_2.toLong())
|
los.writeUInt(DatabaseHeaderKDBX.DBSIG_2)
|
||||||
los.writeUInt(header.version)
|
los.writeUInt(header.version)
|
||||||
|
|
||||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CipherID, uuidTo16Bytes(databaseKDBX.dataCipher))
|
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CipherID, uuidTo16Bytes(databaseKDBX.dataCipher))
|
||||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CompressionFlags, intTo4Bytes(DatabaseHeaderKDBX.getFlagFromCompression(databaseKDBX.compressionAlgorithm)))
|
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CompressionFlags, uIntTo4Bytes(DatabaseHeaderKDBX.getFlagFromCompression(databaseKDBX.compressionAlgorithm)))
|
||||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.MasterSeed, header.masterSeed)
|
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.MasterSeed, header.masterSeed)
|
||||||
|
|
||||||
if (header.version < DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
if (header.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.TransformSeed, header.transformSeed)
|
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.TransformSeed, header.transformSeed)
|
||||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.TransformRounds, longTo8Bytes(databaseKDBX.numberKeyEncryptionRounds))
|
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.TransformRounds, longTo8Bytes(databaseKDBX.numberKeyEncryptionRounds))
|
||||||
} else {
|
} else {
|
||||||
@@ -101,10 +101,10 @@ constructor(private val databaseKDBX: DatabaseKDBX,
|
|||||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.EncryptionIV, header.encryptionIV)
|
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.EncryptionIV, header.encryptionIV)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.version < DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
if (header.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.InnerRandomstreamKey, header.innerRandomStreamKey)
|
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.InnerRandomstreamKey, header.innerRandomStreamKey)
|
||||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.StreamStartBytes, header.streamStartBytes)
|
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.StreamStartBytes, header.streamStartBytes)
|
||||||
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.InnerRandomStreamID, intTo4Bytes(header.innerRandomStream!!.id))
|
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.InnerRandomStreamID, uIntTo4Bytes(header.innerRandomStream!!.id))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (databaseKDBX.containsPublicCustomData()) {
|
if (databaseKDBX.containsPublicCustomData()) {
|
||||||
@@ -136,7 +136,7 @@ constructor(private val databaseKDBX: DatabaseKDBX,
|
|||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
private fun writeHeaderFieldSize(size: Int) {
|
private fun writeHeaderFieldSize(size: Int) {
|
||||||
if (header.version < DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
if (header.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
los.writeUShort(size)
|
los.writeUShort(size)
|
||||||
} else {
|
} else {
|
||||||
los.writeInt(size)
|
los.writeInt(size)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class DatabaseInnerHeaderOutputKDBX(private val database: DatabaseKDBX,
|
|||||||
dataOutputStream.writeInt(4)
|
dataOutputStream.writeInt(4)
|
||||||
if (header.innerRandomStream == null)
|
if (header.innerRandomStream == null)
|
||||||
throw IOException("Can't write innerRandomStream")
|
throw IOException("Can't write innerRandomStream")
|
||||||
dataOutputStream.writeInt(header.innerRandomStream!!.id)
|
dataOutputStream.writeInt(header.innerRandomStream!!.id.toInt())
|
||||||
|
|
||||||
val streamKeySize = header.innerRandomStreamKey.size
|
val streamKeySize = header.innerRandomStreamKey.size
|
||||||
dataOutputStream.write(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.InnerRandomstreamKey.toInt())
|
dataOutputStream.write(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.InnerRandomstreamKey.toInt())
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import com.kunzisoft.keepass.database.file.DatabaseHeader
|
|||||||
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDB
|
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDB
|
||||||
import com.kunzisoft.keepass.stream.LittleEndianDataOutputStream
|
import com.kunzisoft.keepass.stream.LittleEndianDataOutputStream
|
||||||
import com.kunzisoft.keepass.stream.NullOutputStream
|
import com.kunzisoft.keepass.stream.NullOutputStream
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.BufferedOutputStream
|
import java.io.BufferedOutputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
@@ -117,18 +118,18 @@ class DatabaseOutputKDB(private val mDatabaseKDB: DatabaseKDB,
|
|||||||
|
|
||||||
when {
|
when {
|
||||||
mDatabaseKDB.encryptionAlgorithm === EncryptionAlgorithm.AESRijndael -> {
|
mDatabaseKDB.encryptionAlgorithm === EncryptionAlgorithm.AESRijndael -> {
|
||||||
header.flags = header.flags or DatabaseHeaderKDB.FLAG_RIJNDAEL
|
header.flags = UnsignedInt(header.flags.toInt() or DatabaseHeaderKDB.FLAG_RIJNDAEL.toInt())
|
||||||
}
|
}
|
||||||
mDatabaseKDB.encryptionAlgorithm === EncryptionAlgorithm.Twofish -> {
|
mDatabaseKDB.encryptionAlgorithm === EncryptionAlgorithm.Twofish -> {
|
||||||
header.flags = header.flags or DatabaseHeaderKDB.FLAG_TWOFISH
|
header.flags = UnsignedInt(header.flags.toInt() or DatabaseHeaderKDB.FLAG_TWOFISH.toInt())
|
||||||
}
|
}
|
||||||
else -> throw DatabaseOutputException("Unsupported algorithm.")
|
else -> throw DatabaseOutputException("Unsupported algorithm.")
|
||||||
}
|
}
|
||||||
|
|
||||||
header.version = DatabaseHeaderKDB.DBVER_DW
|
header.version = DatabaseHeaderKDB.DBVER_DW
|
||||||
header.numGroups = mDatabaseKDB.numberOfGroups()
|
header.numGroups = UnsignedInt(mDatabaseKDB.numberOfGroups())
|
||||||
header.numEntries = mDatabaseKDB.numberOfEntries()
|
header.numEntries = UnsignedInt(mDatabaseKDB.numberOfEntries())
|
||||||
header.numKeyEncRounds = mDatabaseKDB.numberKeyEncryptionRounds.toInt() // TODO Signed Long - Unsigned Int #443
|
header.numKeyEncRounds = UnsignedInt.fromLong(mDatabaseKDB.numberKeyEncryptionRounds)
|
||||||
|
|
||||||
setIVs(header)
|
setIVs(header)
|
||||||
|
|
||||||
@@ -279,6 +280,5 @@ class DatabaseOutputKDB(private val mDatabaseKDB: DatabaseKDB,
|
|||||||
if (data != null) {
|
if (data != null) {
|
||||||
los.write(data)
|
los.write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,7 +85,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
header = outputHeader(mOS)
|
header = outputHeader(mOS)
|
||||||
|
|
||||||
val osPlain: OutputStream
|
val osPlain: OutputStream
|
||||||
osPlain = if (header!!.version < DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
osPlain = if (header!!.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
val cos = attachStreamEncryptor(header!!, mOS)
|
val cos = attachStreamEncryptor(header!!, mOS)
|
||||||
cos.write(header!!.streamStartBytes)
|
cos.write(header!!.streamStartBytes)
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
else -> osPlain
|
else -> osPlain
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header!!.version >= DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
if (header!!.version.toLong() >= DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
val ihOut = DatabaseInnerHeaderOutputKDBX(mDatabaseKDBX, header!!, osXml)
|
val ihOut = DatabaseInnerHeaderOutputKDBX(mDatabaseKDBX, header!!, osXml)
|
||||||
ihOut.output()
|
ihOut.output()
|
||||||
}
|
}
|
||||||
@@ -209,7 +209,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
writeObject(DatabaseKDBXXML.ElemDbDescChanged, mDatabaseKDBX.descriptionChanged.date)
|
writeObject(DatabaseKDBXXML.ElemDbDescChanged, mDatabaseKDBX.descriptionChanged.date)
|
||||||
writeObject(DatabaseKDBXXML.ElemDbDefaultUser, mDatabaseKDBX.defaultUserName, true)
|
writeObject(DatabaseKDBXXML.ElemDbDefaultUser, mDatabaseKDBX.defaultUserName, true)
|
||||||
writeObject(DatabaseKDBXXML.ElemDbDefaultUserChanged, mDatabaseKDBX.defaultUserNameChanged.date)
|
writeObject(DatabaseKDBXXML.ElemDbDefaultUserChanged, mDatabaseKDBX.defaultUserNameChanged.date)
|
||||||
writeObject(DatabaseKDBXXML.ElemDbMntncHistoryDays, mDatabaseKDBX.maintenanceHistoryDays)
|
writeObject(DatabaseKDBXXML.ElemDbMntncHistoryDays, mDatabaseKDBX.maintenanceHistoryDays.toLong())
|
||||||
writeObject(DatabaseKDBXXML.ElemDbColor, mDatabaseKDBX.color)
|
writeObject(DatabaseKDBXXML.ElemDbColor, mDatabaseKDBX.color)
|
||||||
writeObject(DatabaseKDBXXML.ElemDbKeyChanged, mDatabaseKDBX.keyLastChanged.date)
|
writeObject(DatabaseKDBXXML.ElemDbKeyChanged, mDatabaseKDBX.keyLastChanged.date)
|
||||||
writeObject(DatabaseKDBXXML.ElemDbKeyChangeRec, mDatabaseKDBX.keyChangeRecDays)
|
writeObject(DatabaseKDBXXML.ElemDbKeyChangeRec, mDatabaseKDBX.keyChangeRecDays)
|
||||||
@@ -230,7 +230,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
writeUuid(DatabaseKDBXXML.ElemLastTopVisibleGroup, mDatabaseKDBX.lastTopVisibleGroupUUID)
|
writeUuid(DatabaseKDBXXML.ElemLastTopVisibleGroup, mDatabaseKDBX.lastTopVisibleGroupUUID)
|
||||||
|
|
||||||
// Seem to work properly if always in meta
|
// Seem to work properly if always in meta
|
||||||
if (header!!.version < DatabaseHeaderKDBX.FILE_VERSION_32_4)
|
if (header!!.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong())
|
||||||
writeMetaBinaries()
|
writeMetaBinaries()
|
||||||
|
|
||||||
writeCustomData(mDatabaseKDBX.customData)
|
writeCustomData(mDatabaseKDBX.customData)
|
||||||
@@ -274,7 +274,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
Log.e(TAG, "Unable to retrieve header", unknownKDF)
|
Log.e(TAG, "Unable to retrieve header", unknownKDF)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.version < DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
if (header.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
header.innerRandomStream = CrsAlgorithm.Salsa20
|
header.innerRandomStream = CrsAlgorithm.Salsa20
|
||||||
header.innerRandomStreamKey = ByteArray(32)
|
header.innerRandomStreamKey = ByteArray(32)
|
||||||
} else {
|
} else {
|
||||||
@@ -288,7 +288,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
throw DatabaseOutputException("Invalid random cipher")
|
throw DatabaseOutputException("Invalid random cipher")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header.version < DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
if (header.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
random.nextBytes(header.streamStartBytes)
|
random.nextBytes(header.streamStartBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,7 +385,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
|
|
||||||
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
|
||||||
private fun writeObject(name: String, value: Date) {
|
private fun writeObject(name: String, value: Date) {
|
||||||
if (header!!.version < DatabaseHeaderKDBX.FILE_VERSION_32_4) {
|
if (header!!.version.toLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toLong()) {
|
||||||
writeObject(name, DatabaseKDBXXML.DateFormatter.format(value))
|
writeObject(name, DatabaseKDBXXML.DateFormatter.format(value))
|
||||||
} else {
|
} else {
|
||||||
val dt = DateTime(value)
|
val dt = DateTime(value)
|
||||||
@@ -489,7 +489,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
xml.startTag(null, DatabaseKDBXXML.ElemAutoType)
|
xml.startTag(null, DatabaseKDBXXML.ElemAutoType)
|
||||||
|
|
||||||
writeObject(DatabaseKDBXXML.ElemAutoTypeEnabled, autoType.enabled)
|
writeObject(DatabaseKDBXXML.ElemAutoTypeEnabled, autoType.enabled)
|
||||||
writeObject(DatabaseKDBXXML.ElemAutoTypeObfuscation, autoType.obfuscationOptions)
|
writeObject(DatabaseKDBXXML.ElemAutoTypeObfuscation, autoType.obfuscationOptions.toLong())
|
||||||
|
|
||||||
if (autoType.defaultSequence.isNotEmpty()) {
|
if (autoType.defaultSequence.isNotEmpty()) {
|
||||||
writeObject(DatabaseKDBXXML.ElemAutoTypeDefaultSeq, autoType.defaultSequence, true)
|
writeObject(DatabaseKDBXXML.ElemAutoTypeDefaultSeq, autoType.defaultSequence, true)
|
||||||
@@ -629,7 +629,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
|
|||||||
writeObject(DatabaseKDBXXML.ElemLastAccessTime, node.lastAccessTime.date)
|
writeObject(DatabaseKDBXXML.ElemLastAccessTime, node.lastAccessTime.date)
|
||||||
writeObject(DatabaseKDBXXML.ElemExpiryTime, node.expiryTime.date)
|
writeObject(DatabaseKDBXXML.ElemExpiryTime, node.expiryTime.date)
|
||||||
writeObject(DatabaseKDBXXML.ElemExpires, node.expires)
|
writeObject(DatabaseKDBXXML.ElemExpires, node.expires)
|
||||||
writeObject(DatabaseKDBXXML.ElemUsageCount, node.usageCount)
|
writeObject(DatabaseKDBXXML.ElemUsageCount, node.usageCount.toLong())
|
||||||
writeObject(DatabaseKDBXXML.ElemLocationChanged, node.locationChanged.date)
|
writeObject(DatabaseKDBXXML.ElemLocationChanged, node.locationChanged.date)
|
||||||
|
|
||||||
xml.endTag(null, DatabaseKDBXXML.ElemTimes)
|
xml.endTag(null, DatabaseKDBXXML.ElemTimes)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.kunzisoft.keepass.database.element.entry.EntryKDB
|
|||||||
import com.kunzisoft.keepass.database.file.output.GroupOutputKDB.Companion.GROUPID_FIELD_SIZE
|
import com.kunzisoft.keepass.database.file.output.GroupOutputKDB.Companion.GROUPID_FIELD_SIZE
|
||||||
import com.kunzisoft.keepass.stream.*
|
import com.kunzisoft.keepass.stream.*
|
||||||
import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils
|
import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
@@ -54,12 +55,12 @@ class EntryOutputKDB
|
|||||||
// Group ID
|
// Group ID
|
||||||
mOutputStream.write(GROUPID_FIELD_TYPE)
|
mOutputStream.write(GROUPID_FIELD_TYPE)
|
||||||
mOutputStream.write(GROUPID_FIELD_SIZE)
|
mOutputStream.write(GROUPID_FIELD_SIZE)
|
||||||
mOutputStream.write(intTo4Bytes(mEntry.parent!!.id))
|
mOutputStream.write(uIntTo4Bytes(UnsignedInt(mEntry.parent!!.id)))
|
||||||
|
|
||||||
// Image ID
|
// Image ID
|
||||||
mOutputStream.write(IMAGEID_FIELD_TYPE)
|
mOutputStream.write(IMAGEID_FIELD_TYPE)
|
||||||
mOutputStream.write(IMAGEID_FIELD_SIZE)
|
mOutputStream.write(IMAGEID_FIELD_SIZE)
|
||||||
mOutputStream.write(intTo4Bytes(mEntry.icon.iconId))
|
mOutputStream.write(uIntTo4Bytes(UnsignedInt(mEntry.icon.iconId)))
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
//byte[] title = mEntry.title.getBytes("UTF-8");
|
//byte[] title = mEntry.title.getBytes("UTF-8");
|
||||||
@@ -101,14 +102,9 @@ class EntryOutputKDB
|
|||||||
// Binary
|
// Binary
|
||||||
mOutputStream.write(BINARY_DATA_FIELD_TYPE)
|
mOutputStream.write(BINARY_DATA_FIELD_TYPE)
|
||||||
val binaryData = mEntry.binaryData
|
val binaryData = mEntry.binaryData
|
||||||
val binaryDataLength = binaryData?.length() ?: 0
|
val binaryDataLength = binaryData?.length() ?: 0L
|
||||||
val binaryDataLengthRightSize = if (binaryDataLength <= Int.MAX_VALUE) {
|
|
||||||
binaryDataLength.toInt()
|
|
||||||
} else {
|
|
||||||
0 // TODO if length > UInt.maxvalue show exception #443
|
|
||||||
}
|
|
||||||
// Write data length
|
// Write data length
|
||||||
mOutputStream.write(intTo4Bytes(binaryDataLengthRightSize))
|
mOutputStream.write(uIntTo4Bytes(UnsignedInt.fromLong(binaryDataLength)))
|
||||||
// Write data
|
// Write data
|
||||||
if (binaryDataLength > 0) {
|
if (binaryDataLength > 0) {
|
||||||
binaryData?.getInputDataStream().use { inputStream ->
|
binaryData?.getInputDataStream().use { inputStream ->
|
||||||
@@ -140,7 +136,7 @@ class EntryOutputKDB
|
|||||||
private fun writePassword(str: String, os: OutputStream): Int {
|
private fun writePassword(str: String, os: OutputStream): Int {
|
||||||
val initial = str.toByteArray(Charset.forName("UTF-8"))
|
val initial = str.toByteArray(Charset.forName("UTF-8"))
|
||||||
val length = initial.size + 1
|
val length = initial.size + 1
|
||||||
os.write(intTo4Bytes(length))
|
os.write(uIntTo4Bytes(UnsignedInt(length)))
|
||||||
os.write(initial)
|
os.write(initial)
|
||||||
os.write(0x00)
|
os.write(0x00)
|
||||||
return length
|
return length
|
||||||
@@ -164,13 +160,13 @@ class EntryOutputKDB
|
|||||||
val BINARY_DATA_FIELD_TYPE:ByteArray = uShortTo2Bytes(14)
|
val BINARY_DATA_FIELD_TYPE:ByteArray = uShortTo2Bytes(14)
|
||||||
val END_FIELD_TYPE:ByteArray = uShortTo2Bytes(0xFFFF)
|
val END_FIELD_TYPE:ByteArray = uShortTo2Bytes(0xFFFF)
|
||||||
|
|
||||||
val LONG_FOUR:ByteArray = intTo4Bytes(4)
|
val LONG_FOUR:ByteArray = uIntTo4Bytes(UnsignedInt(4))
|
||||||
val UUID_FIELD_SIZE:ByteArray = intTo4Bytes(16)
|
val UUID_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(16))
|
||||||
val DATE_FIELD_SIZE:ByteArray = intTo4Bytes(5)
|
val DATE_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(5))
|
||||||
val IMAGEID_FIELD_SIZE:ByteArray = intTo4Bytes(4)
|
val IMAGEID_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(4))
|
||||||
val LEVEL_FIELD_SIZE:ByteArray = intTo4Bytes(4)
|
val LEVEL_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(4))
|
||||||
val FLAGS_FIELD_SIZE:ByteArray = intTo4Bytes(4)
|
val FLAGS_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(4))
|
||||||
val ZERO_FIELD_SIZE:ByteArray = intTo4Bytes(0)
|
val ZERO_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(0))
|
||||||
val ZERO_FIVE:ByteArray = byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00)
|
val ZERO_FIVE:ByteArray = byteArrayOf(0x00, 0x00, 0x00, 0x00, 0x00)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ package com.kunzisoft.keepass.database.file.output
|
|||||||
|
|
||||||
import com.kunzisoft.keepass.database.element.group.GroupKDB
|
import com.kunzisoft.keepass.database.element.group.GroupKDB
|
||||||
import com.kunzisoft.keepass.stream.dateTo5Bytes
|
import com.kunzisoft.keepass.stream.dateTo5Bytes
|
||||||
import com.kunzisoft.keepass.stream.intTo4Bytes
|
import com.kunzisoft.keepass.stream.uIntTo4Bytes
|
||||||
import com.kunzisoft.keepass.stream.uShortTo2Bytes
|
import com.kunzisoft.keepass.stream.uShortTo2Bytes
|
||||||
import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils
|
import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ class GroupOutputKDB (private val mGroup: GroupKDB, private val mOutputStream: O
|
|||||||
// Group ID
|
// Group ID
|
||||||
mOutputStream.write(GROUPID_FIELD_TYPE)
|
mOutputStream.write(GROUPID_FIELD_TYPE)
|
||||||
mOutputStream.write(GROUPID_FIELD_SIZE)
|
mOutputStream.write(GROUPID_FIELD_SIZE)
|
||||||
mOutputStream.write(intTo4Bytes(mGroup.id))
|
mOutputStream.write(uIntTo4Bytes(UnsignedInt(mGroup.id)))
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
mOutputStream.write(NAME_FIELD_TYPE)
|
mOutputStream.write(NAME_FIELD_TYPE)
|
||||||
@@ -68,7 +69,7 @@ class GroupOutputKDB (private val mGroup: GroupKDB, private val mOutputStream: O
|
|||||||
// Image ID
|
// Image ID
|
||||||
mOutputStream.write(IMAGEID_FIELD_TYPE)
|
mOutputStream.write(IMAGEID_FIELD_TYPE)
|
||||||
mOutputStream.write(IMAGEID_FIELD_SIZE)
|
mOutputStream.write(IMAGEID_FIELD_SIZE)
|
||||||
mOutputStream.write(intTo4Bytes(mGroup.icon.iconId))
|
mOutputStream.write(uIntTo4Bytes(UnsignedInt(mGroup.icon.iconId)))
|
||||||
|
|
||||||
// Level
|
// Level
|
||||||
mOutputStream.write(LEVEL_FIELD_TYPE)
|
mOutputStream.write(LEVEL_FIELD_TYPE)
|
||||||
@@ -78,7 +79,7 @@ class GroupOutputKDB (private val mGroup: GroupKDB, private val mOutputStream: O
|
|||||||
// Flags
|
// Flags
|
||||||
mOutputStream.write(FLAGS_FIELD_TYPE)
|
mOutputStream.write(FLAGS_FIELD_TYPE)
|
||||||
mOutputStream.write(FLAGS_FIELD_SIZE)
|
mOutputStream.write(FLAGS_FIELD_SIZE)
|
||||||
mOutputStream.write(intTo4Bytes(mGroup.flags))
|
mOutputStream.write(uIntTo4Bytes(UnsignedInt(mGroup.groupFlags)))
|
||||||
|
|
||||||
// End
|
// End
|
||||||
mOutputStream.write(END_FIELD_TYPE)
|
mOutputStream.write(END_FIELD_TYPE)
|
||||||
@@ -98,11 +99,11 @@ class GroupOutputKDB (private val mGroup: GroupKDB, private val mOutputStream: O
|
|||||||
val FLAGS_FIELD_TYPE:ByteArray = uShortTo2Bytes(9)
|
val FLAGS_FIELD_TYPE:ByteArray = uShortTo2Bytes(9)
|
||||||
val END_FIELD_TYPE:ByteArray = uShortTo2Bytes(0xFFFF)
|
val END_FIELD_TYPE:ByteArray = uShortTo2Bytes(0xFFFF)
|
||||||
|
|
||||||
val GROUPID_FIELD_SIZE:ByteArray = intTo4Bytes(4)
|
val GROUPID_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(4))
|
||||||
val DATE_FIELD_SIZE:ByteArray = intTo4Bytes(5)
|
val DATE_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(5))
|
||||||
val IMAGEID_FIELD_SIZE:ByteArray = intTo4Bytes(4)
|
val IMAGEID_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(4))
|
||||||
val LEVEL_FIELD_SIZE:ByteArray = intTo4Bytes(2)
|
val LEVEL_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(2))
|
||||||
val FLAGS_FIELD_SIZE:ByteArray = intTo4Bytes(4)
|
val FLAGS_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(4))
|
||||||
val ZERO_FIELD_SIZE:ByteArray = intTo4Bytes(0)
|
val ZERO_FIELD_SIZE:ByteArray = uIntTo4Bytes(UnsignedInt(0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -444,8 +444,8 @@ class NestedDatabaseSettingsFragment : NestedSettingsFragment() {
|
|||||||
mMemoryPref?.summary = memoryToShow.toString()
|
mMemoryPref?.summary = memoryToShow.toString()
|
||||||
}
|
}
|
||||||
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_PARALLELISM_TASK -> {
|
DatabaseTaskNotificationService.ACTION_DATABASE_UPDATE_PARALLELISM_TASK -> {
|
||||||
val oldParallelism = data.getInt(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
|
val oldParallelism = data.getLong(DatabaseTaskNotificationService.OLD_ELEMENT_KEY)
|
||||||
val newParallelism = data.getInt(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
|
val newParallelism = data.getLong(DatabaseTaskNotificationService.NEW_ELEMENT_KEY)
|
||||||
val parallelismToShow =
|
val parallelismToShow =
|
||||||
if (result.isSuccess) {
|
if (result.isSuccess) {
|
||||||
newParallelism
|
newParallelism
|
||||||
|
|||||||
@@ -35,27 +35,26 @@ class ParallelismPreferenceDialogFragmentCompat : DatabaseSavePreferenceDialogFr
|
|||||||
override fun onDialogClosed(positiveResult: Boolean) {
|
override fun onDialogClosed(positiveResult: Boolean) {
|
||||||
if (positiveResult) {
|
if (positiveResult) {
|
||||||
database?.let { database ->
|
database?.let { database ->
|
||||||
var parallelism: Int = try {
|
val parallelism: Long = try {
|
||||||
inputText.toInt()
|
inputText.toLong()
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
MIN_PARALLELISM
|
MIN_PARALLELISM
|
||||||
}
|
}
|
||||||
if (parallelism < MIN_PARALLELISM) {
|
|
||||||
parallelism = MIN_PARALLELISM
|
|
||||||
}
|
|
||||||
// TODO Max Parallelism
|
|
||||||
|
|
||||||
val oldParallelism = database.parallelism
|
val oldParallelism = database.parallelism
|
||||||
database.parallelism = parallelism
|
database.parallelism = parallelism
|
||||||
|
|
||||||
mProgressDialogThread?.startDatabaseSaveParallelism(oldParallelism, parallelism, mDatabaseAutoSaveEnable)
|
mProgressDialogThread?.startDatabaseSaveParallelism(
|
||||||
|
oldParallelism,
|
||||||
|
parallelism,
|
||||||
|
mDatabaseAutoSaveEnable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val MIN_PARALLELISM = 1
|
const val MIN_PARALLELISM = 1L
|
||||||
|
|
||||||
fun newInstance(key: String): ParallelismPreferenceDialogFragmentCompat {
|
fun newInstance(key: String): ParallelismPreferenceDialogFragmentCompat {
|
||||||
val fragment = ParallelismPreferenceDialogFragmentCompat()
|
val fragment = ParallelismPreferenceDialogFragmentCompat()
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.stream
|
package com.kunzisoft.keepass.stream
|
||||||
|
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
@@ -80,7 +81,7 @@ class HashedBlockInputStream(inputStream: InputStream) : InputStream() {
|
|||||||
bufferPos = 0
|
bufferPos = 0
|
||||||
|
|
||||||
val index = baseStream.readUInt()
|
val index = baseStream.readUInt()
|
||||||
if (index != bufferIndex) {
|
if (index.toLong() != bufferIndex) {
|
||||||
throw IOException("Invalid data format")
|
throw IOException("Invalid data format")
|
||||||
}
|
}
|
||||||
bufferIndex++
|
bufferIndex++
|
||||||
@@ -90,11 +91,7 @@ class HashedBlockInputStream(inputStream: InputStream) : InputStream() {
|
|||||||
throw IOException("Invalid data format")
|
throw IOException("Invalid data format")
|
||||||
}
|
}
|
||||||
|
|
||||||
val bufferSize = baseStream.readBytes4ToInt()
|
val bufferSize = baseStream.readBytes4ToUInt().toInt()
|
||||||
if (bufferSize < 0) {
|
|
||||||
throw IOException("Invalid data format")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bufferSize == 0) {
|
if (bufferSize == 0) {
|
||||||
for (hash in 0 until HASH_SIZE) {
|
for (hash in 0 until HASH_SIZE) {
|
||||||
if (storedHash[hash].toInt() != 0) {
|
if (storedHash[hash].toInt() != 0) {
|
||||||
@@ -144,7 +141,7 @@ class HashedBlockInputStream(inputStream: InputStream) : InputStream() {
|
|||||||
if (!readHashedBlock()) return -1
|
if (!readHashedBlock()) return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
val output = byteToUInt(buffer[bufferPos])
|
val output = UnsignedInt.fromByte(buffer[bufferPos]).toInt()
|
||||||
bufferPos++
|
bufferPos++
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.stream
|
package com.kunzisoft.keepass.stream
|
||||||
|
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
@@ -98,7 +99,7 @@ class HashedBlockOutputStream : OutputStream {
|
|||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
private fun writeHashedBlock() {
|
private fun writeHashedBlock() {
|
||||||
baseStream.writeUInt(bufferIndex)
|
baseStream.writeUInt(UnsignedInt.fromLong(bufferIndex))
|
||||||
bufferIndex++
|
bufferIndex++
|
||||||
|
|
||||||
if (bufferPos > 0) {
|
if (bufferPos > 0) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.stream
|
package com.kunzisoft.keepass.stream
|
||||||
|
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.security.InvalidKeyException
|
import java.security.InvalidKeyException
|
||||||
@@ -43,7 +44,7 @@ class HmacBlockInputStream(baseStream: InputStream, private val verify: Boolean,
|
|||||||
if (!readSafeBlock()) return -1
|
if (!readSafeBlock()) return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
val output = byteToUInt(buffer[bufferPos])
|
val output = UnsignedInt.fromByte(buffer[bufferPos]).toInt()
|
||||||
bufferPos++
|
bufferPos++
|
||||||
|
|
||||||
return output
|
return output
|
||||||
@@ -97,10 +98,10 @@ class HmacBlockInputStream(baseStream: InputStream, private val verify: Boolean,
|
|||||||
if (pbBlockSize.size != 4) {
|
if (pbBlockSize.size != 4) {
|
||||||
throw IOException("File corrupted")
|
throw IOException("File corrupted")
|
||||||
}
|
}
|
||||||
val blockSize = bytes4ToInt(pbBlockSize)
|
val blockSize = bytes4ToUInt(pbBlockSize)
|
||||||
bufferPos = 0
|
bufferPos = 0
|
||||||
|
|
||||||
buffer = baseStream.readBytes(blockSize)
|
buffer = baseStream.readBytes(blockSize.toInt())
|
||||||
|
|
||||||
if (verify) {
|
if (verify) {
|
||||||
val cmpHmac: ByteArray
|
val cmpHmac: ByteArray
|
||||||
@@ -134,7 +135,7 @@ class HmacBlockInputStream(baseStream: InputStream, private val verify: Boolean,
|
|||||||
|
|
||||||
blockIndex++
|
blockIndex++
|
||||||
|
|
||||||
if (blockSize == 0) {
|
if (blockSize.toLong() == 0L) {
|
||||||
endOfStream = true
|
endOfStream = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.stream
|
package com.kunzisoft.keepass.stream
|
||||||
|
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.security.InvalidKeyException
|
import java.security.InvalidKeyException
|
||||||
@@ -87,7 +88,7 @@ class HmacBlockOutputStream(outputStream: OutputStream,
|
|||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
private fun writeSafeBlock() {
|
private fun writeSafeBlock() {
|
||||||
val bufBlockIndex = longTo8Bytes(blockIndex)
|
val bufBlockIndex = longTo8Bytes(blockIndex)
|
||||||
val blockSizeBuf = intTo4Bytes(bufferPos)
|
val blockSizeBuf = uIntTo4Bytes(UnsignedInt(bufferPos))
|
||||||
|
|
||||||
val blockHmac: ByteArray
|
val blockHmac: ByteArray
|
||||||
val blockKey = HmacBlockStream.getHmacKey64(key, blockIndex)
|
val blockKey = HmacBlockStream.getHmacKey64(key, blockIndex)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.stream
|
package com.kunzisoft.keepass.stream
|
||||||
|
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
|
||||||
@@ -32,15 +33,10 @@ class LittleEndianDataInputStream(private val baseStream: InputStream) : InputSt
|
|||||||
* be interpreted as an unsigned integer.
|
* be interpreted as an unsigned integer.
|
||||||
*/
|
*/
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun readUInt(): Long {
|
fun readUInt(): UnsignedInt {
|
||||||
return baseStream.readBytes4ToUInt()
|
return baseStream.readBytes4ToUInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
fun readInt(): Int {
|
|
||||||
return baseStream.readBytes4ToInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun readUShort(): Int {
|
fun readUShort(): Int {
|
||||||
val buf = ByteArray(2)
|
val buf = ByteArray(2)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.kunzisoft.keepass.stream
|
package com.kunzisoft.keepass.stream
|
||||||
|
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
@@ -30,8 +31,8 @@ import java.io.OutputStream
|
|||||||
class LittleEndianDataOutputStream(private val baseStream: OutputStream) : OutputStream() {
|
class LittleEndianDataOutputStream(private val baseStream: OutputStream) : OutputStream() {
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun writeUInt(uint: Long) { // TODO UInt #443
|
fun writeUInt(uInt: UnsignedInt) {
|
||||||
baseStream.write(intTo4Bytes(uint.toInt()))
|
baseStream.write(uIntTo4Bytes(uInt))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
@@ -66,7 +67,7 @@ class LittleEndianDataOutputStream(private val baseStream: OutputStream) : Outpu
|
|||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun writeInt(value: Int) {
|
fun writeInt(value: Int) {
|
||||||
baseStream.write(intTo4Bytes(value))
|
baseStream.write(uIntTo4Bytes(UnsignedInt(value)))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package com.kunzisoft.keepass.stream
|
|||||||
|
|
||||||
import com.kunzisoft.keepass.database.element.DateInstant
|
import com.kunzisoft.keepass.database.element.DateInstant
|
||||||
import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils.bytesToString
|
import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils.bytesToString
|
||||||
|
import com.kunzisoft.keepass.utils.UnsignedInt
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -80,13 +81,8 @@ fun InputStream.readBytes(length: Int, bufferSize: Int, readBytes: (bytesRead: B
|
|||||||
* be interpreted as an unsigned integer.
|
* be interpreted as an unsigned integer.
|
||||||
*/
|
*/
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun InputStream.readBytes4ToUInt(): Long {
|
fun InputStream.readBytes4ToUInt(): UnsignedInt {
|
||||||
return readBytes4ToInt().toLong() and INT_TO_LONG_MASK
|
return bytes4ToUInt(readBytesLength(4))
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
fun InputStream.readBytes4ToInt(): Int {
|
|
||||||
return bytes4ToInt(readBytesLength(4))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
@@ -141,18 +137,11 @@ fun bytes64ToLong(buf: ByteArray): Long {
|
|||||||
+ (buf[7].toLong() and 0xFF shl 56))
|
+ (buf[7].toLong() and 0xFF shl 56))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private const val INT_TO_LONG_MASK: Long = 0xffffffffL
|
|
||||||
|
|
||||||
fun bytes4ToUInt(buf: ByteArray): Long {
|
|
||||||
return bytes4ToInt(buf).toLong() and INT_TO_LONG_MASK
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a 32-bit value.
|
* Read a 32-bit value.
|
||||||
*/
|
*/
|
||||||
fun bytes4ToInt(buf: ByteArray): Int {
|
fun bytes4ToUInt(buf: ByteArray): UnsignedInt {
|
||||||
return ((buf[0].toInt() and 0xFF)
|
return UnsignedInt((buf[0].toInt() and 0xFF)
|
||||||
+ (buf[1].toInt() and 0xFF shl 8)
|
+ (buf[1].toInt() and 0xFF shl 8)
|
||||||
+ (buf[2].toInt() and 0xFF shl 16)
|
+ (buf[2].toInt() and 0xFF shl 16)
|
||||||
+ (buf[3].toInt() and 0xFF shl 24))
|
+ (buf[3].toInt() and 0xFF shl 24))
|
||||||
@@ -182,11 +171,11 @@ fun bytes5ToDate(buf: ByteArray, calendar: Calendar = Calendar.getInstance()): D
|
|||||||
System.arraycopy(buf, 0, cDate, 0, dateSize)
|
System.arraycopy(buf, 0, cDate, 0, dateSize)
|
||||||
|
|
||||||
val readOffset = 0
|
val readOffset = 0
|
||||||
val dw1 = byteToUInt(cDate[readOffset])
|
val dw1 = UnsignedInt.fromByte(cDate[readOffset]).toInt()
|
||||||
val dw2 = byteToUInt(cDate[readOffset + 1])
|
val dw2 = UnsignedInt.fromByte(cDate[readOffset + 1]).toInt()
|
||||||
val dw3 = byteToUInt(cDate[readOffset + 2])
|
val dw3 = UnsignedInt.fromByte(cDate[readOffset + 2]).toInt()
|
||||||
val dw4 = byteToUInt(cDate[readOffset + 3])
|
val dw4 = UnsignedInt.fromByte(cDate[readOffset + 3]).toInt()
|
||||||
val dw5 = byteToUInt(cDate[readOffset + 4])
|
val dw5 = UnsignedInt.fromByte(cDate[readOffset + 4]).toInt()
|
||||||
|
|
||||||
// Unpack 5 byte structure to date and time
|
// Unpack 5 byte structure to date and time
|
||||||
val year = dw1 shl 6 or (dw2 shr 2)
|
val year = dw1 shl 6 or (dw2 shr 2)
|
||||||
@@ -205,19 +194,12 @@ fun bytes5ToDate(buf: ByteArray, calendar: Calendar = Calendar.getInstance()): D
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an unsigned Integer to byte
|
* Write a 32-bit Int value.
|
||||||
*/
|
*/
|
||||||
fun uIntToByte(value: Int): Byte {
|
fun uIntTo4Bytes(value: UnsignedInt): ByteArray {
|
||||||
return (value and 0xFF).toByte()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write a 32-bit value.
|
|
||||||
*/
|
|
||||||
fun intTo4Bytes(value: Int): ByteArray {
|
|
||||||
val buf = ByteArray(4)
|
val buf = ByteArray(4)
|
||||||
for (i in 0 until 4) {
|
for (i in 0 until 4) {
|
||||||
buf[i] = (value.ushr(8 * i) and 0xFF).toByte()
|
buf[i] = (value.toInt().ushr(8 * i) and 0xFF).toByte()
|
||||||
}
|
}
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
@@ -264,8 +246,8 @@ fun dateTo5Bytes(date: Date, calendar: Calendar = Calendar.getInstance()): ByteA
|
|||||||
val minute = calendar.get(Calendar.MINUTE)
|
val minute = calendar.get(Calendar.MINUTE)
|
||||||
val second = calendar.get(Calendar.SECOND)
|
val second = calendar.get(Calendar.SECOND)
|
||||||
|
|
||||||
buf[0] = uIntToByte(year shr 6 and 0x0000003F)
|
buf[0] = UnsignedInt(year shr 6 and 0x0000003F).toByte()
|
||||||
buf[1] = uIntToByte(year and 0x0000003F shl 2 or (month shr 2 and 0x00000003))
|
buf[1] = UnsignedInt(year and 0x0000003F shl 2 or (month shr 2 and 0x00000003)).toByte()
|
||||||
buf[2] = (month and 0x00000003 shl 6
|
buf[2] = (month and 0x00000003 shl 6
|
||||||
or (day and 0x0000001F shl 1) or (hour shr 4 and 0x00000001)).toByte()
|
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[3] = (hour and 0x0000000F shl 4 or (minute shr 2 and 0x0000000F)).toByte()
|
||||||
@@ -273,9 +255,3 @@ fun dateTo5Bytes(date: Date, calendar: Calendar = Calendar.getInstance()): ByteA
|
|||||||
|
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Convert a byte to an unsigned byte */
|
|
||||||
fun byteToUInt(byte: Byte): Int {
|
|
||||||
return byte.toInt() and 0xFF
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
package com.kunzisoft.keepass.utils
|
package com.kunzisoft.keepass.utils
|
||||||
|
|
||||||
import com.kunzisoft.keepass.stream.intTo4Bytes
|
import com.kunzisoft.keepass.stream.uIntTo4Bytes
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
@@ -57,7 +57,7 @@ object StringDatabaseKDBUtils {
|
|||||||
var str = string
|
var str = string
|
||||||
if (str == null) {
|
if (str == null) {
|
||||||
// Write out a null character
|
// Write out a null character
|
||||||
os.write(intTo4Bytes(1))
|
os.write(uIntTo4Bytes(UnsignedInt(1)))
|
||||||
os.write(0x00)
|
os.write(0x00)
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ object StringDatabaseKDBUtils {
|
|||||||
val initial = str.toByteArray(defaultCharset)
|
val initial = str.toByteArray(defaultCharset)
|
||||||
|
|
||||||
val length = initial.size + 1
|
val length = initial.size + 1
|
||||||
os.write(intTo4Bytes(length))
|
os.write(uIntTo4Bytes(UnsignedInt(length)))
|
||||||
os.write(initial)
|
os.write(initial)
|
||||||
os.write(0x00)
|
os.write(0x00)
|
||||||
|
|
||||||
|
|||||||
86
app/src/main/java/com/kunzisoft/keepass/utils/UnsignedInt.kt
Normal file
86
app/src/main/java/com/kunzisoft/keepass/utils/UnsignedInt.kt
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Jeremy Jamet / Kunzisoft.
|
||||||
|
*
|
||||||
|
* This file is part of KeePassDX.
|
||||||
|
*
|
||||||
|
* KeePassDX is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* KeePassDX is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.kunzisoft.keepass.utils
|
||||||
|
|
||||||
|
class UnsignedInt(private var unsignedValue: Int) {
|
||||||
|
|
||||||
|
constructor(unsignedValue: UnsignedInt) : this(unsignedValue.toInt())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the int value
|
||||||
|
*/
|
||||||
|
fun toInt(): Int {
|
||||||
|
return unsignedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an unsigned Integer to Long
|
||||||
|
*/
|
||||||
|
fun toLong(): Long {
|
||||||
|
return unsignedValue.toLong() and INT_TO_LONG_MASK
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an unsigned Integer to Byte
|
||||||
|
*/
|
||||||
|
fun toByte(): Byte {
|
||||||
|
return (unsignedValue and 0xFF).toByte()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString():String {
|
||||||
|
return toLong().toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as UnsignedInt
|
||||||
|
|
||||||
|
if (unsignedValue != other.unsignedValue) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return unsignedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val INT_TO_LONG_MASK: Long = 0xffffffffL
|
||||||
|
private const val UINT_MAX_VALUE: Long = 4294967296L // 2^32
|
||||||
|
|
||||||
|
val MAX_VALUE = UnsignedInt(UINT_MAX_VALUE.toInt())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a byte to an unsigned byte
|
||||||
|
*/
|
||||||
|
fun fromByte(value: Byte): UnsignedInt {
|
||||||
|
return UnsignedInt(value.toInt() and 0xFF)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(NumberFormatException::class)
|
||||||
|
fun fromLong(value: Long): UnsignedInt {
|
||||||
|
if (value > UINT_MAX_VALUE)
|
||||||
|
throw NumberFormatException("UInt value > $UINT_MAX_VALUE")
|
||||||
|
return UnsignedInt(value.toInt())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 Jeremy Jamet / Kunzisoft.
|
||||||
|
*
|
||||||
|
* This file is part of KeePassDX.
|
||||||
|
*
|
||||||
|
* KeePassDX is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* KeePassDX is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with KeePassDX. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.kunzisoft.keepass.utils
|
||||||
|
|
||||||
|
class UnsignedLong(private var unsignedValue: Long) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an unsigned Integer to Long
|
||||||
|
*/
|
||||||
|
fun toLong(): Long {
|
||||||
|
return unsignedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as UnsignedLong
|
||||||
|
|
||||||
|
if (unsignedValue != other.unsignedValue) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return unsignedValue.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val ULONG_MAX_VALUE: Long = -1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,10 +24,10 @@ import com.kunzisoft.keepass.stream.LittleEndianDataOutputStream;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
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.bytes4ToUInt;
|
||||||
import static com.kunzisoft.keepass.stream.StreamBytesUtilsKt.bytes64ToLong;
|
import static com.kunzisoft.keepass.stream.StreamBytesUtilsKt.bytes64ToLong;
|
||||||
|
|
||||||
@@ -35,6 +35,7 @@ public class VariantDictionary {
|
|||||||
private static final int VdVersion = 0x0100;
|
private static final int VdVersion = 0x0100;
|
||||||
private static final int VdmCritical = 0xFF00;
|
private static final int VdmCritical = 0xFF00;
|
||||||
private static final int VdmInfo = 0x00FF;
|
private static final int VdmInfo = 0x00FF;
|
||||||
|
private static Charset UTF8Charset = Charset.forName("UTF-8");
|
||||||
|
|
||||||
private Map<String, VdType> dict = new HashMap<>();
|
private Map<String, VdType> dict = new HashMap<>();
|
||||||
|
|
||||||
@@ -69,8 +70,8 @@ public class VariantDictionary {
|
|||||||
dict.put(name, new VdType(type, value));
|
dict.put(name, new VdType(type, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUInt32(String name, long value) { putType(VdType.UInt32, name, value); }
|
public void setUInt32(String name, UnsignedInt value) { putType(VdType.UInt32, name, value); }
|
||||||
public long getUInt32(String name) { return (long)dict.get(name).value; }
|
public UnsignedInt getUInt32(String name) { return (UnsignedInt)dict.get(name).value; }
|
||||||
|
|
||||||
public void setUInt64(String name, long value) { putType(VdType.UInt64, name, value); }
|
public void setUInt64(String name, long value) { putType(VdType.UInt64, name, value); }
|
||||||
public long getUInt64(String name) { return (long)dict.get(name).value; }
|
public long getUInt64(String name) { return (long)dict.get(name).value; }
|
||||||
@@ -109,14 +110,14 @@ public class VariantDictionary {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nameLen = lis.readInt();
|
int nameLen = lis.readUInt().toInt();
|
||||||
byte[] nameBuf = lis.readBytes(nameLen);
|
byte[] nameBuf = lis.readBytes(nameLen);
|
||||||
if (nameLen != nameBuf.length) {
|
if (nameLen != nameBuf.length) {
|
||||||
throw new IOException("Invalid format");
|
throw new IOException("Invalid format");
|
||||||
}
|
}
|
||||||
String name = new String(nameBuf, "UTF-8");
|
String name = new String(nameBuf, UTF8Charset);
|
||||||
|
|
||||||
int valueLen = lis.readInt();
|
int valueLen = lis.readUInt().toInt();
|
||||||
byte[] valueBuf = lis.readBytes(valueLen);
|
byte[] valueBuf = lis.readBytes(valueLen);
|
||||||
if (valueLen != valueBuf.length) {
|
if (valueLen != valueBuf.length) {
|
||||||
throw new IOException("Invalid format");
|
throw new IOException("Invalid format");
|
||||||
@@ -140,7 +141,7 @@ public class VariantDictionary {
|
|||||||
break;
|
break;
|
||||||
case VdType.Int32:
|
case VdType.Int32:
|
||||||
if (valueLen == 4) {
|
if (valueLen == 4) {
|
||||||
d.setInt32(name, bytes4ToInt(valueBuf));
|
d.setInt32(name, bytes4ToUInt(valueBuf).toInt());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VdType.Int64:
|
case VdType.Int64:
|
||||||
@@ -149,7 +150,7 @@ public class VariantDictionary {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case VdType.String:
|
case VdType.String:
|
||||||
d.setString(name, new String(valueBuf, "UTF-8"));
|
d.setString(name, new String(valueBuf, UTF8Charset));
|
||||||
break;
|
break;
|
||||||
case VdType.ByteArray:
|
case VdType.ByteArray:
|
||||||
d.setByteArray(name, valueBuf);
|
d.setByteArray(name, valueBuf);
|
||||||
@@ -172,12 +173,7 @@ public class VariantDictionary {
|
|||||||
|
|
||||||
for (Map.Entry<String, VdType> entry: d.dict.entrySet()) {
|
for (Map.Entry<String, VdType> entry: d.dict.entrySet()) {
|
||||||
String name = entry.getKey();
|
String name = entry.getKey();
|
||||||
byte[] nameBuf = null;
|
byte[] nameBuf = nameBuf = name.getBytes(UTF8Charset);
|
||||||
try {
|
|
||||||
nameBuf = name.getBytes("UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
throw new IOException("Couldn't encode parameter name.");
|
|
||||||
}
|
|
||||||
|
|
||||||
VdType vd = entry.getValue();
|
VdType vd = entry.getValue();
|
||||||
|
|
||||||
@@ -189,7 +185,7 @@ public class VariantDictionary {
|
|||||||
switch (vd.type) {
|
switch (vd.type) {
|
||||||
case VdType.UInt32:
|
case VdType.UInt32:
|
||||||
los.writeInt(4);
|
los.writeInt(4);
|
||||||
los.writeUInt((long)vd.value);
|
los.writeUInt((UnsignedInt) vd.value);
|
||||||
break;
|
break;
|
||||||
case VdType.UInt64:
|
case VdType.UInt64:
|
||||||
los.writeInt(8);
|
los.writeInt(8);
|
||||||
@@ -210,7 +206,7 @@ public class VariantDictionary {
|
|||||||
break;
|
break;
|
||||||
case VdType.String:
|
case VdType.String:
|
||||||
String value = (String)vd.value;
|
String value = (String)vd.value;
|
||||||
buf = value.getBytes("UTF-8");
|
buf = value.getBytes(UTF8Charset);
|
||||||
los.writeInt(buf.length);
|
los.writeInt(buf.length);
|
||||||
los.write(buf);
|
los.write(buf);
|
||||||
break;
|
break;
|
||||||
@@ -231,7 +227,6 @@ public class VariantDictionary {
|
|||||||
for (Map.Entry<String, VdType> entry : d.dict.entrySet()) {
|
for (Map.Entry<String, VdType> entry : d.dict.entrySet()) {
|
||||||
String key = entry.getKey();
|
String key = entry.getKey();
|
||||||
VdType value = entry.getValue();
|
VdType value = entry.getValue();
|
||||||
|
|
||||||
dict.put(key, value);
|
dict.put(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,12 +126,11 @@ void throwExceptionF(JNIEnv *env, jclass exception, const char *format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define ARGON2_HASHLEN 32
|
#define ARGON2_HASHLEN 32
|
||||||
#define NB_BLOCKSIZE 1024
|
|
||||||
|
|
||||||
JNIEXPORT jbyteArray
|
JNIEXPORT jbyteArray
|
||||||
JNICALL Java_com_kunzisoft_keepass_crypto_keyDerivation_Argon2Native_nTransformMasterKey(JNIEnv *env,
|
JNICALL Java_com_kunzisoft_keepass_crypto_keyDerivation_Argon2Native_nTransformMasterKey(JNIEnv *env,
|
||||||
jobject this, jbyteArray password, jbyteArray salt, jint parallelism, jlong memory,
|
jobject this, jbyteArray password, jbyteArray salt, jint parallelism, jint memory,
|
||||||
jlong iterations, jbyteArray secretKey, jbyteArray associatedData, jlong version) {
|
jint iterations, jbyteArray secretKey, jbyteArray associatedData, jint version) {
|
||||||
|
|
||||||
argon2_context context;
|
argon2_context context;
|
||||||
uint8_t *out;
|
uint8_t *out;
|
||||||
@@ -151,7 +150,7 @@ JNICALL Java_com_kunzisoft_keepass_crypto_keyDerivation_Argon2Native_nTransformM
|
|||||||
uint8_t *adBuf;
|
uint8_t *adBuf;
|
||||||
uint32_t adLen = getJNIArray(env, associatedData, &adBuf);
|
uint32_t adLen = getJNIArray(env, associatedData, &adBuf);
|
||||||
|
|
||||||
context.out = (uint8_t *) out;
|
context.out = out;
|
||||||
context.outlen = ARGON2_HASHLEN;
|
context.outlen = ARGON2_HASHLEN;
|
||||||
context.pwd = passwordBuf;
|
context.pwd = passwordBuf;
|
||||||
context.pwdlen = passwordLen;
|
context.pwdlen = passwordLen;
|
||||||
@@ -162,7 +161,7 @@ JNICALL Java_com_kunzisoft_keepass_crypto_keyDerivation_Argon2Native_nTransformM
|
|||||||
context.ad = adBuf;
|
context.ad = adBuf;
|
||||||
context.adlen = adLen;
|
context.adlen = adLen;
|
||||||
context.t_cost = (uint32_t) iterations;
|
context.t_cost = (uint32_t) iterations;
|
||||||
context.m_cost = ((uint32_t) memory) / NB_BLOCKSIZE;
|
context.m_cost = (uint32_t) memory;
|
||||||
context.lanes = (uint32_t) parallelism;
|
context.lanes = (uint32_t) parallelism;
|
||||||
context.threads = (uint32_t) parallelism;
|
context.threads = (uint32_t) parallelism;
|
||||||
context.allocate_cbk = NULL;
|
context.allocate_cbk = NULL;
|
||||||
|
|||||||
@@ -438,7 +438,7 @@ uint32_t generate_key_material(void *arg) {
|
|||||||
return flip;
|
return flip;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jbyteArray JNICALL Java_com_kunzisoft_keepass_crypto_finalkey_NativeFinalKey_nTransformMasterKey(JNIEnv *env, jobject this, jbyteArray seed, jbyteArray key, jlong rounds) {
|
JNIEXPORT jbyteArray JNICALL Java_com_kunzisoft_keepass_crypto_finalkey_NativeAESKeyTransformer_nTransformMasterKey(JNIEnv *env, jobject this, jbyteArray seed, jbyteArray key, jlong rounds) {
|
||||||
master_key mk;
|
master_key mk;
|
||||||
uint32_t flip;
|
uint32_t flip;
|
||||||
pthread_t t1, t2;
|
pthread_t t1, t2;
|
||||||
|
|||||||
Reference in New Issue
Block a user