java - 等效于 Java XML 签名方法的 C#
问题描述
尝试通过相反的问题创建签名(Java 等效于 C# XML 签名方法),但没有运气。那么有人可以帮我在 C# 中签署 XmlDocument 吗?通过相反问题的解决方案,我得到异常,即在确切位置没有私钥:signedXml.ComputeSignature();
那么我应该如何在 C# 中实现签名方法,例如我得到了:
imports...
@SuppressWarnings("restriction")
public abstract class BaseAuthRequestGenerator {
public static final String SIGNED_NODE_ID = "uniqueNodeId";
private static final char[] PASSWORD = "testtest".toCharArray();
private static final XMLSignatureFactory XML_SIGNATURE_FACTORY = XMLSignatureFactory.getInstance("DOM");
protected PrivateKey privateKey = null;
protected PublicKey publicKey = null;
public BaseAuthRequestGenerator() {
try {
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(FileUtils.openInputStream(FileUtils.toFile(AuthGenerator.class.getResource("/testKeystore.jks"))), PASSWORD);
for (Enumeration<String> e = keyStore.aliases(); e.hasMoreElements();) {
String alias = e.nextElement();
if (keyStore.isKeyEntry(alias)) {
privateKey = (PrivateKey) keyStore.getKey(alias, PASSWORD);
X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
publicKey = cert.getPublicKey();
break;
}
}
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
public Node marshal(Object data) throws JAXBException {
String packageName = data.getClass().getPackage().getName();
JAXBContext jc = JAXBContext.newInstance(packageName);
DOMResult result = new DOMResult();
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(data, result);
return result.getNode();
}
public String getSignedXml(Node node, String referenceUri) throws Exception {
signNode(node, referenceUri);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
final ByteArrayOutputStream output = new ByteArrayOutputStream();
trans.transform(new DOMSource(node), new StreamResult(output));
return new String(output.toByteArray(), Charset.forName("UTF-8"));
}
public void signNode(Node node, String uri) throws Exception {
DOMSignContext dsc = new DOMSignContext(privateKey, node);
XMLSignatureFactory fac = XML_SIGNATURE_FACTORY;
List<String> prefixList = new ArrayList<String>();
prefixList.add(node.getPrefix());
C14NMethodParameterSpec spec = new ExcC14NParameterSpec(prefixList);
List<Transform> transforms = new ArrayList<Transform>();
transforms.add(fac.newTransform(CanonicalizationMethod.ENVELOPED, (TransformParameterSpec) null));
transforms.add(fac.newTransform(CanonicalizationMethod.EXCLUSIVE, spec));
Reference ref = fac.newReference(uri, fac.newDigestMethod(DigestMethod.SHA1, null), transforms, null, null);
SignedInfo si = fac.newSignedInfo(fac.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE, spec), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
KeyInfoFactory kif = fac.getKeyInfoFactory();
KeyValue kv = kif.newKeyValue(publicKey);
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
}
/**
* Sets ID attribute (named "id") for given node.
* <p>
* Necessary for XML signing/validation when running on JDK 7
*
* @param node node to set ID attribute for
* @see http://stackoverflow.com/questions/17331187/xml-dig-sig-error-after-upgrade-to-java7u25
*/
public void setIdAttribute(Node node) {
Node idAttribute = node.getAttributes().getNamedItem("id");
if (idAttribute != null) {
((Element) node).setIdAttribute("id", true);
}
}
}
要签署 xml 文档,我必须使用证书和 RSA 私钥吗?
如果我只有私钥和证书而没有 KeyStore 怎么办?
C#方法:
private static XDocument SignXDocument(XDocument document)
{
XDocument returnDoc = new XDocument();
XmlDocument convertedDoc = DocumentExtensions.ToXmlDocument(document);
convertedDoc.PreserveWhitespace = true;
X509Certificate2 certificate = GetX509Certificate2();
RSACryptoServiceProvider privateKey = GetPrivateKey(KeyPath);
SignedXml signedXml = new SignedXml(convertedDoc) { SigningKey = certificate.PrivateKey };
Reference reference = new Reference { Uri = "#" + ID };
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
signedXml.AddReference(reference);
// embed public key information for signature validation purposes
KeyInfo keyInfo = new KeyInfo();
KeyInfoX509Data keyInfoX509Data = new KeyInfoX509Data(certificate, X509IncludeOption.ExcludeRoot);
keyInfo.AddClause(keyInfoX509Data);
signedXml.KeyInfo = keyInfo;
signedXml.ComputeSignature();
XmlElement xmldsigXmlElement = signedXml.GetXml();
var changed = xmldsigXmlElement.ToXElement();
document.Add(changed);
return document;
}
解决方案
推荐阅读
- sql - 向 LIMIT 关键字添加多行时,MS Sql Query 变慢
- typescript - 如何防止 Firebase 一遍又一遍地创建同一个用户?
- c# - 在 Unity 和 C# 中显示当前的悬停对象属性/名称
- javascript - 如何选择创建的元素?
- javascript - 删除 jsonObject 替换为 undefined
- mysql - 使用外部表中的变量进行计算的 Mysql 顺序
- java - 是否可以在指南行 AmCharts 中使用会话值?
- spring - Spring 使用 xml 与 Azure blob 存储集成
- c# - 领域驱动设计 - 如何实现始终有效的状态
- javascript - 当我自动完成输入字段时,标签会覆盖值,并且加载时也不会获得长度