BC:BouncyCastle,开源第三方安全组件,支持SM3摘要,尚不支持sm2
OIDS:
SM3withSM2 OID 为1.2.156.10197.1.501。
SM2的公钥参数OID为1.2.156.10197.1.301
<QQ:22066821>
正常的SHA1withRSA证书是这样的:
X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(new X500Name(issuer), serial, notBefore,notAfter, new X500Name(subject), publicKey); // "SHA1withRSA" ContentSigner sigGen = new JcaContentSignerBuilder(alg).setProvider("BC").build(privKey); X509CertificateHolder holder = builder.build(sigGen); CertificateFactory cf = CertificateFactory.getInstance("X.509"); InputStream is1 = new ByteArrayInputStream(holder.toASN1Structure().getEncoded()); X509Certificate theCert = (X509Certificate) cf.generateCertificate(is1); is1.close();
重点是new JcaContentSignerBuilder(alg),把SHA1withRSA更换成SM3withSM2,查看区别,
打开JcaContentSignerBuilder:
public JcaContentSignerBuilder(String signatureAlgorithm) { this.signatureAlgorithm = signatureAlgorithm; this.sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm); }
再打开DefaultSignatureAlgorithmIdentifierFinder,会发现
algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption); algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption); algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
再看PKCSObjectIdentifiers
static final ASN1ObjectIdentifier pkcs_1 = new ASN1ObjectIdentifier("1.2.840.113549.1.1"); /** PKCS#1: 1.2.840.113549.1.1.1 */ static final ASN1ObjectIdentifier rsaEncryption = pkcs_1.branch("1"); /** PKCS#1: 1.2.840.113549.1.1.2 */ static final ASN1ObjectIdentifier md2WithRSAEncryption = pkcs_1.branch("2"); /** PKCS#1: 1.2.840.113549.1.1.3 */ static final ASN1ObjectIdentifier md4WithRSAEncryption = pkcs_1.branch("3"); /** PKCS#1: 1.2.840.113549.1.1.4 */ static final ASN1ObjectIdentifier md5WithRSAEncryption = pkcs_1.branch("4"); /** PKCS#1: 1.2.840.113549.1.1.5 */ static final ASN1ObjectIdentifier sha1WithRSAEncryption = pkcs_1.branch("5");
于是乎,我们似乎明白了,用OID可以构造SM3withSM2的ASN1ObjectIdentifier,只需改动下
DefaultSignatureAlgorithmIdentifierFinder就可以实现。
考虑到BC的jar包是经过sun签名的,如果全部重新编译,会有一系列的问题,至少我还不知道怎么去找sun签名(有人能告知吗?)
采取第二方案,扩展JcaContentSignerBuilder,做的过程中发现JcaContentSignerBuilder中的OperatorHelper无法在包外引用,
于是在org.bouncycastle.operator.jcajce包中扩展,又发现这样做过不了sun的签名检查,怒了......彻底修改包名,
把OperatorHelper也重写,于是乎就有了JcaContentSignerBuilderXA,OperatorHelperXA。
现在,BC签名工具认识SM3withSM2了,具体的实现就靠加密机了,在自己的provider中加入
put("Signature.SM3withSM2", "com.xahtss.jceprovider.sign.SM3withSM2"); put("Signature.1.2.156.10197.1.501", "com.xahtss.jceprovider.sign.SM3withSM2");
在实现类中完成签名操作就可以了。
<生成的证书尚未经过检验>