我正在尝试使用下面的Class在xml请求中附加数字签名,同时在http服务器上发布xml。但是因为Android不允许我使用javax.xml.crypto.dsig。包我无法使用它。
PN DigitalSigner是他们希望我们用来签署xml的第三方类所以我的问题是有没有其他方法来签署Xml请求而不使用javax.xml.crypto.dsig。如果是,那么如何..?
提前致谢
这是班级:
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.KeyStore;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
public class DigitalSigner {
private static final String MEC_TYPE = "DOM";
private static final String WHOLE_DOC_URI = "";
private static final String KEY_STORE_TYPE = "PKCS12";
private KeyStore.PrivateKeyEntry keyEntry;
/**
* Constructor
* @param keyStoreFile - Location of .p12 file
* @param keyStorePassword - Password of .p12 file
* @param alias - Alias of the certificate in .p12 file
*/
public DigitalSigner(InputStream keyStoreFile, char[] keyStorePassword, String alias) {
this.keyEntry = getKeyFromKeyStore(keyStoreFile, keyStorePassword, alias);
if (keyEntry == null) {
throw new RuntimeException("Key could not be read for digital signature. Please check value of signature "
+ "alias and signature password, ");
}
}
/**
* Method to digitally sign an XML document.
* @param xmlDocument - Input XML Document.
* @return Signed XML document
*/
public String signXML(String xmlDocument, boolean includeKeyInfo) {
Security.addProvider(new BouncyCastleProvider());
try {
// Parse the input XML
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document inputDocument = dbf.newDocumentBuilder().parse(new InputSource(new StringReader(xmlDocument)));
// Sign the input XML's DOM document
Document signedDocument = sign(inputDocument, includeKeyInfo);
// Convert the signedDocument to XML String
StringWriter stringWriter = new StringWriter();
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.transform(new DOMSource(signedDocument), new StreamResult(stringWriter));
return stringWriter.getBuffer().toString();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Error while digitally signing the XML document", e);
}
}
private Document sign(Document xmlDoc, boolean includeKeyInfo) throws Exception {
if (System.getenv("SKIP_DIGITAL_SIGNATURE") != null) {
return xmlDoc;
}
// Creating the XMLSignature factory.
XMLSignatureFactory fac = XMLSignatureFactory.getInstance(MEC_TYPE);
// Creating the reference object, reading the whole document for
// signing.
Reference ref = fac.newReference(WHOLE_DOC_URI, fac.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null,
null);
// Create the SignedInfo.
SignedInfo sInfo = fac.newSignedInfo(
fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null),
fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref));
if (keyEntry == null) {
throw new RuntimeException(
"Key could not be read for digital signature.");
}
X509Certificate x509Cert = (X509Certificate) keyEntry.getCertificate();
KeyInfo kInfo = getKeyInfo(x509Cert, fac);
DOMSignContext dsc = new DOMSignContext(this.keyEntry.getPrivateKey(), xmlDoc.getDocumentElement());
XMLSignature signature = fac.newXMLSignature(sInfo, includeKeyInfo ? kInfo : null);
signature.sign(dsc);
Node node = dsc.getParent();
return node.getOwnerDocument();
}
private KeyInfo getKeyInfo(X509Certificate cert, XMLSignatureFactory fac) {
// Create the KeyInfo containing the X509Data.
KeyInfoFactory kif = fac.getKeyInfoFactory();
List x509Content = new ArrayList();
x509Content.add(cert.getSubjectX500Principal().getName());
x509Content.add(cert);
X509Data xd = kif.newX509Data(x509Content);
return kif.newKeyInfo(Collections.singletonList(xd));
}
private KeyStore.PrivateKeyEntry getKeyFromKeyStore(InputStream keyStoreFile, char[] keyStorePassword, String alias) {
// Load the KeyStore and get the signing key and certificate.
InputStream keyFileStream = null;
try {
KeyStore ks = KeyStore.getInstance(KEY_STORE_TYPE);
keyFileStream = keyStoreFile;
ks.load(keyFileStream, keyStorePassword);
KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) ks.getEntry(alias,
new KeyStore.PasswordProtection(keyStorePassword));
return entry;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
if (keyFileStream != null) {
try {
keyFileStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
答案 0 :(得分:0)
Apache XML Security for Java:该库包括标准的JSR-105(Java XML数字签名)API,一种基于DOM的成熟的XML签名和XML加密实现,以及更新的基于StAX的(流媒体) )XML签名和XML加密实现。
因此它应该与Java SE数字签名实现兼容,两者都来自JSR-105。不幸的是,独立开发实现已从Oracle站点中删除。