使用BC库时对PUBKEY的特殊处理

BouncyCastle库(后面简称BC)是我们在开发国密项目时最常用的库,没有之一。但BC库中公钥的表示方法是和标准有区别的,本文帮助你跳过这个坑。

先看一下比较常用的密钥对生成,和公钥提取:

public void printKey() {
        try{
            BouncyCastleProvider provider = new BouncyCastleProvider();
            X9ECParameters parameters = GMNamedCurves.getByName("sm2p256v1");
            ECParameterSpec ecParameterSpec = new ECParameterSpec(parameters.getCurve(),
                    parameters.getG(), parameters.getN(), parameters.getH());
            KeyFactory keyFactory = KeyFactory.getInstance("EC", provider);
            final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
            // 获取密钥对生成器
            final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", provider);
            SecureRandom random = new SecureRandom();
            // 使用SM2的算法区域初始化密钥生成器
            kpg.initialize(sm2Spec, random);
            // 获取密钥对
            KeyPair keyPair = kpg.generateKeyPair();
            //获取 64 位公钥
            BCECPublicKey publicKey = (BCECPublicKey) keyPair.getPublic();
            byte[] pubKeyCompress = publicKey.getQ().getEncoded(true); //压缩
            byte[] pubKey = publicKey.getQ().getEncoded(false); //不压缩
            System.out.println("pubkey Compressed : " + Tools.byteArrayToHexString(pubKeyCompress));
            System.out.println("pubkey : " + Tools.byteArrayToHexString(pubKey));
            //获取 32 位 私钥
            BCECPrivateKey privateKey = (BCECPrivateKey) keyPair.getPrivate();
            byte[] prvKey = privateKey.getD().toByteArray();
            System.out.println("prvKey : " + Tools.byteArrayToHexString(prvKey));

        } catch (InvalidAlgorithmParameterException e) {
            throw new RuntimeException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }

运行后打印如下:

pubkey Compressed : 0209F741685F2C0B9360BD95F26D5BCB158B617585620F2A3B122D0719D7196616
pubkey : 0409F741685F2C0B9360BD95F26D5BCB158B617585620F2A3B122D0719D7196616ED73EE4E483A2A7F4D14309953752A9231193E93551366FB2A15CB3B2DCD3FE2
prvKey : 038E63FD9D41850D4833007B9A5583B425A3022DCF36CCCEB18F118A7BA7DA0D

私钥是32位(HEX表示,两个字符表示一个byte),这个跟我们的理解是一致的。公钥就不一样了,压缩的情况下,公钥有33位,前面多了一个02字节。不压缩的情况下,公钥有65位,前面多了一个04 。这一点一定要注意,当需要使用别的加密工具(例如UKEY进行加密)时,就要看别的加密工具输入的要求,如果输入的公钥是常规的64位,就需要将前面的04去掉。

类似的情况还表现在SM2加密的结果中,SM2加密结果的定义如下:

SM2Cipher::= SEQENCE{
  XCoordinate		INTEGER,					--x 分量 32字节(256位)
  YCoordinate		INTEGER,					--y 分量 32字节(256位)
  HASH				OCTET STRING SIZE(32),	 	--杂凑值 32字节(256位)
  CipherText		OCTET STRING 				--密文   等于明文长度	
}

理论上,SM2加密结果的长度应该比原文长96个字节(64个公钥+32个杂凑值)。但BC库加密出来的数据就会比原文长97个字节,因为他在公钥前面仍然加了一个04。当你使用BC加密的数据,拿到别的环境解密时,就要看是否需要包含这个04字节,不然就解密不出来;同理,当你使用别的加密工具加密出来的数据,希望用BC库来解密时,就要看看是否加上了这个04字节。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值