增加SM3与SM4加密工具
This commit is contained in:
parent
74d888ca6d
commit
1d7949cd02
137
basic-util/src/main/java/ink/wgink/util/security/Sm3Util.java
Normal file
137
basic-util/src/main/java/ink/wgink/util/security/Sm3Util.java
Normal file
@ -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;
|
||||
}
|
||||
|
||||
}
|
200
basic-util/src/main/java/ink/wgink/util/security/Sm4Util.java
Normal file
200
basic-util/src/main/java/ink/wgink/util/security/Sm4Util.java
Normal file
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user