【发布时间】:2014-03-24 11:11:31
【问题描述】:
我正在尝试使用 iText 对 PDF 文档进行数字签名。由于我最终将在 JCE 提供程序中使用硬件加密器,因此我也在尝试在我的单元测试中测试摆脱 BountyCastle 并暂时使用默认的 SUN 实现(直到硬件加密器到达)。
但是,当我运行我的程序时出现以下异常:
线程“主”java.security.NoSuchAlgorithmException 中的异常:没有这样的算法:提供者 SUN 的 SHA256 在 sun.security.jca.GetInstance.getService(GetInstance.java:87) 在 sun.security.jca.GetInstance.getInstance(GetInstance.java:206) 在 java.security.Security.getImpl(Security.java:698) 在 java.security.MessageDigest.getInstance(MessageDigest.java:215) 在 com.itextpdf.text.pdf.security.DigestAlgorithms.getMessageDigest(DigestAlgorithms.java:159) 在 com.itextpdf.text.pdf.security.ProviderDigest.getMessageDigest(ProviderDigest.java:61) 在 com.itextpdf.text.pdf.security.MakeSignature.signDetached(MakeSignature.java:130) 在 SignDoc.signPdf(SignDoc.java:142) 在 SignDoc.main(SignDoc.java:182)
最后几行代码如下:
//ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "BC");
//ExternalDigest digest = new BouncyCastleDigest();
//ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "SUN");
ExternalSignature es = new PrivateKeySignature(pk, "SHA-256", "SunRsaSign");
ExternalDigest digest = new ProviderDigest("SUN");
MakeSignature.signDetached(appearance, digest, es, chain, null, null, null, 0, CryptoStandard.CMS);
如您所见,我只是复制示例并将提供者名称和调用 'new BouncyCastleDigest()' 更改为 'new ProviderDigest("SUN")'
查看iText(5.5.1-SNAPSHOT)的源代码,我发现以下代码片段很可疑:
-
MakeSignature.java 第 142 - 145 行
hashAlgorithm = externalSignature.getHashAlgorithm() 被调用然后用在
DigestAlgorithms.digest(数据, externalDigest.getMessageDigest(hashAlgorithm));
-
PrivateKeySignature.java 第 76 行
由于我使用的是 PrivateKeySignature,所以我查看了 PrivateKeySignature.java,发现它返回了它的私有类成员 hashAlgorithm,这就是它在构造过程中获取值的方式(第 76 行):
this.hashAlgorithm = DigestAlgorithms.getDigest(DigestAlgorithms.getAllowedDigests(hashAlgorithm));
-
DigestAlgorithms.java 方法 getAllowedDigests() 和 getDigest()
反过来,如果在 allowedDigests 哈希映射(在我的例子中为 2.16.840.1.101.3.4.2.1)中找到算法名称,则 getAllowedDigests() 返回算法的 OID,否则返回 null。
getDigest 使用 digestNames 哈希映射从 OID 中获取摘要名称。
但是,digestNames 哈希映射中与 OID 对应的名称是 SHA256,而不是 SHA-256。
因此,得到的最终摘要名称是“SHA256”而不是“SHA-256”,并且“SHA256”导致 SUN 提供程序中出现 NoSuchAlgorithm 异常。
(我尝试使用 SUN 提供程序直接获取消息摘要实例。它成功用于 SHA-256,但抛出了与我在此处报告的 SHA256 相同的异常。
在使用 BC 以外的 JCE 提供程序时,iText 是否存在问题?
如果有人能解释我的问题,不胜感激。
【问题讨论】:
-
JCE 确实没有将“SHA256”定义为 SHA-256 的别名。你能修改 iText 的 digestNames 哈希映射并将 2.16.840.1.101.3.4.2.1->SHA256 条目替换为 2.16.840.1.101.3.4.2.1->SHA-256 吗?
-
感谢您的建议。我认为这可以解决我的问题,但我不确定这是否是正确的方法。不管怎样,我会先试一试。
-
如果我按照建议修改映射,我可以成功通过 MessageDigest.getInstance。但是,当谈到 Signature.getInstance() 时,我立即被“没有这样的算法”异常击中(这一次是 SHA-256withRSA,我相信它期待 SHA256withRSA)。似乎存在一个问题,即摘要的相同算法名称(例如 SHA-256 )可以用作签名算法的前缀,因为算法名称在提供者之间不一致(例如 SHA256 与 SHA-256) .