java生成国密sm2密钥对

1430人浏览 / 0人评论

一、环境

JDK1.8、IDEA、BouncyCastle1.62

二、密钥对生成

1.生成SM2密钥对:

@Slf4j
public class CryptoTest {

    static {
        Security.insertProviderAt(new BouncyCastleProvider(), 1);
    }

    @Test
    public void testGenSm2Key1() throws Exception {
        // 获取SM2椭圆曲线的参数
        ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
        X9ECParameters params = CustomNamedCurves.getByName(sm2Spec.getName());
        log.info("p={}", params.getCurve().getField().getCharacteristic().toString(16));
        log.info("a={}", params.getCurve().getA().toBigInteger().toString(16));
        log.info("b={}", params.getCurve().getB().toBigInteger().toString(16));
        log.info("Gx={}", params.getG().getXCoord().toBigInteger().toString(16));
        log.info("Gy={}", params.getG().getYCoord().toBigInteger().toString(16));
        log.info("n={}", params.getN().toString(16));
        log.info("h={}", params.getH().toString(16));
        // 获取一个椭圆曲线类型的密钥对生成器
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC");
        // 使用SM2参数初始化生成器
        kpg.initialize(sm2Spec, new SecureRandom());
        // 获取密钥对
        KeyPair keyPair = kpg.generateKeyPair();

        PrivateKey privateKey = keyPair.getPrivate();
        log.info("私钥信息:{}, {}", privateKey.getAlgorithm(), privateKey.getFormat());
        log.info("私钥:{}", privateKey.getEncoded());
        log.info("私钥:{}", Base64Encoder.encode(privateKey.getEncoded()));
        PublicKey publicKey = keyPair.getPublic();
        log.info("公钥信息:{}, {}", publicKey.getAlgorithm(), publicKey.getFormat());
        log.info("公钥:{}", publicKey.getEncoded());
        log.info("公钥:{}", Base64Encoder.encode(publicKey.getEncoded()));
    }

}

其中sm2p256v1表明了BC定义的国密SM2推荐的椭圆曲线参数,从下面的输出结果也可以看出来。

2.输出结果:

p=fffffffeffffffffffffffffffffffffffffffff00000000ffffffffffffffff
a=fffffffeffffffffffffffffffffffffffffffff00000000fffffffffffffffc
b=28e9fa9e9d9f5e344d5a9e4bcf6509a7f39789f515ab8f92ddbcbd414d940e93
Gx=32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7
Gy=bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0
n=fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123
h=1
私钥信息:EC, PKCS#8
私钥:[48, -127, -109, 2, 1, 0, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -127, 28, -49, 85, 1, -126, 45, 4, 121, 48, 119, 2, 1, 1, 4, 32, 26, -81, -13, -13, 75, -9, -36, -74, -28, 55, -16, 74, -1, -94, -126, 31, 34, -17, 125, 21, -117, 127, 100, -94, -44, -87, 83, -94, -44, -13, 78, -94, -96, 10, 6, 8, 42, -127, 28, -49, 85, 1, -126, 45, -95, 68, 3, 66, 0, 4, 6, 11, -36, 44, 70, 21, -9, 101, 104, -80, -50, 102, -13, 88, 116, -20, 120, -78, -87, -82, -80, -34, 3, -70, 14, 73, 55, -20, 42, -1, 82, -39, -25, 46, -27, -91, -56, 5, 120, -68, 21, 69, -26, -72, -73, -89, 77, 24, 33, -29, -107, 124, 30, 124, 17, 88, 58, -43, 38, 72, 77, -10, -50, -111]
私钥:MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgGq/z80v33LbkN/BK/6KCHyLvfRWLf2Si1KlTotTzTqKgCgYIKoEcz1UBgi2hRANCAAQGC9wsRhX3ZWiwzmbzWHTseLKprrDeA7oOSTfsKv9S2ecu5aXIBXi8FUXmuLenTRgh45V8HnwRWDrVJkhN9s6R
公钥信息:EC, X.509
公钥:[48, 89, 48, 19, 6, 7, 42, -122, 72, -50, 61, 2, 1, 6, 8, 42, -127, 28, -49, 85, 1, -126, 45, 3, 66, 0, 4, 6, 11, -36, 44, 70, 21, -9, 101, 104, -80, -50, 102, -13, 88, 116, -20, 120, -78, -87, -82, -80, -34, 3, -70, 14, 73, 55, -20, 42, -1, 82, -39, -25, 46, -27, -91, -56, 5, 120, -68, 21, 69, -26, -72, -73, -89, 77, 24, 33, -29, -107, 124, 30, 124, 17, 88, 58, -43, 38, 72, 77, -10, -50, -111]
公钥:MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEBgvcLEYV92VosM5m81h07Hiyqa6w3gO6Dkk37Cr/UtnnLuWlyAV4vBVF5ri3p00YIeOVfB58EVg61SZITfbOkQ==

3.生成ASN1格式的私钥:

SM2的私钥是大于1且小于n-1的整数K,长度为256位,如上图:1AAFF3F...。

从上图还可以看出私钥的结构体中还包括了公钥数据,最后一行就是公钥。

4.生成ASN1格式的公钥:

SM2的公钥是SM2曲线上的一个点Q,由横、纵坐标两个分量来表示为(x,y),每个分量的长度为256位。

解析时还需关注公钥数据是否是以0x04开头,0x04表示非压缩模式。

 

参考资料

[1] Public-Key Cryptography Standards (PKCS) #8

[2] ASN.1查看工具

全部评论