0

我想在 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));

    }
}

输入文件为(在 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 和 WAS 1.6 jdk

请帮我解决这个问题,谢谢。

4

1 回答 1

2

您需要为 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 密钥。只是随机生成它可能不好。不过那是另外一回事了。

于 2015-08-06T23:18:48.243 回答