前言:最近做无纸化项目,需要用到电子签名,而网上基本上只有RSA算法的文章,所以看了下itext签名的部分源码,修改出来的sm2算法签名,分为两种,分离签名和后台私钥签名,这里放出来的是后台私钥签名
修改如下:
//调用方法前加入国密的oid,这里用到反射
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 allowedDigests = DigestAlgorithms.class.getDeclaredField("allowedDigests"); allowedDigests.setAccessible(true); HashMap<String, String> allowedDigestsNames = (HashMap<String, String>) allowedDigests.get(null); allowedDigestsNames.put("SM3", "1.2.156.10197.1.401"); 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");
//SM3的摘要算法 ExternalDigest digest = new ExternalDigest() { @Override public MessageDigest getMessageDigest(String hashAlgorithm) throws GeneralSecurityException { return MessageDigest.getInstance("SM3", BC); } }; //私钥签名,实现ExternalSignature 接口 把官方 PrivateKeySignature的内容全部复制过来,重点在构造方法加入SM2和SM3 public Sm2PrivateKeySignature(PrivateKey pk, String provider) { this.pk = pk; this.provider = provider; this.hashAlgorithm = DigestAlgorithms.getDigest(DigestAlgorithms.getAllowedDigests("SM3")); encryptionAlgorithm = "SM2"; } //修改 Itext的 PdfPKCS7 类修改 setExternalDigest方法,加入 sm2 sm3的 oid public void setExternalDigest(byte digest[], byte RSAdata[], String digestEncryptionAlgorithm) { externalDigest = digest; externalRSAdata = RSAdata; if (digestEncryptionAlgorithm != null) { if (digestEncryptionAlgorithm.equals("RSA")) { this.digestEncryptionAlgorithmOid = SecurityIDs.ID_RSA; } else if (digestEncryptionAlgorithm.equals("DSA")) { this.digestEncryptionAlgorithmOid = SecurityIDs.ID_DSA; } else if (digestEncryptionAlgorithm.equals("ECDSA")) { this.digestEncryptionAlgorithmOid = SecurityIDs.ID_ECDSA; } else if (digestEncryptionAlgorithm.equals("SM2")) { //sm2 this.digestEncryptionAlgorithmOid = GMObjectIdentifiers.sm2sign_with_sm3.getId(); } else if (digestEncryptionAlgorithm.equals("SM3")) { //sm3 this.digestEncryptionAlgorithmOid = GMObjectIdentifiers.sm3.getId(); } else throw new ExceptionConverter(new NoSuchAlgorithmException( MessageLocalization.getComposedMessage("unknown.key.algorithm.1", digestEncryptionAlgorithm))); } }
//把MakeSignature类里signDetached签名方法的 setExternalDigest替换为上面修改过的 ,这里最好重写一遍
提供完整的签名例子和sm2时间戳,sm2测试p12证书
demo地址:https://gitee.com/caoxusheng/itext5-sm2/
sm2时间戳地址:http://47.98.124.142:9091/service/tsa?type=sm2
测试证书颁发地址:可颁发 RSA算法和SM2算法 http://47.98.124.142:9091/cert/applyCert
由于sm2签名在adobe pdf上识别不出来会显示无效,这里可以使用CFCA的验签平台 https://verify.cfca.com.cn/VerifySignWeb/frame.do
验签结果: