创建具有HMAC_SHA1的签名-密钥期望例外



我想使用SignatureMethod创建一个数字签名。HMAC_SHA1,为此我引用了下面的程序

package com.sampel.test;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.*;
import java.util.Collections;
import java.util.Formatter;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
/**
 * This is a simple example of generating an Enveloped XML
 * Signature using the JSR 105 API. The resulting signature will look
 * like (key and signature values will be different):
 *
 * <pre><code>
 *<Envelope xmlns="urn:envelope">
 * <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/2000/09/xmldsig#dsa-sha1"/>
 *     <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>K8M/lPbKnuMDsO0Uzuj75lQtzQI=<DigestValue>
 *     </Reference>
 *   </SignedInfo>
 *   <SignatureValue>
 *     DpEylhQoiUKBoKWmYfajXO7LZxiDYgVtUtCNyTgwZgoChzorA2nhkQ==
 *   </SignatureValue>
 *   <KeyInfo>
 *     <KeyValue>
 *       <DSAKeyValue>
 *         <P>
 *           rFto8uPQM6y34FLPmDh40BLJ1rVrC8VeRquuhPZ6jYNFkQuwxnu/wCvIAMhukPBL
 *           FET8bJf/b2ef+oqxZajEb+88zlZoyG8g/wMfDBHTxz+CnowLahnCCTYBp5kt7G8q
 *           UobJuvjylwj1st7V9Lsu03iXMXtbiriUjFa5gURasN8=
 *         </P>
 *         <Q>
 *           kEjAFpCe4lcUOdwphpzf+tBaUds=
 *         </Q>
 *         <G>
 *           oe14R2OtyKx+s+60O5BRNMOYpIg2TU/f15N3bsDErKOWtKXeNK9FS7dWStreDxo2
 *           SSgOonqAd4FuJ/4uva7GgNL4ULIqY7E+mW5iwJ7n/WTELh98mEocsLXkNh24HcH4
 *           BZfSCTruuzmCyjdV1KSqX/Eux04HfCWYmdxN3SQ/qqw=
 *         </G>
 *         <Y>
 *           pA5NnZvcd574WRXuOA7ZfC/7Lqt4cB0MRLWtHubtJoVOao9ib5ry4rTk0r6ddnOv
 *           AIGKktutzK3ymvKleS3DOrwZQgJ+/BDWDW8kO9R66o6rdjiSobBi/0c2V1+dkqOg
 *           jFmKz395mvCOZGhC7fqAVhHat2EjGPMfgSZyABa7+1k=
 *         </Y>
 *       </DSAKeyValue>
 *     </KeyValue>
 *   </KeyInfo>
 * </Signature>
 *</Envelope>
 * </code></pre>
 */
public class xmlDigSig {
    //
    // Synopsis: java GenEnveloped [document] [output]
    //
    //    where "document" is the name of a file containing the XML document
    //    to be signed, and "output" is the name of the file to store the
    //    signed document. The 2nd argument is optional - if not specified,
    //    standard output will be used.
    //
    public static void main(String[] args) throws Exception {
        // Create a DOM XMLSignatureFactory that will be used to generate the
        // enveloped signature
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
        // Create a Reference to the enveloped document (in this case we are
        // signing the whole document, so a URI of "" signifies that) and
        // also specify the SHA1 digest algorithm and the ENVELOPED Transform.
        Reference ref = fac.newReference
            ("#_0", fac.newDigestMethod(DigestMethod.SHA1, null),
             Collections.singletonList
              (fac.newTransform
                (Transform.ENVELOPED, (TransformParameterSpec) null)),
             null, null);
        // Create the SignedInfo
        SignedInfo si = fac.newSignedInfo
            (fac.newCanonicalizationMethod
             (CanonicalizationMethod.EXCLUSIVE,
              (C14NMethodParameterSpec) null),
             fac.newSignatureMethod(SignatureMethod.DSA_SHA1, null),
             Collections.singletonList(ref));
        // Create a DSA KeyPair
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(512);
        KeyPair kp = kpg.generateKeyPair();
        // Create a KeyValue containing the DSA PublicKey that was generated
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        KeyValue kv = kif.newKeyValue(kp.getPublic());
        // Create a KeyInfo and add the KeyValue to it
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));
        // Instantiate the document to be signed
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc =
            dbf.newDocumentBuilder().parse(new FileInputStream("C:/sample/timestamp.txt"));
        // Create a DOMSignContext and specify the DSA PrivateKey and
        // location of the resulting XMLSignature's parent element
        DOMSignContext dsc = new DOMSignContext
            (kp.getPrivate(), doc.getDocumentElement());
        // Create the XMLSignature (but don't sign it yet)
        XMLSignature signature = fac.newXMLSignature(si, ki);
        // Marshal, generate (and sign) the enveloped signature
        signature.sign(dsc);
        System.out.println(ref.getURI());
        // output the resulting document
        OutputStream os;
        if (args.length > 1) {
           os = new FileOutputStream(args[1]);
        } else {
           os = System.out;
        }
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
    }
}

