diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java b/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java index be228c8..baba9cc 100644 --- a/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java +++ b/blade-core-secure/src/main/java/org/springblade/core/secure/config/SecureConfiguration.java @@ -20,6 +20,7 @@ import lombok.AllArgsConstructor; import org.springblade.core.secure.aspect.AuthAspect; import org.springblade.core.secure.interceptor.ClientInterceptor; import org.springblade.core.secure.interceptor.SecureInterceptor; +import org.springblade.core.secure.props.BladeAuthProperties; import org.springblade.core.secure.props.BladeSecureProperties; import org.springblade.core.secure.props.BladeTokenProperties; import org.springblade.core.secure.provider.ClientDetailsServiceImpl; @@ -42,7 +43,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Order @AutoConfiguration @AllArgsConstructor -@EnableConfigurationProperties({BladeSecureProperties.class, BladeTokenProperties.class}) +@EnableConfigurationProperties({BladeAuthProperties.class, BladeSecureProperties.class, BladeTokenProperties.class}) public class SecureConfiguration implements WebMvcConfigurer { private final SecureRegistry secureRegistry; diff --git a/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeAuthProperties.java b/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeAuthProperties.java new file mode 100644 index 0000000..2ed670a --- /dev/null +++ b/blade-core-secure/src/main/java/org/springblade/core/secure/props/BladeAuthProperties.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springblade.core.secure.props; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * secure放行额外配置 + * + * @author Chill + */ +@Data +@ConfigurationProperties("blade.auth") +public class BladeAuthProperties { + + /** + * sm2公钥 + */ + private String publicKey; + + /** + * sm2私钥 + */ + private String privateKey; + +} diff --git a/blade-core-tool/pom.xml b/blade-core-tool/pom.xml index eb787f4..2d11e53 100644 --- a/blade-core-tool/pom.xml +++ b/blade-core-tool/pom.xml @@ -53,6 +53,11 @@ org.springframework.boot spring-boot-starter-data-redis + + + org.bouncycastle + bcprov-jdk18on + diff --git a/blade-core-tool/src/main/java/org/springblade/core/tool/utils/SM2Util.java b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/SM2Util.java new file mode 100644 index 0000000..ed03380 --- /dev/null +++ b/blade-core-tool/src/main/java/org/springblade/core/tool/utils/SM2Util.java @@ -0,0 +1,234 @@ +/** + * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springblade.core.tool.utils; + +import org.bouncycastle.asn1.gm.GMNamedCurves; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.engines.SM2Engine; +import org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import org.bouncycastle.crypto.params.*; +import org.bouncycastle.crypto.signers.SM2Signer; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.encoders.Hex; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.security.Security; + +/** + * SM2加密、解密、签名和验证工具类。 + * + * @author BladeX + */ +public class SM2Util { + static { + Security.addProvider(new BouncyCastleProvider()); + } + + private static final ECDomainParameters DOMAIN_PARAMS; + + static { + X9ECParameters spec = GMNamedCurves.getByName("sm2p256v1"); + DOMAIN_PARAMS = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN(), spec.getH()); + } + + /** + * 生成SM2密钥对。 + * + * @return 密钥对(公钥和私钥) + */ + public static AsymmetricCipherKeyPair generateKeyPair() { + ECKeyPairGenerator generator = new ECKeyPairGenerator(); + generator.init(new ECKeyGenerationParameters(DOMAIN_PARAMS, new SecureRandom())); + return generator.generateKeyPair(); + } + + + /** + * 使用SM2算法加密文本。 + * + * @param input 文本数据 + * @param publicKey 公钥 + * @return 加密后的数据 + */ + public static byte[] encrypt(String input, String publicKey) { + return encrypt(input, stringToPublicKey(publicKey)); + } + + /** + * 使用SM2算法加密文本。 + * + * @param input 文本数据 + * @param publicKey 公钥 + * @return 加密后的数据 + */ + public static byte[] encrypt(String input, ECPublicKeyParameters publicKey) { + try { + SM2Engine engine = new SM2Engine(); + engine.init(true, new ParametersWithRandom(publicKey, new SecureRandom())); + byte[] inputBytes = input.getBytes(); + return engine.processBlock(inputBytes, 0, inputBytes.length); + } catch (Exception e) { + return null; + } + } + + /** + * 使用SM2算法解密数据。 + * + * @param encrypted 加密的数据 + * @param privateKey 私钥 + * @return 解密后的文本 + */ + public static String decrypt(String encrypted, String privateKey) { + return decrypt(Hex.decode(encrypted), privateKey); + } + + /** + * 使用SM2算法解密数据。 + * + * @param encrypted 加密的数据 + * @param privateKey 私钥 + * @return 解密后的文本 + */ + public static String decrypt(byte[] encrypted, String privateKey) { + return decrypt(encrypted, stringToPrivateKey(privateKey)); + } + + /** + * 使用SM2算法解密数据。 + * + * @param encrypted 加密的数据 + * @param privateKey 私钥 + * @return 解密后的文本 + */ + public static String decrypt(byte[] encrypted, ECPrivateKeyParameters privateKey) { + try { + SM2Engine engine = new SM2Engine(); + engine.init(false, privateKey); + byte[] decryptedBytes = engine.processBlock(encrypted, 0, encrypted.length); + return new String(decryptedBytes); + } catch (Exception e) { + return null; + } + } + + /** + * 使用SM2算法进行数据签名。 + * + * @param input 需要签名的数据 + * @param privateKey 私钥 + * @return 签名 + */ + public static byte[] sign(String input, String privateKey) { + return sign(input, stringToPrivateKey(privateKey)); + } + + /** + * 使用SM2算法进行数据签名。 + * + * @param input 需要签名的数据 + * @param privateKey 私钥 + * @return 签名 + */ + public static byte[] sign(String input, ECPrivateKeyParameters privateKey) { + try { + SM2Signer signer = new SM2Signer(); + signer.init(true, new ParametersWithRandom(privateKey, new SecureRandom())); + byte[] inputBytes = input.getBytes(); + signer.update(inputBytes, 0, inputBytes.length); + return signer.generateSignature(); + } catch (Exception e) { + return null; + } + } + + /** + * 使用SM2算法验证签名。 + * + * @param input 数据 + * @param signature 签名 + * @param publicKey 公钥 + * @return 是否验证成功 + */ + public static boolean verify(String input, byte[] signature, String publicKey) { + return verify(input, signature, stringToPublicKey(publicKey)); + } + + /** + * 使用SM2算法验证签名。 + * + * @param input 数据 + * @param signature 签名 + * @param publicKey 公钥 + * @return 是否验证成功 + */ + public static boolean verify(String input, byte[] signature, ECPublicKeyParameters publicKey) { + try { + SM2Signer signer = new SM2Signer(); + signer.init(false, publicKey); + byte[] inputBytes = input.getBytes(); + signer.update(inputBytes, 0, inputBytes.length); + return signer.verifySignature(signature); + } catch (Exception e) { + return false; + } + } + + /** + * 获取公钥字符串。 + * + * @param keyPair 密钥对 + * @return 公钥字符串 + */ + public static String getPublicKeyString(AsymmetricCipherKeyPair keyPair) { + ECPublicKeyParameters ecPublicKeyParameters = (ECPublicKeyParameters) keyPair.getPublic(); + return Hex.toHexString(ecPublicKeyParameters.getQ().getEncoded(false)); + } + + /** + * 获取私钥字符串。 + * + * @param keyPair 密钥对 + * @return 私钥字符串 + */ + public static String getPrivateKeyString(AsymmetricCipherKeyPair keyPair) { + ECPrivateKeyParameters ecPrivateKeyParameters = (ECPrivateKeyParameters) keyPair.getPrivate(); + return Hex.toHexString(ecPrivateKeyParameters.getD().toByteArray()); + } + + /** + * 从字符串恢复公钥。 + * + * @param data 公钥字符串 + * @return 公钥 + */ + public static ECPublicKeyParameters stringToPublicKey(String data) { + return new ECPublicKeyParameters(DOMAIN_PARAMS.getCurve().decodePoint(Hex.decode(data)), DOMAIN_PARAMS); + } + + /** + * 从字符串恢复私钥。 + * + * @param data 私钥字符串 + * @return 私钥 + */ + public static ECPrivateKeyParameters stringToPrivateKey(String data) { + return new ECPrivateKeyParameters(new BigInteger(Hex.decode(data)), DOMAIN_PARAMS); + } + +} diff --git a/pom.xml b/pom.xml index dc5b8f1..18d225a 100644 --- a/pom.xml +++ b/pom.xml @@ -379,6 +379,12 @@ activation 1.1.1 + + + org.bouncycastle + bcprov-jdk18on + 1.78.1 + org.projectlombok