diff --git a/core/src/main/kotlin/ch/dissem/bitmessage/factory/V3MessageFactory.kt b/core/src/main/kotlin/ch/dissem/bitmessage/factory/V3MessageFactory.kt index 3afa82a..5ad6845 100644 --- a/core/src/main/kotlin/ch/dissem/bitmessage/factory/V3MessageFactory.kt +++ b/core/src/main/kotlin/ch/dissem/bitmessage/factory/V3MessageFactory.kt @@ -62,13 +62,13 @@ object V3MessageFactory { fun getPayload(command: String, stream: InputStream, length: Int): MessagePayload? = when (command) { "version" -> parseVersion(stream) "verack" -> VerAck() - "addr" -> parseAddr(stream) - "inv" -> parseInv(stream) - "getdata" -> parseGetData(stream) + "addr" -> Addr(parseList(stream) { parseAddress(it, false) }) + "inv" -> Inv(parseList(stream) { parseInventoryVector(it) }) + "getdata" -> GetData(parseList(stream) { parseInventoryVector(it) }) "object" -> readObject(stream, length) "custom" -> readCustom(stream, length) else -> { - LOG.debug("Unknown command: " + command) + LOG.debug("Unknown command: $command") null } } @@ -85,73 +85,40 @@ object V3MessageFactory { val stream = Decode.varInt(input, counter) val data = Decode.bytes(input, length - counter.length()) - var payload: ObjectPayload - try { - val dataStream = ByteArrayInputStream(data) - payload = Factory.getObjectPayload(objectType, version, stream, dataStream, data.size) + val payload: ObjectPayload = try { + Factory.getObjectPayload(objectType, version, stream, ByteArrayInputStream(data), data.size) } catch (e: Exception) { if (LOG.isTraceEnabled) { LOG.trace("Could not parse object payload - using generic payload instead", e) LOG.trace(Strings.hex(data)) } - payload = GenericPayload(version, stream, data) + GenericPayload(version, stream, data) } - return ObjectMessage.Builder() - .nonce(nonce) - .expiresTime(expiresTime) - .objectType(objectType) - .stream(stream) - .payload(payload) - .build() + return ObjectMessage( + nonce, expiresTime, payload, objectType, version, stream + ) } - private fun parseGetData(stream: InputStream): GetData { + private fun parseList(stream: InputStream, reader: (InputStream) -> (T)): List { val count = Decode.varInt(stream) - val inventoryVectors = LinkedList() + val items = LinkedList() for (i in 0 until count) { - inventoryVectors.add(parseInventoryVector(stream)) + items.add(reader(stream)) } - return GetData(inventoryVectors) + return items } - private fun parseInv(stream: InputStream): Inv { - val count = Decode.varInt(stream) - val inventoryVectors = LinkedList() - for (i in 0 until count) { - inventoryVectors.add(parseInventoryVector(stream)) - } - return Inv(inventoryVectors) - } - - private fun parseAddr(stream: InputStream): Addr { - val count = Decode.varInt(stream) - val networkAddresses = LinkedList() - for (i in 0 until count) { - networkAddresses.add(parseAddress(stream, false)) - } - return Addr(networkAddresses) - } - - private fun parseVersion(stream: InputStream): Version { - val version = Decode.int32(stream) - val services = Decode.int64(stream) - val timestamp = Decode.int64(stream) - val addrRecv = parseAddress(stream, true) - val addrFrom = parseAddress(stream, true) - val nonce = Decode.int64(stream) - val userAgent = Decode.varString(stream) - val streamNumbers = Decode.varIntList(stream) - - return Version.Builder() - .version(version) - .services(services) - .timestamp(timestamp) - .addrRecv(addrRecv).addrFrom(addrFrom) - .nonce(nonce) - .userAgent(userAgent) - .streams(*streamNumbers).build() - } + private fun parseVersion(stream: InputStream) = Version( + version = Decode.int32(stream), + services = Decode.int64(stream), + timestamp = Decode.int64(stream), + addrRecv = parseAddress(stream, true), + addrFrom = parseAddress(stream, true), + nonce = Decode.int64(stream), + userAgent = Decode.varString(stream), + streams = Decode.varIntList(stream) + ) private fun parseInventoryVector(stream: InputStream) = InventoryVector(Decode.bytes(stream, 32)) @@ -168,13 +135,10 @@ object V3MessageFactory { val services = Decode.int64(stream) val ipv6 = Decode.bytes(stream, 16) val port = Decode.uint16(stream) - return NetworkAddress.Builder() - .time(time) - .stream(streamNumber) - .services(services) - .ipv6(ipv6) - .port(port) - .build() + + return NetworkAddress( + time, streamNumber, services, ipv6, port + ) } private fun testChecksum(checksum: ByteArray, payload: ByteArray): Boolean { diff --git a/core/src/main/kotlin/ch/dissem/bitmessage/ports/AbstractCryptography.kt b/core/src/main/kotlin/ch/dissem/bitmessage/ports/AbstractCryptography.kt index 5792f0f..b8daa98 100644 --- a/core/src/main/kotlin/ch/dissem/bitmessage/ports/AbstractCryptography.kt +++ b/core/src/main/kotlin/ch/dissem/bitmessage/ports/AbstractCryptography.kt @@ -36,12 +36,16 @@ import javax.crypto.spec.SecretKeySpec /** * Implements everything that isn't directly dependent on either Spongy- or Bouncycastle. */ -abstract class AbstractCryptography protected constructor(@JvmField protected val provider: Provider) : Cryptography, InternalContext.ContextHolder { +abstract class AbstractCryptography protected constructor(@JvmField protected val provider: Provider) : Cryptography, + InternalContext.ContextHolder { private lateinit var ctx: InternalContext - @JvmField protected val ALGORITHM_ECDSA = "ECDSA" - @JvmField protected val ALGORITHM_ECDSA_SHA1 = "SHA1withECDSA" - @JvmField protected val ALGORITHM_EVP_SHA256 = "SHA256withECDSA" + @JvmField + protected val ALGORITHM_ECDSA = "ECDSA" + @JvmField + protected val ALGORITHM_ECDSA_SHA1 = "SHA1withECDSA" + @JvmField + protected val ALGORITHM_EVP_SHA256 = "SHA256withECDSA" override fun setContext(context: InternalContext) { ctx = context @@ -65,8 +69,12 @@ abstract class AbstractCryptography protected constructor(@JvmField protected va return mda.digest(mda.digest()) } - override fun doubleSha512(data: ByteArray, length: Int): ByteArray { - val mda = md("SHA-512") + override fun doubleSha512(data: ByteArray, length: Int) = doubleHash("SHA-512", data, length); + + override fun doubleSha256(data: ByteArray, length: Int) = doubleHash("SHA-256", data, length); + + private fun doubleHash(method: String, data: ByteArray, length: Int): ByteArray { + val mda = md(method) mda.update(data, 0, length) return mda.digest(mda.digest()) } @@ -75,12 +83,6 @@ abstract class AbstractCryptography protected constructor(@JvmField protected va return hash("RIPEMD160", *data) } - override fun doubleSha256(data: ByteArray, length: Int): ByteArray { - val mda = md("SHA-256") - mda.update(data, 0, length) - return mda.digest(mda.digest()) - } - override fun sha1(vararg data: ByteArray): ByteArray { return hash("SHA-1", *data) } @@ -91,13 +93,17 @@ abstract class AbstractCryptography protected constructor(@JvmField protected va return result } - override fun doProofOfWork(objectMessage: ObjectMessage, nonceTrialsPerByte: Long, - extraBytes: Long, callback: ProofOfWorkEngine.Callback) { + override fun doProofOfWork( + objectMessage: ObjectMessage, nonceTrialsPerByte: Long, + extraBytes: Long, callback: ProofOfWorkEngine.Callback + ) { val initialHash = getInitialHash(objectMessage) - val target = getProofOfWorkTarget(objectMessage, - max(nonceTrialsPerByte, NETWORK_NONCE_TRIALS_PER_BYTE), max(extraBytes, NETWORK_EXTRA_BYTES)) + val target = getProofOfWorkTarget( + objectMessage, + max(nonceTrialsPerByte, NETWORK_NONCE_TRIALS_PER_BYTE), max(extraBytes, NETWORK_EXTRA_BYTES) + ) ctx.proofOfWorkEngine.calculateNonce(initialHash, target, callback) } @@ -105,7 +111,10 @@ abstract class AbstractCryptography protected constructor(@JvmField protected va @Throws(InsufficientProofOfWorkException::class) override fun checkProofOfWork(objectMessage: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long) { val target = getProofOfWorkTarget(objectMessage, nonceTrialsPerByte, extraBytes) - val value = doubleSha512(objectMessage.nonce ?: throw ApplicationException("Object without nonce"), getInitialHash(objectMessage)) + val value = doubleSha512( + objectMessage.nonce ?: throw ApplicationException("Object without nonce"), + getInitialHash(objectMessage) + ) if (Bytes.lt(target, value, 8)) { throw InsufficientProofOfWorkException(target, value) } @@ -136,7 +145,11 @@ abstract class AbstractCryptography protected constructor(@JvmField protected va return sha512(objectMessage.payloadBytesWithoutNonce) } - override fun getProofOfWorkTarget(objectMessage: ObjectMessage, nonceTrialsPerByte: Long, extraBytes: Long): ByteArray { + override fun getProofOfWorkTarget( + objectMessage: ObjectMessage, + nonceTrialsPerByte: Long, + extraBytes: Long + ): ByteArray { @Suppress("NAME_SHADOWING") val nonceTrialsPerByte = if (nonceTrialsPerByte == 0L) NETWORK_NONCE_TRIALS_PER_BYTE else nonceTrialsPerByte @Suppress("NAME_SHADOWING") @@ -181,12 +194,16 @@ abstract class AbstractCryptography protected constructor(@JvmField protected va } - override fun createPubkey(version: Long, stream: Long, privateSigningKey: ByteArray, privateEncryptionKey: ByteArray, - nonceTrialsPerByte: Long, extraBytes: Long, vararg features: Pubkey.Feature): Pubkey { - return Factory.createPubkey(version, stream, + override fun createPubkey( + version: Long, stream: Long, privateSigningKey: ByteArray, privateEncryptionKey: ByteArray, + nonceTrialsPerByte: Long, extraBytes: Long, vararg features: Pubkey.Feature + ): Pubkey { + return Factory.createPubkey( + version, stream, createPublicKey(privateSigningKey), createPublicKey(privateEncryptionKey), - nonceTrialsPerByte, extraBytes, *features) + nonceTrialsPerByte, extraBytes, *features + ) } override fun keyToBigInt(privateKey: ByteArray): BigInteger { diff --git a/repositories/src/main/kotlin/ch/dissem/bitmessage/repository/JdbcAddressRepository.kt b/repositories/src/main/kotlin/ch/dissem/bitmessage/repository/JdbcAddressRepository.kt index 477aa5a..383c3b2 100644 --- a/repositories/src/main/kotlin/ch/dissem/bitmessage/repository/JdbcAddressRepository.kt +++ b/repositories/src/main/kotlin/ch/dissem/bitmessage/repository/JdbcAddressRepository.kt @@ -32,15 +32,11 @@ import java.util.* class JdbcAddressRepository(config: JdbcConfig) : JdbcHelper(config), AddressRepository { - override fun findContact(ripeOrTag: ByteArray) = find("private_key is null").firstOrNull { - if (it.version > 3) { - Arrays.equals(ripeOrTag, it.tag) - } else { - Arrays.equals(ripeOrTag, it.ripe) - } - } + override fun findContact(ripeOrTag: ByteArray) = find("private_key is null").getByRipeOrTag(ripeOrTag) - override fun findIdentity(ripeOrTag: ByteArray) = find("private_key is not null").firstOrNull { + override fun findIdentity(ripeOrTag: ByteArray) = find("private_key is not null").getByRipeOrTag(ripeOrTag) + + private fun List.getByRipeOrTag(ripeOrTag: ByteArray): BitmessageAddress? = firstOrNull { if (it.version > 3) { Arrays.equals(ripeOrTag, it.tag) } else { @@ -67,11 +63,13 @@ class JdbcAddressRepository(config: JdbcConfig) : JdbcHelper(config), AddressRep try { config.getConnection().use { connection -> connection.createStatement().use { stmt -> - stmt.executeQuery(""" + stmt.executeQuery( + """ SELECT address, alias, public_key, private_key, subscribed, chan FROM Address WHERE $where - """).use { rs -> + """ + ).use { rs -> while (rs.next()) { val address: BitmessageAddress @@ -79,8 +77,10 @@ class JdbcAddressRepository(config: JdbcConfig) : JdbcHelper(config), AddressRep if (privateKeyStream == null) { address = BitmessageAddress(rs.getString("address")) rs.getBlob("public_key")?.let { publicKeyBlob -> - var pubkey: Pubkey = Factory.readPubkey(address.version, address.stream, - publicKeyBlob.binaryStream, publicKeyBlob.length().toInt(), false)!! + var pubkey: Pubkey = Factory.readPubkey( + address.version, address.stream, + publicKeyBlob.binaryStream, publicKeyBlob.length().toInt(), false + )!! if (address.version == 4L && pubkey is V3Pubkey) { pubkey = V4Pubkey(pubkey) } @@ -109,8 +109,10 @@ class JdbcAddressRepository(config: JdbcConfig) : JdbcHelper(config), AddressRep private fun exists(address: BitmessageAddress): Boolean { config.getConnection().use { connection -> connection.createStatement().use { stmt -> - stmt.executeQuery("SELECT '1' FROM Address " + - "WHERE address='" + address.address + "'").use { rs -> return rs.next() } + stmt.executeQuery( + "SELECT '1' FROM Address " + + "WHERE address='" + address.address + "'" + ).use { rs -> return rs.next() } } } } @@ -159,7 +161,8 @@ class JdbcAddressRepository(config: JdbcConfig) : JdbcHelper(config), AddressRep private fun insert(address: BitmessageAddress) { config.getConnection().use { connection -> connection.prepareStatement( - "INSERT INTO Address (address, version, alias, public_key, private_key, subscribed, chan) " + "VALUES (?, ?, ?, ?, ?, ?, ?)").use { ps -> + "INSERT INTO Address (address, version, alias, public_key, private_key, subscribed, chan) " + "VALUES (?, ?, ?, ?, ?, ?, ?)" + ).use { ps -> ps.setString(1, address.address) ps.setLong(2, address.version) ps.setString(3, address.alias) @@ -184,7 +187,10 @@ class JdbcAddressRepository(config: JdbcConfig) : JdbcHelper(config), AddressRep override fun remove(address: BitmessageAddress) { try { - config.getConnection().use { connection -> connection.createStatement().use { stmt -> stmt.executeUpdate("DELETE FROM Address WHERE address = '" + address.address + "'") } } + config.getConnection().use { connection -> + connection.createStatement() + .use { stmt -> stmt.executeUpdate("DELETE FROM Address WHERE address = '" + address.address + "'") } + } } catch (e: SQLException) { LOG.error(e.message, e) }