环境需求

  • bouncycastle provider 1.60以上
  • itext7-core 7.1.6
<dependency><groupId>com.itextpdf</groupId><artifactId>itext7-core</artifactId><version>7.1.6</version><type>pom</type>
</dependency>
<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.64</version>
</dependency>

Quick Start

在新的 bouncycastle 库中已经完全支持了 国密算法,而在itext中对国密算法的支持不太友好。

我们通过下面代码来验证PDF中的PKCS#7类型的数字签名

Security.addProvider(new BouncyCastleProvider());String file = "C:/Users/Administrator/Documents/sm2pkcs7sig.pdf";
PdfReader reader = new PdfReader(file);
// 创建签名工具
PdfDocument pdfDocument = new PdfDocument(reader);
SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
// 获取所有的签名域,域名称列表
List<String> fieldNames = signatureUtil.getSignatureNames();
for (String fieldName : fieldNames) {// 获取签名值的PKCS#7数据PdfPKCS7 pkcs7 = signatureUtil.readSignatureData(fieldName, "BC");// 数字签名验证是否有效boolean isValidate = pkcs7.verifySignatureIntegrityAndAuthenticity();System.out.println("Is signature validate: " + isValidate);
}

C:/Users/Administrator/Documents/sm2pkcs7sig.pdf 是一个采用了SM3withSM2签名的PDF文件

通过上述方法我们在验证类似于SHA1withRSASHA256withRSA的时候是OK,但是在验证国密算法时会抛出下面异常:

Caused by: com.itextpdf.kernel.PdfException: Unknown PdfException....
Caused by: java.security.NoSuchAlgorithmException: no such algorithm: 1.2.156.10197.1.401with1.2.156.10197.1.501 for provider BC...

1.2.156.10197.1.401with1.2.156.10197.1.501 实际上就是 SM3withSM2的OID

实际上 bouncycastle 库中是支持SM3withSM2的OID的算法的,造成这个问题的原因是出在iText上的。

查看 iText7源码 可以知道解析签名算法的方式是从pkcs#7对象中取出:摘要算法、加密算法的OID,然后通过JCE算法提供者,获取对应的签名算法,用于之后的验证

private Signature initSignature(PublicKey key) throws ...String digestAlgorithm = getDigestAlgorithm();if (PdfName.Adbe_x509_rsa_sha1.equals(getFilterSubtype()))digestAlgorithm = "SHA1withRSA";Signature signature = SignUtils.getSignatureHelper(digestAlgorithm, provider);signature.initVerify(key);return signature;
}
public String getDigestAlgorithm() {return getHashAlgorithm() + "with" + getEncryptionAlgorithm();
}
public String getHashAlgorithm() {return DigestAlgorithms.getDigest(digestAlgorithmOid);
}
public String getEncryptionAlgorithm() {String encryptAlgo = EncryptionAlgorithms.getAlgorithm(digestEncryptionAlgorithmOid);if (encryptAlgo == null)encryptAlgo = digestEncryptionAlgorithmOid;return encryptAlgo;
}

出现之所以getDigestAlgorithm 返还了1.2.156.10197.1.401with1.2.156.10197.1.501 而不是 SM3withSM2这样的名字。

原因是:itext中EncryptionAlgorithmsDigestAlgorithms 类的映射关系中没有国密算法的标识符

那么为了简单的解决问题我们直接通过反射加入然后测试是否能够解决

public static void main(String[] args) throws Exception {Security.addProvider(new BouncyCastleProvider());Field digestNamesField = DigestAlgorithms.class.getDeclaredField("digestNames");digestNamesField.setAccessible(true);HashMap<String, String> digestNames = (HashMap<String,String>)digestNamesField.get(null);digestNames.put("1.2.156.10197.1.401", "SM3");Field algorithmNamesField = EncryptionAlgorithms.class.getDeclaredField("algorithmNames");algorithmNamesField.setAccessible(true);HashMap<String, String> algorithmNames = (HashMap<String,String>)algorithmNamesField.get(null);algorithmNames.put("1.2.156.10197.1.501", "SM2");String file = "C:/Users/Administrator/Documents/sm2pkcs7sig.pdf";PdfReader reader = new PdfReader(file);// 创建签名工具PdfDocument pdfDocument = new PdfDocument(reader);SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);// 获取所有的签名域,域名称列表List<String> fieldNames = signatureUtil.getSignatureNames();for (String fieldName : fieldNames) {// 获取签名值的PKCS#7数据PdfPKCS7 pkcs7 = signatureUtil.readSignatureData(fieldName, "BC");// 数字签名验证是否有效boolean isValidate = pkcs7.verifySignatureIntegrityAndAuthenticity();System.out.println("Is signature validate: " + isValidate);}
}

运行结果

Is signature validate: true

确实解决了该问题,更好的做法是继承PdfPKCS7然后做一些内部修改,不过我准备向itext7 库搞一个 Pull req 直接在对应的Map中加入算法标识符就行了。

