Java Bouncycastle XmlSignatureFactory无此算法异常

Java Bouncycastle XmlSignatureFactory无此算法异常,java,bouncycastle,xml-signature,Java,Bouncycastle,Xml Signature,我在使用BouncyCastle检查XMLSignature以验证使用ECDSA的信号时遇到问题 以下是相关代码行: BouncyCastleProvider provider = new BouncyCastleProvider(); Security.addProvider(provider); //some unrelated code XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM", provi

我在使用BouncyCastle检查XMLSignature以验证使用ECDSA的信号时遇到问题

以下是相关代码行:

BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);   
//some unrelated code
XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM", provider);
在最后一行,将在中引发以下异常:

javax.xml.crypto.NoSuchMechanismException: java.security.NoSuchAlgorithmException: no such algorithm: DOM for provider SC
如果我把线路改成

XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");
我明白了

javax.xml.crypto.MarshalException: unsupported SignatureMethod algorithm: http://www.w3.org/2007/05/xmldsig-more#ecdsa-ripemd160

有人知道这是什么原因吗?

在第一个错误中,您可以在错误描述中读到“没有这样的算法:DOM for provider SC”。这很奇怪,因为它说的是“提供商SC”(Sun PC/SC提供商)而不是“提供商BC”(BouncyCastle安全提供商)。看起来您的代码(内部)没有按照您的需要使用Bouncycastle。你应该找出发生这种情况的原因。它可能是关于BC库和类路径(如果您正在使用应用程序服务器)或提供者顺序配置的内容

第二个错误。您改变了获取XMLSignatureFactory的方法。这一个更好,因为如果不指定提供程序,因为:

此方法使用标准JCA提供程序查找机制来查找 并实例化所需对象的XMLSignatureFactory实现 机构类型。它遍历已注册安全性的列表 提供程序,从最首选的提供程序开始。一个新的 来自支持的第一个提供程序的XMLSignatureFactory对象 返回指定的机制

但现在,算法并不存在。那么,为什么呢?在这里,我要说的是BC没有被使用。它在那里?回顾你的类路径

列出所有可用的提供商可能会有所帮助:

for (Provider p : Security.getProviders()) {

    log.debug(p.getName());
    log.debug(p.getInfo());
}

在第一个错误中,您可以在错误描述中读取“没有这样的算法:DOM for provider SC”。这很奇怪,因为它说的是“提供商SC”(Sun PC/SC提供商)而不是“提供商BC”(BouncyCastle安全提供商)。看起来您的代码(内部)没有按照您的需要使用Bouncycastle。你应该找出发生这种情况的原因。它可能是关于BC库和类路径(如果您正在使用应用程序服务器)或提供者顺序配置的内容

第二个错误。您改变了获取XMLSignatureFactory的方法。这一个更好,因为如果不指定提供程序,因为:

此方法使用标准JCA提供程序查找机制来查找 并实例化所需对象的XMLSignatureFactory实现 机构类型。它遍历已注册安全性的列表 提供程序,从最首选的提供程序开始。一个新的 来自支持的第一个提供程序的XMLSignatureFactory对象 返回指定的机制

但现在,算法并不存在。那么,为什么呢?在这里,我要说的是BC没有被使用。它在那里?回顾你的类路径

列出所有可用的提供商可能会有所帮助:

for (Provider p : Security.getProviders()) {

    log.debug(p.getName());
    log.debug(p.getInfo());
}

从第二个异常中猜测,因为要验证xml签名, 您可能已经使用了一些代码,如下面的代码

但是xml表示有如下内容

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>  
            <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>  
            <SignatureMethod Algorithm="http://www.w3.org/2007/05/xmldsig-more#ecdsa-ripemd160"/>  
            <Reference URI="">  
                <Transforms>  
                        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>  
                </Transforms>  
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>  
                <DigestValue>bHS+6uf8KbJV4AGzoHNHLfnXvKM=</DigestValue>  
            </Reference>  
    </SignedInfo>
    ...
</Signature>
只需进入
DOMSignatureMethod.unmarshal
static方法一步,它使用
http://www.w3.org/2007/05/xmldsig-more#ecdsa-ripemd160
查找数字签名算法, 但是
DOMSignatureMethod
只支持以下算法

rsa-sha1
rsa-sha256
rsa-sha384
rsa-sha512
dsa-sha1
dsa-sha256
hmac-sha1
hmac-sha256
hmac-sha384
hmac-sha512
ecdsa-sha1
ecdsa-sha256
ecdsa-sha384
ecdsa-sha512
解决方案是: 将BC提供程序添加到安全性中,并使用org.apache.santuario-xmlsec项目中的XMLSignature进行验证

