一、国密SM4加密
<dependency>
<groupId>org.bouncycastlegroupId>
<artifactId>bcprov-jdk15onartifactId>
<version>1.70version>
dependency>
1.1 工具类
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
import java.util.Arrays;
public class Sm4Util {
private static final String ALGORITHM = "SM4";
private static final String TRANSFORMATION_ECB = ALGORITHM + "/ECB/PKCS7Padding";
private static final String TRANSFORMATION_CBC = ALGORITHM + "/CBC/PKCS7Padding";
private static final String TRANSFORMATION_ECB_NoPADDING = ALGORITHM + "/ECB/NoPadding";
private static final String TRANSFORMATION_CBC_NoPADDING = ALGORITHM + "/CBC/NoPadding";
private static final String ALGORITHM_HMAC_SM4 = "HmacSHA256";
private static final String PROVIDER_NAME = "BC";
static {
Security.addProvider(new BouncyCastleProvider());
}
public static byte[] sign(byte[] key, byte[] data) throws Exception {
Mac mac = Mac.getInstance(ALGORITHM_HMAC_SM4, PROVIDER_NAME);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, ALGORITHM_HMAC_SM4);
mac.init(secretKeySpec);
return mac.doFinal(data);
}
public static boolean verify(byte[] key, byte[] data, byte[] signature) throws Exception {
Mac mac = Mac.getInstance(ALGORITHM_HMAC_SM4, PROVIDER_NAME);
SecretKeySpec secretKeySpec = new SecretKeySpec(key, ALGORITHM_HMAC_SM4);
mac.init(secretKeySpec);
byte[] computedSignature = mac.doFinal(data);
return Arrays.equals(computedSignature, signature);
}
public static byte[] encryptByCbcPkcs7Padding(byte[] key, byte[] data) throws Exception{
Cipher cipher = Cipher.getInstance(TRANSFORMATION_CBC , "BC");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, ALGORITHM);
byte[] iv = new byte[16];
Arrays.fill(iv, (byte) 0x00);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
return cipher.doFinal(data);
}
public static byte[] decryptByCbcPkcs7Padding(byte[] key, byte[] data) throws Exception{
Cipher cipher = Cipher.getInstance(TRANSFORMATION_CBC , "BC");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, ALGORITHM);
byte[] iv = new byte[16];
Arrays.fill(iv, (byte) 0x00);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
return cipher.doFinal(data);
}
public static byte[] encryptByEcbPkcs7Padding(byte[] key, byte[] data) throws Exception{
Cipher cipher = Cipher.getInstance(TRANSFORMATION_ECB , "BC");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
return cipher.doFinal(data);
}
public static byte[] decryptByEcbPkcs7Padding(byte[] key, byte[] data) throws Exception{
Cipher cipher = Cipher.getInstance(TRANSFORMATION_ECB , "BC");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
return cipher.doFinal(data);
}
public static byte[] encryptByEcbPkcs7PaddingNoPadding(byte[] key, byte[] data) throws Exception{
Cipher cipher = Cipher.getInstance(TRANSFORMATION_ECB_NoPADDING , "BC");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
return cipher.doFinal(data);
}
public static byte[] decryptByEcbPkcs7PaddingNoPadding(byte[] key, byte[] data) throws Exception{
Cipher cipher = Cipher.getInstance(TRANSFORMATION_ECB_NoPADDING , "BC");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
return cipher.doFinal(data);
}
public static byte[] encryptByCbcPkcs7PaddingNoPadding(byte[] key, byte[] data) throws Exception{
Cipher cipher = Cipher.getInstance(TRANSFORMATION_CBC_NoPADDING , "BC");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, ALGORITHM);
byte[] iv = new byte[16];
Arrays.fill(iv, (byte) 0x00);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
return cipher.doFinal(data);
}
public static byte[] decryptByCbcPkcs7PaddingNoPadding(byte[] key, byte[] data) throws Exception{
Cipher cipher = Cipher.getInstance(TRANSFORMATION_CBC_NoPADDING , "BC");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, ALGORITHM);
byte[] iv = new byte[16];
Arrays.fill(iv, (byte) 0x00);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
return cipher.doFinal(data);
}
}
1.2 SM4Util使用测试
@SpringBootTest(classes = ServerApplication.class)
public class Sm4UtilTest {
private static final byte[] KEY = KeyGenUtil.generate128BitKey();
private static final String DATA = "This is a test message for SM4 encryption.";
private static final String DATA16 = "HelloWorldYesYes";
@Test
public void testEncryptDecryptEcbPkcs7Padding() throws Exception {
byte[] encrypted = Sm4Util.encryptByEcbPkcs7Padding(KEY, DATA.getBytes());
byte[] signatureData = Sm4Util.sign(KEY, encrypted);
boolean isValid = Sm4Util.verify(KEY, encrypted, signatureData);
System.out.println("签名验证结果:" + isValid);
byte[] decrypted = Sm4Util.decryptByEcbPkcs7Padding(KEY, encrypted);
System.out.println("解密后数据" + new String(decrypted));
}
@Test
public void testEncryptDecryptCbcPkcs7Padding() throws Exception {
byte[] encrypted = Sm4Util.encryptByCbcPkcs7Padding(KEY, DATA.getBytes());
byte[] signatureData = Sm4Util.sign(KEY, encrypted);
boolean isValid = Sm4Util.verify(KEY, encrypted, signatureData);
System.out.println("签名验证结果:" + isValid);
byte[] decrypted = Sm4Util.decryptByCbcPkcs7Padding(KEY, encrypted);
System.out.println("解密后数据" + new String(decrypted));
}
@Test
public void testEncryptDecryptEcbPkcs7PaddingNoPadding() throws Exception {
byte[] encrypted = Sm4Util.encryptByEcbPkcs7PaddingNoPadding(KEY, DATA16.getBytes());
byte[] signatureData = Sm4Util.sign(KEY, encrypted);
boolean isValid = Sm4Util.verify(KEY, encrypted, signatureData);
System.out.println("签名验证结果:" + isValid);
byte[] decrypted = Sm4Util.decryptByEcbPkcs7PaddingNoPadding(KEY, encrypted);
System.out.println("解密后数据" + new String(decrypted));
}
@Test
public void testEncryptDecryptCbcPkcs7PaddingNoPadding() throws Exception {
byte[] encrypted = Sm4Util.encryptByCbcPkcs7PaddingNoPadding(KEY, DATA16.getBytes());
byte[] signatureData = Sm4Util.sign(KEY, encrypted);
boolean isValid = Sm4Util.verify(KEY, encrypted, signatureData);
System.out.println("签名验证结果:" + isValid);
byte[] decrypted = Sm4Util.decryptByCbcPkcs7PaddingNoPadding(KEY, encrypted);
System.out.println("解密后数据" + new String(decrypted));
}
}
二、MyBatis使用SM4加解密
2.1 创建表结构
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (
id BIGINT(20) PRIMARY KEY AUTO_INCREMENT COMMENT '自增主键',
name VARCHAR(128) NOT NULL DEFAULT '' COMMENT '姓名'
);
SELECT * FROM user_info;
INSERT INTO user_info (name) VALUES ('c4f6371b67fac0f224c5b44456d3c71f');
2.2 pom
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.2version>
dependency>
2.3 配置连接地址
spring:
datasource:
username: root
password: root
url: jdbc:mysql:///test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC&nullCatalogMeansCurrent=true
driver-class-name: com.mysql.cj.jdbc.Driver
2.4 编写mapper和xml
public interface UserInfoMapper {
UserInfo getUserInfoById(@Param("id") Long id);
List<UserInfo> list();
}
DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zn.opit.demo.mapper.UserInfoMapper">
<select id="getUserInfoById" resultType="com.zn.opit.demo.entity.UserInfo">
SELECT id, name FROM user_info WHERE id = #{id}
select>
<select id="list" resultType="com.zn.opit.demo.entity.UserInfo">
SELECT id, name FROM user_info
select>
mapper>
2.5 编写SQL拦截器对查询字段解密
@Intercepts(
{
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
}
)
public class EncryptInterceptor implements Interceptor {
private static final byte[] KEY = Sm4Util.decodeHex("6c376375e8e3979f91f805faa860dd43");
@SuppressWarnings(value = "unchecked")
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object resultObj = invocation.proceed();
ArrayList<UserInfo> list = (ArrayList<UserInfo>) resultObj;
for (UserInfo userInfo : list) {
byte[] decrypted = Sm4Util.decryptByEcbPkcs7Padding(KEY, Hex.decodeHex(userInfo.getName()));
userInfo.setName(new String(decrypted));
}
return list;
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
}
2.6 配置解密拦截器
@Configuration
public class MyBatisConfig {
@Bean
public ConfigurationCustomizer mybatisConfigurationCustomizer() {
return configuration -> {
configuration.setMapUnderscoreToCamelCase(true);
EncryptInterceptor encryptInterceptor = new EncryptInterceptor();
configuration.addInterceptor(encryptInterceptor);
};
}
}
2.7 测试执行
@SpringBootTest(classes = ServerApplication.class)
public class MyBatisInterceptorTest {
@Resource
private UserInfoMapper userInfoMapper;
@Test
public void test() {
UserInfo userInfoById = userInfoMapper.getUserInfoById(1L);
System.out.println(userInfoById.getName());
System.out.println("====================");
List<UserInfo> list = userInfoMapper.list();
list.forEach(item -> System.out.println(item.getName()));
}
}