Remove Little Endian output stream

This commit is contained in:
J-Jamet
2021-03-24 12:22:34 +01:00
parent 844588a0d4
commit e5cb160aa4
10 changed files with 79 additions and 163 deletions

View File

@@ -183,12 +183,10 @@ class ValuesTest : TestCase() {
ulongBytes[i] = -1
}
val bos = ByteArrayOutputStream()
val leos = LittleEndianDataOutputStream(bos)
leos.writeLong(UnsignedLong.MAX_VALUE)
leos.close()
val uLongMax = bos.toByteArray()
val byteArrayOutputStream = ByteArrayOutputStream()
byteArrayOutputStream.write8BytesLong(UnsignedLong.MAX_VALUE)
byteArrayOutputStream.close()
val uLongMax = byteArrayOutputStream.toByteArray()
assertArrayEquals(ulongBytes, uLongMax)
}

View File

@@ -25,6 +25,7 @@ import com.kunzisoft.keepass.database.exception.DatabaseOutputException
import com.kunzisoft.keepass.database.file.DatabaseHeader
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDBX
import com.kunzisoft.keepass.stream.*
import com.kunzisoft.keepass.utils.UnsignedInt
import com.kunzisoft.keepass.utils.UnsignedLong
import com.kunzisoft.keepass.utils.VariantDictionary
import java.io.ByteArrayOutputStream
@@ -42,7 +43,6 @@ constructor(private val databaseKDBX: DatabaseKDBX,
private val header: DatabaseHeaderKDBX,
outputStream: OutputStream) {
private val los: LittleEndianDataOutputStream
private val mos: MacOutputStream
private val dos: DigestOutputStream
lateinit var headerHmac: ByteArray
@@ -79,15 +79,14 @@ constructor(private val databaseKDBX: DatabaseKDBX,
dos = DigestOutputStream(outputStream, md)
mos = MacOutputStream(dos, hmac)
los = LittleEndianDataOutputStream(mos)
}
@Throws(IOException::class)
fun output() {
los.writeUInt(DatabaseHeader.PWM_DBSIG_1)
los.writeUInt(DatabaseHeaderKDBX.DBSIG_2)
los.writeUInt(header.version)
mos.write4BytesUInt(DatabaseHeader.PWM_DBSIG_1)
mos.write4BytesUInt(DatabaseHeaderKDBX.DBSIG_2)
mos.write4BytesUInt(header.version)
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CipherID, uuidTo16Bytes(databaseKDBX.dataCipher))
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.CompressionFlags, uIntTo4Bytes(DatabaseHeaderKDBX.getFlagFromCompression(databaseKDBX.compressionAlgorithm)))
@@ -112,14 +111,13 @@ constructor(private val databaseKDBX: DatabaseKDBX,
if (databaseKDBX.containsPublicCustomData()) {
val bos = ByteArrayOutputStream()
val los = LittleEndianDataOutputStream(bos)
VariantDictionary.serialize(databaseKDBX.publicCustomData, los)
VariantDictionary.serialize(databaseKDBX.publicCustomData, bos)
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.PublicCustomData, bos.toByteArray())
}
writeHeaderField(DatabaseHeaderKDBX.PwDbHeaderV4Fields.EndOfHeader, EndHeaderValue)
los.flush()
mos.flush()
hashOfHeader = dos.messageDigest.digest()
headerHmac = mos.mac
}
@@ -127,11 +125,11 @@ constructor(private val databaseKDBX: DatabaseKDBX,
@Throws(IOException::class)
private fun writeHeaderField(fieldId: Byte, pbData: ByteArray?) {
// Write the field id
los.write(fieldId.toInt())
mos.write(fieldId.toInt())
if (pbData != null) {
writeHeaderFieldSize(pbData.size)
los.write(pbData)
mos.write(pbData)
} else {
writeHeaderFieldSize(0)
}
@@ -140,9 +138,9 @@ constructor(private val databaseKDBX: DatabaseKDBX,
@Throws(IOException::class)
private fun writeHeaderFieldSize(size: Int) {
if (header.version.toKotlinLong() < DatabaseHeaderKDBX.FILE_VERSION_32_4.toKotlinLong()) {
los.writeUShort(size)
mos.write2BytesUShort(size)
} else {
los.writeInt(size)
mos.write4BytesUInt(UnsignedInt(size))
}
}

View File

@@ -26,8 +26,9 @@ import com.kunzisoft.keepass.database.element.security.EncryptionAlgorithm
import com.kunzisoft.keepass.database.exception.DatabaseOutputException
import com.kunzisoft.keepass.database.file.DatabaseHeader
import com.kunzisoft.keepass.database.file.DatabaseHeaderKDB
import com.kunzisoft.keepass.stream.LittleEndianDataOutputStream
import com.kunzisoft.keepass.stream.NullOutputStream
import com.kunzisoft.keepass.stream.write2BytesUShort
import com.kunzisoft.keepass.stream.write4BytesUInt
import com.kunzisoft.keepass.utils.UnsignedInt
import java.io.BufferedOutputStream
import java.io.ByteArrayOutputStream
@@ -198,14 +199,13 @@ class DatabaseOutputKDB(private val mDatabaseKDB: DatabaseKDB,
@Suppress("CAST_NEVER_SUCCEEDS")
@Throws(DatabaseOutputException::class)
fun outputPlanGroupAndEntries(outputStream: OutputStream) {
val littleEndianDataOutputStream = LittleEndianDataOutputStream(outputStream)
// useHeaderHash
if (headerHashBlock != null) {
try {
littleEndianDataOutputStream.writeUShort(0x0000)
littleEndianDataOutputStream.writeInt(headerHashBlock!!.size)
littleEndianDataOutputStream.write(headerHashBlock!!)
outputStream.write2BytesUShort(0x0000)
outputStream.write4BytesUInt(UnsignedInt(headerHashBlock!!.size))
outputStream.write(headerHashBlock!!)
} catch (e: IOException) {
throw DatabaseOutputException("Failed to output header hash.", e)
}
@@ -252,24 +252,22 @@ class DatabaseOutputKDB(private val mDatabaseKDB: DatabaseKDB,
}
@Throws(IOException::class)
private fun writeExtData(headerDigest: ByteArray, os: OutputStream) {
val los = LittleEndianDataOutputStream(os)
writeExtDataField(los, 0x0001, headerDigest, headerDigest.size)
private fun writeExtData(headerDigest: ByteArray, outputStream: OutputStream) {
writeExtDataField(outputStream, 0x0001, headerDigest, headerDigest.size)
val headerRandom = ByteArray(32)
val rand = SecureRandom()
rand.nextBytes(headerRandom)
writeExtDataField(los, 0x0002, headerRandom, headerRandom.size)
writeExtDataField(los, 0xFFFF, null, 0)
writeExtDataField(outputStream, 0x0002, headerRandom, headerRandom.size)
writeExtDataField(outputStream, 0xFFFF, null, 0)
}
@Throws(IOException::class)
private fun writeExtDataField(los: LittleEndianDataOutputStream, fieldType: Int, data: ByteArray?, fieldSize: Int) {
los.writeUShort(fieldType)
los.writeInt(fieldSize)
private fun writeExtDataField(outputStream: OutputStream, fieldType: Int, data: ByteArray?, fieldSize: Int) {
outputStream.write2BytesUShort(fieldType)
outputStream.write4BytesUInt(UnsignedInt(fieldSize))
if (data != null) {
los.write(data)
outputStream.write(data)
}
}
}

View File

@@ -122,18 +122,16 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
@Throws(IOException::class)
private fun outputInnerHeader(database: DatabaseKDBX,
header: DatabaseHeaderKDBX,
outputStream: OutputStream) {
val dataOutputStream = LittleEndianDataOutputStream(outputStream)
dataOutputStream: OutputStream) {
dataOutputStream.writeByte(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.InnerRandomStreamID)
dataOutputStream.writeInt(4)
dataOutputStream.write4BytesUInt(UnsignedInt(4))
if (header.innerRandomStream == null)
throw IOException("Can't write innerRandomStream")
dataOutputStream.writeUInt(header.innerRandomStream!!.id)
dataOutputStream.write4BytesUInt(header.innerRandomStream!!.id)
val streamKeySize = header.innerRandomStreamKey.size
dataOutputStream.writeByte(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.InnerRandomstreamKey)
dataOutputStream.writeInt(streamKeySize)
dataOutputStream.write4BytesUInt(UnsignedInt(streamKeySize))
dataOutputStream.write(header.innerRandomStreamKey)
val binaryCache = database.binaryCache
@@ -143,7 +141,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
// Write type binary
dataOutputStream.writeByte(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.Binary)
// Write size
dataOutputStream.writeUInt(UnsignedInt.fromKotlinLong(binary.getSize() + 1))
dataOutputStream.write4BytesUInt(UnsignedInt.fromKotlinLong(binary.getSize() + 1))
// Write protected flag
var flag = DatabaseHeaderKDBX.KdbxBinaryFlags.None
if (binary.isProtected) {
@@ -159,7 +157,7 @@ class DatabaseOutputKDBX(private val mDatabaseKDBX: DatabaseKDBX,
}
dataOutputStream.writeByte(DatabaseHeaderKDBX.PwDbInnerHeaderV4Fields.EndOfHeader)
dataOutputStream.writeInt(0)
dataOutputStream.write4BytesUInt(UnsignedInt(0))
}
@Throws(IllegalArgumentException::class, IllegalStateException::class, IOException::class)

View File

@@ -28,7 +28,7 @@ import kotlin.math.min
class HashedBlockOutputStream : OutputStream {
private lateinit var baseStream: LittleEndianDataOutputStream
private lateinit var baseStream: OutputStream
private lateinit var buffer: ByteArray
private var bufferPos = 0
private var bufferIndex: Long = 0
@@ -47,7 +47,7 @@ class HashedBlockOutputStream : OutputStream {
}
private fun init(os: OutputStream, bufferSize: Int) {
baseStream = LittleEndianDataOutputStream(os)
baseStream = os
buffer = ByteArray(bufferSize)
}
@@ -99,7 +99,7 @@ class HashedBlockOutputStream : OutputStream {
@Throws(IOException::class)
private fun writeHashedBlock() {
baseStream.writeUInt(UnsignedInt.fromKotlinLong(bufferIndex))
baseStream.write4BytesUInt(UnsignedInt.fromKotlinLong(bufferIndex))
bufferIndex++
if (bufferPos > 0) {
@@ -117,13 +117,13 @@ class HashedBlockOutputStream : OutputStream {
} else {
// Write 32-bits of zeros
baseStream.writeLong(0L)
baseStream.writeLong(0L)
baseStream.writeLong(0L)
baseStream.writeLong(0L)
baseStream.write8BytesLong(0L)
baseStream.write8BytesLong(0L)
baseStream.write8BytesLong(0L)
baseStream.write8BytesLong(0L)
}
baseStream.writeInt(bufferPos)
baseStream.write4BytesUInt(UnsignedInt(bufferPos))
if (bufferPos > 0) {
baseStream.write(buffer, 0, bufferPos)

View File

@@ -28,12 +28,10 @@ import java.security.NoSuchAlgorithmException
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
class HmacBlockOutputStream(outputStream: OutputStream,
class HmacBlockOutputStream(private val baseStream: OutputStream,
private val key: ByteArray)
: OutputStream() {
private val baseStream: LittleEndianDataOutputStream = LittleEndianDataOutputStream(outputStream)
private val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
private var bufferPos = 0
private var blockIndex: Long = 0

View File

@@ -33,19 +33,14 @@ object HmacBlockStream {
throw RuntimeException(e)
}
val nos = NullOutputStream()
val dos = DigestOutputStream(nos, hash)
val leos = LittleEndianDataOutputStream(dos)
val digestOutputStream = DigestOutputStream(NullOutputStream(), hash)
try {
leos.writeLong(blockIndex)
leos.write(key)
leos.close()
digestOutputStream.write8BytesLong(blockIndex)
digestOutputStream.write(key)
digestOutputStream.close()
} catch (e: IOException) {
throw RuntimeException(e)
}
//assert(hashKey.length == 64);
return hash.digest()
}
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright 2019 Brian Pellin, 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.stream
import com.kunzisoft.keepass.utils.UnsignedInt
import java.io.IOException
import java.io.OutputStream
/**
* Little Endian version of the DataOutputStream
* @author bpellin
*/
class LittleEndianDataOutputStream(private val baseStream: OutputStream) : OutputStream() {
@Throws(IOException::class)
fun writeUInt(uInt: UnsignedInt) {
baseStream.write(uIntTo4Bytes(uInt))
}
@Throws(IOException::class)
override fun close() {
baseStream.close()
}
@Throws(IOException::class)
override fun flush() {
baseStream.flush()
}
@Throws(IOException::class)
override fun write(buffer: ByteArray, offset: Int, count: Int) {
baseStream.write(buffer, offset, count)
}
@Throws(IOException::class)
override fun write(buffer: ByteArray) {
baseStream.write(buffer)
}
@Throws(IOException::class)
override fun write(oneByte: Int) {
baseStream.write(oneByte)
}
@Throws(IOException::class)
fun writeByte(byte: Byte) {
baseStream.write(byte.toInt())
}
@Throws(IOException::class)
fun writeLong(value: Long) {
baseStream.write(longTo8Bytes(value))
}
@Throws(IOException::class)
fun writeInt(value: Int) {
baseStream.write(uIntTo4Bytes(UnsignedInt(value)))
}
@Throws(IOException::class)
fun writeUShort(value: Int) {
baseStream.write(uShortTo2Bytes(value))
}
}

View File

@@ -24,6 +24,7 @@ import com.kunzisoft.keepass.utils.StringDatabaseKDBUtils.bytesToString
import com.kunzisoft.keepass.utils.UnsignedInt
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.util.*
/**
@@ -118,6 +119,22 @@ fun InputStream.readBytesLength(length: Int): ByteArray {
return buf
}
fun OutputStream.write4BytesUInt(value: UnsignedInt) {
this.write(uIntTo4Bytes(value))
}
fun OutputStream.writeByte(byte: Byte) {
this.write(byte.toInt())
}
fun OutputStream.write8BytesLong(value: Long) {
this.write(longTo8Bytes(value))
}
fun OutputStream.write2BytesUShort(value: Int) {
this.write(uShortTo2Bytes(value))
}
/**
* Read an unsigned 16-bit value.
*/

View File

@@ -21,10 +21,7 @@ package com.kunzisoft.keepass.utils
import com.kunzisoft.keepass.crypto.keyDerivation.KdfParameters
import com.kunzisoft.keepass.stream.*
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.io.InputStream
import java.io.*
import java.nio.charset.Charset
import java.util.*
@@ -123,8 +120,7 @@ open class VariantDictionary {
@Throws(IOException::class)
fun serialize(kdfParameters: KdfParameters): ByteArray {
val byteArrayOutputStream = ByteArrayOutputStream()
val outputStream = LittleEndianDataOutputStream(byteArrayOutputStream)
serialize(kdfParameters, outputStream)
serialize(kdfParameters, byteArrayOutputStream)
return byteArrayOutputStream.toByteArray()
}
@@ -182,48 +178,48 @@ open class VariantDictionary {
@Throws(IOException::class)
fun serialize(variantDictionary: VariantDictionary,
outputStream: LittleEndianDataOutputStream?) {
outputStream: OutputStream?) {
if (outputStream == null) {
return
}
outputStream.writeUShort(VdVersion)
outputStream.write2BytesUShort(VdVersion)
for ((name, vd) in variantDictionary.dict) {
val nameBuf = name.toByteArray(UTF8Charset)
outputStream.write(vd.type.toInt())
outputStream.writeInt(nameBuf.size)
outputStream.write4BytesUInt(UnsignedInt(nameBuf.size))
outputStream.write(nameBuf)
var buf: ByteArray
when (vd.type) {
VdType.UInt32 -> {
outputStream.writeInt(4)
outputStream.writeUInt((vd.value as UnsignedInt))
outputStream.write4BytesUInt(UnsignedInt(4))
outputStream.write4BytesUInt(vd.value as UnsignedInt)
}
VdType.UInt64 -> {
outputStream.writeInt(8)
outputStream.writeLong(vd.value as Long)
outputStream.write4BytesUInt(UnsignedInt(8))
outputStream.write8BytesLong(vd.value as Long)
}
VdType.Bool -> {
outputStream.writeInt(1)
outputStream.write4BytesUInt(UnsignedInt(1))
val bool = if (vd.value as Boolean) 1.toByte() else 0.toByte()
outputStream.write(bool.toInt())
}
VdType.Int32 -> {
outputStream.writeInt(4)
outputStream.writeInt(vd.value as Int)
outputStream.write4BytesUInt(UnsignedInt(4))
outputStream.write4BytesUInt(UnsignedInt(vd.value as Int))
}
VdType.Int64 -> {
outputStream.writeInt(8)
outputStream.writeLong(vd.value as Long)
outputStream.write4BytesUInt(UnsignedInt(8))
outputStream.write8BytesLong(vd.value as Long)
}
VdType.String -> {
val value = vd.value as String
buf = value.toByteArray(UTF8Charset)
outputStream.writeInt(buf.size)
outputStream.write4BytesUInt(UnsignedInt(buf.size))
outputStream.write(buf)
}
VdType.ByteArray -> {
buf = vd.value as ByteArray
outputStream.writeInt(buf.size)
outputStream.write4BytesUInt(UnsignedInt(buf.size))
outputStream.write(buf)
}
else -> {