XML-Signature 语法和签名
一段 XML-signature 的 demo:
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<!-- 规范化的算法 -->
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<!-- 签名算法:rsa-sha1 -->
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<!-- 确定待签名的引用资源 -->
<Reference URI="#_d71a3a8e9fcc45c9e9d248ef7049393fc8f04e5f75">
<!-- 转换算法 -->
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<!-- 消息摘要的算法,比如:SHA1 -->
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<!-- 消息摘要 -->
<DigestValue>k9i4QGA5BDFkW5I+Igr8hR1ibZs=</DigestValue>
</Reference>
</SignedInfo>
<!-- 签名内容 -->
<SignatureValue>
PLIKGZOFbMt8qEM1yw6f/Uct7R9Xd8KWZXw5925gIJdA8+q9MfY34+sQwDcy1Tqnxzak6hx6A6olQr+zJCQH8O/S+sDgCEUhXG+PFU4j2pxnnYqwI3jKc2yeT7A7f8ShStgwN7IgjZ0TFLx2TO3tlZ76 2GwFHNN0lH9ohtAv8Zs=
</SignatureValue>
<!-- KeyInfo 元素可选,表明签名的公钥信息 -->
<KeyInfo>
<X509Data>
<X509Certificate>
MIICaDCCAdGgAaIBAgIEfnIVCzANBgkqhkiG9w0BAQsFADBnMQ4wDAYDVQQGEwVjaGluYTEQMA4G A1UECBMHYmVpamluZzEQMA4GA1UEBxMHYmVpamluZzERMA8GA1UEChMIYmV3aW5uZXIxDTALBgNV BAsTBGJ3MzAxDzANBgNVBAMTBnhpYW9zeTAeFw0xNzExMDgwOTU1NDVaFw0yNzExMDYwOTU1NDVa MGcxDjAMBgNVBAYTBWNoaW5hMRAwDgYDVQQIEwdiZWlqaW5nMRAwDgYDVQQHEwdiZWlqaW5nMREw DwYDVQQKEwhiZXdpbm5lcjENMAsGA1UECxMEYnczMDEPMA0GA1UEAxMGeGlhb3N5MIGfMA0GCSqG SIb3DQEBAQUAA4GNADCBiQKBgQCgmrEMgAMY7zygYqBtYzMal0vTVsQNyjGkD3tbA+pEk18YfN13 UEBoqrp/XQiR4v334xqHjdtG8lxDzEUJ4fQippxMpw6Fab45pz6uOr33DI6X3IwLPxtb7q1MyIj3 TXBY6R01rwIaE+G8/5z76mN5qq4/lhoY3bs0D06pwUSSSQIDAQABoyEwHzAdBgNVHQ4EFgQURAyK 5AjoSEOk32ceEloftZ8TiWcwDQYJKoZIhvcNAQELBQADgYEAZuNWxMO8HOItqAoCI8f6+PfjbL/7 xTwDjs8PxnermmVjACx5JiW0O98M0D5Guo0OABf8mMxiDYQvRwpNoEfMOXr3TjPxqioLMq+s1Nt8 0Duilqel+O6Q/XDJ8rlVdm8vPhLxWZ14FIdI8n7CuuUwUExe4Uj05shCMwgNRo6bmaU=
</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
XML-signature 中的签名算法就是对 XML文档树 进行签名,说明如下:
1、确认签名内容,通过 URL 将这些内容表示为引用资源,用 Reference 标识。对于断言信息来说,其 URI 是saml:Assertion的 ID
2、对待签名的数据进行转化处理,包括执行编码规则、规范化算法等, Transform 指定了转化的算法
3、对整个断言进行消息摘要, DigestMethod 指定了消息摘要算法,消息摘要的结果保存在 DigestValue 元素中
4、构造包含 Reference 的 SignedInfo 元素
5、 CanonicalizationMethod 元素指定了规范化的算法,如果不对其进行规范化处理,验证 xml 签名时可能因为xml 结构表示不同而失败
6、计算 SignedInfo 的摘要,使用 SignatureMethod 声明的签名算法,并对其进行签名,结果保存到 SignatureValue 元素中
7、 KeyInfo 元素可选,表明签名的公钥信息
下面这个工具类实现了 XML-signature 的签名和验签
import java.io.StringWriter;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.PublicKey;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
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.dom.DOMValidateContext;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.io.DOMWriter;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node; @UtilityClass
@Slf4j
public class SignUtils { private static final XMLSignatureFactory XML_SIGNATURE_FACTORY = XMLSignatureFactory.getInstance("DOM"); private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance(); @SneakyThrows
public static Reference getTransformReference(String uri) {
DigestMethod digestMethod = XML_SIGNATURE_FACTORY.newDigestMethod(DigestMethod.SHA1, null);
List<Transform> transforms = Collections.singletonList(XML_SIGNATURE_FACTORY.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null));
return XML_SIGNATURE_FACTORY.newReference("#" + uri, digestMethod, transforms, null, null);
} @SneakyThrows
public static SignedInfo getSignedInfo(Reference ref) {
CanonicalizationMethod method = XML_SIGNATURE_FACTORY.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null);
SignatureMethod signatureMethod = XML_SIGNATURE_FACTORY.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
return XML_SIGNATURE_FACTORY.newSignedInfo(method, signatureMethod, Collections.singletonList(ref));
} @SneakyThrows
public static String sign(Document w3cDoc, PrivateKeyEntry keyEntry, SignedInfo si) {
Optional.ofNullable(w3cDoc)
.map(Document::getDocumentElement)
.map(Node::getFirstChild)
.map(Node::getFirstChild)
.ifPresent(e -> ((Element) e).setIdAttribute("id", true));
DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), Optional.ofNullable(w3cDoc).map(Document::getDocumentElement).get());
XMLSignature signature = XML_SIGNATURE_FACTORY.newXMLSignature(si, null);
signature.sign(dsc);
@Cleanup StringWriter strWriter = new StringWriter();
TRANSFORMER_FACTORY.newTransformer().transform(new DOMSource(w3cDoc), new StreamResult(strWriter));
return strWriter.toString();
} @SneakyThrows
public static boolean checkSign(Node signNode, PublicKey publicKey) {
Optional.ofNullable(signNode.getPreviousSibling()).ifPresent(e -> ((Element) e).setIdAttribute("id", true));
DOMValidateContext valContext = new DOMValidateContext(publicKey, signNode);
XMLSignature signature = XML_SIGNATURE_FACTORY.unmarshalXMLSignature(valContext);
return signature.validate(valContext);
} @SneakyThrows
public static org.w3c.dom.Document convert(org.dom4j.Document doc) {
log.info("org.dom4j.Document,outXml:[{}]", doc.asXML());
return new DOMWriter().write(doc);
} }
下面这个类实现了公、私钥证书的加载:
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.concurrent.atomic.AtomicBoolean;
import lombok.Cleanup;
import lombok.SneakyThrows; public final class X509CertificationLoader implements CertificationLoader { public static final CertificationLoader INSTANCE = new X509CertificationLoader(); private PrivateKeyEntry privateKeyEntry;
private PublicKey publicKey; private AtomicBoolean isPrivateKeyInitiated = new AtomicBoolean(false);
private AtomicBoolean isPublicKeyInitiated = new AtomicBoolean(false); private X509CertificationLoader() {
} @Override
@SneakyThrows
public PrivateKeyEntry getPrivateKey(CertInfo certInfo) {
if (null != privateKeyEntry) {
return privateKeyEntry;
}
if (isPrivateKeyInitiated.compareAndSet(false, true)) {
KeyStore ks = KeyStore.getInstance(KEY_STORE_TYPE);
@Cleanup InputStream fileInputStream = new FileInputStream(certInfo.getPrivateKeyFile());
final char[] passwdChars = certInfo.getPasswd().toCharArray();
ks.load(fileInputStream, passwdChars);
privateKeyEntry = (PrivateKeyEntry) ks.getEntry(ks.aliases().nextElement(), new KeyStore.PasswordProtection(passwdChars));
}
return privateKeyEntry;
} @Override
@SneakyThrows
public PublicKey getPublicKey(CertInfo certInfo) {
if (null != publicKey) {
return publicKey;
}
if (isPublicKeyInitiated.compareAndSet(false, true)) {
@Cleanup InputStream fin = new FileInputStream(certInfo.getPublicKeyFile());
CertificateFactory f = CertificateFactory.getInstance(CERTIFICATE_TYPE_NAME);
X509Certificate certificate = (X509Certificate) f.generateCertificate(fin);
publicKey = certificate.getPublicKey();
}
return publicKey;
} }
import java.security.KeyStore.PrivateKeyEntry;
import java.security.PublicKey; public interface CertificationLoader { String KEY_STORE_TYPE = "PKCS12"; String CERTIFICATE_TYPE_NAME = "X.509"; /**
* 获取包含私钥证书的 KeyStore
*
* @param certInfo 证书文件信息 {@link CertInfo}
* @return KeyStore {@link PrivateKeyEntry}
*/
PrivateKeyEntry getPrivateKey(CertInfo certInfo); /**
* 获取 X509 格式的公钥证书
*
* @param certInfo 证书文件信息 {@link CertInfo}
* @return 公钥证书 {@link PublicKey}
*/
PublicKey getPublicKey(CertInfo certInfo); }
XML-Signature 语法和签名的更多相关文章
- Manifest XML signature is not valid(安装ClickOnce签名未通过验证)
转载:http://stackoverflow.com/questions/12826798/manifest-xml-signature-is-not-valid 安装时,我的问题: PLATFO ...
- 【Azure 存储服务】代码版 Azure Storage Blob 生成 SAS (Shared Access Signature: 共享访问签名)
问题描述 在使用Azure存储服务,为了有效的保护Storage的Access Keys.可以使用另一种授权方式访问资源(Shared Access Signature: 共享访问签名), 它的好处可 ...
- 利用X.509证书对XML进行加密和签名
综述 XML加密和签名技术应用非常广泛. ASP.NET 使用XML加密对配置信息进行加密:InfoPath使用XML签名对表单进行签名:Web服务使用XML加密和签名对SOAP消息进行加 ...
- XML的语法
XML的语法 文档声明: 写法 <?xml version="1.0" ?> 文档声明必须出现在xml文件的第一行和第一列的位置 属性: version="1 ...
- XML DTD语法详解
XML DTD详解 XML DTD详解 前情提要与本文内容介绍 前面的两篇XML相关博文: 第一篇是介绍格式正规的XML: 格式正规的XML:语法 属性 实体 处理指令 样式单 CDATA节 第二 ...
- JAVA企业级开发-xml基础语法&约束&解析(04)
一.什么是xml html:超文本标记语言.它主要是用来封装页面上要显示的数据,最后通过浏览器来解析html文件,然后把数据展示在浏览器上.同样我们可以使用JS和DOM技术对html文件进行解析和操作 ...
- java日志框架系列(4):logback框架xml配置文件语法
1.xml配置文件语法 由于logback配置文件语法特别灵活,因此无法用DTD或schema进行定义. 1.配置文件基本结构 配置文件基本结构:以<configuration>标签开头, ...
- 2016 - 1 - 23 xml解析 -- 语法简介
一: XML的概念 1. 一种可拓展标记语言 2. 与json一样,也是一种常用的数据交互格式 3. 一般也叫XML文档---XML Document 二: XML语法 1.一个完整的XML文档一 ...
- xml的语法与创建
xml语法很简单,但很严格,如果出现错误则不能正常解析,而HTML如果出现局部的错误,照样解析 xml第一行必须写xml头<?xml version='1.0' encoding='utf8'? ...
随机推荐
- Python实现的贪婪算法
个州的听众都收听到.为此,你需要决定在哪些广播台播出.在每个广播台播出都需要支出费用,因此你力图在尽可能少的广播台播出 # 1.创建一个列表,其中包含要覆盖的州 states_needed = set ...
- memcpy函数的实现
1.按1个字节拷贝 (1)不要直接使用形参,要转换成char* (2)目标地址要实现保存 (3)要考虑源和目标内存重叠的情况 void * mymemcpy(void *dest, const voi ...
- ip黑名单-做过ssh扫描黑的ip
# # hosts.deny This file contains access rules which are used to # deny connections to network servi ...
- Fiddler抓包工具简介
1.Fiddler工具: 个人认为Fiddler实际上是一款在浏览器与服务器之间设置代理,对两者之间的通信会话(数据包)进行抓取和处理的一款工具: Fiddler是一个http协议调试代理工具,它能够 ...
- ELK快速入门(四)filebeat替代logstash收集日志
ELK快速入门四-filebeat替代logstash收集日志 filebeat简介 Filebeat是轻量级单用途的日志收集工具,用于在没有安装java的服务器上专门收集日志,可以将日志转发到log ...
- (四)Kubernetes 资源清单定义
Kubernetes常用资源对象 依据资源的主要功能作为分类标准,Kubernetes的API对象大体可分为五个类别,如下: 类型 名称 工作负载(Workload) Pod.ReplicaSet.D ...
- React源码 React ref
ref 的功能,在 react 当中.我们写了一个组件,在这个时候,我们的 render function 里面我们会渲染一系列的子组件或者 dom 节点,有时候我们会希望有这样的需求,就是我们要获取 ...
- 编程题:SaturdayNightStay
"输入2019年的一个时间段,开始时间代表出发,结束时间代表在那一天返回,判断在该时间段内,如果旅行有多少个子时间段可以在周六晚上休息" * 周六晚上休息,即子时间段必须包含周六, ...
- 《快活帮》第八次团队作业:Alpha冲刺
项目 内容 这个作业属于哪个课程 2016计算机科学与工程学院软件工程(西北师范大学) 这个作业的要求在哪里 实验十二 团队作业8-软件测试与ALPHA冲刺 团队名称 快活帮 作业学习目标 (1)掌握 ...
- JPA 报错:Page 2 of 1 containing UNKNOWN instances
JPA 中,page是从0开始,不是从1开始: 因此,将用户输入的从1开始的page页码减1: PageRequest pageRequest = PageRequest.of(page - 1, p ...