电子发票中数字签名的提取解析教程
前言
隨著電子信息技術(shù)的發(fā)展與成熟,加上國家的大力推廣,電子發(fā)票已經(jīng)開始慢慢取代紙質(zhì)發(fā)票。相比傳統(tǒng)的紙質(zhì)發(fā)票,電子發(fā)票除了綠色環(huán)保,節(jié)約成本之外,更重要的是電子發(fā)票采取電子簽章實(shí)現(xiàn)發(fā)票簽名、電子蓋章,具有唯一性、不可抵賴性、防篡改等優(yōu)點(diǎn),而且更加容易稅務(wù)管理。那么,我們平常拿到一張電子發(fā)票,應(yīng)該如何驗(yàn)證它的真?zhèn)文?#xff1f;如何保證它是合法且沒有被別人篡改呢?這就需要對電子發(fā)票的原理有所了解了。下文將慢慢分析電子發(fā)票文件的內(nèi)部結(jié)構(gòu),并嘗試對電子發(fā)票中數(shù)字證書及簽名進(jìn)行解析。
電子發(fā)票的結(jié)構(gòu)
我們收到的電子發(fā)票文件后綴名都是.ofd,它的載體就是OFD版式文件,OFD文件我們可以簡單認(rèn)為它就是我們國家自主研發(fā)與定義的文件格式,類似于PDF,我們通過winzip或者7zip等解壓工具打開,就可以看到它的內(nèi)部結(jié)構(gòu)。
從圖中可以看到,電子發(fā)票主要分為兩個(gè)體系,一個(gè)是內(nèi)容體系,主要描述發(fā)票各個(gè)要素承載的信息以及樣式;另外一個(gè)是簽名體系,用于校驗(yàn)發(fā)票的正確性。
這里和驗(yàn)證相關(guān)的的文件主要是Signature.xml(簽名/簽章描述文件)、Seal.esl(電子印章文件)和SignedValue.dat(簽名值文件)。
電子發(fā)票的驗(yàn)證步驟
我們拿到這三個(gè)文件需要怎么做呢?最權(quán)威的國標(biāo)文件給出了驗(yàn)證的具體步驟,如圖所示:
好家伙,光驗(yàn)證步驟就有a~h步,其中第d步是驗(yàn)證電子印章的有效性,而這里又是涉及到多個(gè)步驟:
怎么理解這一堆復(fù)雜的步驟呢?電子簽章和電子印章的區(qū)別是什么?
想象一下我們收到一張發(fā)票,應(yīng)該怎樣去驗(yàn)證它的真?zhèn)文?#xff1f;
上面提到的第1點(diǎn)就是電子簽章的驗(yàn)證,第2點(diǎn)就是電子印章的驗(yàn)證。兩者缺一不可。
而無論是電子簽章還是電子印章,核心又是對數(shù)字簽名進(jìn)行驗(yàn)證,因此,提取文件中的證書文件是關(guān)鍵。下面以電子印章(Seal.esl)為例,介紹一下如何解析里面的內(nèi)容。
電子印章的文件組成
電子印章文件是一個(gè)二進(jìn)制文件,通過文本工具是無法得知里面的內(nèi)容。實(shí)際上,電子印章是以ASN.1格式來存儲的。
ASN.1是什么東西呢?ASN.1是國際電信標(biāo)準(zhǔn)(ITU-T)定義的標(biāo)準(zhǔn),用來結(jié)構(gòu)化描述證書,ASN.1類似于JSON或者XML這樣的數(shù)據(jù)結(jié)構(gòu)。一般的證書都是通過ASN.1來定義的。
https://lapo.it/asn1js/ 是一個(gè)神奇的在線ASN.1解析網(wǎng)站,把Seal.esl丟上去,可以看到電子印章的內(nèi)容基本都被解析出來了:
可以看到電子印章文件的大致結(jié)構(gòu),里面包含了電子印章的一些基礎(chǔ)信息,例如印章信息、制章者、簽名算法、簽名值等。唯一有點(diǎn)遺憾的是無法通過結(jié)果得知各個(gè)元素的名稱與作用,這是由于網(wǎng)站無法知道我們的數(shù)據(jù)結(jié)構(gòu)是怎樣定義的。我們還是要更加深入研究國標(biāo)中對電子印章的數(shù)據(jù)結(jié)構(gòu)定義。
上圖是電子印章中印章屬性的結(jié)構(gòu)定義,我們可以理解電子印章是在原有數(shù)字證書的基礎(chǔ)上封裝了一些信息,核心還是里面的數(shù)字證書Certificate(如下圖紅框所示),而這個(gè)證書與我們平時(shí)瀏覽器上信任的證書是同一個(gè)東西。
通過Java編寫程序,我們可以更加定制化地專門解析電子印章的內(nèi)容,并且能提取出證書的內(nèi)容,為后面的數(shù)字簽名驗(yàn)證打下基礎(chǔ)。
電子印章的解析
目前最主流的java解析ASN.1內(nèi)容工具是:bcprov,使用方法也相當(dāng)簡單。
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.68</version> </dependency> @Slf4j public class TestAsn1Parser {@Testpublic 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. 根據(jù)國標(biāo)定義,找到證書二進(jìn)制內(nèi)容的位置DEROctetString cert = (DEROctetString) app.getObjectAt(1);ASN1InputStream bin2 = new ASN1InputStream(cert.getOctets());DLSequence seq = (DLSequence) bin2.readObject();// 3. 解析證書內(nèi)容Certificate certificate = Certificate.getInstance(seq);TBSCertificate tbsCertificate = certificate.getTBSCertificate();// 示例:獲取證書內(nèi)數(shù)字簽名的主要元素log.info("簽名算法:{}", certificate.getSignatureAlgorithm().getAlgorithm());log.info("簽名值:{}", certificate.getSignature());TBSCertificate tbsCertificate = certificate.getTBSCertificate();log.info("公鑰:{}", tbsCertificate.getSubjectPublicKeyInfo().getPublicKeyData());} }
例子中只對電子印章中的證書部分進(jìn)行解析,實(shí)際應(yīng)用中我們可以創(chuàng)建對應(yīng)的實(shí)現(xiàn)來完全映射國標(biāo)中的數(shù)據(jù)結(jié)構(gòu)。
通過上面代碼得到電子印章的數(shù)字簽名信息,包括:
有了上面的信息,接下來要做的事情就簡單了,只需對該數(shù)字簽名進(jìn)行驗(yàn)證即可。
后記
上面介紹的僅僅是電子發(fā)票驗(yàn)證的一小部分,由于篇幅有限,除了要對數(shù)字簽名驗(yàn)證以外,還需要驗(yàn)證證書的有效性,這里又涉及到證書鏈與CRL相關(guān)的驗(yàn)證。而電子印章驗(yàn)證通過后還需進(jìn)行電子簽章的驗(yàn)證。有時(shí)間的話將進(jìn)一步補(bǔ)充介紹后面的步驟。
電子發(fā)票涉及相關(guān)的內(nèi)容較多,包括了OFD、ASN.1和信息安全、密碼學(xué)等相關(guān)知識,特別是相關(guān)國家標(biāo)準(zhǔn)較多,需要仔細(xì)參考研究其中的描述說明。上面的示例僅作參考,如有錯(cuò)漏,還請見諒。
By Ryan.ou
參考資料
[1] GB/T 33190-2016 電子文件存儲與交換格式 版式文檔
[2] GB/T 38540-2020 信息安全技術(shù) 安全電子簽章密碼 技術(shù)規(guī)范
[3] GB/T 20518 2018 信息安全技術(shù) 公鑰基礎(chǔ)設(shè)施 數(shù)字證書格式
[4] OFD開源讀寫組件
[5] ASN.1在線解析網(wǎng)站
[6] https://blog.csdn.net/weixin_42497593/article/details/112151171
總結(jié)
以上是生活随笔為你收集整理的电子发票中数字签名的提取解析教程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 keytool 生成安卓应用程序签
- 下一篇: mybatis 报错. Cause: o