소스 검색

Bypass BC deprecation check on Android (#1481)

Co-authored-by: Karlatemp <[email protected]>

Co-authored-by: Karlatemp <[email protected]>
RainChan 4 년 전
부모
커밋
06c1652d53
3개의 변경된 파일33개의 추가작업 그리고 4개의 파일을 삭제
  1. 3 1
      buildSrc/src/main/kotlin/Versions.kt
  2. 3 2
      mirai-core/build.gradle.kts
  3. 27 1
      mirai-core/src/androidMain/kotlin/utils/crypto/ECDHJvmDesktop.kt

+ 3 - 1
buildSrc/src/main/kotlin/Versions.kt

@@ -45,6 +45,7 @@ object Versions {
     const val asm = "9.1"
     const val difflib = "1.3.0"
     const val netty = "4.1.63.Final"
+    const val bouncycastle = "1.64"
 
     const val junit = "5.7.2"
 
@@ -121,4 +122,5 @@ const val `jetbrains-annotations` = "org.jetbrains:annotations:19.0.0"
 const val `caller-finder` = "io.github.karlatemp:caller:1.1.1"
 
 const val `android-runtime` = "com.google.android:android:${Versions.android}"
-const val `netty-all` = "io.netty:netty-all:${Versions.netty}"
+const val `netty-all` = "io.netty:netty-all:${Versions.netty}"
+const val `bouncycastle` = "org.bouncycastle:bcprov-jdk15on:${Versions.bouncycastle}"

+ 3 - 2
mirai-core/build.gradle.kts

@@ -73,6 +73,7 @@ kotlin {
                 implementation1(`kotlinx-coroutines-io`)
                 implementation(`netty-all`)
                 implementation(`log4j-api`)
+                implementation(bouncycastle)
             }
         }
 
@@ -95,14 +96,14 @@ kotlin {
                     implementation(kotlin("test-junit5", Versions.kotlinCompiler))
                     implementation(kotlin("test-annotations-common"))
                     implementation(kotlin("test-common"))
-                    implementation("org.bouncycastle:bcprov-jdk15on:1.64")
+                    //implementation("org.bouncycastle:bcprov-jdk15on:1.64")
                 }
             }
         }
 
         val jvmMain by getting {
             dependencies {
-                implementation("org.bouncycastle:bcprov-jdk15on:1.64")
+                //implementation("org.bouncycastle:bcprov-jdk15on:1.64")
                 // api(kotlinx("coroutines-debug", Versions.coroutines))
             }
         }

+ 27 - 1
mirai-core/src/androidMain/kotlin/utils/crypto/ECDHJvmDesktop.kt

@@ -11,6 +11,7 @@ package net.mamoe.mirai.internal.utils.crypto
 
 import net.mamoe.mirai.utils.decodeBase64
 import net.mamoe.mirai.utils.md5
+import net.mamoe.mirai.utils.recoverCatchingSuppressed
 import java.security.*
 import java.security.spec.ECGenParameterSpec
 import java.security.spec.X509EncodedKeySpec
@@ -32,6 +33,31 @@ internal actual class ECDHKeyPairImpl(
     override val maskedShareKey: ByteArray by lazy { ECDH.calculateShareKey(privateKey, initialPublicKey) }
 }
 
+/**
+ * 绕过在Android P之后的版本无法使用EC的限制
+ * https://cs.android.com/android/platform/superproject/+/master:libcore/ojluni/src/main/java/sun/security/jca/Providers.java;l=371;bpv=1;bpt=1
+ * https://android-developers.googleblog.com/2018/03/cryptography-changes-in-android-p.html
+ * */
+private class AndroidProvider : Provider("sbAndroid", 1.0, "") {
+    override fun getService(type: String?, algorithm: String?): Service? {
+        if (type == "KeyFactory" && algorithm == "EC") {
+            return object : Service(this, type, algorithm, "", emptyList(), emptyMap()) {
+                override fun newInstance(constructorParameter: Any?): Any {
+                    return org.bouncycastle.jcajce.provider.asymmetric.ec.KeyFactorySpi.EC()
+                }
+            }
+        }
+        return super.getService(type, algorithm)
+    }
+}
+
+private val ANDROID_PROVIDER by lazy { AndroidProvider() }
+private val ecKf by lazy {
+    runCatching { KeyFactory.getInstance("EC", "BC") }
+        .recoverCatchingSuppressed { KeyFactory.getInstance("EC", ANDROID_PROVIDER) }
+        .getOrThrow()
+}
+
 internal actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
     actual companion object {
         private const val curveName = "prime256v1" // p-256
@@ -88,7 +114,7 @@ internal actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
         }
 
         actual fun constructPublicKey(key: ByteArray): ECDHPublicKey {
-            return KeyFactory.getInstance("EC", "BC").generatePublic(X509EncodedKeySpec(key))
+            return ecKf.generatePublic(X509EncodedKeySpec(key))
         }
     }