我正在尝试使用海绵城堡验证Android上的ECDSA数字签名。我有一个X509Certificate
,其中包含我需要用来验证它的公钥,但我不太清楚如何获得PublicKey
(向下投射ECPublicKey
)用于ECDSASigner
类。
我使用c#版本的BouncyCastle完成了这一点,它看起来像这样:
ECDsaSigner signer = new ECDsaSigner();
signer.Init(false, cert.GetPubliKey());
在Java版本的api中,X509Certificate.getPublicKey()
方法返回PublicKey
类而不是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
类来处理这个问题,而不是直接使用ECDSASigner
类。我仍然想了解ECDSASigner
类是如何在所有这些抽象内部使用的(只是为了我自己的好奇心)。
无论如何,这是我的代码看起来像验证ECDSA签名(至少对于我的使用)。希望这将帮助一些未来的人试图解决类似的问题:
Signature sig = Signature.getInstance("NONEwithECDSA", "BC");
sig.initVerify(pubKey);
sig.update(plainBytes);
if (!sig.verify(signedBytes)) {
throw new Exception("ECDSA signature verification failed.");
}
正如您自己注意到的,您需要使用Signature类。JCA是Java中默认的加密方式,它使用提供者模式:
- 首先,你必须注册要使用的提供商,例如
Android上的默认提供商是一个精简的BouncyCastle。海绵城堡是一个功能齐全的复制BouncyCastle(重命名以避免名称冲突)。还有Sun/Oracle的JCA。
- 下一步,请求签名实例,例如:
Signature sig =签名。getInstance("NONEwithECDSA"、"公元前");之前这里,JCA查找名称为"BC"的提供程序,以及它是否注册了一个支持"NONEwithECDSA"签名的SignatureSpi类。"Signature"类作为工厂类工作,它也包装了实际的实现类。
最后,您可以使用签名实例:<>以前sig.initVerify (pubKey); 之前
首先,它在Signature类中执行一些代码(通常只是验证),然后调用底层的SignatureSpi类。当你试图直接使用提供程序时,这个中间层可能是缺失的,例如,类初始化可能需要额外的步骤。
要查看更多细节,您可以下载bouncy/sponge castle源代码并在调试器中执行示例-这不是android特定的,因此您可以,例如,在Eclipse中创建桌面应用程序