public boolean verify(String signedXML) throws Exception {
    Document doc = null;
    try (InputStream is = new ByteArrayInputStream(signedXML.getBytes(Charset.forName("utf-8")))) {
        doc = MyXMLUtils.read(is, false);
    }

    XPathFactory xpf = XPathFactory.newInstance();
    XPath xpath = xpf.newXPath();
    xpath.setNamespaceContext(new DSNamespaceContext());

    String expression = "//ds:Signature[1]";
    Element sigElement =
            (Element) xpath.evaluate(expression, doc, XPathConstants.NODE);

    XMLSignature signature = new XMLSignature(sigElement, "");
    KeyInfo ki = signature.getKeyInfo();

    if (ki == null) {
        throw new RuntimeException("No keyinfo");
    }
    PublicKey pk = signature.getKeyInfo().getPublicKey();

    if (pk == null) {
        throw new RuntimeException("No public key");
    }

    return signature.checkSignatureValue(pk);
}

来自repo的更多演示:

根据第二个异常猜测,因为您希望验证xml签名, 您可能已经使用了一些代码,如下面的代码

但是xml表示有如下内容

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>  
            <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>  
            <SignatureMethod Algorithm="http://www.w3.org/2007/05/xmldsig-more#ecdsa-ripemd160"/>  
            <Reference URI="">  
                <Transforms>  
                        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>  
                </Transforms>  
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>  
                <DigestValue>bHS+6uf8KbJV4AGzoHNHLfnXvKM=</DigestValue>  
            </Reference>  
    </SignedInfo>
    ...
</Signature>
只需进入
DOMSignatureMethod.unmarshal
static方法一步,它使用
http://www.w3.org/2007/05/xmldsig-more#ecdsa-ripemd160
查找数字签名算法, 但是
DOMSignatureMethod
只支持以下算法

rsa-sha1
rsa-sha256
rsa-sha384
rsa-sha512
dsa-sha1
dsa-sha256
hmac-sha1
hmac-sha256
hmac-sha384
hmac-sha512
ecdsa-sha1
ecdsa-sha256
ecdsa-sha384
ecdsa-sha512
解决方案是: 将BC提供程序添加到安全性中,并使用org.apache.santuario-xmlsec项目中的XMLSignature进行验证

public boolean verify(String signedXML) throws Exception {
    Document doc = null;
    try (InputStream is = new ByteArrayInputStream(signedXML.getBytes(Charset.forName("utf-8")))) {
        doc = MyXMLUtils.read(is, false);
    }

    XPathFactory xpf = XPathFactory.newInstance();
    XPath xpath = xpf.newXPath();
    xpath.setNamespaceContext(new DSNamespaceContext());

    String expression = "//ds:Signature[1]";
    Element sigElement =
            (Element) xpath.evaluate(expression, doc, XPathConstants.NODE);

    XMLSignature signature = new XMLSignature(sigElement, "");
    KeyInfo ki = signature.getKeyInfo();

    if (ki == null) {
        throw new RuntimeException("No keyinfo");
    }
    PublicKey pk = signature.getKeyInfo().getPublicKey();

    if (pk == null) {
        throw new RuntimeException("No public key");
    }

    return signature.checkSignatureValue(pk);
}

repo的更多演示:

BouncyCastle Security Provider v1.46在我列出所有Providers时被列出。我们看到完整的条目是:“name:SC”“info:BouncyCastle Security Provider v1.46”,所以SC是BouncyCastleprovider。确定吗?看看这个:当我列出提供商BouncyCastle的名字是“BC”时,我只能告诉你我看到了什么,日志上写着SC=BouncyCastle Security Provider^^^你解决过这个问题吗?我无法从答案或评论中判断。问题是Bouncy Castle没有为XmlSignatureFactory提供服务,当我列出所有提供程序时,会列出AFAIC.BouncyCastle安全提供程序v1.46。我们看到完整的条目是:“name:SC”“info:BouncyCastle安全提供程序v1.46”,所以SC就是BouncyCastle提供程序。确定吗?看看这个:当我列出提供商BouncyCastle的名字是“BC”时,我只能告诉你我看到了什么,日志上写着SC=BouncyCastle Security Provider^^^你解决过这个问题吗?我无法从答案或评论中判断。问题是Bouncy Castle没有为XmlSignatureFactory AFAIC提供服务。