使用BC库加解密 国密SM2踩坑指南

本文介绍了在使用BouncyCastle(BC)库进行国密SM2加密解密过程中遇到的问题,包括与前端SM2加密不兼容、密钥格式差异、密文排列方式不一致及解密时额外的04开头问题。为解决这些问题,作者提供了引入依赖、处理密钥格式、修改密文排列方式和处理解密前的04前缀等解决方案。
摘要由CSDN通过智能技术生成

 国密SM2 BC库踩坑

SM2加密解密网上很多人都是bouncycastle库,但我实际使用的时候却遇到了很多坑

1、和前端SM2不适配,前端和后端能分别使用SM2加密解密,前端加密后端却无法解密

2、前端生成加密有0-C1C2C3;1-C1C3C2两种模式可选,但使用BC库却完全没有相关方法,甚至一开始我都不知道这是干什么的

3、搞清楚加密模式了,用前端生成的密钥对,放到后端去用居然还会报错

1.引入依赖

<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId>bcprov-jdk15on</artifactId>
	<version>1.57</version>
</dependency>
<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId>bcprov-ext-jdk15on</artifactId>
	<version>1.57</version>
</dependency>

公共常量

    /**sm2曲线参数名称*/
    public static final String CRYPTO_NAME_SM2 = "sm2p256v1";
    /**sm2-签名id*/
    public static final String SIGN_ID = "1234567812345678";

前端sm加密库用sm-crypto

2.生成密钥对,此处需要注意BC库的密钥格式和标准密钥有一定差别,注意看注释

/**
     * 获取sm2密钥对
     * BC库使用的公钥=64个字节+1个字节(04标志位),BC库使用的私钥=32个字节
     * SM2秘钥的组成部分有 私钥D 、公钥X 、 公钥Y , 他们都可以用长度为64的16进制的HEX串表示,
     * <br/>SM2公钥并不是直接由X+Y表示 , 而是额外添加了一个头,当启用压缩时:公钥=有头+公钥X ,即省略了公钥Y的部分
     * @param compressed 是否压缩公钥(加密解密都使用BC库才能使用压缩)
     * @return
     */
    public static KeyPairOfString getSm2Keys(boolean compressed){
        //获取一条SM2曲线参数
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName(CRYPTO_NAME_SM2);
        //构造domain参数
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
        //1.创建密钥生成器
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
        //2.初始化生成器,带上随机数
        try {
            keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
        } catch (NoSuchAlgorithmException e) {
            logger.error("生成公私钥对时出现异常:", e);
        }
        //3.生成密钥对
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
        ECPublicKeyParameters publicKeyParameters = (ECPublicKeyParameters)asymmetricCipherKeyPair.getPublic();
        ECPoint ecPoint = publicKeyParameters.getQ();
        // 把公钥放入map中,默认压缩公钥
        // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
        String publicKey = Hex.toHexString(ecPoint.getEncoded(compressed));
        ECPrivateKeyParameters privateKeyParameters = (ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate();
        BigInteger intPrivateKey = privateKeyParameters.getD();
        // 把私钥放入map中
        String privateKey = intPrivateKey.toString(16);
        logger.debug("\npublicKey:{}\nprivateKey:{}", publicKey, privateKey);
        return new KeyPairOfString(publicKey, privateKey);
    }


/**
 * 密钥对保存类,保存一对
  • 66
    点赞
  • 81
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值