基于国密(SM2,SM3,SM4)的数字信封加密加签实现

饭宝  金牌会员 | 2024-8-16 23:19:57 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 576|帖子 576|积分 1728

一、 数字信封的工作原理

1.1 数据加密
起首,发送方利用一种对称加密算法(如SM4,AES)对必要传输的数据举行加密。对称加密算法利用相同的密钥举行加密息争密,因此加密速率快,得当大量数据的加密。
1.2 密钥加密
接下来,发送方利用接收方的公钥和一种非对称加密算法(如SM2,RSA)对刚才天生的对称密钥举行加密。如许,纵然有人截获了加密的数据和加密后的密钥,没有接收方的私钥也无法解密密钥,进而无法解密数据。
1.3 数据传输
加密后的数据和加密后的密钥(即数字信封)一起发送给接收方。
1.4 数据解密
接收方收到数字信封后,起首利用自己的私钥解密密钥,得到原始的对称密钥。然后,利用这个对称密钥解密数据,得到原始的明文信息。
二、国密简朴介绍

这里只做简朴介绍,详细内容自行百度。
2.1  SM2 为非对称加密:可以用 RSA作为对比明白。基于 ECC。该算法已公开。由于该算法基于 ECC,故其署名速率与秘钥天生速率都快于 RSA。ECC 256位(SM2 采用的就是 ECC 256 位的一种)安全强度比 RSA 2048 位高,但运算速率快于RSA。
2.2  SM3 消息择要:可以用 MD5 作为对比明白。该算法已公开。校验结果为 256 位。
2.3  SM4 无线局域网尺度的分组数据算法:对称加密,密钥长度和分组长度均为128位。可以用 AES作为对比明白。
二、 数据加工过程

如下图所示,这是请求方(客户端)对数据加密加签的过程,与接收方(服务端)对数据验签解密的过程。
一样平常情况,接收方(服务端)天生一对SM2的秘钥,自己保存私钥,公钥给到请求方(客户端)。同时请求方(客户端)也天生一对SM2的秘钥,自己保存私钥,公钥给到接收方(服务端)

三、 代码演示

3.1 添加依靠

  1.         <dependency>
  2.             <groupId>cn.hutool</groupId>
  3.             <artifactId>hutool-crypto</artifactId>
  4.         </dependency>
  5.         <dependency>
  6.             <groupId>org.bouncycastle</groupId>
  7.             <artifactId>bcpkix-jdk18on</artifactId>
  8.             <version>1.78.1</version>
  9.         </dependency>
  10.         <dependency>
  11.             <groupId>junit</groupId>
  12.             <artifactId>junit</artifactId>
  13.         </dependency>
复制代码
3.2 请求数据 :SecretParam

  1. import lombok.Data;
  2. import java.io.Serializable;
  3. @Data
  4. public class SecretParam implements Serializable {
  5.     private static final long serialVersionUID = -7945826159661698028L;
  6.     /**
  7.      * 应用id
  8.      */
  9.     private String appId;
  10.     /**
  11.      * 时间戳
  12.      */
  13.     private String timestamp;
  14.     /**
  15.      * 签名
  16.      */
  17.     private String sign;
  18.     /**
  19.      * 请求id
  20.      */
  21.     private String requestId;
  22.     /**
  23.      * 密文
  24.      */
  25.     private String ciphertext;
  26.     /**
  27.      * 临时密钥
  28.      */
  29.     private String tempKey;
  30. }
