From 1d7949cd02141c54c9f7b030fd1e9f1e07cf987d Mon Sep 17 00:00:00 2001 From: wanggeng <450292408@qq.com> Date: Tue, 16 Aug 2022 16:47:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0SM3=E4=B8=8ESM4=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/ink/wgink/util/security/Sm3Util.java | 137 ++++++++++++ .../java/ink/wgink/util/security/Sm4Util.java | 200 ++++++++++++++++++ .../ink/wgink/common/config/BeanConfig.java | 15 -- .../password/Sm3HMacPasswordEncoder.java | 28 +++ .../common/password/Sm4PasswordEncoder.java | 29 +++ .../assets/js/common/layui-input-tree.js | 6 +- 6 files changed, 398 insertions(+), 17 deletions(-) create mode 100644 basic-util/src/main/java/ink/wgink/util/security/Sm3Util.java create mode 100644 basic-util/src/main/java/ink/wgink/util/security/Sm4Util.java create mode 100644 common/src/main/java/ink/wgink/common/password/Sm3HMacPasswordEncoder.java create mode 100644 common/src/main/java/ink/wgink/common/password/Sm4PasswordEncoder.java diff --git a/basic-util/src/main/java/ink/wgink/util/security/Sm3Util.java b/basic-util/src/main/java/ink/wgink/util/security/Sm3Util.java new file mode 100644 index 00000000..245ae7b2 --- /dev/null +++ b/basic-util/src/main/java/ink/wgink/util/security/Sm3Util.java @@ -0,0 +1,137 @@ +package ink.wgink.util.security; + +import org.bouncycastle.crypto.digests.SM3Digest; +import org.bouncycastle.crypto.macs.HMac; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; + +import java.io.UnsupportedEncodingException; +import java.security.Security; +import java.util.Arrays; + +/** + * @ClassName: Sm3Util + * @Description: + * @Author: wanggeng + * @Date: 2022/8/16 16:24 + * @Version: 1.0 + */ +public class Sm3Util { + + private static final String ENCODING = "UTF-8"; + + static { + Security.addProvider(new BouncyCastleProvider()); + } + + /** + * sm3算法加密 + * + * @param paramStr 待加密字符串 + * @return 返回加密后,固定长度=32的16进制字符串 + * @explain + */ + public static String encrypt(String paramStr) { + // 将返回的hash值转换成16进制字符串 + String resultHexString = ""; + try { + // 将字符串转换成byte数组 + byte[] srcData = paramStr.getBytes(ENCODING); + // 调用hash() + byte[] resultHash = hash(srcData); + // 将返回的hash值转换成16进制字符串 + resultHexString = ByteUtils.toHexString(resultHash); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return resultHexString; + } + + /** + * 返回长度=32的byte数组 + * + * @param srcData + * @return + * @explain 生成对应的hash值 + */ + public static byte[] hash(byte[] srcData) { + SM3Digest digest = new SM3Digest(); + //update the message digest with a single byte. + digest.update(srcData, 0, srcData.length); + byte[] hash = new byte[digest.getDigestSize()]; + //close the digest, producing the final digest value. + digest.doFinal(hash, 0); + return hash; + } + + /** + * sm3算法加密 + * + * @param paramStr 待加密字符串 + * @param key 密钥 + * @return 返回加密后,固定长度=32的16进制字符串 + * @explain + */ + public static String encryptPlus(String paramStr, String key) { + // 将返回的hash值转换成16进制字符串 + String resultHexString = ""; + try { + // 将字符串转换成byte数组 + byte[] srcData = paramStr.getBytes(ENCODING); + // 调用hash() + byte[] resultHash = hmac(srcData, key.getBytes(ENCODING)); + // 将返回的hash值转换成16进制字符串 + resultHexString = ByteUtils.toHexString(resultHash); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return resultHexString; + } + + /** + * 通过密钥进行加密 + * + * @param key 密钥 + * @param srcData 被加密的byte数组 + * @return + * @explain 指定密钥进行加密 + */ + private static byte[] hmac(byte[] key, byte[] srcData) { + KeyParameter keyParameter = new KeyParameter(key); + SM3Digest digest = new SM3Digest(); + HMac mac = new HMac(digest); + mac.init(keyParameter); + mac.update(srcData, 0, srcData.length); + byte[] result = new byte[mac.getMacSize()]; + mac.doFinal(result, 0); + return result; + } + + /** + * 判断源数据与加密数据是否一致 + * + * @param srcStr 原字符串 + * @param sm3HexString 16进制字符串 + * @return 校验结果 + * @explain 通过验证原数组和生成的hash数组是否为同一数组,验证2者是否为同一数据 + */ + public static boolean verify(String srcStr, String sm3HexString) { + boolean flag = false; + try { + //使用指定的字符集将字符串编码为 byte 序列,并将结果存储到一个新的 byte 数组中 + byte[] srcData = srcStr.getBytes(ENCODING); + //16进制 --> byte[] + byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString); + byte[] newHash = hash(srcData); + //判断数组是否相等 + if (Arrays.equals(newHash, sm3Hash)) { + flag = true; + } + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return flag; + } + +} diff --git a/basic-util/src/main/java/ink/wgink/util/security/Sm4Util.java b/basic-util/src/main/java/ink/wgink/util/security/Sm4Util.java new file mode 100644 index 00000000..25f7f3ac --- /dev/null +++ b/basic-util/src/main/java/ink/wgink/util/security/Sm4Util.java @@ -0,0 +1,200 @@ +package ink.wgink.util.security; + +import org.apache.commons.codec.binary.Hex; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.pqc.math.linearalgebra.ByteUtils; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Arrays; + +/** + * @ClassName: Sm4Util + * @Description: sm4 + * @Author: wanggeng + * @Date: 2022/8/16 16:04 + * @Version: 1.0 + */ +public class Sm4Util { + static { + Security.addProvider(new BouncyCastleProvider()); + } + + private static final String ENCODING = "UTF-8"; + public static final String ALGORITHM_NAME = "SM4"; + // 加密算法/分组加密模式/分组填充方式 + // PKCS5Padding-以8个字节为一组进行分组加密 + // 定义分组加密模式使用:PKCS5Padding + public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding"; + // 128-32位16进制;256-64位16进制 + public static final int DEFAULT_KEY_SIZE = 128; + + /** + * 自动生成密钥 + * + * @return + * @explain + */ + public static String generateKey() throws Exception { + return new String(Hex.encodeHex(generateKey(DEFAULT_KEY_SIZE), false)); + } + + /** + * @param keySize + * @return + * @throws Exception + * @explain + */ + public static byte[] generateKey(int keySize) throws Exception { + KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME); + kg.init(keySize, new SecureRandom()); + return kg.generateKey().getEncoded(); + } + + /** + * 生成ECB暗号 + * + * @param algorithmName 算法名称 + * @param mode 模式 + * @param key + * @return + * @throws Exception + * @explain ECB模式(电子密码本模式:Electronic codebook) + */ + private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception { + Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME); + Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME); + cipher.init(mode, sm4Key); + return cipher; + } + + /** + * sm4加密 + * + * @param hexKey 16进制密钥(忽略大小写) + * @param paramStr 待加密字符串 + * @return 返回16进制的加密字符串 + * @explain 加密模式:ECB + * 密文长度不固定,会随着被加密字符串长度的变化而变化 + */ + public static String encryptEcb(String hexKey, String paramStr) { + try { + String cipherText = ""; + // 16进制字符串-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // String-->byte[] + byte[] srcData = paramStr.getBytes(ENCODING); + // 加密后的数组 + byte[] cipherArray = encrypt_Ecb_Padding(keyData, srcData); + // byte[]-->hexString + cipherText = ByteUtils.toHexString(cipherArray); + return cipherText; + } catch (Exception e) { + return paramStr; + } + } + + /** + * 加密模式之Ecb + * + * @param key + * @param data + * @return + * @throws Exception + * @explain + */ + public static byte[] encrypt_Ecb_Padding(byte[] key, byte[] data) throws Exception { + Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key); + return cipher.doFinal(data); + } + + /** + * sm4解密 + * + * @param hexKey 16进制密钥 + * @param cipherText 16进制的加密字符串(忽略大小写) + * @return 解密后的字符串 + * @throws Exception + * @explain 解密模式:采用ECB + */ + public static String decryptEcb(String hexKey, String cipherText) { + // 用于接收解密后的字符串 + String decryptStr = ""; + // hexString-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // hexString-->byte[] + byte[] cipherData = ByteUtils.fromHexString(cipherText); + // 解密 + byte[] srcData = new byte[0]; + try { + srcData = decrypt_Ecb_Padding(keyData, cipherData); + // byte[]-->String + decryptStr = new String(srcData, ENCODING); + } catch (Exception e) { + e.printStackTrace(); + } + return decryptStr; + } + + /** + * 解密 + * + * @param key + * @param cipherText + * @return + * @throws Exception + * @explain + */ + public static byte[] decrypt_Ecb_Padding(byte[] key, byte[] cipherText) throws Exception { + Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key); + return cipher.doFinal(cipherText); + } + + /** + * 校验加密前后的字符串是否为同一数据 + * + * @param hexKey 16进制密钥(忽略大小写) + * @param cipherText 16进制加密后的字符串 + * @param paramStr 加密前的字符串 + * @return 是否为同一数据 + * @throws Exception + * @explain + */ + public static boolean verifyEcb(String hexKey, String cipherText, String paramStr) throws Exception { + // 用于接收校验结果 + boolean flag = false; + // hexString-->byte[] + byte[] keyData = ByteUtils.fromHexString(hexKey); + // 将16进制字符串转换成数组 + byte[] cipherData = ByteUtils.fromHexString(cipherText); + // 解密 + byte[] decryptData = decrypt_Ecb_Padding(keyData, cipherData); + // 将原字符串转换成byte[] + byte[] srcData = paramStr.getBytes(ENCODING); + // 判断2个数组是否一致 + flag = Arrays.equals(decryptData, srcData); + return flag; + } + + public static void main(String[] args) { + try { +// String json = "123"; +// System.out.println("加密前源数据————" + json); + // 生成32位16进制密钥 + String key = Sm4Util.generateKey(); + System.out.println(key + "-----生成key"); +// String cipher = Sm4Util.encryptEcb(key, json); +// System.out.println("加密串---" + cipher); +// System.out.println(Sm4Util.verifyEcb(key, cipher, json)); +// json = Sm4Util.decryptEcb(key, cipher); +// System.out.println("解密后数据---" + json); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/common/src/main/java/ink/wgink/common/config/BeanConfig.java b/common/src/main/java/ink/wgink/common/config/BeanConfig.java index 020ffb80..b3bca573 100644 --- a/common/src/main/java/ink/wgink/common/config/BeanConfig.java +++ b/common/src/main/java/ink/wgink/common/config/BeanConfig.java @@ -65,19 +65,4 @@ public class BeanConfig { return new BCryptPasswordEncoder(); } - @Bean - public PasswordEncoder customPasswordEncoder() { - return new PasswordEncoder() { - @Override - public String encode(CharSequence charSequence) { - return charSequence.toString(); - } - - @Override - public boolean matches(CharSequence charSequence, String s) { - return true; - } - }; - } - } diff --git a/common/src/main/java/ink/wgink/common/password/Sm3HMacPasswordEncoder.java b/common/src/main/java/ink/wgink/common/password/Sm3HMacPasswordEncoder.java new file mode 100644 index 00000000..ea7a07ee --- /dev/null +++ b/common/src/main/java/ink/wgink/common/password/Sm3HMacPasswordEncoder.java @@ -0,0 +1,28 @@ +package ink.wgink.common.password; + +import ink.wgink.util.security.Sm3Util; +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * @ClassName: Sm3hmacPasswordEncoder + * @Description: SM3-HMAC + * @Author: wanggeng + * @Date: 2022/8/16 15:43 + * @Version: 1.0 + */ +public class Sm3HMacPasswordEncoder implements PasswordEncoder { + + private static String KEY = "4A2A0E14ED344656769A3B0BC4D48A59"; + + @Override + public String encode(CharSequence rawPassword) { + return Sm3Util.encryptPlus(rawPassword.toString(), KEY); + } + + @Override + public boolean matches(CharSequence rawPassword, String encodedPassword) { + return StringUtils.equals(Sm3Util.encryptPlus(rawPassword.toString(), KEY), encodedPassword); + } + +} diff --git a/common/src/main/java/ink/wgink/common/password/Sm4PasswordEncoder.java b/common/src/main/java/ink/wgink/common/password/Sm4PasswordEncoder.java new file mode 100644 index 00000000..670a2c3f --- /dev/null +++ b/common/src/main/java/ink/wgink/common/password/Sm4PasswordEncoder.java @@ -0,0 +1,29 @@ +package ink.wgink.common.password; + +import ink.wgink.util.security.Sm4Util; +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.crypto.password.PasswordEncoder; + +/** + * @ClassName: Sm4PasswordEncoder + * @Description: SM4 + * @Author: wanggeng + * @Date: 2022/8/16 16:01 + * @Version: 1.0 + */ +public class Sm4PasswordEncoder implements PasswordEncoder { + + private static String KEY = "1F7F3097E835988D0BD61C97717BA2BC"; + + @Override + public String encode(CharSequence rawPassword) { + return Sm4Util.encryptEcb(KEY, rawPassword.toString()); + } + + @Override + public boolean matches(CharSequence rawPassword, String encodedPassword) { + return StringUtils.equals(Sm4Util.encryptEcb(KEY, rawPassword.toString()), encodedPassword); + } + + +} diff --git a/common/src/main/resources/static/assets/js/common/layui-input-tree.js b/common/src/main/resources/static/assets/js/common/layui-input-tree.js index 2f0548be..a49f3cbe 100644 --- a/common/src/main/resources/static/assets/js/common/layui-input-tree.js +++ b/common/src/main/resources/static/assets/js/common/layui-input-tree.js @@ -28,6 +28,7 @@ function LayuiInputTree(layui) { var getSelectedData = opt.getSelectedData; var onConfirm = opt.onConfirm; var onClear = opt.onClear; + var defaultParams = opt.defaultParams; var key = opt.key; var id = opt.id; var inputDomId = '#' + id; @@ -103,7 +104,7 @@ function LayuiInputTree(layui) { type: 'get', url: url, autoParam: ['id'], - otherParam: {}, + otherParam: defaultParams ? defaultParams : {}, dataFilter: function (treeId, parentNode, childNodes) { if (!childNodes) return null; $.each(childNodes, function (index, item) { @@ -141,6 +142,7 @@ function LayuiInputTree(layui) { var onConfirm = opt.onConfirm; var onClear = opt.onClear; var checkboxType = opt.checkboxType; + var defaultParams = opt.defaultParams; var id = opt.id; var key = opt.key; var inputDomId = '#' + id; @@ -268,7 +270,7 @@ function LayuiInputTree(layui) { type: 'get', url: url, autoParam: ['id'], - otherParam: {}, + otherParam: defaultParams ? defaultParams : {}, dataFilter: function (treeId, parentNode, childNodes) { if (!childNodes) return null; $.each(childNodes, function (index, item) {