wip MessageSigner3

This commit is contained in:
Bixilon 2023-01-05 17:27:27 +01:00
parent 556f564591
commit 28d10a2e81
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
8 changed files with 87 additions and 11 deletions

View File

@ -15,13 +15,14 @@ package de.bixilon.minosoft.data.chat.signature
import de.bixilon.minosoft.data.chat.signature.signer.MessageSigner
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.versions.Version
import java.security.PrivateKey
import java.time.Instant
import java.util.*
class MessageChain(version: Version) {
val signer = MessageSigner.forVersion(version)
class MessageChain(version: Version, connection: PlayConnection) {
val signer = MessageSigner.forVersion(version, connection)
fun signMessage(privateKey: PrivateKey, message: String, preview: ChatComponent?, salt: Long, sender: UUID, time: Instant, lastSeen: LastSeenMessageList): ByteArray {
return signer.signMessage(privateKey, message, preview, salt, sender, time, lastSeen)

View File

@ -0,0 +1,28 @@
/*
* Minosoft
* Copyright (C) 2020-2023 Moritz Zwerger
*
* This program 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.
*
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
*/
package de.bixilon.minosoft.data.chat.signature
import java.util.*
class MessageLink(
val index: Int,
val sender: UUID,
val sessionId: UUID,
) {
fun next(): MessageLink {
// TODO: check Int.MAX_VALUE
return MessageLink(index + 1, sender, sessionId)
}
}

View File

@ -1,6 +1,6 @@
/*
* Minosoft
* Copyright (C) 2020-2022 Moritz Zwerger
* Copyright (C) 2020-2023 Moritz Zwerger
*
* This program 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.
*
@ -18,4 +18,4 @@ import java.time.Instant
class MessageExpiredError(
val sent: Instant,
val received: Instant,
) : Exception("Message expired: Sent at $sent, but received to late at $received")
) : Exception("Message expired: Sent at $sent, but received too late at $received")

View File

@ -15,6 +15,7 @@ package de.bixilon.minosoft.data.chat.signature.signer
import de.bixilon.minosoft.data.chat.signature.LastSeenMessageList
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
import de.bixilon.minosoft.protocol.versions.Version
import java.security.PrivateKey
@ -28,14 +29,14 @@ interface MessageSigner {
companion object {
fun forVersion(version: Version): MessageSigner {
fun forVersion(version: Version, connection: PlayConnection): MessageSigner {
if (version < ProtocolVersions.V_1_19_1_PRE4) {
return MessageSigner1(version)
}
if (version < ProtocolVersions.V_22W42A) {
return MessageSigner2(version)
}
return MessageSigner3(version)
return MessageSigner3(version, connection)
}
}
}

View File

@ -14,9 +14,9 @@
package de.bixilon.minosoft.data.chat.signature.signer
import com.google.common.hash.Hashing
import com.google.common.primitives.Longs
import de.bixilon.minosoft.data.chat.signature.LastSeenMessageList
import de.bixilon.minosoft.data.chat.signature.signer.MessageSigningUtil.getSignatureBytes
import de.bixilon.minosoft.data.chat.signature.signer.MessageSigningUtil.update
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.protocol.protocol.OutByteBuffer
import de.bixilon.minosoft.protocol.protocol.ProtocolVersions
@ -59,8 +59,7 @@ class MessageSigner2(
val hash = Hashing.sha256().hashBytes(buffer.toArray()).asBytes()
previous?.let { signature.update(it) }
signature.update(Longs.toByteArray(sender.mostSignificantBits))
signature.update(Longs.toByteArray(sender.leastSignificantBits))
signature.update(sender)
signature.update(hash)
return signature.sign()

View File

@ -13,8 +13,15 @@
package de.bixilon.minosoft.data.chat.signature.signer
import com.google.common.primitives.Ints
import com.google.common.primitives.Longs
import de.bixilon.minosoft.data.chat.signature.LastSeenMessageList
import de.bixilon.minosoft.data.chat.signature.MessageLink
import de.bixilon.minosoft.data.chat.signature.signer.MessageSigningUtil.update
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.protocol.ProtocolUtil.encodeNetwork
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.protocol.encryption.CryptManager
import de.bixilon.minosoft.protocol.versions.Version
import java.security.PrivateKey
import java.time.Instant
@ -22,9 +29,41 @@ import java.util.*
class MessageSigner3(
private val version: Version,
private val connection: PlayConnection,
) : MessageSigner {
private var link: MessageLink = MessageLink(0, connection.account.uuid, connection.sessionId)
override fun signMessage(privateKey: PrivateKey, message: String, preview: ChatComponent?, salt: Long, sender: UUID, time: Instant, lastSeen: LastSeenMessageList): ByteArray {
TODO("Not yet implemented!")
val signature = CryptManager.createSignature(version)
signature.initSign(privateKey)
signature.update(Ints.toByteArray(1))
val link = nextLink()
signature.update(link.sender)
signature.update(link.sessionId)
signature.update(Ints.toByteArray(link.index))
// message body
signature.update(Longs.toByteArray(salt))
signature.update(Longs.toByteArray(time.epochSecond))
val encoded = message.encodeNetwork()
signature.update(Ints.toByteArray(encoded.size))
signature.update(encoded)
signature.update(Ints.toByteArray(lastSeen.messages.size))
for (lastSeenMessage in lastSeen.messages) {
signature.update(lastSeenMessage.signature)
}
return signature.sign()
}
private fun nextLink(): MessageLink {
this.link = this.link.next()
return this.link
}
}

View File

@ -14,11 +14,19 @@
package de.bixilon.minosoft.data.chat.signature.signer
import com.fasterxml.jackson.core.io.JsonStringEncoder
import com.google.common.primitives.Longs
import de.bixilon.minosoft.protocol.ProtocolUtil.encodeNetwork
import java.security.Signature
import java.util.*
object MessageSigningUtil {
fun String.getSignatureBytes(): ByteArray {
return """{"text":"${String(JsonStringEncoder.getInstance().quoteAsString(this))}"}""".encodeNetwork()
}
fun Signature.update(uuid: UUID) {
update(Longs.toByteArray(uuid.mostSignificantBits))
update(Longs.toByteArray(uuid.leastSignificantBits))
}
}

View File

@ -47,7 +47,7 @@ import java.time.Instant
class ConnectionUtil(
private val connection: PlayConnection,
) {
private val chain = MessageChain(connection.version)
private val chain = MessageChain(connection.version, connection)
private val random = SecureRandom()
fun sendDebugMessage(message: Any) {