From b95f2a04353274e2631d0354577bb1af2ba9423d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Thu, 7 May 2026 11:31:52 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E4=BC=98=E5=8C=96=20=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E5=8D=87=E7=BA=A7=E5=88=B01024=E5=AF=86=E9=92=A5=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AF=86=E9=92=A5=E9=95=BF=E5=BA=A6=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C(=E4=B8=8D=E6=94=AF=E6=8C=811024=E4=BB=A5=E4=B8=8B?= =?UTF-8?q?=E4=B8=8D=E5=AE=89=E5=85=A8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application.yml | 8 +- .../common/encrypt/filter/CryptoFilter.java | 3 + .../common/encrypt/utils/EncryptUtils.java | 74 +++++++++++++++++-- 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 5ef14e2b3..b8848f036 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -149,11 +149,11 @@ api-decrypt: # AES 加密头标识 headerFlag: encrypt-key # 响应加密公钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 - # 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= - publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ== + # 对应前端解密私钥 MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAObq7yrxfvyieZtTjAYyrdvi59tYTXxjO5ajmPCRSXBY9M9wQ1tli297JN6mnY53UJMNyOFNSZVi8WSFoIXjpR87FmvChJlzeN/dZdd3SEs48Ee66XKeSePYqxa8oO5GKDsnajgpsOHKXSeeVSIysiIPS2/WsEqk0In9P4w3RsRFAgMBAAECgYBiMEWwce24SPICnRzuScBpvmsudrbEDIH7BOd0a6LZlcnLJwZNJ7mJlshPsHNQb+WgEf135+BBGEhioPtn0yuTdEuKP4kB9UdYUKiayWCoWhJpesv7sAD4RDClV7dhuV+gcd1AXD+YzyRIPbGm0VC2U+4q8/+UPRpVjqskbLVTgQJBAPRpou7g3S8n4XB527kq0D8I3+ZYwMxZhszwhrCDpJU319+ucmpLVwYIzDmZVeID2QQdUaDfIEViFHu95xDrGiUCQQDx3YOKn3yaEctk/ERVn7hDAyAXUbd8/pv2b24/M/l1ZevlsFem8U4Jk5Mu64t3z3YGJoymEjQmbucwT01iKhehAkEAxlnccsRmfFh/KkqauKE4M4++NTAd9zlInpUsmZ+cN8UEGnF2RTEzRKBrLOt1uWCqBB7PGiE6DVTVjr7FAQPrSQJAT5yeY87DcONSk9cFlzmPqV8p/QME5rvYEnHzVBKDlkUKNPyqnWToTvaoh9U4fyNmsfeWbEOprszqhFhWHG3GgQJAK8+ynmyFhaw63+Hx2KU5zR4hVuQso2IzrEurGxCxybV6mR7VBerb4502+EPx3PmOgxQL+niUFhcMWxcvBFP9+A== + publicKey: MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDm6u8q8X78onmbU4wGMq3b4ufbWE18YzuWo5jwkUlwWPTPcENbZYtveyTepp2Od1CTDcjhTUmVYvFkhaCF46UfOxZrwoSZc3jf3WXXd0hLOPBHuulynknj2KsWvKDuRig7J2o4KbDhyl0nnlUiMrIiD0tv1rBKpNCJ/T+MN0bERQIDAQAB # 请求解密私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 - # 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== - privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= + # 对应前端加密公钥 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDvEDuRIOM3oZPWj9Ukoc5pQklR4PFH6/clnjeFqjDLIgDyQvjxhgqAZQA+E9eD6qu6FsXPmK8djcL+nh3cFHz4pX473jDvO3Sve+8yL3VRQ0n2pRgQ2a01MJsy+WwTZCBYWf0VnLRIvANUoWQgy9vz94q7Va44dg7A1/3ICf+xAwIDAQAB + privateKey: MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAO8QO5Eg4zehk9aP1SShzmlCSVHg8Ufr9yWeN4WqMMsiAPJC+PGGCoBlAD4T14Pqq7oWxc+Yrx2Nwv6eHdwUfPilfjveMO87dK977zIvdVFDSfalGBDZrTUwmzL5bBNkIFhZ/RWctEi8A1ShZCDL2/P3irtVrjh2DsDX/cgJ/7EDAgMBAAECgYEAhNZAQyRDHWZq/45soS5Hw7VRiG21pIE5k22W7G7lLfp3DCaqrYoNy8pTmCruVh7PzVdaE0CEDaf38gNqFCBOT8iTFQiYV3am4W3hsEQM5wmVBeTvCM5P2jsaaBQbqmneRjiZVbs6ha205JSho1Oc85NbaZa8gFVjwZgZWJrbzgECQQD/iZWhkRPtbdeai/Xk7D/eIXKh1Gxid0rWKQq8ikxbaiergn47XzNKrpROVyka3Gn85o7jJphgxp99R3r8sH71AkEA738Dn7xs+I4Y+MLa2EcT78JG3f/VhlWS/ks3qGJ2dfqwS7ntnmf5Q+2Xw+9UcuiK/TxD8K/0inSCkIMeWBOFFwJBAIoTebq3faEJfTqQ7ekojsokIKC4+2epNdLKknaV8/RhQ9Y0yKikJD7yXkiGaDuPZeW1Xvf2XtfL+1niSd5IMBECQDCOOMbe5dzyuj9dCg+FQZZ/dey2XK0Slm22BD/ATrIWtD12IaXXAKNz/Sv9TsrJOLykxkV69wJHIt13p+RFeNsCQGn5XGRn4ZCRVCesJYXyx29MTqkl8sD/gzYcURTZYjHqX2EvtvAyC6gBm9H0EbxmHIi4Oq0tITzklCXj5SpvBEw= springdoc: api-docs: diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java index 79d58daf1..2445541e5 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java @@ -10,6 +10,7 @@ import org.dromara.common.core.utils.SpringUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.encrypt.annotation.ApiEncrypt; import org.dromara.common.encrypt.properties.ApiDecryptProperties; +import org.dromara.common.encrypt.utils.EncryptUtils; import org.springframework.http.HttpMethod; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerExceptionResolver; @@ -29,6 +30,8 @@ public class CryptoFilter implements Filter { public CryptoFilter(ApiDecryptProperties properties) { this.properties = properties; + EncryptUtils.validateRsaPublicKey(properties.getPublicKey()); + EncryptUtils.validateRsaPrivateKey(properties.getPrivateKey()); } @Override diff --git a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java index fb15a3b04..1d5396708 100644 --- a/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java +++ b/ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java @@ -10,6 +10,13 @@ import cn.hutool.crypto.asymmetric.RSA; import cn.hutool.crypto.asymmetric.SM2; import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.interfaces.RSAKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; @@ -20,6 +27,11 @@ import java.util.Map; */ public class EncryptUtils { + /** + * RSA密钥最小位数 + */ + public static final int MIN_RSA_KEY_SIZE = 1024; + /** * 公钥 */ @@ -272,11 +284,17 @@ public class EncryptUtils { * @return 公私钥Map */ public static Map generateRsaKey() { - Map keyMap = new HashMap<>(2); - RSA rsa = SecureUtil.rsa(); - keyMap.put(PRIVATE_KEY, rsa.getPrivateKeyBase64()); - keyMap.put(PUBLIC_KEY, rsa.getPublicKeyBase64()); - return keyMap; + try { + Map keyMap = new HashMap<>(2); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(MIN_RSA_KEY_SIZE); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + keyMap.put(PRIVATE_KEY, java.util.Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded())); + keyMap.put(PUBLIC_KEY, java.util.Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded())); + return keyMap; + } catch (GeneralSecurityException e) { + throw new IllegalStateException("生成RSA密钥失败", e); + } } /** @@ -290,6 +308,7 @@ public class EncryptUtils { if (StrUtil.isBlank(publicKey)) { throw new IllegalArgumentException("RSA需要传入公钥进行加密"); } + validateRsaPublicKey(publicKey); RSA rsa = SecureUtil.rsa(null, publicKey); return rsa.encryptBase64(data, StandardCharsets.UTF_8, KeyType.PublicKey); } @@ -305,6 +324,7 @@ public class EncryptUtils { if (StrUtil.isBlank(publicKey)) { throw new IllegalArgumentException("RSA需要传入公钥进行加密"); } + validateRsaPublicKey(publicKey); RSA rsa = SecureUtil.rsa(null, publicKey); return rsa.encryptHex(data, StandardCharsets.UTF_8, KeyType.PublicKey); } @@ -320,10 +340,54 @@ public class EncryptUtils { if (StrUtil.isBlank(privateKey)) { throw new IllegalArgumentException("RSA需要传入私钥进行解密"); } + validateRsaPrivateKey(privateKey); RSA rsa = SecureUtil.rsa(privateKey, null); return rsa.decryptStr(data, KeyType.PrivateKey, StandardCharsets.UTF_8); } + /** + * 校验RSA公钥最低位数 + * + * @param publicKey 公钥 + */ + public static void validateRsaPublicKey(String publicKey) { + if (StrUtil.isBlank(publicKey)) { + throw new IllegalArgumentException("RSA需要传入公钥"); + } + try { + byte[] keyBytes = java.util.Base64.getDecoder().decode(publicKey); + RSAKey rsaKey = (RSAKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(keyBytes)); + validateRsaKeySize(rsaKey); + } catch (IllegalArgumentException | GeneralSecurityException e) { + throw new IllegalArgumentException("RSA公钥格式错误或密钥长度低于" + MIN_RSA_KEY_SIZE + "位", e); + } + } + + /** + * 校验RSA私钥最低位数 + * + * @param privateKey 私钥 + */ + public static void validateRsaPrivateKey(String privateKey) { + if (StrUtil.isBlank(privateKey)) { + throw new IllegalArgumentException("RSA需要传入私钥"); + } + try { + byte[] keyBytes = java.util.Base64.getDecoder().decode(privateKey); + RSAKey rsaKey = (RSAKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(keyBytes)); + validateRsaKeySize(rsaKey); + } catch (IllegalArgumentException | GeneralSecurityException e) { + throw new IllegalArgumentException("RSA私钥格式错误或密钥长度低于" + MIN_RSA_KEY_SIZE + "位", e); + } + } + + private static void validateRsaKeySize(RSAKey rsaKey) { + int keySize = rsaKey.getModulus().bitLength(); + if (keySize < MIN_RSA_KEY_SIZE) { + throw new IllegalArgumentException("RSA密钥长度不能低于" + MIN_RSA_KEY_SIZE + "位,当前为" + keySize + "位"); + } + } + /** * md5加密 *