电子发票中数字签名的提取解析教程

您所在的位置:网站首页 如何提取文件印章 电子发票中数字签名的提取解析教程

电子发票中数字签名的提取解析教程

2024-07-12 18:28| 来源: 网络整理| 查看: 265

前言

随着电子信息技术的发展与成熟,加上国家的大力推广,电子发票已经开始慢慢取代纸质发票。相比传统的纸质发票,电子发票除了绿色环保,节约成本之外,更重要的是电子发票采取电子签章实现发票签名、电子盖章,具有唯一性、不可抵赖性、防篡改等优点,而且更加容易税务管理。那么,我们平常拿到一张电子发票,应该如何验证它的真伪呢?如何保证它是合法且没有被别人篡改呢?这就需要对电子发票的原理有所了解了。下文将慢慢分析电子发票文件的内部结构,并尝试对电子发票中数字证书及签名进行解析。

电子发票的结构

我们收到的电子发票文件后缀名都是.ofd,它的载体就是OFD版式文件,OFD文件我们可以简单认为它就是我们国家自主研发与定义的文件格式,类似于PDF,我们通过winzip或者7zip等解压工具打开,就可以看到它的内部结构。 在这里插入图片描述 从图中可以看到,电子发票主要分为两个体系,一个是内容体系,主要描述发票各个要素承载的信息以及样式;另外一个是签名体系,用于校验发票的正确性。 这里和验证相关的的文件主要是Signature.xml(签名/签章描述文件)、Seal.esl(电子印章文件)和SignedValue.dat(签名值文件)。

电子发票的验证步骤

我们拿到这三个文件需要怎么做呢?最权威的国标文件给出了验证的具体步骤,如图所示: 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 好家伙,光验证步骤就有a~h步,其中第d步是验证电子印章的有效性,而这里又是涉及到多个步骤: 在这里插入图片描述 怎么理解这一堆复杂的步骤呢?电子签章和电子印章的区别是什么? 想象一下我们收到一张发票,应该怎样去验证它的真伪呢?

需要保证电子发票是开票者开具的,文件并没有被篡改过。需要验证发票上的印章是真实有效的。

上面提到的第1点就是电子签章的验证,第2点就是电子印章的验证。两者缺一不可。 而无论是电子签章还是电子印章,核心又是对数字签名进行验证,因此,提取文件中的证书文件是关键。下面以电子印章(Seal.esl)为例,介绍一下如何解析里面的内容。

电子印章的文件组成

电子印章文件是一个二进制文件,通过文本工具是无法得知里面的内容。实际上,电子印章是以ASN.1格式来存储的。 ASN.1是什么东西呢?ASN.1是国际电信标准(ITU-T)定义的标准,用来结构化描述证书,ASN.1类似于JSON或者XML这样的数据结构。一般的证书都是通过ASN.1来定义的。 https://lapo.it/asn1js/ 是一个神奇的在线ASN.1解析网站,把Seal.esl丢上去,可以看到电子印章的内容基本都被解析出来了: 在这里插入图片描述 可以看到电子印章文件的大致结构,里面包含了电子印章的一些基础信息,例如印章信息、制章者、签名算法、签名值等。唯一有点遗憾的是无法通过结果得知各个元素的名称与作用,这是由于网站无法知道我们的数据结构是怎样定义的。我们还是要更加深入研究国标中对电子印章的数据结构定义。 在这里插入图片描述 上图是电子印章中印章属性的结构定义,我们可以理解电子印章是在原有数字证书的基础上封装了一些信息,核心还是里面的数字证书Certificate(如下图红框所示),而这个证书与我们平时浏览器上信任的证书是同一个东西。 在这里插入图片描述 通过Java编写程序,我们可以更加定制化地专门解析电子印章的内容,并且能提取出证书的内容,为后面的数字签名验证打下基础。

电子印章的解析

目前最主流的java解析ASN.1内容工具是:bcprov,使用方法也相当简单。

org.bouncycastle bcprov-jdk15on 1.68 @Slf4j public class TestAsn1Parser { @Test public void testData() throws Exception{ // 1. 读取电子印章(Seal.esl) ASN1InputStream bin = new ASN1InputStream(new ByteArrayInputStream(IOUtils.toByteArray(AsnParser.class.getResourceAsStream("Seal.esl")))); ASN1Primitive obj = bin.readObject(); DLSequence app = (DLSequence) obj; // 2. 根据国标定义,找到证书二进制内容的位置 DEROctetString cert = (DEROctetString) app.getObjectAt(1); ASN1InputStream bin2 = new ASN1InputStream(cert.getOctets()); DLSequence seq = (DLSequence) bin2.readObject(); // 3. 解析证书内容 Certificate certificate = Certificate.getInstance(seq); TBSCertificate tbsCertificate = certificate.getTBSCertificate(); // 示例:获取证书内数字签名的主要元素 log.info("签名算法:{}", certificate.getSignatureAlgorithm().getAlgorithm()); log.info("签名值:{}", certificate.getSignature()); TBSCertificate tbsCertificate = certificate.getTBSCertificate(); log.info("公钥:{}", tbsCertificate.getSubjectPublicKeyInfo().getPublicKeyData()); } }

在这里插入图片描述 例子中只对电子印章中的证书部分进行解析,实际应用中我们可以创建对应的实现来完全映射国标中的数据结构。 通过上面代码得到电子印章的数字签名信息,包括:

签名算法是1.2.156.10197.1.501(国标中对应的是国密算法:基于SM3的SM2签名)签名值公钥

有了上面的信息,接下来要做的事情就简单了,只需对该数字签名进行验证即可。

后记

上面介绍的仅仅是电子发票验证的一小部分,由于篇幅有限,除了要对数字签名验证以外,还需要验证证书的有效性,这里又涉及到证书链与CRL相关的验证。而电子印章验证通过后还需进行电子签章的验证。有时间的话将进一步补充介绍后面的步骤。 电子发票涉及相关的内容较多,包括了OFD、ASN.1和信息安全、密码学等相关知识,特别是相关国家标准较多,需要仔细参考研究其中的描述说明。上面的示例仅作参考,如有错漏,还请见谅。 By Ryan.ou

参考资料

[1] GB/T 33190-2016 电子文件存储与交换格式 版式文档 [2] GB/T 38540-2020 信息安全技术 安全电子签章密码 技术规范 [3] GB/T 20518 2018 信息安全技术 公钥基础设施 数字证书格式 [4] OFD开源读写组件 [5] ASN.1在线解析网站 [6] https://blog.csdn.net/weixin_42497593/article/details/112151171



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3