mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
Fix OOM #256
This commit is contained in:
@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.database.element
|
|||||||
import android.os.Parcel
|
import android.os.Parcel
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
|
||||||
import com.kunzisoft.keepass.utils.MemUtil
|
import com.kunzisoft.keepass.utils.MemoryUtil
|
||||||
|
|
||||||
import java.util.HashMap
|
import java.util.HashMap
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ class AutoType : Parcelable {
|
|||||||
this.enabled = parcel.readByte().toInt() != 0
|
this.enabled = parcel.readByte().toInt() != 0
|
||||||
this.obfuscationOptions = parcel.readLong()
|
this.obfuscationOptions = parcel.readLong()
|
||||||
this.defaultSequence = parcel.readString()
|
this.defaultSequence = parcel.readString()
|
||||||
this.windowSeqPairs = MemUtil.readStringParcelableMap(parcel)
|
this.windowSeqPairs = MemoryUtil.readStringParcelableMap(parcel)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun describeContents(): Int {
|
override fun describeContents(): Int {
|
||||||
@@ -59,7 +59,7 @@ class AutoType : Parcelable {
|
|||||||
dest.writeByte((if (enabled) 1 else 0).toByte())
|
dest.writeByte((if (enabled) 1 else 0).toByte())
|
||||||
dest.writeLong(obfuscationOptions)
|
dest.writeLong(obfuscationOptions)
|
||||||
dest.writeString(defaultSequence)
|
dest.writeString(defaultSequence)
|
||||||
MemUtil.writeStringParcelableMap(dest, windowSeqPairs)
|
MemoryUtil.writeStringParcelableMap(dest, windowSeqPairs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun put(key: String, value: String) {
|
fun put(key: String, value: String) {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ package com.kunzisoft.keepass.database.element
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException
|
import com.kunzisoft.keepass.database.exception.InvalidKeyFileException
|
||||||
import com.kunzisoft.keepass.database.exception.KeyFileEmptyException
|
import com.kunzisoft.keepass.database.exception.KeyFileEmptyException
|
||||||
import com.kunzisoft.keepass.utils.MemUtil
|
import com.kunzisoft.keepass.utils.MemoryUtil
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
@@ -118,43 +118,41 @@ abstract class PwDatabase<Group : PwGroup<*, Group, Entry>, Entry : PwEntry<Grou
|
|||||||
@Throws(InvalidKeyFileException::class, IOException::class)
|
@Throws(InvalidKeyFileException::class, IOException::class)
|
||||||
protected fun getFileKey(keyInputStream: InputStream): ByteArray {
|
protected fun getFileKey(keyInputStream: InputStream): ByteArray {
|
||||||
|
|
||||||
val bos = ByteArrayOutputStream()
|
val keyByteArrayOutputStream = ByteArrayOutputStream()
|
||||||
MemUtil.copyStream(keyInputStream, bos)
|
MemoryUtil.copyStream(keyInputStream, keyByteArrayOutputStream)
|
||||||
val keyData = bos.toByteArray()
|
//StreamUtils.copy(keyInputStream, keyByteArrayOutputStream);
|
||||||
|
val keyData = keyByteArrayOutputStream.toByteArray()
|
||||||
|
|
||||||
val bis = ByteArrayInputStream(keyData)
|
val keyByteArrayInputStream = ByteArrayInputStream(keyData)
|
||||||
val key = loadXmlKeyFile(bis)
|
val key = loadXmlKeyFile(keyByteArrayInputStream)
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
val fileSize = keyData.size.toLong()
|
when (keyData.size.toLong()) {
|
||||||
if (fileSize == 0L) {
|
0L -> throw KeyFileEmptyException()
|
||||||
throw KeyFileEmptyException()
|
32L -> return keyData
|
||||||
} else if (fileSize == 32L) {
|
64L -> try {
|
||||||
return keyData
|
|
||||||
} else if (fileSize == 64L) {
|
|
||||||
try {
|
|
||||||
return hexStringToByteArray(String(keyData))
|
return hexStringToByteArray(String(keyData))
|
||||||
} catch (e: IndexOutOfBoundsException) {
|
} catch (e: IndexOutOfBoundsException) {
|
||||||
// Key is not base 64, treat it as binary data
|
// Key is not base 64, treat it as binary data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val md: MessageDigest
|
val messageDigest: MessageDigest
|
||||||
try {
|
try {
|
||||||
md = MessageDigest.getInstance("SHA-256")
|
messageDigest = MessageDigest.getInstance("SHA-256")
|
||||||
} catch (e: NoSuchAlgorithmException) {
|
} catch (e: NoSuchAlgorithmException) {
|
||||||
throw IOException("SHA-256 not supported")
|
throw IOException("SHA-256 not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
md.update(keyData)
|
messageDigest.update(keyData)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
println(e.toString())
|
println(e.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
return md.digest()
|
return messageDigest.digest()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun loadXmlKeyFile(keyInputStream: InputStream): ByteArray?
|
protected abstract fun loadXmlKeyFile(keyInputStream: InputStream): ByteArray?
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import android.os.Parcel
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.kunzisoft.keepass.database.element.security.ProtectedBinary
|
import com.kunzisoft.keepass.database.element.security.ProtectedBinary
|
||||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||||
import com.kunzisoft.keepass.utils.MemUtil
|
import com.kunzisoft.keepass.utils.MemoryUtil
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
||||||
@@ -94,9 +94,9 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
|||||||
iconCustom = parcel.readParcelable(PwIconCustom::class.java.classLoader)
|
iconCustom = parcel.readParcelable(PwIconCustom::class.java.classLoader)
|
||||||
usageCount = parcel.readLong()
|
usageCount = parcel.readLong()
|
||||||
locationChanged = parcel.readParcelable(PwDate::class.java.classLoader)
|
locationChanged = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||||
customData = MemUtil.readStringParcelableMap(parcel)
|
customData = MemoryUtil.readStringParcelableMap(parcel)
|
||||||
fields = MemUtil.readStringParcelableMap(parcel, ProtectedString::class.java)
|
fields = MemoryUtil.readStringParcelableMap(parcel, ProtectedString::class.java)
|
||||||
// TODO binaries = MemUtil.readStringParcelableMap(parcel, ProtectedBinary.class);
|
// TODO binaries = MemoryUtil.readStringParcelableMap(parcel, ProtectedBinary.class);
|
||||||
foregroundColor = parcel.readString()
|
foregroundColor = parcel.readString()
|
||||||
backgroundColor = parcel.readString()
|
backgroundColor = parcel.readString()
|
||||||
overrideURL = parcel.readString()
|
overrideURL = parcel.readString()
|
||||||
@@ -112,9 +112,9 @@ class PwEntryV4 : PwEntry<PwGroupV4, PwEntryV4>, NodeV4Interface {
|
|||||||
dest.writeParcelable(iconCustom, flags)
|
dest.writeParcelable(iconCustom, flags)
|
||||||
dest.writeLong(usageCount)
|
dest.writeLong(usageCount)
|
||||||
dest.writeParcelable(locationChanged, flags)
|
dest.writeParcelable(locationChanged, flags)
|
||||||
MemUtil.writeStringParcelableMap(dest, customData)
|
MemoryUtil.writeStringParcelableMap(dest, customData)
|
||||||
MemUtil.writeStringParcelableMap(dest, flags, fields)
|
MemoryUtil.writeStringParcelableMap(dest, flags, fields)
|
||||||
// TODO MemUtil.writeStringParcelableMap(dest, flags, binaries);
|
// TODO MemoryUtil.writeStringParcelableMap(dest, flags, binaries);
|
||||||
dest.writeString(foregroundColor)
|
dest.writeString(foregroundColor)
|
||||||
dest.writeString(backgroundColor)
|
dest.writeString(backgroundColor)
|
||||||
dest.writeString(overrideURL)
|
dest.writeString(overrideURL)
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class PwGroupV4 : PwGroup<UUID, PwGroupV4, PwEntryV4>, NodeV4Interface {
|
|||||||
iconCustom = parcel.readParcelable(PwIconCustom::class.java.classLoader)
|
iconCustom = parcel.readParcelable(PwIconCustom::class.java.classLoader)
|
||||||
usageCount = parcel.readLong()
|
usageCount = parcel.readLong()
|
||||||
locationChanged = parcel.readParcelable(PwDate::class.java.classLoader)
|
locationChanged = parcel.readParcelable(PwDate::class.java.classLoader)
|
||||||
// TODO customData = MemUtil.readStringParcelableMap(in);
|
// TODO customData = MemoryUtil.readStringParcelableMap(in);
|
||||||
notes = parcel.readString()
|
notes = parcel.readString()
|
||||||
isExpanded = parcel.readByte().toInt() != 0
|
isExpanded = parcel.readByte().toInt() != 0
|
||||||
defaultAutoTypeSequence = parcel.readString()
|
defaultAutoTypeSequence = parcel.readString()
|
||||||
@@ -88,7 +88,7 @@ class PwGroupV4 : PwGroup<UUID, PwGroupV4, PwEntryV4>, NodeV4Interface {
|
|||||||
dest.writeParcelable(iconCustom, flags)
|
dest.writeParcelable(iconCustom, flags)
|
||||||
dest.writeLong(usageCount)
|
dest.writeLong(usageCount)
|
||||||
dest.writeParcelable(locationChanged, flags)
|
dest.writeParcelable(locationChanged, flags)
|
||||||
// TODO MemUtil.writeStringParcelableMap(dest, customData);
|
// TODO MemoryUtil.writeStringParcelableMap(dest, customData);
|
||||||
dest.writeString(notes)
|
dest.writeString(notes)
|
||||||
dest.writeByte((if (isExpanded) 1 else 0).toByte())
|
dest.writeByte((if (isExpanded) 1 else 0).toByte())
|
||||||
dest.writeString(defaultAutoTypeSequence)
|
dest.writeString(defaultAutoTypeSequence)
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ import com.kunzisoft.keepass.stream.HmacBlockInputStream
|
|||||||
import com.kunzisoft.keepass.stream.LEDataInputStream
|
import com.kunzisoft.keepass.stream.LEDataInputStream
|
||||||
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
||||||
import com.kunzisoft.keepass.database.file.KDBX4DateUtil
|
import com.kunzisoft.keepass.database.file.KDBX4DateUtil
|
||||||
import com.kunzisoft.keepass.utils.MemUtil
|
import com.kunzisoft.keepass.utils.MemoryUtil
|
||||||
import com.kunzisoft.keepass.utils.Types
|
import com.kunzisoft.keepass.utils.Types
|
||||||
import org.spongycastle.crypto.StreamCipher
|
import org.spongycastle.crypto.StreamCipher
|
||||||
import org.xmlpull.v1.XmlPullParser
|
import org.xmlpull.v1.XmlPullParser
|
||||||
@@ -933,7 +933,7 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
|
|||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
private fun createProtectedBinaryFromData(protection: Boolean, data: ByteArray): ProtectedBinary {
|
private fun createProtectedBinaryFromData(protection: Boolean, data: ByteArray): ProtectedBinary {
|
||||||
return if (data.size > MemUtil.BUFFER_SIZE_BYTES) {
|
return if (data.size > MemoryUtil.BUFFER_SIZE_BYTES) {
|
||||||
val file = File(streamDir, unusedCacheFileName)
|
val file = File(streamDir, unusedCacheFileName)
|
||||||
FileOutputStream(file).use { outputStream -> outputStream.write(data) }
|
FileOutputStream(file).use { outputStream -> outputStream.write(data) }
|
||||||
ProtectedBinary(protection, file, data.size)
|
ProtectedBinary(protection, file, data.size)
|
||||||
@@ -971,7 +971,7 @@ class ImporterV4(private val streamDir: File) : Importer<PwDatabaseV4>() {
|
|||||||
var data = Base64Coder.decode(base64)
|
var data = Base64Coder.decode(base64)
|
||||||
|
|
||||||
if (compressed) {
|
if (compressed) {
|
||||||
data = MemUtil.decompress(data)
|
data = MemoryUtil.decompress(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
return createProtectedBinaryFromData(false, data)
|
return createProtectedBinaryFromData(false, data)
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import com.kunzisoft.keepass.database.element.PwDatabaseV4
|
|||||||
import com.kunzisoft.keepass.database.file.PwDbHeaderV4
|
import com.kunzisoft.keepass.database.file.PwDbHeaderV4
|
||||||
import com.kunzisoft.keepass.stream.ActionReadBytes
|
import com.kunzisoft.keepass.stream.ActionReadBytes
|
||||||
import com.kunzisoft.keepass.stream.LEDataOutputStream
|
import com.kunzisoft.keepass.stream.LEDataOutputStream
|
||||||
import com.kunzisoft.keepass.utils.MemUtil
|
import com.kunzisoft.keepass.utils.MemoryUtil
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
import kotlin.experimental.or
|
import kotlin.experimental.or
|
||||||
@@ -56,7 +56,7 @@ class PwDbInnerHeaderOutputV4(private val db: PwDatabaseV4, private val header:
|
|||||||
los.write(flag.toInt())
|
los.write(flag.toInt())
|
||||||
|
|
||||||
protectedBinary.getData()?.let {
|
protectedBinary.getData()?.let {
|
||||||
MemUtil.readBytes(it, ActionReadBytes { buffer ->
|
MemoryUtil.readBytes(it, ActionReadBytes { buffer ->
|
||||||
los.write(buffer)
|
los.write(buffer)
|
||||||
})
|
})
|
||||||
} ?: throw IOException("Can't write protected binary")
|
} ?: throw IOException("Can't write protected binary")
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ import com.kunzisoft.keepass.stream.HashedBlockOutputStream
|
|||||||
import com.kunzisoft.keepass.stream.HmacBlockOutputStream
|
import com.kunzisoft.keepass.stream.HmacBlockOutputStream
|
||||||
import com.kunzisoft.keepass.stream.LEDataOutputStream
|
import com.kunzisoft.keepass.stream.LEDataOutputStream
|
||||||
import com.kunzisoft.keepass.database.file.KDBX4DateUtil
|
import com.kunzisoft.keepass.database.file.KDBX4DateUtil
|
||||||
import com.kunzisoft.keepass.utils.MemUtil
|
import com.kunzisoft.keepass.utils.MemoryUtil
|
||||||
import com.kunzisoft.keepass.utils.Types
|
import com.kunzisoft.keepass.utils.Types
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import org.spongycastle.crypto.StreamCipher
|
import org.spongycastle.crypto.StreamCipher
|
||||||
@@ -423,7 +423,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
|
|||||||
try (InputStream base64InputStream =
|
try (InputStream base64InputStream =
|
||||||
IOUtil.pipe(inputStream,
|
IOUtil.pipe(inputStream,
|
||||||
o -> new Base64OutputStream(o, DEFAULT))) {
|
o -> new Base64OutputStream(o, DEFAULT))) {
|
||||||
MemUtil.readBytes(base64InputStream,
|
MemoryUtil.readBytes(base64InputStream,
|
||||||
buffer -> xml.text(Arrays.toString(buffer)));
|
buffer -> xml.text(Arrays.toString(buffer)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,7 +448,7 @@ class PwDbV4Output(private val mDatabaseV4: PwDatabaseV4, outputStream: OutputSt
|
|||||||
if (mDatabaseV4.compressionAlgorithm === PwCompressionAlgorithm.Gzip) {
|
if (mDatabaseV4.compressionAlgorithm === PwCompressionAlgorithm.Gzip) {
|
||||||
xml.attribute(null, PwDatabaseV4XML.AttrCompressed, PwDatabaseV4XML.ValTrue)
|
xml.attribute(null, PwDatabaseV4XML.AttrCompressed, PwDatabaseV4XML.ValTrue)
|
||||||
|
|
||||||
val compressData = MemUtil.compress(buffer)
|
val compressData = MemoryUtil.compress(buffer)
|
||||||
xml.text(String(Base64Coder.encode(compressData)))
|
xml.text(String(Base64Coder.encode(compressData)))
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -38,24 +38,26 @@ import java.util.HashMap
|
|||||||
import java.util.zip.GZIPInputStream
|
import java.util.zip.GZIPInputStream
|
||||||
import java.util.zip.GZIPOutputStream
|
import java.util.zip.GZIPOutputStream
|
||||||
|
|
||||||
object MemUtil {
|
object MemoryUtil {
|
||||||
|
|
||||||
private val TAG = MemUtil::class.java.name
|
private val TAG = MemoryUtil::class.java.name
|
||||||
const val BUFFER_SIZE_BYTES = 3 * 128
|
const val BUFFER_SIZE_BYTES = 3 * 128
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
fun copyStream(inputStream: InputStream, out: OutputStream) {
|
fun copyStream(inputStream: InputStream, out: OutputStream) {
|
||||||
val buf = ByteArray(BUFFER_SIZE_BYTES)
|
val buffer = ByteArray(BUFFER_SIZE_BYTES)
|
||||||
val read: Int
|
|
||||||
try {
|
try {
|
||||||
read = inputStream.read(buf)
|
var read = inputStream.read(buffer)
|
||||||
while (read != -1) {
|
while (read != -1) {
|
||||||
out.write(buf, 0, read)
|
out.write(buffer, 0, read)
|
||||||
|
read = inputStream.read(buffer)
|
||||||
|
if (Thread.interrupted()) {
|
||||||
|
throw InterruptedException()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error: OutOfMemoryError) {
|
} catch (error: OutOfMemoryError) {
|
||||||
throw IOException(error)
|
throw IOException(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
Reference in New Issue
Block a user