iText-GM: IText5国密PDF电子签章,基于《GB/T 38540-2020 安全电子签章规范》开发

[](#itext-gm)iText-GM

[](#%E5%85%8D%E8%B4%A3%E5%A3%B0%E6%98%8E)免责声明

  1. 对使用本软件所产生的风险自行承担。作者不承担与使用本软件相关的任何责任。
  2. 代码包含第三方软件和组件,这些软件和组件受到其自身的许可证限制。应遵守这些许可证的要求。
  3. 代码可能存在错误、缺陷或安全漏洞。应自行评估和管理使用风险,并采取适当的安全措施。
  4. 作者保留随时更改或终止本软件的权利,并不承担因此而产生的任何责任。
  5. 测试用例中的证书,电子印章数据,印章图片均为测试数据,如名称等信息侵权,请联系我进行删除。
  6. 在使用本代码之前,请确保您已详细阅读并理解了免责声明中的条款。如果您不同意本免责声明的任何部分,请立即停止使用本代码。

IText国密电子签章,基于《GB/T 38540-2020 安全电子签章规范》
准备条件:
1.签名验签服务器 2.SM2证书 3.电子印章数据(需SM2证书绑定在印章数据里,完成制章) 4.签名验签服务器SDK(调用服务器进行签名)

[](#%E9%AA%8C%E7%AD%BE%E5%9C%B0%E5%9D%80httpsdzyzshgovcnlogincode105)验签地址:https://dzyz.sh.gov.cn/login?code=105
[](#pdf-gbt-38540-2020-%E7%AD%BE%E7%BD%B2)PDF 《GB/T 38540-2020》 签署

GetPdfHashParamVo paramVo = new GetPdfHashParamVo();
Path pdf = Paths.get("src/main/resources", "test.pdf");
paramVo.setPdf(Files.readAllBytes(pdf));
paramVo.setPageNo(1);
paramVo.setLlx(240);
paramVo.setLly(290);
paramVo.setUrx(paramVo.getLlx() + 120);
paramVo.setUry(paramVo.getLly() + 120);
Path seal = Paths.get("src/main/resources", "深圳测试科技有限公司.seal");
paramVo.setSeal(SESeal.getInstance(Files.readAllBytes(seal)));
paramVo.setLocation("深圳");
paramVo.setReason("国密电子签章测试");
// 创建签名域,获取pdf文件摘要
GetPdfHash getPdfHash = ITextGM.getPdfHash(paramVo);
TSAClient tsaClient = new GMTSAClient(new URL("http://1.12.67.126:8082/tsa/sign?type=SM2"), null, null,
new SM3.Digest());
PrivateKey prvKey = PkiUtil.getPrivateKey(Base64.decodeBase64(privateKey));
X509Certificate signCert = PkiUtil.readX509Certificate(Base64.decodeBase64(cert));
// 签署摘要》》》下面方法仅用于测试,按照合规方面,需要使用国家认可的签名验签服务器以及国家认可的CA机构的SM2证书
SESV4Container signature = new SESV4Container(prvKey, paramVo.getSeal(), signCert);
GMTimeStampHook timeStampHook = new GMTimeStampHook(tsaClient);
signature.setTimeStampHook(timeStampHook);
byte[] p7 = signature.sign(getPdfHash.getDigesHash(), "Signature.xml");
// 签署pdf
byte[] signSuccess = ITextGM.signDeferred(getPdfHash.getEmptySignaturePdf(), p7, getPdfHash.getFieldName());
FileUtils.writeByteArrayToFile(new File("src/main/resources/sign.pdf"), signSuccess);

[](#pdf-gbt-38540-2020-%E5%88%86%E7%A6%BB%E5%BC%8F%E7%AD%BE%E5%90%8D%E5%AE%9E%E9%99%85%E4%BD%BF%E7%94%A8%E8%BF%87%E7%A8%8B%E5%8F%AA%E9%9C%80%E5%AF%B9byte-p1--getpdfhashgettbs_signgetencoded-%E4%BB%8E%E4%BD%A0%E7%9A%84%E7%AD%BE%E5%90%8D%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%8E%B7%E5%8F%96p1%E7%AD%BE%E5%90%8D%E7%BB%93%E6%9E%9C%E5%8D%B3%E5%8F%AF%E5%AE%8C%E6%88%90%E5%9B%BD%E5%AF%86%E7%94%B5%E5%AD%90%E7%AD%BE%E7%AB%A0)PDF 《GB/T 38540-2020》 分离式签名,实际使用过程,只需对byte[] p1 = getPdfHash.getTBS_Sign().getEncoded() 从你的签名服务器获取p1签名结果,即可完成国密电子签章

GetPdfHashParamVo paramVo = new GetPdfHashParamVo();
Path pdf = Paths.get("src/main/resources", "test.pdf");
paramVo.setPdf(Files.readAllBytes(pdf));
paramVo.setPageNo(1);
paramVo.setLlx(240);
paramVo.setLly(290);
paramVo.setUrx(paramVo.getLlx() + 120);
paramVo.setUry(paramVo.getLly() + 120);
Path seal = Paths.get("src/main/resources", "深圳测试科技有限公司.seal");
paramVo.setSeal(SESeal.getInstance(Files.readAllBytes(seal)));
paramVo.setLocation("深圳");
paramVo.setReason("国密电子签章测试");
// 创建签名域,获取pdf文件摘要,组装待签名数据
GetPdfHash getPdfHash = ITextGM.getPdfHash(paramVo);
TSAClient tsaClient = new GMTSAClient(new URL("http://1.12.67.126:8082/tsa/sign?type=SM2"), null, null,
new SM3.Digest());
PrivateKey prvKey = PkiUtil.getPrivateKey(Base64.decodeBase64(privateKey));
X509Certificate signCert = PkiUtil.readX509Certificate(Base64.decodeBase64(cert));
GMTimeStampHook timeStampHook = new GMTimeStampHook(tsaClient);
// 以下为模拟外部签名测试,电子签章请使用符合国家规范具有国家型号证书的设备进行
SESV4ContainerV2 signV2 = new SESV4ContainerV2(paramVo.getSeal(), signCert, timeStampHook);
/**
* 模拟签名服务器进行签名,实际使用过程,只需要使用签名服务器对getPdfHash.getTBS_Sign().getEncoded()
* 进行一个p1签名即可
*/
byte[] p1 = PkiUtil.sign(prvKey, "SM3WithSM2", getPdfHash.getTBS_Sign().getEncoded());
// 组装电子签章数据
byte[] p7 = signV2.sign(getPdfHash.getTBS_Sign(), p1);
// 签署pdf
byte[] signSuccess = ITextGM.signDeferred(getPdfHash.getEmptySignaturePdf(), p7, getPdfHash.getFieldName());
FileUtils.writeByteArrayToFile(new File("src/main/resources/signPdf2.pdf"), signSuccess);

[](#pdf-gbt-38540-2020%E7%AD%BE%E7%BD%B2%E6%95%88%E6%9E%9C)PDF 《GB/T 38540-2020》签署效果

输入图片说明

[](#pdf-gbt-38540-2020%E9%AA%8C%E7%AD%BE%E6%95%88%E6%9E%9C)PDF 《GB/T 38540-2020》验签效果

输入图片说明

[](#%E6%84%9F%E8%B0%A2)感谢

https://gitee.com/ofdrw/ofdrw

[](#itext-rsa%E5%88%86%E7%A6%BB%E5%BC%8F%E7%AD%BE%E5%90%8D)IText RSA分离式签名

[](#%E5%88%86%E7%A6%BB%E5%BC%8F%E7%AD%BE%E5%90%8D%E5%9C%BA%E6%99%AF%E4%BB%8E%E5%A4%96%E9%83%A8%E8%AE%BE%E5%A4%87%E8%8E%B7%E5%8F%96p1%E6%95%B0%E6%8D%AE%E4%BE%8B%E5%A6%82ukey%E7%AD%BE%E5%90%8D%E9%AA%8C%E7%AD%BE%E6%9C%8D%E5%8A%A1%E5%99%A8kms%E7%B3%BB%E7%BB%9F)分离式签名,场景:从外部设备获取p1数据,例如ukey,签名验签服务器,KMS系统

GetPdfHashParamVo paramVo = new GetPdfHashParamVo();
Path pdf = Paths.get("src/main/resources", "test.pdf");
paramVo.setPdf(Files.readAllBytes(pdf));
paramVo.setPageNo(1);
paramVo.setLlx(240);
paramVo.setLly(290);
paramVo.setUrx(paramVo.getLlx() + 120);
paramVo.setUry(paramVo.getLly() + 120);
paramVo.setLocation("深圳南山区");
paramVo.setReason("分离式签名测试");
paramVo.setHashAlgorithm("SHA256");
Path sealImage = Paths.get("src/main/resources", "深圳测试科技有限公司_公章.png");
paramVo.setSignImage(Files.readAllBytes(sealImage));
// 创建签名域,获取pdf文件摘要
GetPdfHash getPdfHash = ITextSignHashUtil.getPdfHash(paramVo);
TSAClient tsaClient = new TSAClientBouncyCastle("http://1.12.67.126:8082/tsa/sign?type=RSA", null, null, 4096,
"SHA256");
PrivateKey prvKey = PkiUtil.getPrivateKey(Base64.decodeBase64(pkStr));
X509Certificate signCert = PkiUtil.readX509Certificate(Base64.decodeBase64(certStr));
// 签署p1,以下为模拟外部签名测试
byte[] p1 = PkiUtil.sign(prvKey, "SHA256WithRSA", getPdfHash.getSignHash());
// 签署p7
byte[] p7 = ITextSignHashUtil.signHash(getPdfHash.getDigesHash(), p1,
PkiUtil.getCertificateChain(signCert.getEncoded()), "SHA256", tsaClient);
// 签署pdf
byte[] signSuccess = ITextGM.signDeferred(getPdfHash.getEmptySignaturePdf(), p7, getPdfHash.getFieldName());
FileUtils.writeByteArrayToFile(new File("src/main/resources/sign_hash.pdf"), signSuccess);

[](#adobe%E9%AA%8C%E7%AD%BE%E6%95%88%E6%9E%9C)Adobe验签效果

输入图片说明


原网址: 访问
创建于: 2024-06-11 17:09:09
目录: default
标签: 无

请先后发表评论
  • 最新评论
  • 总共0条评论