Java笔记-SM2(国密2)的调用及SM2SM3SM4使用场景

Posted IT1995

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java笔记-SM2(国密2)的调用及SM2SM3SM4使用场景相关的知识,希望对你有一定的参考价值。

注意:本博文仅仅说明SM2的使用,应用场景等,不研究其算法。

SM2是非对称加密算法,对应应用层程序员来说,使用逻辑和RSA一样。

他的最主要的功能:

①非对称加密;

②签名和验签

对于应用层程序员来说,必须熟悉他的使用,以及他的应用领域,一般在写一个安全的应用时,如果单单使用SM2是不安全的,基本上SM2、SM3、SM4都会同时使用。一般都是用SM4对数据内容加密,使用SM3,对内容进行摘要,再使用SM2,对摘要进行签名。这个是数据发送端做的事情。接收端,先用SM2,对摘要进行验签,验签成功后,就做到了防抵赖,对发送过来的内容进行SM3摘要,看下生成的摘要和验签后的摘要是否一致,用于防篡改。

大体逻辑就是这样的。

另外SM4在加密解密需要相同的密钥,这个我们可以通过编写密钥交换模块实现生成相同的密钥。用于SM4对称加密。

对于应用层来说,说白了就是把RSA换成SM2、把MD5换成SM3,把AES换成SM4,这下大家明白了吧。

这里使用hutool这个库进行SM2的操作!

关于非对称加密的公钥和私钥,可以使用hutool生成,也可以使用openssl生成

openssl生成SM2公钥私钥:

openssl ecparam -genkey -name SM2 -out priv.key
openssl ec -in priv.key -pubout -out pub.key

生成的密钥如下:

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE5SMhCzQHRkg5cjVY4NgnZbniyslJ
G9hsmcibn8Q/vpqUOV7jE428SuQ9qo/gH9US3oVoEC40xmmJ6yswZhG1GA==
-----END PUBLIC KEY-----
-----BEGIN EC PARAMETERS-----
BggqgRzPVQGCLQ==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIE8DQeWXexdeDsDh/e/SeZsT3SXFFxYTPvQrp2wO3Zc9oAoGCCqBHM9V
AYItoUQDQgAE5SMhCzQHRkg5cjVY4NgnZbniyslJG9hsmcibn8Q/vpqUOV7jE428
SuQ9qo/gH9US3oVoEC40xmmJ6yswZhG1GA==
-----END EC PRIVATE KEY-----

关于非对称还要注意几点:

公钥是通过私钥产生的;

公钥加密,私钥解密是加密的过程

私钥加密,公钥解密是签名的过程;

源码如下:

package cn.it1995;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;

import javax.swing.*;
import java.security.KeyPair;

public class Main 

    static String txt = "Hello World";

    /***
     * 随机生成的密钥对加密或解密
     */
    public static void test1()

        SM2 sm2 = SmUtil.sm2();

        System.out.println("私钥:" + sm2.getPrivateKey());
        System.out.println("公钥:" + sm2.getPublicKey());

        String encryptStr = sm2.encryptBcd(txt, KeyType.PublicKey);
        String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));

        System.out.println("密文:" + encryptStr);
        System.out.println("明文:" + decryptStr);
    

    /***
     * 自定义密钥对加密或解密
     */
    public static void test2()

        KeyPair pair = SecureUtil.generateKeyPair("SM2");
        byte[] privateKey = pair.getPrivate().getEncoded();
        byte[] publicKey = pair.getPublic().getEncoded();

        System.out.println("私钥:");
        for(Integer i = 0; i < privateKey.length; i++)

            System.out.print(privateKey[i] + " ");
        

        System.out.println();
        System.out.println("公钥:");
        for(Integer i = 0; i < publicKey.length; i++)

            System.out.print(publicKey[i] + " ");
        
        System.out.println();

        SM2 sm2 = SmUtil.sm2(privateKey, publicKey);

        String encryptStr = sm2.encryptBcd(txt, KeyType.PublicKey);
        String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));

        System.out.println("密文:" + encryptStr);
        System.out.println("明文:" + decryptStr);
    

    /***
     * 使用OpenSSL生成的SM2公钥和私钥加密或解密
     */
    public static void test3()

        String privateKey = "MHcCAQEEIE8DQeWXexdeDsDh/e/SeZsT3SXFFxYTPvQrp2wO3Zc9oAoGCCqBHM9VAYItoUQDQgAE5SMhCzQHRkg5cjVY4NgnZbniyslJG9hsmcibn8Q/vpqUOV7jE428SuQ9qo/gH9US3oVoEC40xmmJ6yswZhG1GA==";
        String publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE5SMhCzQHRkg5cjVY4NgnZbniyslJG9hsmcibn8Q/vpqUOV7jE428SuQ9qo/gH9US3oVoEC40xmmJ6yswZhG1GA==";

        SM2 sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey));
        String encryptStr = sm2.encryptBcd(txt, KeyType.PublicKey);
        String decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(encryptStr, KeyType.PrivateKey));

        System.out.println("密文:" + encryptStr);
        System.out.println("明文:" + decryptStr);
    

    /***
     * 随机密钥 签名和验签
     */
    public static void test4()

        SM2 sm2 = SmUtil.sm2();
        String sign = sm2.signHex(HexUtil.encodeHexStr(txt));
        System.out.println("sign:" + sign);
        boolean verify = sm2.verifyHex(HexUtil.encodeHexStr(txt), sign);
        System.out.println("verify:" + verify);
    

    /***
     * 自定义密钥对 签名和验签
     */
    public static void test5()

        KeyPair pair = SecureUtil.generateKeyPair("SM2");
        final SM2 sm2 = new SM2(pair.getPrivate(), pair.getPublic());

        byte[] sign = sm2.sign(txt.getBytes());
        System.out.println("sign");
        for(Integer i = 0; i < sign.length; i++)

            System.out.print(sign[i] + " ");
        
        System.out.println();

        boolean verify = sm2.verify(txt.getBytes(), sign);
        System.out.print("verify:" + verify);
    

    /**
     * OpenSSL密钥对 签名和验签
     */
    public static void test6()

        String privateKey = "MHcCAQEEIE8DQeWXexdeDsDh/e/SeZsT3SXFFxYTPvQrp2wO3Zc9oAoGCCqBHM9VAYItoUQDQgAE5SMhCzQHRkg5cjVY4NgnZbniyslJG9hsmcibn8Q/vpqUOV7jE428SuQ9qo/gH9US3oVoEC40xmmJ6yswZhG1GA==";
        String publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE5SMhCzQHRkg5cjVY4NgnZbniyslJG9hsmcibn8Q/vpqUOV7jE428SuQ9qo/gH9US3oVoEC40xmmJ6yswZhG1GA==";

        SM2 sm2 = SmUtil.sm2(Base64.decode(privateKey), Base64.decode(publicKey));
        byte[] sign = sm2.sign(txt.getBytes());

        System.out.println("sign");
        for(Integer i = 0; i < sign.length; i++)

            System.out.print(sign[i] + " ");
        
        System.out.println();

        boolean verify = sm2.verify(txt.getBytes(), sign);
        System.out.print("verify:" + verify);
    

    /***
     * 分开的:私钥签名,公钥验签
     * 密钥使用OpenSSL生成
     */
    public static void test7()

        String privateKey = "MHcCAQEEIE8DQeWXexdeDsDh/e/SeZsT3SXFFxYTPvQrp2wO3Zc9oAoGCCqBHM9VAYItoUQDQgAE5SMhCzQHRkg5cjVY4NgnZbniyslJG9hsmcibn8Q/vpqUOV7jE428SuQ9qo/gH9US3oVoEC40xmmJ6yswZhG1GA==";
        String publicKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE5SMhCzQHRkg5cjVY4NgnZbniyslJG9hsmcibn8Q/vpqUOV7jE428SuQ9qo/gH9US3oVoEC40xmmJ6yswZhG1GA==";

        SM2 sm2Sign = SmUtil.sm2(Base64.decode(privateKey), null);
        sm2Sign.usePlainEncoding();
        byte[] sign = sm2Sign.sign(txt.getBytes(), null);

        System.out.println("sign");
        for(Integer i = 0; i < sign.length; i++)

            System.out.print(sign[i] + " ");
        
        System.out.println();

        SM2 sm2 = SmUtil.sm2(null, Base64.decode(publicKey));
        sm2.usePlainEncoding();
        boolean verify = sm2.verify(txt.getBytes(), sign);
        System.out.print("verify:" + verify);
    

    public void test8()


    

    public static void main(String[] args) 

        test1();
        System.out.println("--------------------华丽的分割线------------------------");
        test2();
        System.out.println("--------------------华丽的分割线------------------------");
        test3();
        System.out.println("--------------------华丽的分割线------------------------");
        test4();
        System.out.println("--------------------华丽的分割线------------------------");
        test5();
        System.out.println("--------------------华丽的分割线------------------------");
        test6();
        System.out.println("--------------------华丽的分割线------------------------");
        test7();
    

程序运行如下:

D:\\java8\\content\\bin\\java.exe -javaagent:D:\\idea\\content\\lib\\idea_rt.jar=50163:D:\\idea\\content\\bin -Dfile.encoding=UTF-8 -classpath D:\\java8\\content\\jre\\lib\\charsets.jar;D:\\java8\\content\\jre\\lib\\deploy.jar;D:\\java8\\content\\jre\\lib\\ext\\access-bridge-64.jar;D:\\java8\\content\\jre\\lib\\ext\\cldrdata.jar;D:\\java8\\content\\jre\\lib\\ext\\dnsns.jar;D:\\java8\\content\\jre\\lib\\ext\\jaccess.jar;D:\\java8\\content\\jre\\lib\\ext\\jfxrt.jar;D:\\java8\\content\\jre\\lib\\ext\\localedata.jar;D:\\java8\\content\\jre\\lib\\ext\\nashorn.jar;D:\\java8\\content\\jre\\lib\\ext\\sunec.jar;D:\\java8\\content\\jre\\lib\\ext\\sunjce_provider.jar;D:\\java8\\content\\jre\\lib\\ext\\sunmscapi.jar;D:\\java8\\content\\jre\\lib\\ext\\sunpkcs11.jar;D:\\java8\\content\\jre\\lib\\ext\\zipfs.jar;D:\\java8\\content\\jre\\lib\\javaws.jar;D:\\java8\\content\\jre\\lib\\jce.jar;D:\\java8\\content\\jre\\lib\\jfr.jar;D:\\java8\\content\\jre\\lib\\jfxswt.jar;D:\\java8\\content\\jre\\lib\\jsse.jar;D:\\java8\\content\\jre\\lib\\management-agent.jar;D:\\java8\\content\\jre\\lib\\plugin.jar;D:\\java8\\content\\jre\\lib\\resources.jar;D:\\java8\\content\\jre\\lib\\rt.jar;D:\\IDEAProject\\SM2Demo\\target\\classes;D:\\newGenRepository\\repository\\cn\\hutool\\hutool-all\\5.7.6\\hutool-all-5.7.6.jar;D:\\newGenRepository\\repository\\org\\bouncycastle\\bcprov-jdk15to18\\1.68\\bcprov-jdk15to18-1.68.jar cn.it1995.Main
私钥:EC Private Key [69:a6:2d:32:b5:e8:19:e0:69:a8:a1:f4:ad:2e:60:eb:9d:49:b2:2a]
            X: 8b9cd15f1f6cc97674c0f0dd1613890700805ecbfb7368eade20fa91565c1d49
            Y: 7ca52554e76f04471b69ef8b042080e596937d4d7fd3311c642d5b6a2b2c781d

公钥:EC Public Key [69:a6:2d:32:b5:e8:19:e0:69:a8:a1:f4:ad:2e:60:eb:9d:49:b2:2a]
            X: 8b9cd15f1f6cc97674c0f0dd1613890700805ecbfb7368eade20fa91565c1d49
            Y: 7ca52554e76f04471b69ef8b042080e596937d4d7fd3311c642d5b6a2b2c781d