输入文件为(in timestamp.txt)

<u:Timestamp u:Id="_0" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
                <u:Created>2015-06-18T17:34:40.325Z</u:Created>
                <u:Expires>2015-06-18T17:39:40.325Z</u:Expires>
            </u:Timestamp>

我得到以下值的输出(因为它引用了DSA方法)

<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha1"/>

但我需要一个值(与HMAC_SHA1方法)

<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>

所以我用SignatureMethod.HMAC_SHA1而不是SignatureMethod.DSA_SHA1修改了代码,然后它开始给我下面的例外,也无法为HMAC_SHA1找到合适的KeyPairGenerator。

Exception in thread "main" javax.xml.crypto.dsig.XMLSignatureException: java.security.InvalidKeyException: Secret key expected
    at com.ibm.xml.crypto.dsig.dom.SignedInfoImpl.sign(SignedInfoImpl.java:189)
    at com.ibm.xml.crypto.dsig.dom.XMLSignatureImpl.sign(XMLSignatureImpl.java:162)
    at com.anthem.kytest.xmlDigSig.main(xmlDigSig.java:134)
Caused by: java.security.InvalidKeyException: Secret key expected
    at com.ibm.crypto.provider.HmacSHA1.engineInit(Unknown Source)
    at javax.crypto.Mac.a(Unknown Source)
    at javax.crypto.Mac.init(Unknown Source)
    at com.ibm.xml.crypto.dsig.SignatureEngineHMAC.initSign(SignatureEngineHMAC.java:102)
    at com.ibm.xml.crypto.dsig.dom.SignedInfoImpl.sign(SignedInfoImpl.java:168)
    ... 2 more
java.security.InvalidKeyException: Secret key expected
    at com.ibm.crypto.provider.HmacSHA1.engineInit(Unknown Source)
    at javax.crypto.Mac.a(Unknown Source)
    at javax.crypto.Mac.init(Unknown Source)
    at com.ibm.xml.crypto.dsig.SignatureEngineHMAC.initSign(SignatureEngineHMAC.java:102)
    at com.ibm.xml.crypto.dsig.dom.SignedInfoImpl.sign(SignedInfoImpl.java:168)
    at com.ibm.xml.crypto.dsig.dom.XMLSignatureImpl.sign(XMLSignatureImpl.java:162)
    at com.anthem.kytest.xmlDigSig.main(xmlDigSig.java:134)

如何使用HMAC_SHA1创建签名方法,是否有可用的教程/示例

环境RSA/WAS 7 with WAS 1.6 jdk

请帮我一下,谢谢。

您需要为HMAC生成一个对称密钥,而不是密钥对。密钥对本质上是用于非对称加密的,如RSA和DSA。

所以尝试用HMAC密钥的生成来替换密钥对生成:

byte[] randomKey = new byte[20];
SecureRandom rng = new SecureRandom();
rng.nextBytes(randomKey);
SecretKey hmacKey = new SecretKeySpec(randomKey, "HMAC");
KeyInfoFactory kif = fac.getKeyInfoFactory();
KeyName kv = kif.newKeyName("owlstead");
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv)); 

我无法验证你的代码,因为在我的机器上使用"#_0"作为参考存在问题。

当然,你也需要以某种方式安全地分发HMAC密钥。只是随机生成它可能是不好的。这是另一个主题

最新更新