国密SM2,SM3,SM4在BC上的实现(一)

本文介绍了如何在BC(Bouncy Castle)框架上实现国密SM2、SM3和SM4算法,包括MAC、密钥生成、加解密、签名和数字证书的创建。特别地,文章讨论了SM2在PDF数字签名中的应用,并提供了项目结构图。
摘要由CSDN通过智能技术生成

SM2,SM3,SM4算法的实现在网络上实现有不少,但是实现只是加解密,签名等,如果说要生成国密数字证书就麻烦了,还有最近银行的项目上需要用ITEXT对pdf进行国密跟RSA证书数字签名,这个用SM2单独的签名是不能实现的,因为ITEXT签名是基于BC框架的,这里就是在BC框架上添加SM2,SM4算法,以及SM3摘要算法,在这里跟大家分享一下。
BC框架是基于JCA,JCE来实现的,关于JCA,JCE这里就不详述了。既然我们要添加这几种算法,我们要实现那几步呢?
1,实现MAC
2,实现SM2,SM3,SM4算法
3,SM2,SM4算法的密钥(KeyPairGenerator)
4,加解密(Cipher);
5,签名(Signature);
6,数字证书(Certificate)
话不多说,先上几张效果图。
一 ,SM2加解密
结果图

 public static String SM2_Cipher(boolean all,String enData) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        StringBuilder sb = new StringBuilder();
        byte[] sourceData = enData.getBytes();
        KeyPair keyPair = generateKeyPair(all?sb:null);
        Cipher cp1 = Cipher.getInstance("SM2");
        sb.append("public key = ");
        sb.append(bytesToHexString(keyPair.getPublic().getEncoded()));
        sb.append("\nprivate key = ");
        sb.append(bytesToHexString(keyPair.getPrivate().getEncoded()));
以下是使用Java实现国密SM2数字签名的示例代码: ```java import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.digests.SM3Digest; import org.bouncycastle.crypto.engines.SM2Engine; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyGenerationParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.signers.SM2Signer; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.util.encoders.Hex; import java.math.BigInteger; import java.security.Security; public class SM2SignDemo { public static void main(String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); // 生成密钥对 ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); ECKeyGenerationParameters keyGenerationParams = new ECKeyGenerationParameters( new ECDomainParameters(SM2Util.SM2_p, SM2Util.SM2_a, SM2Util.SM2_b, SM2Util.SM2_ecparams_G, SM2Util.SM2_n), SM2Util.SM2_random); keyPairGenerator.init(keyGenerationParams); AsymmetricCipherKeyPair keyPair = keyPairGenerator.generateKeyPair(); ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate(); ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic(); // 签名 SM2Signer signer = new SM2Signer(); signer.init(true, privateKey); byte[] msg = "Hello, world!".getBytes(); byte[] z = SM2Util.getSM2Z("1234567812345678".getBytes(), publicKey.getQ()); signer.update(z, 0, z.length); signer.update(msg, 0, msg.length); BigInteger[] sig = signer.generateSignature(); String signature = Hex.toHexString(sig[0].toByteArray()) + Hex.toHexString(sig[1].toByteArray()); System.out.println("Signature: " + signature); // 验证签名 signer.init(false, publicKey); signer.update(z, 0, z.length); signer.update(msg, 0, msg.length); System.out.println("Signature verification result: " + signer.verifySignature(sig[0], sig[1])); } } class SM2Util { static final BigInteger SM2_p = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16); static final BigInteger SM2_a = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16); static final BigInteger SM2_b = new BigInteger("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16); static final BigInteger SM2_n = new BigInteger("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16); static final BigInteger SM2_h = BigInteger.valueOf(1); static final BigInteger SM2_Gx = new BigInteger("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE171F996B8FEEF18EE", 16); static final BigInteger SM2_Gy = new BigInteger("BC3736A2F4F6779C59BDCEE36B692153D0A5D10B213A3D89B0C7C5AE0FD36B88", 16); static final ECDomainParameters SM2_ecparams_G = new ECDomainParameters(SM2_p, SM2_a, SM2_b, new org.bouncycastle.math.ec.ECPoint.SecP256K1(SM2_p, SM2_a, SM2_b, new BigInteger[]{SM2_Gx, SM2_Gy}, SM2_n, SM2_h)); static final SM3Digest SM2_256_DIGEST = new SM3Digest(); static final byte[] SM2_DEFAULT_USER_ID = "1234567812345678".getBytes(); static final SecureRandom SM2_random = new SecureRandom(); /** * 获取SM2签名中的Z值 */ static byte[] getSM2Z(byte[] userId, org.bouncycastle.math.ec.ECPoint userKey) { byte[] userIdDigest = new byte[32]; SM2_256_DIGEST.update(userId, 0, userId.length); SM2_256_DIGEST.doFinal(userIdDigest, 0); byte[] x = userKey.getXCoord().getEncoded(); byte[] y = userKey.getYCoord().getEncoded(); byte[] z = new byte[userIdDigest.length + x.length + y.length]; System.arraycopy(userIdDigest, 0, z, 0, userIdDigest.length); System.arraycopy(x, 0, z, userIdDigest.length, x.length); System.arraycopy(y, 0, z, userIdDigest.length + x.length, y.length); return z; } } ``` 在上面的示例代码中,我们使用了BouncyCastle库来实现SM2数字签名。其中,`SM2Signer`类用于签名和验签,`ECDomainParameters`类用于定义椭圆曲线参数,`SM3Digest`类用于计算摘要,`SM2Util`类用于定义一些常量和工具方法。 在签名过程中,我们需要先计算出SM2签名中的Z值,然后将Z值和待签名的消息传入`SM2Signer`类中进行签名签名结果为两个整数,需要将它们转换为十六进制字符串拼接在一起即可得到最终的签名值。 在验签过程中,我们需要使用相同的Z值和待验签的消息来初始化`SM2Signer`类,然后将签名值传入进行验签。如果验签成功,`verifySignature`方法会返回`true`,否则返回`false`。 需要注意的是,以上示例代码仅供参考,实际使用时需要根据具体需求进行修改和优化。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值