Merge branch 'feature/RefactorImporter' into develop

This commit is contained in:
J-Jamet
2019-11-13 17:29:30 +01:00
21 changed files with 155 additions and 211 deletions

View File

@@ -30,9 +30,9 @@ import junit.framework.TestCase
import com.kunzisoft.keepass.database.element.PwDate
import com.kunzisoft.keepass.stream.LEDataInputStream
import com.kunzisoft.keepass.stream.LEDataOutputStream
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
class TypesTest : TestCase() {
class DatabaseInputOutputUtilsTest : TestCase() {
fun testReadWriteLongZero() {
testReadWriteLong(0.toByte())
@@ -155,8 +155,8 @@ class TypesTest : TestCase() {
setArray(orig, value, 0, 1)
val one = Types.readUByte(orig, 0)
Types.writeUByte(one, dest, 0)
val one = DatabaseInputOutputUtils.readUByte(orig, 0)
DatabaseInputOutputUtils.writeUByte(one, dest, 0)
assertArrayEquals(orig, dest)
@@ -185,8 +185,8 @@ class TypesTest : TestCase() {
val bUUID = ByteArray(16)
rnd.nextBytes(bUUID)
val uuid = Types.bytestoUUID(bUUID)
val eUUID = Types.UUIDtoBytes(uuid)
val uuid = DatabaseInputOutputUtils.bytestoUUID(bUUID)
val eUUID = DatabaseInputOutputUtils.UUIDtoBytes(uuid)
assertArrayEquals("UUID match failed", bUUID, eUUID)
}
@@ -200,7 +200,7 @@ class TypesTest : TestCase() {
val bos = ByteArrayOutputStream()
val leos = LEDataOutputStream(bos)
leos.writeLong(Types.ULONG_MAX_VALUE)
leos.writeLong(DatabaseInputOutputUtils.ULONG_MAX_VALUE)
leos.close()
val uLongMax = bos.toByteArray()

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.crypto.engine
import com.kunzisoft.keepass.crypto.CipherFactory
import com.kunzisoft.keepass.database.element.PwEncryptionAlgorithm
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import java.security.InvalidAlgorithmParameterException
import java.security.InvalidKeyException
import java.security.NoSuchAlgorithmException
@@ -47,7 +47,7 @@ class AesEngine : CipherEngine() {
companion object {
val CIPHER_UUID: UUID = Types.bytestoUUID(
val CIPHER_UUID: UUID = DatabaseInputOutputUtils.bytestoUUID(
byteArrayOf(0x31.toByte(), 0xC1.toByte(), 0xF2.toByte(), 0xE6.toByte(), 0xBF.toByte(), 0x71.toByte(), 0x43.toByte(), 0x50.toByte(), 0xBE.toByte(), 0x58.toByte(), 0x05.toByte(), 0x21.toByte(), 0x6A.toByte(), 0xFC.toByte(), 0x5A.toByte(), 0xFF.toByte()))
}
}

View File

@@ -20,7 +20,7 @@
package com.kunzisoft.keepass.crypto.engine
import com.kunzisoft.keepass.database.element.PwEncryptionAlgorithm
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import org.spongycastle.jce.provider.BouncyCastleProvider
import java.security.InvalidAlgorithmParameterException
import java.security.InvalidKeyException
@@ -50,7 +50,7 @@ class ChaCha20Engine : CipherEngine() {
companion object {
val CIPHER_UUID: UUID = Types.bytestoUUID(
val CIPHER_UUID: UUID = DatabaseInputOutputUtils.bytestoUUID(
byteArrayOf(0xD6.toByte(), 0x03.toByte(), 0x8A.toByte(), 0x2B.toByte(), 0x8B.toByte(), 0x6F.toByte(), 0x4C.toByte(), 0xB5.toByte(), 0xA5.toByte(), 0x24.toByte(), 0x33.toByte(), 0x9A.toByte(), 0x31.toByte(), 0xDB.toByte(), 0xB5.toByte(), 0x9A.toByte()))
}
}

View File

@@ -21,7 +21,7 @@ package com.kunzisoft.keepass.crypto.engine
import com.kunzisoft.keepass.crypto.CipherFactory
import com.kunzisoft.keepass.database.element.PwEncryptionAlgorithm
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import java.security.InvalidAlgorithmParameterException
import java.security.InvalidKeyException
@@ -53,7 +53,7 @@ class TwofishEngine : CipherEngine() {
companion object {
val CIPHER_UUID: UUID = Types.bytestoUUID(
val CIPHER_UUID: UUID = DatabaseInputOutputUtils.bytestoUUID(
byteArrayOf(0xAD.toByte(), 0x68.toByte(), 0xF2.toByte(), 0x9F.toByte(), 0x57.toByte(), 0x6F.toByte(), 0x4B.toByte(), 0xB9.toByte(), 0xA3.toByte(), 0x6A.toByte(), 0xD4.toByte(), 0x7A.toByte(), 0xF9.toByte(), 0x65.toByte(), 0x34.toByte(), 0x6C.toByte()))
}
}

View File

@@ -23,7 +23,7 @@ import android.content.res.Resources
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.crypto.CryptoUtil
import com.kunzisoft.keepass.crypto.finalkey.FinalKeyFactory
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import java.io.IOException
import java.security.SecureRandom
import java.util.*
@@ -88,7 +88,7 @@ class AesKdf internal constructor() : KdfEngine() {
private const val DEFAULT_ROUNDS = 6000
val CIPHER_UUID: UUID = Types.bytestoUUID(
val CIPHER_UUID: UUID = DatabaseInputOutputUtils.bytestoUUID(
byteArrayOf(0xC9.toByte(),
0xD9.toByte(),
0xF3.toByte(),

View File

@@ -21,7 +21,7 @@ package com.kunzisoft.keepass.crypto.keyDerivation
import android.content.res.Resources
import com.kunzisoft.keepass.R
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import java.io.IOException
import java.security.SecureRandom
import java.util.*
@@ -126,7 +126,7 @@ class Argon2Kdf internal constructor() : KdfEngine() {
companion object {
val CIPHER_UUID: UUID = Types.bytestoUUID(
val CIPHER_UUID: UUID = DatabaseInputOutputUtils.bytestoUUID(
byteArrayOf(0xEF.toByte(),
0x63.toByte(),
0x6D.toByte(),

View File

@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.crypto.keyDerivation;
import com.kunzisoft.keepass.utils.VariantDictionary;
import com.kunzisoft.keepass.stream.LEDataInputStream;
import com.kunzisoft.keepass.stream.LEDataOutputStream;
import com.kunzisoft.keepass.utils.Types;
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -44,7 +44,7 @@ public class KdfParameters extends VariantDictionary {
}
protected void setParamUUID() {
setByteArray(ParamUUID, Types.UUIDtoBytes(kdfUUID));
setByteArray(ParamUUID, DatabaseInputOutputUtils.UUIDtoBytes(kdfUUID));
}
public static KdfParameters deserialize(byte[] data) throws IOException {
@@ -56,7 +56,7 @@ public class KdfParameters extends VariantDictionary {
return null;
}
UUID uuid = Types.bytestoUUID(d.getByteArray(ParamUUID));
UUID uuid = DatabaseInputOutputUtils.bytestoUUID(d.getByteArray(ParamUUID));
KdfParameters kdfP = new KdfParameters(uuid);
kdfP.copyTo(d);

View File

@@ -23,7 +23,7 @@ import android.content.res.Resources
import android.os.Parcel
import android.os.Parcelable
import androidx.core.os.ConfigurationCompat
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import java.util.*
/**
@@ -188,11 +188,11 @@ class PwDate : Parcelable {
*/
fun readTime(buf: ByteArray?, offset: Int, calendar: Calendar?): Date {
var time = calendar
val dw1 = Types.readUByte(buf!!, offset)
val dw2 = Types.readUByte(buf, offset + 1)
val dw3 = Types.readUByte(buf, offset + 2)
val dw4 = Types.readUByte(buf, offset + 3)
val dw5 = Types.readUByte(buf, offset + 4)
val dw1 = DatabaseInputOutputUtils.readUByte(buf!!, offset)
val dw2 = DatabaseInputOutputUtils.readUByte(buf, offset + 1)
val dw3 = DatabaseInputOutputUtils.readUByte(buf, offset + 2)
val dw4 = DatabaseInputOutputUtils.readUByte(buf, offset + 3)
val dw5 = DatabaseInputOutputUtils.readUByte(buf, offset + 4)
// Unpack 5 byte structure to date and time
val year = dw1 shl 6 or (dw2 shr 2)
@@ -236,8 +236,8 @@ class PwDate : Parcelable {
val minute = cal.get(Calendar.MINUTE)
val second = cal.get(Calendar.SECOND)
buf[0] = Types.writeUByte(year shr 6 and 0x0000003F)
buf[1] = Types.writeUByte(year and 0x0000003F shl 2 or (month shr 2 and 0x00000003))
buf[0] = DatabaseInputOutputUtils.writeUByte(year shr 6 and 0x0000003F)
buf[1] = DatabaseInputOutputUtils.writeUByte(year and 0x0000003F shl 2 or (month shr 2 and 0x00000003))
buf[2] = (month and 0x00000003 shl 6
or (day and 0x0000001F shl 1) or (hour shr 4 and 0x00000001)).toByte()
buf[3] = (hour and 0x0000000F shl 4 or (minute shr 2 and 0x0000000F)).toByte()

View File

@@ -21,11 +21,7 @@ package com.kunzisoft.keepass.database.element
import android.os.Parcel
import android.os.Parcelable
import java.io.UnsupportedEncodingException
import java.util.Arrays
import java.util.UUID
import java.util.*
/**
* Structure containing information about one entry.
@@ -56,12 +52,11 @@ class PwEntryV3 : PwEntry<Int, UUID, PwGroupV3, PwEntryV3>, PwNodeV3Interface {
* @return the actual binaryData byte array.
*/
var binaryData: ByteArray = ByteArray(0)
private set
// Determine if this is a MetaStream entry
val isMetaStream: Boolean
get() {
if (Arrays.equals(binaryData, ByteArray(0))) return false
if (binaryData.contentEquals(ByteArray(0))) return false
if (notes.isEmpty()) return false
if (binaryDesc != PMS_ID_BINDESC) return false
if (title.isEmpty()) return false
@@ -85,10 +80,11 @@ class PwEntryV3 : PwEntry<Int, UUID, PwGroupV3, PwEntryV3>, PwNodeV3Interface {
constructor(parcel: Parcel) : super(parcel) {
title = parcel.readString() ?: title
username = parcel.readString() ?: username
parcel.readByteArray(passwordBytes)
password = parcel.readString() ?: password
url = parcel.readString() ?: url
notes = parcel.readString() ?: notes
binaryDesc = parcel.readString() ?: binaryDesc
binaryData = ByteArray(parcel.readInt())
parcel.readByteArray(binaryData)
}
@@ -104,10 +100,11 @@ class PwEntryV3 : PwEntry<Int, UUID, PwGroupV3, PwEntryV3>, PwNodeV3Interface {
super.writeToParcel(dest, flags)
dest.writeString(title)
dest.writeString(username)
dest.writeByteArray(passwordBytes)
dest.writeString(password)
dest.writeString(url)
dest.writeString(notes)
dest.writeString(binaryDesc)
dest.writeInt(binaryData.size)
dest.writeByteArray(binaryData)
}
@@ -115,11 +112,7 @@ class PwEntryV3 : PwEntry<Int, UUID, PwGroupV3, PwEntryV3>, PwNodeV3Interface {
super.updateWith(source)
title = source.title
username = source.username
val passLen = source.passwordBytes.size
passwordBytes = ByteArray(passLen)
System.arraycopy(source.passwordBytes, 0, passwordBytes, 0, passLen)
password = source.password
url = source.url
notes = source.notes
binaryDesc = source.binaryDesc
@@ -131,32 +124,10 @@ class PwEntryV3 : PwEntry<Int, UUID, PwGroupV3, PwEntryV3>, PwNodeV3Interface {
override var username = ""
var passwordBytes: ByteArray = ByteArray(0)
private set
/** Securely erase old password before copying new. */
fun setPassword(buf: ByteArray, offset: Int, len: Int) {
fill(passwordBytes, 0.toByte())
passwordBytes = ByteArray(len)
System.arraycopy(buf, offset, passwordBytes, 0, len)
}
/**
* @return the actual password byte array.
*/
override var password: String
get() = String(passwordBytes)
set(pass) {
var password: ByteArray
try {
password = pass.toByteArray(charset("UTF-8"))
setPassword(password, 0, password.size)
} catch (e: UnsupportedEncodingException) {
password = pass.toByteArray()
setPassword(password, 0, password.size)
}
}
override var password = ""
override var url = ""
@@ -167,13 +138,6 @@ class PwEntryV3 : PwEntry<Int, UUID, PwGroupV3, PwEntryV3>, PwNodeV3Interface {
override val type: Type
get() = Type.ENTRY
fun setBinaryData(buf: ByteArray, offset: Int, len: Int) {
/** Securely erase old data before copying new. */
fill(binaryData, 0.toByte())
binaryData = ByteArray(len)
System.arraycopy(buf, offset, binaryData, 0, len)
}
companion object {
/** Size of byte buffer needed to hold this struct. */
@@ -184,21 +148,13 @@ class PwEntryV3 : PwEntry<Int, UUID, PwGroupV3, PwEntryV3>, PwNodeV3Interface {
@JvmField
val CREATOR: Parcelable.Creator<PwEntryV3> = object : Parcelable.Creator<PwEntryV3> {
override fun createFromParcel(`in`: Parcel): PwEntryV3 {
return PwEntryV3(`in`)
override fun createFromParcel(parcel: Parcel): PwEntryV3 {
return PwEntryV3(parcel)
}
override fun newArray(size: Int): Array<PwEntryV3?> {
return arrayOfNulls(size)
}
}
/**
* fill byte array
*/
private fun fill(array: ByteArray, value: Byte) {
for (i in array.indices)
array[i] = value
}
}
}

View File

@@ -80,6 +80,7 @@ class ProtectedBinary : Parcelable {
private constructor(parcel: Parcel) {
isProtected = parcel.readByte().toInt() != 0
data = ByteArray(parcel.readInt())
parcel.readByteArray(data)
dataFile = File(parcel.readString())
size = parcel.readInt()
@@ -130,8 +131,9 @@ class ProtectedBinary : Parcelable {
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeByte((if (isProtected) 1 else 0).toByte())
dest.writeInt(data?.size ?: 0)
dest.writeByteArray(data)
dest.writeString(dataFile!!.absolutePath)
dest.writeString(dataFile?.absolutePath)
dest.writeInt(size)
}

View File

@@ -29,7 +29,7 @@ import com.kunzisoft.keepass.database.exception.LoadDatabaseVersionException
import com.kunzisoft.keepass.stream.CopyInputStream
import com.kunzisoft.keepass.stream.HmacBlockStream
import com.kunzisoft.keepass.stream.LEDataInputStream
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
@@ -239,7 +239,7 @@ class PwDbHeaderV4(private val databaseV4: PwDatabaseV4) : PwDbHeader() {
throw IOException("Invalid cipher ID.")
}
databaseV4.dataCipher = Types.bytestoUUID(pbId)
databaseV4.dataCipher = DatabaseInputOutputUtils.bytestoUUID(pbId)
}
private fun setTransformRound(roundsByte: ByteArray?) {
@@ -319,7 +319,7 @@ class PwDbHeaderV4(private val databaseV4: PwDatabaseV4) : PwDbHeader() {
@Throws(IOException::class)
fun computeHeaderHmac(header: ByteArray, key: ByteArray): ByteArray {
val blockKey = HmacBlockStream.GetHmacKey64(key, Types.ULONG_MAX_VALUE)
val blockKey = HmacBlockStream.GetHmacKey64(key, DatabaseInputOutputUtils.ULONG_MAX_VALUE)
val hmac: Mac
try {

View File

@@ -55,7 +55,7 @@ import com.kunzisoft.keepass.database.file.PwDbHeaderV3
import com.kunzisoft.keepass.stream.LEDataInputStream
import com.kunzisoft.keepass.stream.NullOutputStream
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import javax.crypto.*
import javax.crypto.spec.IvParameterSpec
@@ -287,7 +287,7 @@ class ImporterV3 : Importer<PwDatabaseV3>() {
0x0000 -> {
}
0x0001 -> grp.setGroupId(LEDataInputStream.readInt(buf, offset))
0x0002 -> grp.title = Types.readCString(buf, offset)
0x0002 -> grp.title = DatabaseInputOutputUtils.readCString(buf, offset)
0x0003 -> grp.creationTime = PwDate(buf, offset)
0x0004 -> grp.lastModificationTime = PwDate(buf, offset)
0x0005 -> grp.lastAccessTime = PwDate(buf, offset)
@@ -309,7 +309,7 @@ class ImporterV3 : Importer<PwDatabaseV3>() {
when (fieldType) {
0x0000 -> {
}
0x0001 -> ent.nodeId = PwNodeIdUUID(Types.bytestoUUID(buf, offsetMutable))
0x0001 -> ent.nodeId = PwNodeIdUUID(DatabaseInputOutputUtils.bytestoUUID(buf, offsetMutable))
0x0002 -> {
val pwGroupV3 = mDatabaseToOpen.createGroup()
pwGroupV3.nodeId = PwNodeIdInt(LEDataInputStream.readInt(buf, offsetMutable))
@@ -325,17 +325,17 @@ class ImporterV3 : Importer<PwDatabaseV3>() {
ent.icon = db.iconFactory.getIcon(iconId)
}
0x0004 -> ent.title = Types.readCString(buf, offsetMutable)
0x0005 -> ent.url = Types.readCString(buf, offsetMutable)
0x0006 -> ent.username = Types.readCString(buf, offsetMutable)
0x0007 -> ent.setPassword(buf, offsetMutable, Types.strlen(buf, offsetMutable))
0x0008 -> ent.notes = Types.readCString(buf, offsetMutable)
0x0004 -> ent.title = DatabaseInputOutputUtils.readCString(buf, offsetMutable)
0x0005 -> ent.url = DatabaseInputOutputUtils.readCString(buf, offsetMutable)
0x0006 -> ent.username = DatabaseInputOutputUtils.readCString(buf, offsetMutable)
0x0007 -> ent.password = DatabaseInputOutputUtils.readPassword(buf, offsetMutable)
0x0008 -> ent.notes = DatabaseInputOutputUtils.readCString(buf, offsetMutable)
0x0009 -> ent.creationTime = PwDate(buf, offsetMutable)
0x000A -> ent.lastModificationTime = PwDate(buf, offsetMutable)
0x000B -> ent.lastAccessTime = PwDate(buf, offsetMutable)
0x000C -> ent.expiryTime = PwDate(buf, offsetMutable)
0x000D -> ent.binaryDesc = Types.readCString(buf, offsetMutable)
0x000E -> ent.setBinaryData(buf, offsetMutable, fieldSize)
0x000D -> ent.binaryDesc = DatabaseInputOutputUtils.readCString(buf, offsetMutable)
0x000E -> ent.binaryData = DatabaseInputOutputUtils.readBytes(buf, offsetMutable, fieldSize)
}// Ignore field
}

View File

@@ -36,7 +36,7 @@ import com.kunzisoft.keepass.stream.HmacBlockInputStream
import com.kunzisoft.keepass.stream.LEDataInputStream
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
import com.kunzisoft.keepass.utils.MemoryUtil
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import org.spongycastle.crypto.StreamCipher
import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserException
@@ -876,7 +876,7 @@ class ImporterV4(private val streamDir: File,
// TODO: Switch to framework Base64 once API level 8 is the minimum
val buf = Base64Coder.decode(encoded)
return Types.bytestoUUID(buf)
return DatabaseInputOutputUtils.bytestoUUID(buf)
}
@Throws(IOException::class, XmlPullParserException::class)

View File

@@ -28,7 +28,7 @@ import com.kunzisoft.keepass.database.exception.DatabaseOutputException
import com.kunzisoft.keepass.stream.HmacBlockStream
import com.kunzisoft.keepass.stream.LEDataOutputStream
import com.kunzisoft.keepass.stream.MacOutputStream
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import java.io.ByteArrayOutputStream
import java.io.IOException
@@ -66,7 +66,7 @@ constructor(private val db: PwDatabaseV4, private val header: PwDbHeaderV4, os:
val hmac: Mac
try {
hmac = Mac.getInstance("HmacSHA256")
val signingKey = SecretKeySpec(HmacBlockStream.GetHmacKey64(db.hmacKey, Types.ULONG_MAX_VALUE), "HmacSHA256")
val signingKey = SecretKeySpec(HmacBlockStream.GetHmacKey64(db.hmacKey, DatabaseInputOutputUtils.ULONG_MAX_VALUE), "HmacSHA256")
hmac.init(signingKey)
} catch (e: NoSuchAlgorithmException) {
throw DatabaseOutputException(e)
@@ -86,7 +86,7 @@ constructor(private val db: PwDatabaseV4, private val header: PwDbHeaderV4, os:
los.writeUInt(PwDbHeaderV4.DBSIG_2.toLong())
los.writeUInt(header.version)
writeHeaderField(PwDbHeaderV4.PwDbHeaderV4Fields.CipherID, Types.UUIDtoBytes(db.dataCipher))
writeHeaderField(PwDbHeaderV4.PwDbHeaderV4Fields.CipherID, DatabaseInputOutputUtils.UUIDtoBytes(db.dataCipher))
writeHeaderField(PwDbHeaderV4.PwDbHeaderV4Fields.CompressionFlags, LEDataOutputStream.writeIntBuf(PwDbHeaderV4.getFlagFromCompression(db.compressionAlgorithm)))
writeHeaderField(PwDbHeaderV4.PwDbHeaderV4Fields.MasterSeed, header.masterSeed)

View File

@@ -40,7 +40,7 @@ import com.kunzisoft.keepass.stream.HmacBlockOutputStream
import com.kunzisoft.keepass.stream.LEDataOutputStream
import com.kunzisoft.keepass.database.file.KDBX4DateUtil
import com.kunzisoft.keepass.utils.MemoryUtil
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import org.joda.time.DateTime
import org.spongycastle.crypto.StreamCipher
import org.xmlpull.v1.XmlSerializer
@@ -505,7 +505,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)
private fun writeObject(name: String, uuid: UUID) {
val data = Types.UUIDtoBytes(uuid)
val data = DatabaseInputOutputUtils.UUIDtoBytes(uuid)
writeObject(name, String(Base64Coder.encode(data)))
}

View File

@@ -21,7 +21,7 @@ package com.kunzisoft.keepass.database.file.save
import com.kunzisoft.keepass.database.element.PwEntryV3
import com.kunzisoft.keepass.stream.LEDataOutputStream
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import java.io.IOException
import java.io.OutputStream
@@ -30,7 +30,7 @@ class PwEntryOutputV3
/**
* Output the PwGroupV3 to the stream
*/
(private val mPE: PwEntryV3, private val mOS: OutputStream) {
(private val mEntry: PwEntryV3, private val mOutputStream: OutputStream) {
/**
* Returns the number of bytes written by the stream
* @return Number of bytes written
@@ -45,98 +45,82 @@ class PwEntryOutputV3
length += 134 // Length of fixed size fields
// UUID
mOS.write(UUID_FIELD_TYPE)
mOS.write(UUID_FIELD_SIZE)
mOS.write(Types.UUIDtoBytes(mPE.id))
mOutputStream.write(UUID_FIELD_TYPE)
mOutputStream.write(UUID_FIELD_SIZE)
mOutputStream.write(DatabaseInputOutputUtils.UUIDtoBytes(mEntry.id))
// Group ID
mOS.write(GROUPID_FIELD_TYPE)
mOS.write(LONG_FOUR)
mOS.write(LEDataOutputStream.writeIntBuf(mPE.parent!!.id))
mOutputStream.write(GROUPID_FIELD_TYPE)
mOutputStream.write(LONG_FOUR)
mOutputStream.write(LEDataOutputStream.writeIntBuf(mEntry.parent!!.id))
// Image ID
mOS.write(IMAGEID_FIELD_TYPE)
mOS.write(LONG_FOUR)
mOS.write(LEDataOutputStream.writeIntBuf(mPE.icon.iconId))
mOutputStream.write(IMAGEID_FIELD_TYPE)
mOutputStream.write(LONG_FOUR)
mOutputStream.write(LEDataOutputStream.writeIntBuf(mEntry.icon.iconId))
// Title
//byte[] title = mPE.title.getBytes("UTF-8");
mOS.write(TITLE_FIELD_TYPE)
val titleLen = Types.writeCString(mPE.title, mOS)
length += titleLen.toLong()
//byte[] title = mEntry.title.getBytes("UTF-8");
mOutputStream.write(TITLE_FIELD_TYPE)
length += DatabaseInputOutputUtils.writeCString(mEntry.title, mOutputStream).toLong()
// URL
mOS.write(URL_FIELD_TYPE)
val urlLen = Types.writeCString(mPE.url, mOS)
length += urlLen.toLong()
mOutputStream.write(URL_FIELD_TYPE)
length += DatabaseInputOutputUtils.writeCString(mEntry.url, mOutputStream).toLong()
// Username
mOS.write(USERNAME_FIELD_TYPE)
val userLen = Types.writeCString(mPE.username, mOS)
length += userLen.toLong()
mOutputStream.write(USERNAME_FIELD_TYPE)
length += DatabaseInputOutputUtils.writeCString(mEntry.username, mOutputStream).toLong()
// Password
val password = mPE.passwordBytes
mOS.write(PASSWORD_FIELD_TYPE)
mOS.write(LEDataOutputStream.writeIntBuf(password.size + 1))
mOS.write(password)
mOS.write(0)
length += (password.size + 1).toLong()
mOutputStream.write(PASSWORD_FIELD_TYPE)
length += DatabaseInputOutputUtils.writePassword(mEntry.password, mOutputStream).toLong()
// Additional
mOS.write(ADDITIONAL_FIELD_TYPE)
val addlLen = Types.writeCString(mPE.notes, mOS)
length += addlLen.toLong()
mOutputStream.write(ADDITIONAL_FIELD_TYPE)
length += DatabaseInputOutputUtils.writeCString(mEntry.notes, mOutputStream).toLong()
// Create date
writeDate(CREATE_FIELD_TYPE, mPE.creationTime.byteArrayDate)
writeDate(CREATE_FIELD_TYPE, mEntry.creationTime.byteArrayDate)
// Modification date
writeDate(MOD_FIELD_TYPE, mPE.lastModificationTime.byteArrayDate)
writeDate(MOD_FIELD_TYPE, mEntry.lastModificationTime.byteArrayDate)
// Access date
writeDate(ACCESS_FIELD_TYPE, mPE.lastAccessTime.byteArrayDate)
writeDate(ACCESS_FIELD_TYPE, mEntry.lastAccessTime.byteArrayDate)
// Expiration date
writeDate(EXPIRE_FIELD_TYPE, mPE.expiryTime.byteArrayDate)
writeDate(EXPIRE_FIELD_TYPE, mEntry.expiryTime.byteArrayDate)
// Binary desc
mOS.write(BINARY_DESC_FIELD_TYPE)
val descLen = Types.writeCString(mPE.binaryDesc, mOS)
length += descLen.toLong()
// Binary data
val dataLen = writeByteArray(mPE.binaryData)
length += dataLen.toLong()
// Binary
writeBinary(mEntry.binaryData)
// End
mOS.write(END_FIELD_TYPE)
mOS.write(ZERO_FIELD_SIZE)
}
@Throws(IOException::class)
private fun writeByteArray(data: ByteArray?): Int {
val dataLen: Int = data?.size ?: 0
mOS.write(BINARY_DATA_FIELD_TYPE)
mOS.write(LEDataOutputStream.writeIntBuf(dataLen))
if (data != null) {
mOS.write(data)
}
return dataLen
mOutputStream.write(END_FIELD_TYPE)
mOutputStream.write(ZERO_FIELD_SIZE)
}
@Throws(IOException::class)
private fun writeDate(type: ByteArray, date: ByteArray?) {
mOS.write(type)
mOS.write(DATE_FIELD_SIZE)
mOutputStream.write(type)
mOutputStream.write(DATE_FIELD_SIZE)
if (date != null) {
mOS.write(date)
mOutputStream.write(date)
} else {
mOS.write(ZERO_FIVE)
mOutputStream.write(ZERO_FIVE)
}
}
@Throws(IOException::class)
private fun writeBinary(data: ByteArray?) {
mOutputStream.write(BINARY_DESC_FIELD_TYPE)
length += DatabaseInputOutputUtils.writeCString(mEntry.binaryDesc, mOutputStream).toLong()
val dataLen: Int = data?.size ?: 0
mOutputStream.write(BINARY_DATA_FIELD_TYPE)
length += DatabaseInputOutputUtils.writeBytes(data, dataLen, mOutputStream)
}
companion object {
// Constants
val UUID_FIELD_TYPE:ByteArray = LEDataOutputStream.writeUShortBuf(1)

View File

@@ -21,7 +21,7 @@ package com.kunzisoft.keepass.database.file.save
import com.kunzisoft.keepass.database.element.PwGroupV3
import com.kunzisoft.keepass.stream.LEDataOutputStream
import com.kunzisoft.keepass.utils.Types
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils
import java.io.IOException
import java.io.OutputStream
@@ -44,7 +44,7 @@ class PwGroupOutputV3
// Name
mOS.write(NAME_FIELD_TYPE)
Types.writeCString(mPG.title, mOS)
DatabaseInputOutputUtils.writeCString(mPG.title, mOS)
// Create date
mOS.write(CREATE_FIELD_TYPE)

View File

@@ -19,7 +19,7 @@
*/
package com.kunzisoft.keepass.database.search;
import com.kunzisoft.keepass.utils.Types;
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils;
import java.util.UUID;
@@ -27,7 +27,7 @@ public class UuidUtil {
public static String toHexString(UUID uuid) {
if (uuid == null) { return null; }
byte[] buf = Types.UUIDtoBytes(uuid);
byte[] buf = DatabaseInputOutputUtils.UUIDtoBytes(uuid);
if (buf == null) { return null; }
int len = buf.length;

View File

@@ -19,7 +19,7 @@
*/
package com.kunzisoft.keepass.stream;
import com.kunzisoft.keepass.utils.Types;
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils;
import java.io.IOException;
import java.io.InputStream;
@@ -151,7 +151,7 @@ public class HashedBlockInputStream extends InputStream {
if ( ! ReadHashedBlock() ) return -1;
}
int output = Types.readUByte(buffer, bufferPos);
int output = DatabaseInputOutputUtils.readUByte(buffer, bufferPos);
bufferPos++;
return output;

View File

@@ -19,7 +19,7 @@
*/
package com.kunzisoft.keepass.stream;
import com.kunzisoft.keepass.utils.Types;
import com.kunzisoft.keepass.utils.DatabaseInputOutputUtils;
import java.io.IOException;
import java.io.InputStream;
@@ -56,7 +56,7 @@ public class HmacBlockInputStream extends InputStream {
if (!readSafeBlock()) return -1;
}
int output = Types.readUByte(buffer, bufferPos);
int output = DatabaseInputOutputUtils.readUByte(buffer, bufferPos);
bufferPos++;
return output;

View File

@@ -46,7 +46,7 @@ import com.kunzisoft.keepass.stream.LEDataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.UUID;
@@ -55,20 +55,24 @@ import java.util.UUID;
*
* @author Bill Zwicky <wrzwicky@pobox.com>
*/
public class Types {
public class DatabaseInputOutputUtils {
public static long ULONG_MAX_VALUE = -1;
private static Charset defaultCharset = Charset.forName("UTF-8");
private static final byte[] CRLFbuf = { 0x0D, 0x0A };
private static final String CRLF = new String(CRLFbuf);
private static final String SEP = System.getProperty("line.separator");
private static final boolean REPLACE = !SEP.equals(CRLF);
/** Read an unsigned byte */
public static int readUByte( byte[] buf, int offset ) {
return ((int)buf[offset] & 0xFF);
}
/** Write an unsigned byte
*
* @param val
* @param buf
* @param offset
/**
* Write an unsigned byte
*/
public static void writeUByte(int val, byte[] buf, int offset) {
buf[offset] = (byte)(val & 0xFF);
@@ -85,42 +89,16 @@ public class Types {
/**
* Return len of null-terminated string (i.e. distance to null)
* within a byte buffer.
*
* @param buf
* @param offset
* @return
*/
public static int strlen( byte[] buf, int offset ) {
private static int strlen( byte[] buf, int offset ) {
int len = 0;
while( buf[offset + len] != 0 )
len++;
return len;
}
/**
* Copy a sequence of bytes into a new array.
*
* @param b - source array
* @param offset - first byte
* @param len - number of bytes
* @return new byte[len]
*/
public static byte[] extract( byte[] b, int offset, int len ) {
byte[] b2 = new byte[len];
System.arraycopy( b, offset, b2, 0, len );
return b2;
}
private static final byte[] CRLFbuf = { 0x0D, 0x0A };
private static final String CRLF = new String(CRLFbuf);
private static final String SEP = System.getProperty("line.separator");
private static final boolean REPLACE = ! SEP.equals(CRLF);
public static String readCString(byte[] buf, int offset) throws UnsupportedEncodingException {
String jstring = new String(buf, offset, strlen(buf, offset), "UTF-8");
public static String readCString(byte[] buf, int offset) {
String jstring = new String(buf, offset, strlen(buf, offset), defaultCharset);
if ( REPLACE ) {
jstring = jstring.replace(CRLF, SEP);
@@ -141,7 +119,7 @@ public class Types {
str = str.replace(SEP, CRLF);
}
byte[] initial = str.getBytes("UTF-8");
byte[] initial = str.getBytes(defaultCharset);
int length = initial.length+1;
os.write(LEDataOutputStream.writeIntBuf(length));
@@ -151,6 +129,33 @@ public class Types {
return length;
}
public static String readPassword(byte[] buf, int offset) {
return new String(buf, offset, strlen(buf, offset), defaultCharset);
}
public static int writePassword(String str, OutputStream os) throws IOException {
byte[] initial = str.getBytes(defaultCharset);
int length = initial.length+1;
os.write(LEDataOutputStream.writeIntBuf(length));
os.write(initial);
os.write(0x00);
return length;
}
public static byte[] readBytes(byte[] buf, int offset, int len) {
byte[] binaryData = new byte[len];
System.arraycopy(buf, offset, binaryData, 0, len);
return binaryData;
}
public static int writeBytes(byte[] data, int dataLen, OutputStream os ) throws IOException {
os.write(LEDataOutputStream.writeIntBuf(dataLen));
if (data != null) {
os.write(data);
}
return dataLen;
}
public static UUID bytestoUUID(byte[] buf) {
return bytestoUUID(buf, 0);
}
@@ -167,15 +172,12 @@ public class Types {
}
return new UUID(msb, lsb);
}
public static byte[] UUIDtoBytes(UUID uuid) {
byte[] buf = new byte[16];
LEDataOutputStream.writeLong(uuid.getMostSignificantBits(), buf, 0);
LEDataOutputStream.writeLong(uuid.getLeastSignificantBits(), buf, 8);
return buf;
}