mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-05 07:30:09 +08:00
Add ECDH
This commit is contained in:
parent
101d655e6b
commit
d3c97fb6d4
@ -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)
|
||||
|
@ -1,7 +1,5 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
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)
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
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)
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
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)
|
||||
}
|
||||
}
|
@ -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")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user