复制代码
3.3 加密工具类:SecretUtils

  1. import cn.hutool.core.util.HexUtil;
  2. import cn.hutool.crypto.SecureUtil;
  3. import cn.hutool.crypto.SmUtil;
  4. import cn.hutool.crypto.asymmetric.KeyType;
  5. import cn.hutool.crypto.asymmetric.SM2;
  6. import cn.hutool.crypto.symmetric.SM4;
  7. import com.alibaba.fastjson2.JSON;
  8. import com.ruoyi.common.core.domain.param.SecretParam;
  9. import org.junit.Test;
  10. import java.security.KeyPair;
  11. public class SecretUtils {
  12.     private static final String SM4_IV = "TB0Rd7ivgZuV5YlK";
  13.     private static final String SM4_MODE = "GCM";
  14.     private static final String SM4_PADDING = "NoPadding";
  15.     private String privateKeyServer = "308193020100301306072a8648ce3d020106082a811ccf5501822d047930770201010420740e61da0a403ac783a9f07b1db6e64d43879653f12eb7963b24bf3b45f6946da00a06082a811ccf5501822da144034200047dc182b4ce3c2067b6ef2e625ef1dd80847e77de8cfae129c1c6d19b206224727950c20fcd55f2da0fc1a57d1db4ce3dba4ad541e0e8784d701799b4c7b46b22";
  16.     private String publicKeyServer = "3059301306072a8648ce3d020106082a811ccf5501822d034200047dc182b4ce3c2067b6ef2e625ef1dd80847e77de8cfae129c1c6d19b206224727950c20fcd55f2da0fc1a57d1db4ce3dba4ad541e0e8784d701799b4c7b46b22";
  17.     private String privateKeyClient = "308193020100301306072a8648ce3d020106082a811ccf5501822d047930770201010420adb28bf95e7b6789bd16cfad436827220cefbe979069e0cf3169f5ba7aae8585a00a06082a811ccf5501822da14403420004b0a92c23a94166797243276622059ab6970e1b6fc8b263d8e52f14518b3b700f2c188e80965a25ef2245e7d29e33569bbefc44abac442ab0608956be83673696";
  18.     private String publicKeyClient = "3059301306072a8648ce3d020106082a811ccf5501822d03420004b0a92c23a94166797243276622059ab6970e1b6fc8b263d8e52f14518b3b700f2c188e80965a25ef2245e7d29e33569bbefc44abac442ab0608956be83673696";
  19.     @Test
  20.     public void generateKey() {
  21.         KeyPair pair = SecureUtil.generateKeyPair("SM2");
  22.         byte[] privateKeyS1 = pair.getPrivate().getEncoded();
  23.         byte[] publicKeyC1 = pair.getPublic().getEncoded();
  24.         String privateKeyS = HexUtil.encodeHexStr(privateKeyS1);
  25.         String publicKeyC = HexUtil.encodeHexStr(publicKeyC1);
  26.         System.out.println("服务端-私钥: " + privateKeyS);
  27.         System.out.println("服务端-公钥: " + publicKeyC);
  28.         KeyPair pair2 = SecureUtil.generateKeyPair("SM2");
  29.         byte[] privateKeyC2 = pair2.getPrivate().getEncoded();
  30.         byte[] publicKeyS2 = pair2.getPublic().getEncoded();
  31.         String privateKeyC = HexUtil.encodeHexStr(privateKeyC2);
  32.         String publicKeyS = HexUtil.encodeHexStr(publicKeyS2);
  33.         System.out.println("客户端-私钥: " + privateKeyC);
  34.         System.out.println("客户端-公钥: " + publicKeyS);
  35.     }
  36.     @Test
  37.     public void sendDate() {
  38.         String param = "今天的天气不错哦!";
  39.         System.out.println("客户端-待加密数据: " + param);
  40.         byte[] key = SmUtil.sm4().getSecretKey().getEncoded();
  41.         String secret = HexUtil.encodeHexStr(key);
  42.         System.out.println("随机生成sm4秘钥: " + secret);
  43.         SM4 sm4 = getSm4(secret);
  44.         byte[] encrypt = sm4.encrypt(param);
  45.         String encryptStr = HexUtil.encodeHexStr(encrypt);
  46.         System.out.println("客户端-对数据加密: " + encryptStr);
  47.         String digest = SmUtil.sm3(encryptStr);
  48.         System.out.println("客户端-对密文摘要: " + digest);
  49.         SM2 sm2PrivateC = SmUtil.sm2(privateKeyClient, null);
  50.         String sign = sm2PrivateC.signHex(digest);
  51.         System.out.println("客户端-使用sm2对摘要签名: " + sign);
  52.         SM2 sm2PublicC = SmUtil.sm2(null, publicKeyServer);
  53.         String sm4BySm2 = sm2PublicC.encryptHex(secret, KeyType.PublicKey);
  54.         System.out.println("客户端-使用sm2加密sm4秘钥: " + sm4BySm2);
  55.         SecretParam secretParam = new SecretParam();
  56.         secretParam.setCiphertext(encryptStr);
  57.         secretParam.setTempKey(sm4BySm2);
  58.         secretParam.setSign(sign);
  59.         secretParam.setAppId("001");
  60.         secretParam.setRequestId("002");
  61.         secretParam.setTimestamp(String.valueOf(System.currentTimeMillis()));
  62.         System.out.println("客户端-发送数据 = " + JSON.toJSONString(secretParam));
  63.     }
  64.     @Test
  65.     public void receiveDate() {
  66.         String json = "{"appId":"001","ciphertext":"9b9812773f83716023d22dc8336fe4bede33af2db21db9e6ef3002707a86d880c1e01e9e63d18159ed91d6","requestId":"002","sign":"3046022100bc7adc0ef8425be4a2e1a0793cc83fab7449cdf3811b3faae885ad358b2e9ff0022100a862520b82525475150fefdbaec0bbfb3b19782b6e2298096fbc000e50a25b78","tempKey":"04c95074063f875347575e041fd95dca07cb3cc0064b2c58416ec0d7898f028b593446379783292c80e4d6dddf765f5b691a3db45f5b133a59f7df01c77b167f97dd06b1b569f19a4f35c330f4b2713b9a1a913be108df62f4005741b8ba9dd5d6fc82dde1d4234b37d06514f70f4db6ef1006d42d4393469b9ee47e08607c6464","timestamp":"1721113417664"}\n";
  67.         SecretParam secretParam = JSON.parseObject(json, SecretParam.class);
  68.         // 服务端处理
  69.         System.out.println("服务端-省略appid, requestId, timestamp校验");
  70.         String digestCheck = SmUtil.sm3(secretParam.getCiphertext());
  71.         System.out.println("服务端-对密文生成摘要: " + digestCheck);
  72.         SM2 sm2PublicS = SmUtil.sm2(null, publicKeyClient);
  73.         boolean signFlag = sm2PublicS.verifyHex(digestCheck, secretParam.getSign());
  74.         System.out.println("服务端-对摘要验签 = " + signFlag);
  75.         SM2 sm2PrivateS = SmUtil.sm2(privateKeyServer, null);
  76.         String tempKey = sm2PrivateS.decryptStr(secretParam.getTempKey(), KeyType.PrivateKey);
  77.         System.out.println("服务端-使用sm2解密sm4秘钥: " + tempKey);
  78.         SM4 sm4 = getSm4(tempKey);
  79.         String decryptStr = sm4.decryptStr(secretParam.getCiphertext());
  80.         System.out.println("服务端-对数据解密: " + decryptStr);
  81.     }
  82.     /**
  83.      * 根据给定的密钥,获取一个SM4加密算法的实例
  84.      *
  85.      * @param key 密钥,需要是16进制字符串格式
  86.      * @return SM4加密算法的实例
  87.      */
  88.     private static SM4 getSm4(String key) {
  89.         return new SM4(SM4_MODE, SM4_PADDING, HexUtil.decodeHex(key), SM4_IV.getBytes());
  90.     }
  91. }
复制代码
3.4 结果打印演示

3.4.1 天生SM2的公钥和私钥

3.4.2 请求方(客户端)发送数据

3.4.3  接收方(服务端)接收数据




免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

饭宝

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表