使用 SpongyCastle 验证 ECDSA 签名

Verify ECDSA signature using SpongyCastle

我正在尝试使用 SpongyCastle 在 Android 上验证 ECDSA 数字签名。我有一个 X509Certificate,其中包含我需要用来验证它的 public 密钥,但我不太清楚如何获得 PublicKey(向下转换 ECPublicKey ) 用于 ECDSASigner class.

我使用 BouncyCastle 的 C# 版本完成了此操作,如下所示:

ECDsaSigner signer = new ECDsaSigner();
signer.Init(false, cert.GetPubliKey());

在 API 的 Java 版本中,X509Certificate.getPublicKey() 方法 returns 是 PublicKey class 而不是 AsymmetricKeyParameter。但是,ECDSASigner.init() 方法需要一个 CipherParameters 对象。我不知道如何为 ECDSA 执行此操作。

对于 RSA 签名,我只是手动重建了一个新的 RSAKeyParameters 对象:

RSAEngine engine = new RSAEngine();
engine.init(
    false,
    new RSAKeyParameters(
        false,
        ((RSAPublicKey) pubKey).getModulus(),
        ((RSAPublicKey) pubKey).getPublicExponent()
    )
);

这似乎不太理想,但我认为它应该可行。但我什至无法弄清楚如何为 ECDSA 做同样的事情。我认为有更好的方法来执行此操作,但我无法找出要使用的正确 API。

我想我终于明白了。看起来我需要使用 Signature class 来处理这个问题,而不是直接使用 ECDSASigner class。我仍然想了解 ECDSASigner class 是如何在所有这些抽象内部使用的(只是出于我自己的好奇心)。

无论如何,这就是我的代码用来验证 ECDSA 签名的样子(至少供我使用)。希望这会帮助将来尝试解决类似问题的人:

Signature sig = Signature.getInstance("NONEwithECDSA", "BC");
sig.initVerify(pubKey);
sig.update(plainBytes);
if (!sig.verify(signedBytes)) {
    throw new Exception("ECDSA signature verification failed.");
}

正如您自己所说,您需要使用签名 class。 JCA 是在 Java 中进行加密的默认方式,它使用提供者模式:

  1. 首先,您必须注册要使用的提供商,例如
Security.addProvider(new BouncyCastleProvider());

Android 上的默认提供程序是一个缩减的 BouncyCastle。 SpongyCastle 是 BouncyCastle 的全功能副本(重命名以避免名称冲突)。还有 Sun/Oracle JCA 可用。

  1. 接下来,您请求一个签名实例,例如:
Signature sig = Signature.getInstance("NONEwithECDSA", "BC");

在这里,JCA 查找名称为 "BC" 的提供程序,以及它是否已注册支持 "NONEwithECDSA" 签名的 SignatureSpi class。 "Signature" class 作为工厂 class 工作,它也包装了实际的实现 class.

  1. 终于可以使用签名实例了:
sig.initVerify(pubKey);

首先,它会在Signatureclass中执行一些代码(通常只是验证),然后调用底层的SignatureSpiclass。当您尝试直接使用提供程序时,可能缺少这个中间层,例如,class 初始化可能需要额外的步骤。

要查看更多详细信息,您可以下载 bouncy/spongy 城堡源代码并在调试器中执行示例 - 这不是 Android 特定的,因此您可以,例如,在蚀.