mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-02 05:00:35 +08:00
Implement ECDH on native with OpenSSL
This commit is contained in:
parent
8655f44a50
commit
29c8d13795
buildSrc/src/main/kotlin
gradle.propertiesmirai-core
build.gradle.kts
src
commonMain/kotlin
commonTest/kotlin/utils/crypto
jvmBaseMain/kotlin/utils/crypto
jvmMain/kotlin/utils/crypto
nativeMain
@ -81,6 +81,8 @@ val LINUX_TARGETS = setOf("linuxX64")
|
||||
|
||||
val UNIX_LIKE_TARGETS by lazy { LINUX_TARGETS + MAC_TARGETS }
|
||||
|
||||
val NATIVE_TARGETS by lazy { UNIX_LIKE_TARGETS + WIN_TARGETS }
|
||||
|
||||
|
||||
fun Project.configureHMPP() {
|
||||
extensions.getByType(KotlinMultiplatformExtension::class.java).apply {
|
||||
|
@ -24,4 +24,5 @@ mirai.android.target.api.level=24
|
||||
# Enable if you want to use mavenLocal for both Gradle plugin and project dependencies resolutions.
|
||||
systemProp.use.maven.local=false
|
||||
org.gradle.caching=true
|
||||
kotlin.native.ignoreIncorrectDependencies=true
|
||||
kotlin.native.ignoreIncorrectDependencies=true
|
||||
kotlin.mpp.enableCInteropCommonization=true
|
@ -10,6 +10,7 @@
|
||||
@file:Suppress("UNUSED_VARIABLE")
|
||||
|
||||
import BinaryCompatibilityConfigurator.configureBinaryValidators
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
@ -105,6 +106,14 @@ kotlin {
|
||||
}
|
||||
}
|
||||
|
||||
NATIVE_TARGETS.forEach { target ->
|
||||
(targets.getByName(target) as KotlinNativeTarget).compilations.getByName("main").cinterops.create("OpenSSL")
|
||||
.apply {
|
||||
defFile = projectDir.resolve("src/nativeMain/cinterop/OpenSSL.def")
|
||||
packageName("openssl")
|
||||
}
|
||||
}
|
||||
|
||||
configure(WIN_TARGETS.map { getByName(it + "Main") }) {
|
||||
dependencies {
|
||||
implementation(`ktor-client-curl`)
|
||||
|
@ -199,10 +199,8 @@ internal class MessageProtocolFacadeImpl(
|
||||
val instances = protocols
|
||||
.sortedWith(MessageProtocol.PriorityComparator.reversed())
|
||||
for (instance in instances) {
|
||||
println("instance: $instance, class=${instance::class}")
|
||||
instance.collectProcessors(object : ProcessorCollector() {
|
||||
override fun <T : SingleMessage> add(encoder: MessageEncoder<T>, elementType: KClass<T>) {
|
||||
println("add: $encoder, $elementType")
|
||||
this@MessageProtocolFacadeImpl.encoderPipeline.registerProcessor(
|
||||
MessageEncoderProcessor(
|
||||
encoder,
|
||||
@ -212,27 +210,22 @@ internal class MessageProtocolFacadeImpl(
|
||||
}
|
||||
|
||||
override fun add(decoder: MessageDecoder) {
|
||||
println("add: $decoder")
|
||||
this@MessageProtocolFacadeImpl.decoderPipeline.registerProcessor(MessageDecoderProcessor(decoder))
|
||||
}
|
||||
|
||||
override fun add(preprocessor: OutgoingMessagePreprocessor) {
|
||||
println("add: $preprocessor")
|
||||
preprocessorPipeline.registerProcessor(OutgoingMessageProcessorAdapter(preprocessor))
|
||||
}
|
||||
|
||||
override fun add(transformer: OutgoingMessageTransformer) {
|
||||
println("add: $transformer")
|
||||
outgoingPipeline.registerProcessor(OutgoingMessageProcessorAdapter(transformer))
|
||||
}
|
||||
|
||||
override fun add(sender: OutgoingMessageSender) {
|
||||
println("add: $sender")
|
||||
outgoingPipeline.registerProcessor(OutgoingMessageProcessorAdapter(sender))
|
||||
}
|
||||
|
||||
override fun add(postprocessor: OutgoingMessagePostprocessor) {
|
||||
println("add: $postprocessor")
|
||||
outgoingPipeline.registerProcessor(OutgoingMessageProcessorAdapter(postprocessor))
|
||||
}
|
||||
|
||||
|
@ -201,10 +201,8 @@ protected constructor(
|
||||
override val processors: MutableDeque<ProcessorBox<P>> = ConcurrentLinkedDeque()
|
||||
|
||||
override fun registerProcessor(processor: P): ProcessorPipeline.DisposableRegistry {
|
||||
println("registerProcessor: $processor")
|
||||
val box = ProcessorBox(processor)
|
||||
processors.add(box)
|
||||
println("processors.add fin")
|
||||
return ProcessorPipeline.DisposableRegistry {
|
||||
processors.remove(box)
|
||||
}
|
||||
|
@ -15,9 +15,7 @@ import net.mamoe.mirai.utils.hexToBytes
|
||||
|
||||
internal expect interface ECDHPrivateKey
|
||||
|
||||
internal expect interface ECDHPublicKey {
|
||||
fun getEncoded(): ByteArray
|
||||
}
|
||||
internal expect interface ECDHPublicKey
|
||||
|
||||
internal expect class ECDHKeyPairImpl : ECDHKeyPair
|
||||
|
||||
@ -48,9 +46,6 @@ internal interface ECDHKeyPair {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 椭圆曲线密码, ECDH 加密
|
||||
*/
|
||||
internal expect class ECDH(keyPair: ECDHKeyPair) {
|
||||
val keyPair: ECDHKeyPair
|
||||
|
||||
@ -62,8 +57,11 @@ internal expect class ECDH(keyPair: ECDHKeyPair) {
|
||||
companion object {
|
||||
val isECDHAvailable: Boolean
|
||||
|
||||
|
||||
/**
|
||||
* 由完整的 publicKey ByteArray 得到 [ECDHPublicKey]
|
||||
* This API is platform dependent.
|
||||
* On JVM you need to add `signHead`,
|
||||
* but on Native you need to provide a key with initial byte value 0x04 and of 65 bytes' length.
|
||||
*/
|
||||
fun constructPublicKey(key: ByteArray): ECDHPublicKey
|
||||
|
||||
@ -78,7 +76,7 @@ internal expect class ECDH(keyPair: ECDHKeyPair) {
|
||||
fun generateKeyPair(initialPublicKey: ECDHPublicKey = defaultInitialPublicKey.key): ECDHKeyPair
|
||||
|
||||
/**
|
||||
* 由一对密匙计算 shareKey
|
||||
* 由一对密匙计算服务器需要的 shareKey
|
||||
*/
|
||||
fun calculateShareKey(privateKey: ECDHPrivateKey, publicKey: ECDHPublicKey): ByteArray
|
||||
}
|
||||
@ -119,19 +117,12 @@ internal data class ECDHWithPublicKey(private val initialPublicKey: ECDHInitialP
|
||||
@Serializable
|
||||
internal data class ECDHInitialPublicKey(val version: Int = 1, val keyStr: String, val expireTime: Long = 0) {
|
||||
@Transient
|
||||
internal val key: ECDHPublicKey = keyStr.adjustToPublicKey()
|
||||
internal val key: ECDHPublicKey = keyStr.hexToBytes().adjustToPublicKey()
|
||||
}
|
||||
|
||||
internal expect val publicKeyForVerify: ECDHPublicKey
|
||||
|
||||
internal val defaultInitialPublicKey: ECDHInitialPublicKey by lazy { ECDHInitialPublicKey(keyStr = "04EBCA94D733E399B2DB96EACDD3F69A8BB0F74224E2B44E3357812211D2E62EFBC91BB553098E25E33A799ADC7F76FEB208DA7C6522CDB0719A305180CC54A82E") }
|
||||
private val signHead = "3059301306072a8648ce3d020106082a8648ce3d030107034200".hexToBytes()
|
||||
|
||||
internal fun String.adjustToPublicKey(): ECDHPublicKey {
|
||||
return this.hexToBytes().adjustToPublicKey()
|
||||
}
|
||||
|
||||
internal fun ByteArray.adjustToPublicKey(): ECDHPublicKey {
|
||||
internal expect fun ByteArray.adjustToPublicKey(): ECDHPublicKey
|
||||
|
||||
return ECDH.constructPublicKey(signHead + this)
|
||||
}
|
||||
internal val ECDH.Companion.curveName get() = "prime256v1" // p-256
|
||||
|
70
mirai-core/src/commonTest/kotlin/utils/crypto/ECDHTest.kt
Normal file
70
mirai-core/src/commonTest/kotlin/utils/crypto/ECDHTest.kt
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils.crypto
|
||||
|
||||
import net.mamoe.mirai.internal.test.AbstractTest
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertContentEquals
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
internal class ECDHTest : AbstractTest() {
|
||||
|
||||
@Test
|
||||
fun `can generate key pair`() {
|
||||
val alice = ECDH.generateKeyPair()
|
||||
val bob = ECDH.generateKeyPair()
|
||||
|
||||
val aliceSecret = ECDH.calculateShareKey(alice.privateKey, bob.publicKey)
|
||||
val bobSecret = ECDH.calculateShareKey(bob.privateKey, alice.publicKey)
|
||||
|
||||
println(aliceSecret.toUHexString())
|
||||
assertContentEquals(aliceSecret, bobSecret)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `can get masked keys`() {
|
||||
val alice = ECDH.generateKeyPair()
|
||||
|
||||
println(alice)
|
||||
val maskedPublicKey = alice.maskedPublicKey
|
||||
println(maskedPublicKey.toUHexString())
|
||||
assertEquals(0x04, maskedPublicKey.first())
|
||||
println(alice.maskedShareKey.toUHexString())
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
EC_KEY *alice = create_key();
|
||||
EC_KEY *bob = create_key();
|
||||
assert(alice != NULL && bob != NULL);
|
||||
|
||||
const EC_POINT *alice_public = EC_KEY_get0_public_key(alice);
|
||||
const EC_POINT *bob_public = EC_KEY_get0_public_key(bob);
|
||||
|
||||
size_t alice_secret_len;
|
||||
size_t bob_secret_len;
|
||||
|
||||
unsigned char *alice_secret = get_secret(alice, bob_public, &alice_secret_len);
|
||||
unsigned char *bob_secret = get_secret(bob, alice_public, &bob_secret_len);
|
||||
assert(alice_secret != NULL && bob_secret != NULL
|
||||
&& alice_secret_len == bob_secret_len);
|
||||
|
||||
for (int i = 0; i < alice_secret_len; i++)
|
||||
assert(alice_secret[i] == bob_secret[i]);
|
||||
|
||||
EC_KEY_free(alice);
|
||||
EC_KEY_free(bob);
|
||||
OPENSSL_free(alice_secret);
|
||||
OPENSSL_free(bob_secret);
|
||||
|
||||
return 0;
|
||||
*/
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
package net.mamoe.mirai.internal.utils.crypto
|
||||
|
||||
import net.mamoe.mirai.utils.decodeBase64
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import java.security.KeyFactory
|
||||
import java.security.KeyPair
|
||||
import java.security.PrivateKey
|
||||
@ -36,8 +37,13 @@ internal actual class ECDHKeyPairImpl(
|
||||
}
|
||||
|
||||
|
||||
internal actual val publicKeyForVerify: ECDHPublicKey by lazy {
|
||||
internal val publicKeyForVerify: ECDHPublicKey by lazy {
|
||||
KeyFactory.getInstance("RSA")
|
||||
.generatePublic(X509EncodedKeySpec("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuJTW4abQJXeVdAODw1CamZH4QJZChyT08ribet1Gp0wpSabIgyKFZAOxeArcCbknKyBrRY3FFI9HgY1AyItH8DOUe6ajDEb6c+vrgjgeCiOiCVyum4lI5Fmp38iHKH14xap6xGaXcBccdOZNzGT82sPDM2Oc6QYSZpfs8EO7TYT7KSB2gaHz99RQ4A/Lel1Vw0krk+DescN6TgRCaXjSGn268jD7lOO23x5JS1mavsUJtOZpXkK9GqCGSTCTbCwZhI33CpwdQ2EHLhiP5RaXZCio6lksu+d8sKTWU1eEiEb3cQ7nuZXLYH7leeYFoPtbFV4RicIWp0/YG+RP7rLPCwIDAQAB".decodeBase64()))
|
||||
}
|
||||
|
||||
private val signHead = "3059301306072a8648ce3d020106082a8648ce3d030107034200".hexToBytes()
|
||||
|
||||
internal actual fun ByteArray.adjustToPublicKey(): ECDHPublicKey {
|
||||
return ECDH.constructPublicKey(signHead + this)
|
||||
}
|
||||
|
@ -12,14 +12,16 @@ package net.mamoe.mirai.internal.utils.crypto
|
||||
import net.mamoe.mirai.utils.decodeBase64
|
||||
import net.mamoe.mirai.utils.md5
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import java.security.*
|
||||
import java.security.KeyFactory
|
||||
import java.security.KeyPairGenerator
|
||||
import java.security.Security
|
||||
import java.security.Signature
|
||||
import java.security.spec.ECGenParameterSpec
|
||||
import java.security.spec.X509EncodedKeySpec
|
||||
import javax.crypto.KeyAgreement
|
||||
|
||||
internal actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
|
||||
actual companion object {
|
||||
private const val curveName = "prime256v1" // p-256
|
||||
|
||||
actual val isECDHAvailable: Boolean
|
||||
|
||||
|
43
mirai-core/src/nativeMain/cinterop/OpenSSL.def
Normal file
43
mirai-core/src/nativeMain/cinterop/OpenSSL.def
Normal file
@ -0,0 +1,43 @@
|
||||
headers = openssl/ec.h openssl/ecdh.h openssl/evp.h
|
||||
|
||||
linkerOpts.osx = -lcrypto \
|
||||
-lssl \
|
||||
-L/opt/openssl/lib \
|
||||
-L/opt/homebrew/Cellar/openssl@3/3.0.3/lib \
|
||||
-L/opt/homebrew/opt/openssl@3/lib \
|
||||
|
||||
compilerOpts.osx = -I/opt/openssl/include \
|
||||
-I/usr/local/include/openssl@3 \
|
||||
-I/opt/homebrew/Cellar/openssl@3/3.0.3/include \
|
||||
-I/usr/include/openssl@3 \
|
||||
-I/opt/homebrew/opt/openssl@3/include
|
||||
|
||||
linkerOpts.linux = -lcrypto \
|
||||
-lssl \
|
||||
-L/usr/lib64 \
|
||||
-L/usr/lib/x86_64-linux-gnu \
|
||||
-L/opt/local/lib \
|
||||
-L/usr/local/opt/openssl@3/lib \
|
||||
-L/opt/homebrew/opt/openssl@3/lib
|
||||
|
||||
compilerOpts.linux = -I/opt/local/include/openssl@3 \
|
||||
-I/usr/bin/openssl@3 \
|
||||
-I/usr/local/include/openssl@3 \
|
||||
-I/usr/include/openssl@3 \
|
||||
-I/opt/homebrew/opt/openssl@3/include
|
||||
|
||||
linkerOpts.mingw_x64 = -lcrypto \
|
||||
-lssl \
|
||||
-L/usr/lib64 \
|
||||
-L/usr/lib/x86_64-linux-gnu \
|
||||
-L/opt/local/lib \
|
||||
-L/usr/local/opt/openssl@3/lib \
|
||||
-L/opt/homebrew/opt/openssl@3/lib \
|
||||
-LC:/Tools/msys64/mingw64/lib \
|
||||
-LC:/Tools/msys2/mingw64/lib
|
||||
|
||||
compilerOpts.mingw_x64 = -I/opt/local/include/openssl@3 \
|
||||
-I/usr/bin/openssl@3 \
|
||||
-I/usr/local/include/openssl@3 \
|
||||
-I/usr/include/openssl@3 \
|
||||
-I/opt/homebrew/opt/openssl@3/include
|
232
mirai-core/src/nativeMain/kotlin/utils/crypto/ECDH.kt
Normal file
232
mirai-core/src/nativeMain/kotlin/utils/crypto/ECDH.kt
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils.crypto
|
||||
|
||||
import kotlinx.cinterop.*
|
||||
import net.mamoe.mirai.utils.hexToBytes
|
||||
import net.mamoe.mirai.utils.md5
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
import openssl.*
|
||||
import platform.posix.errno
|
||||
import platform.posix.free
|
||||
|
||||
private const val curveId = NID_X9_62_prime256v1
|
||||
|
||||
// shared, not freed!
|
||||
private val group by lazy { EC_GROUP_new_by_curve_name(curveId) ?: error("Failed to get EC_GROUP") }
|
||||
|
||||
private val convForm by lazy { EC_GROUP_get_point_conversion_form(group) }
|
||||
|
||||
// shared, not freed!
|
||||
private val bnCtx by lazy { BN_CTX_new() }
|
||||
|
||||
|
||||
internal actual interface ECDHPublicKey : OpenSSLKey {
|
||||
val encoded: ByteArray
|
||||
fun toPoint(): CPointer<EC_POINT>
|
||||
}
|
||||
|
||||
internal actual interface ECDHPrivateKey : OpenSSLKey {
|
||||
fun toBignum(): CPointer<BIGNUM>
|
||||
}
|
||||
|
||||
internal class OpenSslPrivateKey(
|
||||
override val hex: String, // use Kotlin's memory
|
||||
) : ECDHPrivateKey {
|
||||
|
||||
override fun toBignum(): CPointer<BIGNUM> {
|
||||
val bn = BN_new() ?: error("Failed BN_new")
|
||||
val values = cValuesOf(bn)
|
||||
BN_hex2bn(values, hex).let { r ->
|
||||
if (r <= 0) error("Failed BN_hex2bn: $r")
|
||||
}
|
||||
return bn
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromKey(key: CPointer<EC_KEY>): OpenSslPrivateKey {
|
||||
val bn = EC_KEY_get0_private_key(key) ?: error("Failed EC_KEY_get0_private_key")
|
||||
val hex = try {
|
||||
val ptr = BN_bn2hex(bn) ?: error("Failed EC_POINT_bn2point")
|
||||
try {
|
||||
ptr.toKString()
|
||||
} finally {
|
||||
free(ptr)
|
||||
}
|
||||
} finally {
|
||||
BN_free(bn)
|
||||
}
|
||||
return OpenSslPrivateKey(hex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal interface OpenSSLKey {
|
||||
val hex: String
|
||||
}
|
||||
|
||||
internal class OpenSslPublicKey(override val hex: String) : ECDHPublicKey {
|
||||
override val encoded: ByteArray = hex.hexToBytes()
|
||||
|
||||
override fun toPoint(): CPointer<EC_POINT> {
|
||||
val point = EC_POINT_new(group)
|
||||
EC_POINT_hex2point(group, hex, point, bnCtx) ?: error("Failed EC_POINT_hex2point")
|
||||
return point!!
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun fromKey(key: CPointer<EC_KEY>): OpenSslPublicKey =
|
||||
fromPoint(EC_KEY_get0_public_key(key) ?: error("Failed to get private key"))
|
||||
|
||||
fun fromPoint(point: CPointer<EC_POINT>): OpenSslPublicKey {
|
||||
return OpenSslPublicKey(point.toKtHex())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal actual class ECDHKeyPairImpl(
|
||||
override val privateKey: OpenSslPrivateKey,
|
||||
override val publicKey: OpenSslPublicKey,
|
||||
private val initialPublicKey: ECDHPublicKey
|
||||
) : ECDHKeyPair {
|
||||
|
||||
override val maskedPublicKey: ByteArray by lazy { publicKey.encoded }
|
||||
override val maskedShareKey: ByteArray by lazy { ECDH.calculateShareKey(privateKey, initialPublicKey) }
|
||||
|
||||
companion object {
|
||||
fun fromKey(
|
||||
key: CPointer<EC_KEY>,
|
||||
initialPublicKey: ECDHPublicKey = defaultInitialPublicKey.key
|
||||
): ECDHKeyPairImpl {
|
||||
return ECDHKeyPairImpl(OpenSslPrivateKey.fromKey(key), OpenSslPublicKey.fromKey(key), initialPublicKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun CPointer<EC_POINT>.toKtHex(): String {
|
||||
val ptr = EC_POINT_point2hex(group, this, convForm, bnCtx) ?: error("Failed EC_POINT_point2hex")
|
||||
return try {
|
||||
ptr.toKString()
|
||||
} finally {
|
||||
free(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
|
||||
|
||||
/**
|
||||
* 由 [keyPair] 的私匙和 [peerPublicKey] 计算 shareKey
|
||||
*/
|
||||
actual fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray {
|
||||
return calculateShareKey(keyPair.privateKey, peerPublicKey)
|
||||
}
|
||||
|
||||
actual companion object {
|
||||
actual val isECDHAvailable: Boolean get() = true
|
||||
|
||||
/**
|
||||
* 由完整的 publicKey ByteArray 得到 [ECDHPublicKey]
|
||||
*/
|
||||
actual fun constructPublicKey(key: ByteArray): ECDHPublicKey {
|
||||
memScoped {
|
||||
key.usePinned { pin ->
|
||||
val group = EC_GROUP_new_by_curve_name(curveId)
|
||||
?: error("Failed to create EC_GROUP")
|
||||
|
||||
val p = EC_POINT_new(group) ?: error("Failed to create EC_POINT")
|
||||
|
||||
EC_POINT_hex2point(group, pin.get().toUHexString("").lowercase(), p, bnCtx)
|
||||
|
||||
return OpenSslPublicKey.fromPoint(p)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 由完整的 rsaKey 校验 publicKey
|
||||
*/
|
||||
actual fun verifyPublicKey(
|
||||
version: Int,
|
||||
publicKey: String,
|
||||
publicKeySign: String
|
||||
): Boolean = true
|
||||
|
||||
/**
|
||||
* 生成随机密匙对
|
||||
*/
|
||||
actual fun generateKeyPair(initialPublicKey: ECDHPublicKey): ECDHKeyPair {
|
||||
val key: CPointer<EC_KEY> = EC_KEY_new_by_curve_name(curveId)
|
||||
?: throw IllegalStateException("Failed to create key curve, $errno")
|
||||
|
||||
if (1 != EC_KEY_generate_key(key)) {
|
||||
throw IllegalStateException("Failed to generate key, $errno")
|
||||
}
|
||||
|
||||
try {
|
||||
return ECDHKeyPairImpl.fromKey(key, initialPublicKey)
|
||||
} finally {
|
||||
free(key) // TODO: THIS MAY CAUSE MEMORY LEAK. But EC_KEY_free() will terminate the process for unknown reason.
|
||||
}
|
||||
}
|
||||
|
||||
fun calculateCanonicalShareKey(privateKey: ECDHPrivateKey, publicKey: ECDHPublicKey): ByteArray {
|
||||
check(publicKey is OpenSslPublicKey)
|
||||
check(privateKey is OpenSslPrivateKey)
|
||||
|
||||
val k = EC_KEY_new_by_curve_name(curveId) ?: error("Failed to create EC key")
|
||||
try {
|
||||
val privateBignum = privateKey.toBignum()
|
||||
try {
|
||||
EC_KEY_set_private_key(k, privateKey.toBignum()).let { r ->
|
||||
if (r != 1) error("Failed EC_KEY_set_private_key: $r")
|
||||
}
|
||||
|
||||
val fieldSize = EC_GROUP_get_degree(group)
|
||||
if (fieldSize <= 0) {
|
||||
error("Failed EC_GROUP_get_degree: $fieldSize")
|
||||
}
|
||||
|
||||
var secretLen = (fieldSize + 7) / 8
|
||||
|
||||
val publicPoint = publicKey.toPoint()
|
||||
try {
|
||||
ByteArray(secretLen.convert()).usePinned { pin ->
|
||||
secretLen = ECDH_compute_key(pin.addressOf(0), secretLen.convert(), publicPoint, k, null)
|
||||
if (secretLen <= 0) {
|
||||
error("Failed to compute secret")
|
||||
}
|
||||
|
||||
return pin.get().copyOf(secretLen)
|
||||
}
|
||||
} finally {
|
||||
EC_POINT_free(publicPoint)
|
||||
}
|
||||
} finally {
|
||||
BN_free(privateBignum)
|
||||
}
|
||||
} finally {
|
||||
EC_KEY_free(k)
|
||||
}
|
||||
}
|
||||
|
||||
actual fun calculateShareKey(
|
||||
privateKey: ECDHPrivateKey,
|
||||
publicKey: ECDHPublicKey
|
||||
): ByteArray = calculateCanonicalShareKey(privateKey, publicKey).copyOf(16).md5()
|
||||
}
|
||||
|
||||
actual override fun toString(): String = "ECDH($keyPair)"
|
||||
}
|
||||
|
||||
internal actual fun ByteArray.adjustToPublicKey(): ECDHPublicKey {
|
||||
return ECDH.constructPublicKey(this)
|
||||
}
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2022 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/dev/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils.crypto
|
||||
|
||||
internal actual interface ECDHPrivateKey
|
||||
internal actual interface ECDHPublicKey {
|
||||
actual fun getEncoded(): ByteArray
|
||||
}
|
||||
|
||||
internal actual class ECDHKeyPairImpl(
|
||||
override val privateKey: ECDHPrivateKey,
|
||||
override val publicKey: ECDHPublicKey,
|
||||
override val maskedShareKey: ByteArray,
|
||||
override val maskedPublicKey: ByteArray
|
||||
) : ECDHKeyPair
|
||||
|
||||
/**
|
||||
* 椭圆曲线密码, ECDH 加密
|
||||
*/
|
||||
internal actual class ECDH actual constructor(keyPair: ECDHKeyPair) {
|
||||
actual val keyPair: ECDHKeyPair
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
/**
|
||||
* 由 [keyPair] 的私匙和 [peerPublicKey] 计算 shareKey
|
||||
*/
|
||||
actual fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
actual companion object {
|
||||
actual val isECDHAvailable: Boolean
|
||||
get() = TODO("Not yet implemented")
|
||||
|
||||
/**
|
||||
* 由完整的 publicKey ByteArray 得到 [ECDHPublicKey]
|
||||
*/
|
||||
actual fun constructPublicKey(key: ByteArray): ECDHPublicKey {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
/**
|
||||
* 由完整的 rsaKey 校验 publicKey
|
||||
*/
|
||||
actual fun verifyPublicKey(
|
||||
version: Int,
|
||||
publicKey: String,
|
||||
publicKeySign: String
|
||||
): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机密匙对
|
||||
*/
|
||||
actual fun generateKeyPair(initialPublicKey: ECDHPublicKey): ECDHKeyPair {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
/**
|
||||
* 由一对密匙计算 shareKey
|
||||
*/
|
||||
actual fun calculateShareKey(
|
||||
privateKey: ECDHPrivateKey,
|
||||
publicKey: ECDHPublicKey
|
||||
): ByteArray {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
actual override fun toString(): String {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal actual val publicKeyForVerify: ECDHPublicKey
|
||||
get() = TODO("Not yet implemented")
|
Loading…
Reference in New Issue
Block a user