SM4加密登录实现
This commit is contained in:
parent
64c2ca090c
commit
f58c1f92da
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package com.chinaweal.aiccs.org.controller;
|
package com.chinaweal.aiccs.org.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.chinaweal.aiccs.common.base.controller.BaseController;
|
import com.chinaweal.aiccs.common.base.controller.BaseController;
|
||||||
import com.chinaweal.aiccs.common.util.OAuthTokenUtils;
|
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.common.util.StringUtils;
|
||||||
import com.chinaweal.aiccs.org.entity.OauthAccessToken;
|
import com.chinaweal.aiccs.org.entity.OauthAccessToken;
|
||||||
import com.chinaweal.aiccs.org.entity.OauthAuthorizationCode;
|
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.aiccs.org.service.IOauthClientService;
|
||||||
import com.chinaweal.aicorg.model.AICUser;
|
import com.chinaweal.aicorg.model.AICUser;
|
||||||
import com.chinaweal.aicorg.services.OrgUM;
|
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.Api;
|
||||||
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
@ -35,6 +41,8 @@ import java.net.URLEncoder;
|
||||||
@RequestMapping("oauth2")
|
@RequestMapping("oauth2")
|
||||||
public class OAuth2Controller extends BaseController {
|
public class OAuth2Controller extends BaseController {
|
||||||
|
|
||||||
|
@Value("${oauth2.sm4.key}")
|
||||||
|
private String sm4Key;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IOauthClientService oauthClientService;
|
private IOauthClientService oauthClientService;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
@ -504,4 +512,22 @@ public class OAuth2Controller extends BaseController {
|
||||||
fullUserInfo.setPicture(null);
|
fullUserInfo.setPicture(null);
|
||||||
return fullUserInfo;
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -151,3 +151,6 @@ punishment:
|
||||||
account: 'xyfljgxt'
|
account: 'xyfljgxt'
|
||||||
password: '5d08zWhr0g18ncbvKp'
|
password: '5d08zWhr0g18ncbvKp'
|
||||||
deckey: 'GGXYLHJC'
|
deckey: 'GGXYLHJC'
|
||||||
|
oauth2:
|
||||||
|
sm4:
|
||||||
|
key: ${SM4_LOGIN_KEY:59eefc6ab7b5c9f06de12a3eefb06db5}
|
||||||
Loading…
Reference in New Issue