SM4加密登录实现

This commit is contained in:
黎润豪 2026-01-04 15:49:11 +08:00
parent 64c2ca090c
commit f58c1f92da
3 changed files with 136 additions and 0 deletions

View File

@ -0,0 +1,107 @@
package com.chinaweal.aiccs.common.util;
import org.bouncycastle.crypto.engines.SM4Engine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.encoders.Hex;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
/**
*
* @author lroyia
* @since 2026/1/4 15:33
**/
public class SM4Utils {
private static final int BLOCK_SIZE = 16;
/**
* SM4 加密
*
* @param plaintext 明文字符串
* @param sm4Key SM4密钥
* @return 十六进制格式的密文字符串
*/
public static String encrypt(String plaintext, String sm4Key) {
try {
byte[] keyBytes = Hex.decode(sm4Key);
byte[] plaintextBytes = plaintext.getBytes(StandardCharsets.UTF_8);
// 生成随机 IV
byte[] iv = new byte[BLOCK_SIZE];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
// 执行加密
SM4Engine engine = new SM4Engine();
CBCBlockCipher blockCipher = new CBCBlockCipher(engine);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher);
KeyParameter keyParameter = new KeyParameter(keyBytes);
ParametersWithIV params = new ParametersWithIV(keyParameter, iv);
cipher.init(true, params);
byte[] encrypted = new byte[cipher.getOutputSize(plaintextBytes.length)];
int len = cipher.processBytes(plaintextBytes, 0, plaintextBytes.length, encrypted, 0);
len += cipher.doFinal(encrypted, len);
// 将 IV 和密文合并返回
byte[] result = new byte[iv.length + len];
System.arraycopy(iv, 0, result, 0, iv.length);
System.arraycopy(encrypted, 0, result, iv.length, len);
return Hex.toHexString(result);
} catch (Exception e) {
throw new RuntimeException("SM4 加密失败", e);
}
}
/**
* SM4 解密
*
* @param ciphertext 十六进制格式的密文字符串
* @return 解密后的明文字符串
*/
public static String decrypt(String ciphertext, String sm4Key) {
try {
byte[] keyBytes = Hex.decode(sm4Key);
byte[] ciphertextBytes = Hex.decode(ciphertext);
if (ciphertextBytes.length < BLOCK_SIZE) {
throw new IllegalArgumentException("密文长度不足");
}
// 提取 IV 和密文
byte[] iv = new byte[BLOCK_SIZE];
byte[] encrypted = new byte[ciphertextBytes.length - BLOCK_SIZE];
System.arraycopy(ciphertextBytes, 0, iv, 0, BLOCK_SIZE);
System.arraycopy(ciphertextBytes, BLOCK_SIZE, encrypted, 0, encrypted.length);
// 执行解密
SM4Engine engine = new SM4Engine();
CBCBlockCipher blockCipher = new CBCBlockCipher(engine);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher);
KeyParameter keyParameter = new KeyParameter(keyBytes);
ParametersWithIV params = new ParametersWithIV(keyParameter, iv);
cipher.init(false, params);
byte[] decrypted = new byte[cipher.getOutputSize(encrypted.length)];
int len = cipher.processBytes(encrypted, 0, encrypted.length, decrypted, 0);
len += cipher.doFinal(decrypted, len);
// 移除填充并返回明文
byte[] result = new byte[len];
System.arraycopy(decrypted, 0, result, 0, len);
return new String(result, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new RuntimeException("SM4 解密失败", e);
}
}
}

View File

@ -1,8 +1,10 @@
package com.chinaweal.aiccs.org.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chinaweal.aiccs.common.base.controller.BaseController;
import com.chinaweal.aiccs.common.util.OAuthTokenUtils;
import com.chinaweal.aiccs.common.util.SM4Utils;
import com.chinaweal.aiccs.common.util.StringUtils;
import com.chinaweal.aiccs.org.entity.OauthAccessToken;
import com.chinaweal.aiccs.org.entity.OauthAuthorizationCode;
@ -13,9 +15,13 @@ import com.chinaweal.aiccs.org.service.IOauthAuthorizationCodeService;
import com.chinaweal.aiccs.org.service.IOauthClientService;
import com.chinaweal.aicorg.model.AICUser;
import com.chinaweal.aicorg.services.OrgUM;
import com.chinaweal.youfool.framework.springboot.rest.RestResult;
import com.chinaweal.youfool.framework.springboot.rest.ResultCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@ -35,6 +41,8 @@ import java.net.URLEncoder;
@RequestMapping("oauth2")
public class OAuth2Controller extends BaseController {
@Value("${oauth2.sm4.key}")
private String sm4Key;
@Autowired
private IOauthClientService oauthClientService;
@Autowired
@ -504,4 +512,22 @@ public class OAuth2Controller extends BaseController {
fullUserInfo.setPicture(null);
return fullUserInfo;
}
/**
* 获取一个加密登录的登录用数据串
*
* @param request 请求用户获取当前登录信息
* @return 加密串
*/
@ApiOperation("获取一个加密登录的登录用数据串")
@GetMapping("sm4/encrypted/data")
public RestResult<String> getSm4EncryptedData(HttpServletRequest request) {
AICUser loginUser = getLoginUser(request);
if (loginUser == null) {
return RestResult.error(ResultCode.USER_NOT_LOGGED_IN);
}
JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(loginUser));
jsonObject.put("expired", System.currentTimeMillis() + 1000 * 60 * 5);// 增加有效期
return RestResult.ok(SM4Utils.encrypt(jsonObject.toJSONString(), sm4Key));
}
}

View File

@ -151,3 +151,6 @@ punishment:
account: 'xyfljgxt'
password: '5d08zWhr0g18ncbvKp'
deckey: 'GGXYLHJC'
oauth2:
sm4:
key: ${SM4_LOGIN_KEY:59eefc6ab7b5c9f06de12a3eefb06db5}