Java Android签名初始化验证导致异常

Java Android签名初始化验证导致异常,java,android,kotlin,cryptography,digital-signature,Java,Android,Kotlin,Cryptography,Digital Signature,我创建了一个服务器,它可以用随机点响应客户机。 服务器代码 private static void generateKeys() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { ECGenParameterSpec ecSpec = new ECGenParameterSpec(SPEC); KeyPairGenerator g = KeyPairGenerator.getInstance

我创建了一个服务器,它可以用随机点响应客户机。 服务器代码

private static void generateKeys() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
    ECGenParameterSpec ecSpec = new ECGenParameterSpec(SPEC);
    KeyPairGenerator g = KeyPairGenerator.getInstance("EC");
    g.initialize(ecSpec, new SecureRandom());
    KeyPair keypair = g.generateKeyPair();
    publicKey = keypair.getPublic();
    privateKey = keypair.getPrivate();
}

private static JSONObject getPoints() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException {
    if(null == publicKey && null == privateKey)
        generateKeys();
    JSONObject object = new JSONObject();
    String falseSignature = "AAAaaaAAAaaa111AAAaaaAAAaaa111111AAAaaaAAAAAAAAAAAAAAAaaaaaaa111AAAAAAAAAAAAAAAAAaaaaaAAAAAAaaa1";
    try {
        Signature ecdsaSign = Signature.getInstance(ALGO);

        String pub = Base64.getEncoder().encodeToString(publicKey.getEncoded());
        List<Point> points = generatePointsList(10);
        JSONArray array = new JSONArray();
        JSONArray finalArray = array;
        points.forEach(
                i -> {
                    try {
                        ecdsaSign.initSign(privateKey);
                        JSONObject obj = new JSONObject();
                        ecdsaSign.update(i.getString().getBytes(StandardCharsets.UTF_8));
                        byte[] signature = ecdsaSign.sign();
                        String sig = Base64.getEncoder().encodeToString(signature);
                        obj.put("signature", sig);
                        obj.put("point", i.toJson());
                        finalArray.put(obj);
                    } catch (SignatureException | InvalidKeyException e) {
                        e.printStackTrace();
                    }
                }
        );
        List<Point> falsePoints = generatePointsList(5);
        falsePoints.forEach(
                i -> {
                    JSONObject obj = new JSONObject();
                    obj.put("signature", falseSignature);
                    obj.put("point", i.toJson());
                    finalArray.put(obj);
                }
        );
        object.put("publicKey", pub);
        object.put("algorithm", ALGO);
        array = shuffleJsonArray(finalArray);
        object.put("points", array);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
    return object;
}
结果是一个带有公钥和点数组及其签名的json:

{"publicKey":"MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEcWZ5gZI6R2GZQhQ78zDWP4O6wkkc968MzrTbnwETYWKvBdAFyJzlfXmn43ISWqtmFqsSeEmUPT1vabpkbJi9SQ==","algorithm":"SHA256withECDSA","points":[{"signature":"MEYCIQC4FytGoPJOspQDHp7yjsglGuHhv16MBctUUy1VgtVznQIhANV+7drv8aXinT7IBT7apaVlIFE9/Gz/UzPRkj+1dUp4","point":{"x":141,"y":33}},{"signature":"AAAaaaAAAaaa111AAAaaaAAAaaa111111AAAaaaAAAAAAAAAAAAAAAaaaaaaa111AAAAAAAAAAAAAAAAAaaaaaAAAAAAaaa1","point":{"x":88,"y":41}},{"signature":"MEUCIQDaCibfFoh9TVSVZVJuOkT/GTssjEFjYoIn0UdHg4wtTAIgf7Pa52udA4UVIWAPdM5m3wnkgo3/LqT8Q/qQs0USMGU=","point":{"x":119,"y":179}}}]
kotlin上的Android客户端代码:

public fun getPoints(){
    coroutineScope.launch {
        val getPointsInfoDeferred = executeAsync { getPoints()}
        try {
            _status.value = ServerApiStatus.LOADING
            val points = getPointsInfoDeferred.await()
            algo = points.algorithm
            publicKey = getPubKey(points.publicKey)
            _pointsProp.value = points.points.map { ParselableInfo(points.publicKey,
                checkPoints(it),
                it) }
            _status.value = ServerApiStatus.COMPLETED
        }catch (e: Exception){
            _status.value = ServerApiStatus.ERROR
            Log.i("OVERVIEW MODEL", "some exception: ${e.message}")
            _pointsProp.value = listOf()
        }
    }
}

private fun getPubKey(pubkey:String): PublicKey {
    val publicKeySpec: EncodedKeySpec = X509EncodedKeySpec(Base64.decode(pubkey, Base64.DEFAULT))
    val keyFactory: KeyFactory = KeyFactory.getInstance("EC")
    return keyFactory.generatePublic(publicKeySpec)
}

private fun getPointString(x: Int, y: Int): String{
    return "$x$y"
}

private fun checkPoints(pointWithSign: PointWithSignature): Boolean{
    val sign: Signature = Signature.getInstance(algo)
    val point = pointWithSign.point
    return try {
        val a = String(publicKey.encoded)
        sign.initVerify(publicKey)
        sign.update(getPointString(point.x, point.y).toByteArray(StandardCharsets.UTF_8))
        return sign.verify(pointWithSign.signature.toByteArray(StandardCharsets.UTF_8))

    } catch (e: java.lang.Exception) {
        false
    }
}
所以“sign.initVerify(publicKey)”行导致异常-解析公钥错误,甚至公钥对象是在函数“getPubKey”中创建的。我不知道我哪里错了

堆栈跟踪:

java.security.InvalidKeyException: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: Error parsing public key
at com.android.org.conscrypt.OpenSSLKey.fromPublicKey(OpenSSLKey.java:251)
at com.android.org.conscrypt.OpenSSLSignature.engineInitVerify(OpenSSLSignature.java:215)
at java.security.Signature$Delegate.init(Signature.java:1354)
at java.security.Signature$Delegate.chooseProvider(Signature.java:1310)
at java.security.Signature$Delegate.engineInitVerify(Signature.java:1374)
at java.security.Signature.initVerify(Signature.java:601)
at com.example.disserclient.overview.OverviewModel.checkPoints(OverviewModel.kt:91)
at com.example.disserclient.overview.OverviewModel.access$checkPoints(OverviewModel.kt:22)
at com.example.disserclient.overview.OverviewModel$getPoints$1.invokeSuspend(OverviewModel.kt:57)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7076)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Caused by: com.android.org.conscrypt.OpenSSLX509CertificateFactory$ParsingException: Error parsing public key
at com.android.org.conscrypt.NativeCrypto.EVP_parse_public_key(Native Method)
at com.android.org.conscrypt.OpenSSLKey.fromPublicKey(OpenSSLKey.java:249)

