我想使用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密钥。只是随机生成它可能是不好的。这是另一个主题