Commit d3c97fb6 authored by Him188's avatar Him188

Add ECDH

parent 101d655e
......@@ -6,6 +6,7 @@ import kotlinx.io.core.toByteArray
import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.qqandroid.utils.*
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.ECDH
import net.mamoe.mirai.utils.io.hexToBytes
/*
......@@ -27,7 +28,7 @@ internal open class QQAndroidClient(
val context: Context,
val account: BotAccount,
val ecdh: ECDH = ECDH.Default,
val ecdh: ECDH = ECDH(),
val device: DeviceInfo = SystemDeviceInfo(context)
) {
val tgtgtKey: ByteArray = generateTgtgtKey(device.guid)
......
package net.mamoe.mirai.qqandroid.utils
import net.mamoe.mirai.utils.io.chunkedHexToBytes
/**
* From QQAndroid 8.2.0
* `oicq.wlogin_sdk.tools.EcdhCrypt`
......@@ -9,11 +7,12 @@ import net.mamoe.mirai.utils.io.chunkedHexToBytes
* Constant to avoid calculations
*/
interface ECDH {
/*
object Default : ECDH {
override val publicKey: ByteArray = "020b03cf3d99541f29ffec281bebbd4ea211292ac1f53d7128".chunkedHexToBytes()
override val shareKey: ByteArray = "4da0f614fc9f29c2054c77048a6566d7".chunkedHexToBytes()
override val privateKey: ByteArray = ByteArray(16)
}
}*/
val publicKey: ByteArray
......
......@@ -136,6 +136,7 @@ kotlin {
api(kotlinx("io-jvm", kotlinXIoVersion))
api(kotlinx("serialization-runtime", serializationVersion))
api("org.bouncycastle:bcprov-jdk15on:1.64")
runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE
}
}
......
package net.mamoe.mirai.utils.cryptor
import net.mamoe.mirai.utils.md5
import java.security.*
import java.security.spec.X509EncodedKeySpec
import javax.crypto.KeyAgreement
actual typealias ECDHPrivateKey = PrivateKey
actual typealias ECDHPublicKey = PublicKey
actual class ECDHKeyPair(
private val delegate: KeyPair
) {
actual val privateKey: ECDHPrivateKey get() = delegate.private
actual val publicKey: ECDHPublicKey get() = delegate.public
actual val shareKey: ByteArray = ECDH.calculateShareKey(privateKey, initialPublicKey)
}
@Suppress("FunctionName")
actual fun ECDH() = ECDH(ECDH.generateKeyPair())
actual class ECDH actual constructor(val keyPair: ECDHKeyPair) {
actual companion object {
actual fun generateKeyPair(): ECDHKeyPair {
return ECDHKeyPair(KeyPairGenerator.getInstance("ECDH").genKeyPair())
}
actual fun calculateShareKey(
privateKey: ECDHPrivateKey,
publicKey: ECDHPublicKey
): ByteArray {
val instance = KeyAgreement.getInstance("ECDH", "BC")
instance.init(privateKey)
instance.doPhase(publicKey, true)
return md5(instance.generateSecret())
}
actual fun constructPublicKey(key: ByteArray): ECDHPublicKey {
return KeyFactory.getInstance("EC", "BC").generatePublic(X509EncodedKeySpec(key))
}
}
actual fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray {
return calculateShareKey(keyPair.privateKey, peerPublicKey)
}
}
\ No newline at end of file
package net.mamoe.mirai.utils.cryptor
import net.mamoe.mirai.utils.io.chunkedHexToBytes
import net.mamoe.mirai.utils.io.toUHexString
expect interface ECDHPrivateKey {
fun getEncoded(): ByteArray
}
expect interface ECDHPublicKey {
fun getEncoded(): ByteArray
}
expect class ECDHKeyPair {
val privateKey: ECDHPrivateKey
val publicKey: ECDHPublicKey
val shareKey: ByteArray
}
expect class ECDH(keyPair: ECDHKeyPair) {
fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray
companion object {
fun constructPublicKey(key: ByteArray): ECDHPublicKey
fun generateKeyPair(): ECDHKeyPair
fun calculateShareKey(privateKey: ECDHPrivateKey, publicKey: ECDHPublicKey): ByteArray
}
}
@Suppress("FunctionName")
expect fun ECDH(): ECDH
internal val initialPublicKey =
ECDH.constructPublicKey("3046301006072A8648CE3D020106052B8104001F03320004928D8850673088B343264E0C6BACB8496D697799F37211DEB25BB73906CB089FEA9639B4E0260498B51A992D50813DA8".chunkedHexToBytes())
private val commonHeadFor02 = "302E301006072A8648CE3D020106052B8104001F031A00".chunkedHexToBytes()
private val commonHeadForNot02 = "3046301006072A8648CE3D020106052B8104001F033200".chunkedHexToBytes()
private const val constantHead = "3046301006072A8648CE3D020106052B8104001F03320004"
private val byteArray_04 = byteArrayOf(0x04)
fun ByteArray.adjustToPublicKey(): ECDHPublicKey {
val key = if (this[0].toInt() == 0x02) { // from server
commonHeadFor02 + this
} else if (!this.toUHexString("").startsWith(constantHead)) {
commonHeadForNot02 +
if (this[0].toInt() == 0x04) this
else (byteArray_04 + this)
} else this
return ECDH.constructPublicKey(this)
}
\ No newline at end of file
package net.mamoe.mirai.utils.cryptor
import net.mamoe.mirai.utils.md5
import java.security.*
import java.security.spec.X509EncodedKeySpec
import javax.crypto.KeyAgreement
actual typealias ECDHPrivateKey = PrivateKey
actual typealias ECDHPublicKey = PublicKey
actual class ECDHKeyPair(
private val delegate: KeyPair
) {
actual val privateKey: ECDHPrivateKey get() = delegate.private
actual val publicKey: ECDHPublicKey get() = delegate.public
actual val shareKey: ByteArray = ECDH.calculateShareKey(privateKey, publicKey)
}
@Suppress("FunctionName")
actual fun ECDH() = ECDH(ECDH.generateKeyPair())
actual class ECDH actual constructor(val keyPair: ECDHKeyPair) {
actual companion object {
actual fun generateKeyPair(): ECDHKeyPair {
return ECDHKeyPair(KeyPairGenerator.getInstance("ECDH").genKeyPair())
}
actual fun calculateShareKey(
privateKey: ECDHPrivateKey,
publicKey: ECDHPublicKey
): ByteArray {
val instance = KeyAgreement.getInstance("ECDH", "BC")
instance.init(privateKey)
instance.doPhase(publicKey, true)
return md5(instance.generateSecret())
}
actual fun constructPublicKey(key: ByteArray): ECDHPublicKey {
return KeyFactory.getInstance("EC", "BC").generatePublic(X509EncodedKeySpec(key))
}
}
actual fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray {
return calculateShareKey(keyPair.privateKey, peerPublicKey)
}
}
\ No newline at end of file
......@@ -45,7 +45,7 @@ dependencies {
implementation(project(":mirai-core-timpc"))
// runtimeOnly(files("../mirai-core/build/classes/kotlin/jvm/main")) // classpath is not added correctly by IDE
implementation("org.bouncycastle:bcprov-jdk15:1.46")
implementation("org.bouncycastle:bcprov-jdk15on:1.64")
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment