国密SM2的调用及SM2、SM3、SM4使用场景52
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 |