所以我找到了解决办法。正如@Maarten-Restore Monica所建议的,我尝试使用Bouncy castle provider。而且它有效! 在创建密钥对之前的服务器端,我添加了以下行:

Security.insertProviderAt(new BouncyCastleProvider(), 1);
在客户端,我做了一些更改:

val keyFactory: KeyFactory = KeyFactory.getInstance("EC", castleProvider)

castleProvider是来自的BouncyCastleProvider

'org.bouncycastle',名称:'bcprov-jdk15on',版本:'1.64'

另外,我忘记了服务器端的Base64编码,所以我更改了签名验证:

sign.verify(Base64.decode(pointWithSign.signature, Base64.DEFAULT))

有两个问题我不知道该问题的答案(对不起,我错过了您提供的公钥)。1.这是
pubkey
参数中的确切字符串吗?2.Android是否支持secp256k1?我看到一些提示,只有secp256r1存在,但我无法确认这一点。可能会生成一个secp256k1密钥对来检查这一点;如果它不存在,您可能需要bouncy castle提供商。最后,你能显示完整的堆栈跟踪吗?@Maarten-恢复Monica我不知道,你说的“精确字符串”在pubkey参数中是什么意思,我只创建了这个公钥,不能更改。我会检查android是否支持secp2561。我在应答块中添加了stacktrace。很多时候,人们在创建和解密/验证之间设法破坏密文或加密输出。这就是我问的原因,但这对你来说似乎不是问题,很高兴你解决了。顺便说一下,请注意,你的尼克是非常难找到的。
val sign: Signature = Signature.getInstance(points.algorithm, castleProvider)
sign.verify(Base64.decode(pointWithSign.signature, Base64.DEFAULT))