使用HMAC_SHA1创建签名 - 密钥预期异常

时间:2015-07-23 17:03:02

标签: java digital-signature hmacsha1 key-generator

我想在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创建Signature方法,是否有任何教程/示例可用。

环境RSA / WAS 7,WAS 1.6 jdk

请帮我这个, 感谢。

1 个答案:

答案 0 :(得分:0)

您需要为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密钥。只是随机生成它可能并不好。但这是一个不同的主题。