Explorar o código

登录验证修改成SM4

ZhuDeKang hai 2 meses
pai
achega
80275d8f5c

+ 7 - 3
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java

@@ -1,5 +1,6 @@
 package com.ruoyi.web.controller.system;
 
+import com.ruoyi.common.utils.SM4Util;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -82,6 +83,9 @@ public class SysProfileController extends BaseController
         return error("修改个人信息异常,请联系管理员");
     }
 
+    @Autowired
+    private SM4Util sm4Util;
+
     /**
      * 重置密码
      */
@@ -92,15 +96,15 @@ public class SysProfileController extends BaseController
         LoginUser loginUser = getLoginUser();
         String userName = loginUser.getUsername();
         String password = loginUser.getPassword();
-        if (!SecurityUtils.matchesPassword(oldPassword, password))
+        if (!SecurityUtils.matchesPassword(sm4Util,oldPassword, password))
         {
             return error("修改密码失败,旧密码错误");
         }
-        if (SecurityUtils.matchesPassword(newPassword, password))
+        if (SecurityUtils.matchesPassword(sm4Util,newPassword, password))
         {
             return error("新密码不能与旧密码相同");
         }
-        newPassword = SecurityUtils.encryptPassword(newPassword);
+        newPassword = SecurityUtils.encryptPassword(sm4Util,newPassword);
         if (userService.resetUserPwd(userName, newPassword) > 0)
         {
             // 更新缓存用户密码

+ 2 - 2
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java

@@ -128,7 +128,7 @@ public class SysUserController extends BaseController
             return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
         }
         user.setCreateBy(getUsername());
-        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        user.setPassword(SecurityUtils.encryptPassword(sm4Util,user.getPassword()));
 
         user.setPhonenumber(sm4Util.encrypt(user.getPhonenumber()));
         user.setEmail(sm4Util.encrypt(user.getEmail()));
@@ -184,7 +184,7 @@ public class SysUserController extends BaseController
     {
         userService.checkUserAllowed(user);
         userService.checkUserDataScope(user.getUserId());
-        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        user.setPassword(SecurityUtils.encryptPassword(sm4Util,user.getPassword()));
         user.setUpdateBy(getUsername());
         return toAjax(userService.resetPwd(user));
     }

+ 4 - 1
ruoyi-admin/src/main/resources/application.yml

@@ -165,4 +165,7 @@ id.datacenterId: 1
 
 #sm4密钥
 sm4:
-  secret-key: "8E4A7C2F9B1D5E3A6C8F0B2D4E6A8C05" # 32位十六进制字符串,对应16字节密钥
+  secret-key: "8E4A7C2F9B1D5E3A6C8F0B2D4E6A8C05" # 32位十六进制字符串,对应16字节密钥
+sm2:
+  private-key: "sm2p256v1"
+  public-key: "sm2x562v3"

+ 41 - 1
ruoyi-admin/src/test/java/com/ruoyi/JasyptTest.java

@@ -3,6 +3,7 @@ package com.ruoyi;
 import com.ruoyi.common.core.domain.entity.SysDept;
 import com.ruoyi.common.core.domain.entity.SysRole;
 import com.ruoyi.common.core.domain.entity.SysUser;
+import com.ruoyi.common.utils.SM2EnhancedUtil;
 import com.ruoyi.common.utils.SM4Util;
 import com.ruoyi.interfaces.domain.MdModelInfo;
 import com.ruoyi.interfaces.domain.PtService;
