电子发票中数字签名的提取解析教程
前言
隨著電子信息技術的發展與成熟,加上國家的大力推廣,電子發票已經開始慢慢取代紙質發票。相比傳統的紙質發票,電子發票除了綠色環保,節約成本之外,更重要的是電子發票采取電子簽章實現發票簽名、電子蓋章,具有唯一性、不可抵賴性、防篡改等優點,而且更加容易稅務管理。那么,我們平常拿到一張電子發票,應該如何驗證它的真偽呢?如何保證它是合法且沒有被別人篡改呢?這就需要對電子發票的原理有所了解了。下文將慢慢分析電子發票文件的內部結構,并嘗試對電子發票中數字證書及簽名進行解析。
電子發票的結構
我們收到的電子發票文件后綴名都是.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,使用方法也相當簡單。
<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. 根據國標定義,找到證書二進制內容的位置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());} }
例子中只對電子印章中的證書部分進行解析,實際應用中我們可以創建對應的實現來完全映射國標中的數據結構。
通過上面代碼得到電子印章的數字簽名信息,包括:
有了上面的信息,接下來要做的事情就簡單了,只需對該數字簽名進行驗證即可。
后記
上面介紹的僅僅是電子發票驗證的一小部分,由于篇幅有限,除了要對數字簽名驗證以外,還需要驗證證書的有效性,這里又涉及到證書鏈與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
總結
以上是生活随笔為你收集整理的电子发票中数字签名的提取解析教程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 keytool 生成安卓应用程序签
- 下一篇: mybatis 报错. Cause: o