使用国密SM2进行接口对接遇到的问题

需求:对方提供的是128位公钥和64位私钥,都是16进制数据,然后我这边进行加密,再把数据进行传输。
下面展示一些 我自己思考的测试类,其中生成16进制公私钥的代码是对方提供,但不能用于加解密,所以我转换成了正常形式。
SM2Utils的国密算法工具类,直接在网上找一份,能够提供加解密功能就可以,我这里就不添加了。
直接上代码:

import com.zefu.inter.util.SM2Utils;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
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.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;

import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;

public class Test {

    private static BigInteger n = new BigInteger("FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "7203DF6B" + "21C6052B" + "53BBF409" + "39D54123", 16);
    private static BigInteger p = new BigInteger("FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF" + "FFFFFFFF", 16);
    private static BigInteger a = new BigInteger("FFFFFFFE" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "FFFFFFFF" + "00000000" + "FFFFFFFF" + "FFFFFFFC", 16);
    private static BigInteger b = new BigInteger("28E9FA9E" + "9D9F5E34" + "4D5A9E4B" + "CF6509A7" + "F39789F5" + "15AB8F92" + "DDBCBD41" + "4D940E93", 16);
    private static BigInteger gx = new BigInteger("32C4AE2C" + "1F198119" + "5F990446" + "6A39C994" + "8FE30BBF" + "F2660BE1" + "715A4589" + "334C74C7", 16);
    private static BigInteger gy = new BigInteger("BC3736A2" + "F4F6779C" + "59BDCEE3" + "6B692153" + "D0A9877C" + "C62A4740" + "02DF32E5" + "2139F0A0", 16);

    private static ECDomainParameters ecc_bc_spec;

    private static SecureRandom random = new SecureRandom();
    private static ECCurve.Fp curve;
    private static ECPoint G;

    static  {
        curve = new ECCurve.Fp(p, a, b);
        G = curve.createPoint(gx, gy);
        ecc_bc_spec = new ECDomainParameters(curve, G, n);
    }
    public static void main(String[] args) {

        X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
        ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
        try {
            keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
        BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        String privateKeyHex = privatekey.toString(16);
        // 公钥,16进制格式,发给前端,格式如04813d4d97ad31bd9d18d785f337f683233099d5abed09cb397152d50ac28cc0ba43711960e811d90453db5f5a9518d660858a8d0c57e359a8bf83427760ebcbba
        ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
        String publicKeyHex = Hex.toHexString(ecPoint.getEncoded(false));
        // 16进制128位公钥加密会报错 java.lang.IllegalArgumentException: Invalid point encoding 0x-2d
        // 但有时为了数据安全,有对接时也会转换成此形式
        System.out.println("16进制私钥privateKeyHex="+privateKeyHex);
        System.out.println("16进制加密后publicKeyHex="+publicKeyHex);
        // 自己产生的话,可以考虑是否转换成正常形式传输和加密解密
        byte[] bytes = privatekey.toByteArray();
        String p = new String(Base64.getEncoder().encode(bytes), StandardCharsets.UTF_8);
        ECPoint normalize = G.multiply(privatekey).normalize();
        byte[] encoded = normalize.getEncoded(true);
        String s = new String(Base64.getEncoder().encode(encoded), StandardCharsets.UTF_8);
        System.out.println("普通形式公钥="+s);
        System.out.println("普通形式私钥="+p);
        String encrypt = SM2Utils.encrypt("测试", s);
        String decrypt = SM2Utils.decrypt(encrypt, p);
        System.out.println("普通形式加密后="+encrypt);
        System.out.println("普通形式解密后="+decrypt);

        // 对方提供的16进制128位公钥
        byte[] encode = Hex.decode("0488bd526b852922a1f73075d42f5508a6877fc0927017015eb459f0ee41a825de3fb64505aef1e5c5dc09e44fa83f274bb67d929d99b50d01d5568523ce7e8106");
        String s2 = new String(Base64.getEncoder().encode(encode), StandardCharsets.UTF_8);
        System.out.println("s2="+s2);
        String encrypt2 = SM2Utils.encrypt("测试", "BIi9UmuFKSKh9zB11C9VCKaHf8CScBcBXrRZ8O5BqCXeP7ZFBa7x5cXcCeRPqD8nS7Z9kp2ZtQ0B1VaFI85+gQY=");
        System.out.println("加密="+encrypt2);
        // 对方提供的16进制64位私钥
        BigInteger bigInteger = new BigInteger("c1baa288dfb71dbab3c6c0ad77319499d747aab79fafb3149cc5ef23711f795", 16);
        System.out.println("bigInteger="+bigInteger);
        byte[] bytes2 = bigInteger.toByteArray();
        String p2 = new String(Base64.getEncoder().encode(bytes2), StandardCharsets.UTF_8);
        String decrypt2 = SM2Utils.decrypt(encrypt2, p2);
        System.out.println("解密="+decrypt2);
    }

}

测试的结果

16进制私钥privateKeyHex=96e251b3b82b9b198294cb287f82b7664be83b2090af24a0876a2cd3fde4cc7
16进制加密后publicKeyHex=04133e0fa3e7a60f98020b03e0750fb9c8ab238cabaec43cd5d68102c15f295d61dc33fd9911f714df98160b267220b701ef1289655d054751d1262619b11ec788
普通形式公钥=AhM+D6Pnpg+YAgsD4HUPucirI4yrrsQ81daBAsFfKV1h
普通形式私钥=CW4lGzuCubGYKUyyh/grdmS+g7IJCvJKCHaizT/eTMc=
解密成功
普通形式加密后=046cd9a3f615b6ea28395b08bbc0cccfead19df5dcb21ffb0762cad5a4377521aaf9b7262cead29b1395405babc0204c62db70d056a825e146c1832da7b48dffae93837292f15f0deb5d0827e3c24b9a0abb468ed3ce40db6db932e5dbb8b5f5c5e884ebe82467
普通形式解密后=测试
s2=BIi9UmuFKSKh9zB11C9VCKaHf8CScBcBXrRZ8O5BqCXeP7ZFBa7x5cXcCeRPqD8nS7Z9kp2ZtQ0B1VaFI85+gQY=
加密=04fee43f5e4b6b7ae702b0075ff8076a6d87cb585852e75cb381f7ffd0c1211e088dd58b664ccfa12e57111b62b8b8807ac293f72ba4cc36c4810e0920c37a141f1bbecdbe26efa2253a4ee56f5b31b7d0b22404a80ed5e84198b28bda3d1b8ea0331f60c4043e
bigInteger=5476633443977505618369540050644988899101043299003294044843441042303369738133
解密成功
解密=测试
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值