参考

[1]. GMSSL . http://gmssl.org/docs/oid.html

PDF itext pkcs#7 国密签名验证相关推荐

  1. Apache APISIX 玩转 Tongsuo 国密插件

    文|罗泽轩 Apache APISIX PMC 本文通过解读国密的相关内容与标准,呈现了当下国内技术环境中对于国密功能支持的现状.并从 API 网关 Apache APISIX 的角度,带来有关国密的 ...

  2. 基于Itext的PDF国密电子签名及其实现

    1.基础准备: 1.1 推荐大家阅读https://blog.csdn.net/liumengya007007/article/details/53129323 ,首先完成RSA的电子签名.有一个关于 ...

  3. rsa签名算法实现_国密算法在链化未来区块链中的运用

    密码学是区块链的基础,区块链中大量采用了密码学算法,包括对称加密,非对称加密,单向散列算法,数字签名等技术. 为了实现密码学技术的自主可控,中国也定义了自己的国密标准,2020年央行颁布的<金融 ...

  4. OpenSSL 1.1.1 新特性: 全面支持国密SM2/SM3/SM4加密算法

    OpenSSL项目最近6个月添加了许多新特性, 包括对中国SM2/SM3/SM4算法的支持: SM2椭圆曲线: https://github.com/openssl/openssl/pull/4793 ...

  5. 坚持自主可控,长安链ChainMaker全面拥抱国密的技术实践

    密码技术作为与核技术.航天技术并列的国家三大安全核心技术之一,在保障信息安全,增强我国行业信息系统的"安全可控"等方面具有关键作用.长期以来国际上较为通用的商用算法是由美国安全局发 ...

  6. 国密算法—SM2介绍及基于BC的实现

    国密算法-SM2介绍及基于BC的实现 文章目录 国密算法-SM2介绍及基于BC的实现 简介 私钥 公钥 数据格式 密钥数据格式 私钥数据格式 公钥数据格式 加密数据格式 签名数据格式 计算过程 生成密 ...

  7. SM4国密算法实现分析

    SM4国密算法实现分析 代码下载请见 上一篇文章 AES算法实现分析 SM4的说明(pdf):http://download.csdn.net/detail/leechiyang/5008528 算法 ...

  8. 前端国密加解密使用方法SM2、SM3、SM4

    国密算法,即国家商用密码算法.是由国家密码管理局认定和公布的密码算法标准及其应用规范,其中部分密码算法已经成为国际标准.如SM系列密码,SM代表商密,即商业密码,是指用于商业的.不涉及国家秘密的密码技 ...

  9. 国密算法Go语言实现(详解)(九) ——SM2(椭圆曲线公钥密码算法)

    国密算法Go语言实现(详解)(九) --SM2(椭圆曲线公钥密码算法) 原创代码:https://github.com/ZZMarquis/gm 引用时,请导入原创代码库.本文仅以注释方式详解代码逻辑 ...

最新文章

  1. LabVIEW色彩分类识别(基础篇—15)
  2. 糟糕的css用法 1
  3. 迅速解决!!!!!启动Tomcat报错PermGen space
  4. Win10_MySQL环境搭建以及Navicat的使用全解
  5. Silverlight C# 游戏开发:面向对象在游戏中的实例(一)
  6. icinga2 php模块,在Ubuntu 18.04系统上安装Icinga2监视工具的方法
  7. 洛谷P5703、P5704、P5705、P5706题题解(Java语言描述)
  8. 流行的某导航网站系统源码 收录系统源码
  9. mysql 1130本地连接_mysql ERROR 1130 问题解决方案
  10. mongovue mysql_MongoDB 客户端 MongoVue
  11. 鉴相,鉴频以及环路跟踪算法的理解:
  12. Excel+VBA 区域数据的去重
  13. 人工智能的目标与进化
  14. 最后冲刺—信息系统开发与管理
  15. 记录一次时间戳、夏令时、时区线上问题分析
  16. 后端-科室信息管理接口
  17. cad2012打开后闪退_2012cad闪退怎么解决win10_cad2012闪退win10系统如何修复
  18. OSSIM开源安全信息管理系统(十六)
  19. linux 常用命令——MySql 5.7添加用户、删除用户与授权
  20. 用什么方式推广莆田鞋最好?C原版本真的能买吗

热门文章

  1. spring boot + ignite
  2. 利用RecordRTC.js实现H5录音功能
  3. 【Machine Learning】初识机器学习
  4. Springboot 超简单实现在线预览,Word文档 doc、xlsx、pdf、txt等
  5. OTB2013平台跑OTB2015的results遇到的问题
  6. H - 互质数的个数(一)
  7. 高通骁龙410C开发板基础知识
  8. 服务器Nacos集群搭建及使用总结
  9. Matlab工具箱下载地址汇总
  10. 安卓开发下载图片保存到手机后图片没在相册看到的问题