密文:043AB278DCB9C19E64251B406DB855873AB65BD302CD321ACB509A12449559AD67C7EB8CA0FBE290D06BA9750D38EB70A69DC14C0ECF01803DA4971D471F0C3303D0C69A1001DACC048AECAA0F191196041DA367BBEB100F7C02506B57F51568F17A7C1024E90D30F7D20006
明文:Hello World
--------------------华丽的分割线------------------------
私钥:
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 -88 107 3 126 93 -49 -79 -127 52 60 55 125 -50 38 78 68 -34 81 -84 -97 -82 69 0 3 -72 40 23 15 -41 112 -96 -97 -96 10 6 8 42 -127 28 -49 85 1 -126 45 -95 68 3 66 0 4 -35 21 15 107 92 -61 82 34 -25 34 24 42 122 -18 88 117 -49 -20 50 -92 -10 -99 77 46 -80 -20 -121 99 13 -114 54 -105 34 -1 -72 77 7 -87 -112 84 -91 64 71 91 40 -78 -126 119 10 -113 97 6 94 -47 12 -8 37 -11 -61 81 96 14 -51 -97 
公钥:
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 -35 21 15 107 92 -61 82 34 -25 34 24 42 122 -18 88 117 -49 -20 50 -92 -10 -99 77 46 -80 -20 -121 99 13 -114 54 -105 34 -1 -72 77 7 -87 -112 84 -91 64 71 91 40 -78 -126 119 10 -113 97 6 94 -47 12 -8 37 -11 -61 81 96 14 -51 -97 
密文:049625A78A0D48E6C41F55A097E6039C84EE6EF402477A2ACB9FF3D319913731750F3ADAB9186190F0B9EDFBC91B66867A323FFE1C01B5F543ED52D27CFAFBE6E9D37FF3B698D4931196D8D68E81A70726DA67F4C4E59F0007AAA06459704DB40DF8E21E81A9970D35EFD0ED
明文:Hello World
--------------------华丽的分割线------------------------
密文:04D10EE79A33A1A8CE7407544908732F039C244C6FD04D59D5586B701455432209FA93B57142410E69B2BF1B8C8F8176FBDC8AB92FE07BD8C67F3FB121E10E58F1D66AD53E8FDB9408E9CF86E0B463F2968A166BF8F53D8EBEF97E37A325BD49C5F4D6A2AD06851F7DC7E158
明文:Hello World
--------------------华丽的分割线------------------------
sign:3044022025d780da4e9e9756966a5f9bfcfac402bd23fed5ef8e7430605aa409fbddf5ae0220230d911af4bfac036641968fffb7e4fabb17b7e40e85f506bffb8b67932139bf
verify:true
--------------------华丽的分割线------------------------
sign
48 70 2 33 0 -69 -7 -33 44 122 -10 73 60 14 7 -64 58 77 -57 6 -17 16 16 -78 6 114 -80 -100 -118 102 -70 -38 -90 26 -74 -118 91 2 33 0 -127 119 -13 -46 75 27 -52 79 98 42 -68 -44 35 7 -28 -128 -65 84 74 120 -116 -65 -97 77 32 -21 -7 23 -17 59 -84 124 
verify:true--------------------华丽的分割线------------------------
sign
48 68 2 32 42 -28 -26 -47 -126 -12 81 -47 68 -80 62 106 -114 -96 -121 -117 -36 -76 77 -35 -106 4 15 103 67 28 -40 -11 -61 26 -96 31 2 32 87 97 -38 20 -111 33 -73 87 100 31 -123 71 110 -118 4 -32 -67 -35 -52 50 -66 -100 99 -83 4 -39 -64 -73 -97 -31 71 67 
verify:true--------------------华丽的分割线------------------------
sign
-100 16 -120 93 -98 -23 -87 8 112 75 107 -14 -103 19 -38 -76 115 -86 -128 -120 -95 -20 97 64 123 11 125 -114 18 21 -48 6 87 15 -74 -23 -89 -3 -87 81 -35 0 7 -123 -71 106 8 -31 -96 -12 -49 -70 120 115 -116 47 114 30 6 75 -120 78 117 78 
verify:true
Process finished with exit code 0

程序打包下载地址:

https://github.com/fengfanchen/Java/tree/master/SM2Demo

以上是关于Java笔记-SM2(国密2)的调用及SM2SM3SM4使用场景的主要内容,如果未能解决你的问题,请参考以下文章

国密SM2的前端加密,后端解密(Java版本)及SM3 摘要加密

密码技术--国密SM2椭圆曲线公钥密码算法及Go语言应用

Java-国密算法SM2实现(bouncycastle)

Java-国密算法SM2实现(bouncycastle)

国密算法说明SM2SM3SM4

国密算法