@@ -47,10 +48,38 @@ public class JasyptTest {
     @Autowired
     private SysRoleMapper roleMapper;
 
+    @Autowired
+    private SM2EnhancedUtil sm2Util;
+
 
     @Test
     public void test() {
 
+        System.out.println("=== SM2签名验签测试 ===");
+
+        // 测试数据
+        String testData = "33f50ef2fc52f9a5a554a39c91854f20";
+
+        // 生成签名
+        String signature = sm2Util.sign(testData);
+        System.out.println("原始数据: " + testData);
+        System.out.println("签名结果: " + signature);
+
+        // 验证签名
+        boolean isValid = sm2Util.verify(testData, signature);
+        System.out.println("签名验证: " + isValid);
+
+        // 测试篡改数据
+        boolean isTamperedValid = sm2Util.verify("被篡改的数据", signature);
+        System.out.println("篡改数据验证: " + isTamperedValid);
+
+        // 显示密钥信息
+        System.out.println("公钥长度: " + sm2Util.getPublicKeyBase64().length());
+        System.out.println("私钥长度: " + sm2Util.getPrivateKeyBase64().length());
+        System.out.println("自检结果: " + sm2Util.selfCheck());
+    }
+    //System.out.println(sm4Util.encrypt("Gw#$1601"));
+
 /*List<MdModelInfo> mdModelInfos = modelMapper.selectMdModelInfoList(new MdModelInfo());
         mdModelInfos.forEach(p->{
             p.sign();
@@ -82,11 +111,13 @@ public class JasyptTest {
         });
 */
 
+/*
         List<SysDept> sysDepts = deptMapper.selectDeptList(new SysDept());
         sysDepts.forEach(p->{
             p.sign();
             deptMapper.updateDept(p);
         });
+*/
 
 /*
 
@@ -111,5 +142,14 @@ public class JasyptTest {
             System.out.println(    p.getDataSignature());
         });*/
 
-    }
+
+/*
+        String encrypt = sm4Util.encrypt("admin");
+        String common = sm4Util.encrypt("common");
+
+        System.out.println(encrypt);
+        System.out.println(common);
+*/
+
+
 }

+ 117 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/SM2EnhancedUtil.java

@@ -0,0 +1,117 @@
+package com.ruoyi.common.utils;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * 增强版SM2工具类
+ */
+@Component
+public class SM2EnhancedUtil {
+
+    @Value("${sm2.private-key}")
+    private String configPrivateKey;
+
+    @Value("${sm2.public-key}")
+    private String configPublicKey;
+
+    private PrivateKey privateKey;
+    private PublicKey publicKey;
+    private KeyPair keyPair;
+
+    @PostConstruct
+    public void init() {
+        // 如果配置了密钥,则使用配置的密钥
+        if (configPrivateKey != null && !configPrivateKey.trim().isEmpty() &&
+            configPublicKey != null && !configPublicKey.trim().isEmpty()) {
+            this.privateKey = SM2Util.loadPrivateKey(configPrivateKey);
+            this.publicKey = SM2Util.loadPublicKey(configPublicKey);
+            this.keyPair = new KeyPair(publicKey, privateKey);
+        } else {
+            // 否则生成新的密钥对
+            this.keyPair = SM2Util.generateKeyPair();
+            this.privateKey = keyPair.getPrivate();
+            this.publicKey = keyPair.getPublic();
+            
+            // 输出生成的密钥(仅用于开发环境)
+            System.out.println("生成的SM2公钥: " + getPublicKeyBase64());
+            System.out.println("生成的SM2私钥: " + getPrivateKeyBase64());
+        }
+    }
+
+    /**
+     * 使用配置的私钥签名
+     */
+    public String sign(String data) {
+        return SM2Util.sign(data.getBytes(), privateKey);
+    }
+
+    /**
+     * 使用配置的公钥验签
+     */
+    public boolean verify(String data, String signature) {
+        return SM2Util.verify(data.getBytes(), signature, publicKey);
+    }
+
+    /**
+     * 使用配置的私钥签名(字节数组)
+     */
+    public String sign(byte[] data) {
+        return SM2Util.sign(data, privateKey);
+    }
+
+    /**
+     * 使用配置的公钥验签(字节数组)
+     */
+    public boolean verify(byte[] data, String signature) {
+        return SM2Util.verify(data, signature, publicKey);
+    }
+
+    /**
+     * 获取当前使用的私钥(Base64)
+     */
+    public String getPrivateKeyBase64() {
+        return SM2Util.privateKeyToString(privateKey);
+    }
+
+    /**
+     * 获取当前使用的公钥(Base64)
+     */
+    public String getPublicKeyBase64() {
+        return SM2Util.publicKeyToString(publicKey);
+    }
+
+    /**
+     * 获取密钥对
+     */
+    public KeyPair getKeyPair() {
+        return keyPair;
+    }
+
+    /**
+     * 生成新的密钥对并更新当前实例
+     */
+    public void generateNewKeyPair() {
+        this.keyPair = SM2Util.generateKeyPair();
+        this.privateKey = keyPair.getPrivate();
+        this.publicKey = keyPair.getPublic();
+    }
+
+    /**
+     * 验证工具类是否正常工作
+     */
+    public boolean selfCheck() {
+        try {
+            String testData = "SM2签名测试数据";
+            String signature = sign(testData);
+            return verify(testData, signature);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+}

+ 109 - 0
ruoyi-common/src/main/java/com/ruoyi/common/utils/SM2Util.java

@@ -0,0 +1,109 @@
+package com.ruoyi.common.utils;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.springframework.stereotype.Component;
+
+import java.security.*;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+
+/**
+ * SM2非对称加密工具类 - 兼容版本
+ */
+@Component
+public class SM2Util {
+
+    static {
+        Security.addProvider(new BouncyCastleProvider());
+    }
+
+    /**
+     * 生成SM2密钥对
+     */
+    public static KeyPair generateKeyPair() {
+        try {
+            // 使用标准的KeyPairGenerator
+            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
+
+            // 使用SM2参数
+            keyPairGenerator.initialize(256); // SM2使用256位
+
+            return keyPairGenerator.generateKeyPair();
+        } catch (Exception e) {
+            throw new RuntimeException("生成SM2密钥对失败", e);
+        }
+    }
+
+    /**
+     * 使用私钥对数据进行签名
+     */
+    public static String sign(byte[] data, PrivateKey privateKey) {
+        try {
+            Signature signature = Signature.getInstance("SM3withSM2", "BC");
+            signature.initSign(privateKey);
+            signature.update(data);
+            byte[] signBytes = signature.sign();
+            return Base64.getEncoder().encodeToString(signBytes);
+        } catch (Exception e) {
+            throw new RuntimeException("SM2签名失败", e);
+        }
+    }
+
+    /**
+     * 使用公钥验证签名
+     */
+    public static boolean verify(byte[] data, String signature, PublicKey publicKey) {
+        try {
+            Signature verifier = Signature.getInstance("SM3withSM2", "BC");
+            verifier.initVerify(publicKey);
+            verifier.update(data);
+            byte[] signatureBytes = Base64.getDecoder().decode(signature);
+            return verifier.verify(signatureBytes);
+        } catch (Exception e) {
+            throw new RuntimeException("SM2验签失败", e);
+        }
+    }
+
+    /**
+     * 从Base64字符串加载私钥
+     */
+    public static PrivateKey loadPrivateKey(String base64PrivateKey) {
+        try {
+            byte[] keyBytes = Base64.getDecoder().decode(base64PrivateKey);
+            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
+            KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
+            return keyFactory.generatePrivate(keySpec);
+        } catch (Exception e) {
+            throw new RuntimeException("加载SM2私钥失败", e);
+        }
+    }
+
+    /**
+     * 从Base64字符串加载公钥
+     */
+    public static PublicKey loadPublicKey(String base64PublicKey) {
+        try {
+            byte[] keyBytes = Base64.getDecoder().decode(base64PublicKey);
+            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+            KeyFactory keyFactory = KeyFactory.getInstance("EC", "BC");
+            return keyFactory.generatePublic(keySpec);
+        } catch (Exception e) {
+            throw new RuntimeException("加载SM2公钥失败", e);
+        }
+    }
+
+    /**
+     * 将私钥转换为Base64字符串
+     */
+    public static String privateKeyToString(PrivateKey privateKey) {
+        return Base64.getEncoder().encodeToString(privateKey.getEncoded());
+    }
+
+    /**
+     * 将公钥转换为Base64字符串
+     */
+    public static String publicKeyToString(PublicKey publicKey) {
+        return Base64.getEncoder().encodeToString(publicKey.getEncoded());
+    }
+}

+ 9 - 6
ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java

@@ -100,11 +100,11 @@ public class SecurityUtils
      * @param password 密码
      * @return 加密字符串
      */
-    public static String encryptPassword(String password)
+    public static String encryptPassword(SM4Util sm4Util,String password)
     {
 /*        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
         return passwordEncoder.encode(password);*/
-        try {
+/*        try {
             // 密码+密钥进行SM3哈希
             String passwordToEncode = password + SM3_SECRET;
 
@@ -115,7 +115,8 @@ public class SecurityUtils
             return Base64.getEncoder().encodeToString(hash);
         } catch (Exception e) {
             throw new RuntimeException("SM3密码加密失败", e);
-        }
+        }*/
+        return sm4Util.encrypt(password);
 
     }
 
@@ -126,7 +127,7 @@ public class SecurityUtils
      * @param encodedPassword 加密后字符
      * @return 结果
      */
-    public static boolean matchesPassword(String rawPassword, String encodedPassword)
+    public static boolean matchesPassword(SM4Util sm4Util,String rawPassword, String encodedPassword)
     {
 /*        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
         return passwordEncoder.matches(rawPassword, encodedPassword);*/
@@ -134,7 +135,9 @@ public class SecurityUtils
             return false;
         }
 
-        try {
+        return sm4Util.decrypt(encodedPassword).equals(rawPassword);
+
+ /*       try {
             // 使用相同的逻辑计算输入密码的哈希值
             String passwordToCheck = rawPassword + SM3_SECRET;
 
@@ -145,7 +148,7 @@ public class SecurityUtils
             return encodedPassword.equals(checkEncoded);
         } catch (Exception e) {
             return false;
-        }
+        }*/
     }
 
     /**

+ 12 - 7
ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java

@@ -1,5 +1,6 @@
 package com.ruoyi.framework.config;
 
+import com.ruoyi.common.utils.SM4Util;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.framework.config.properties.PermitAllUrlProperties;
 import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
@@ -65,7 +66,11 @@ public class SecurityConfig {
     @Autowired
     private PermitAllUrlProperties permitAllUrl;
 
-/*
+
+    @Autowired
+    private SM4Util sm4Util;
+
+    /*
     */
 /**
      * 身份验证实现
@@ -81,30 +86,30 @@ public class SecurityConfig {
 */
 
     /**
-     * 身份验证实现 - 使用 SM3 密码编码器
+     * 身份验证实现 - 使用 SM4 密码编码器
      */
     @Bean
     public AuthenticationManager authenticationManager() {
         DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
         daoAuthenticationProvider.setUserDetailsService(userDetailsService);
-        daoAuthenticationProvider.setPasswordEncoder(sm3PasswordEncoder()); // 改为 SM3 编码器
+        daoAuthenticationProvider.setPasswordEncoder(sm4PasswordEncoder()); // 改为 SM4 编码器
         return new ProviderManager(daoAuthenticationProvider);
     }
 
     /**
-     * SM3 密码编码器 Bean
+     * SM4 密码编码器 Bean
      */
     @Bean
-    public PasswordEncoder sm3PasswordEncoder() {
+    public PasswordEncoder sm4PasswordEncoder() {
         return new PasswordEncoder() {
             @Override
             public String encode(CharSequence rawPassword) {
-                return SecurityUtils.encryptPassword(rawPassword.toString());
+                return SecurityUtils.encryptPassword(sm4Util,rawPassword.toString());
             }
 
             @Override
             public boolean matches(CharSequence rawPassword, String encodedPassword) {
-                return SecurityUtils.matchesPassword(rawPassword.toString(), encodedPassword);
+                return SecurityUtils.matchesPassword(sm4Util,rawPassword.toString(), encodedPassword);
             }
         };
     }

+ 7 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java

@@ -1,6 +1,8 @@
 package com.ruoyi.framework.web.service;
 
 import java.util.concurrent.TimeUnit;
+
+import com.ruoyi.common.utils.SM4Util;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.security.core.Authentication;
@@ -71,9 +73,13 @@ public class SysPasswordService
         }
     }
 
+
+    @Autowired
+    private SM4Util sm4Util;
+
     public boolean matches(SysUser user, String rawPassword)
     {
-        return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
+        return SecurityUtils.matchesPassword(sm4Util,rawPassword, user.getPassword());
     }
 
     public void clearLoginRecordCache(String loginName)

+ 7 - 1
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java

@@ -1,5 +1,6 @@
 package com.ruoyi.framework.web.service;
 
+import com.ruoyi.common.utils.SM4Util;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 import com.ruoyi.common.constant.CacheConstants;
@@ -35,6 +36,11 @@ public class SysRegisterService
     @Autowired
     private RedisCache redisCache;
 
+
+
+    @Autowired
+    private SM4Util sm4Util;
+
     /**
      * 注册
      */
@@ -76,7 +82,7 @@ public class SysRegisterService
         else
         {
             sysUser.setNickName(username);
-            sysUser.setPassword(SecurityUtils.encryptPassword(password));
+            sysUser.setPassword(SecurityUtils.encryptPassword(sm4Util,password));
             boolean regFlag = userService.registerUser(sysUser);
             if (!regFlag)
             {

+ 1 - 1
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java

@@ -526,7 +526,7 @@ public class SysUserServiceImpl implements ISysUserService
                     BeanValidators.validateWithException(validator, user);
                     deptService.checkDeptDataScope(user.getDeptId());
                     String password = configService.selectConfigByKey("sys.user.initPassword");
-                    user.setPassword(SecurityUtils.encryptPassword(password));
+                    user.setPassword(SecurityUtils.encryptPassword(sm4Util,password));
                     user.setCreateBy(operName);
                     user.sign();
                     userMapper.insertUser(user);