package com.sinosig.common.util.encrypt;
import com.sinosig.common.config.DbDataProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@Slf4j
public class SM4StringTypeHandler extends BaseTypeHandler<String> {
// DbDataProperties.encryptKey="pAsBzrwZ%QSd$~H+"
@Override
public void setNonNullParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
try {
String encryptedValue = SM4Utils.encryptHex(parameter, DbDataProperties.encryptKey);
ps.setString(i, encryptedValue);
} catch (Exception e) {
log.error("Error encrypting value: ", e);
}
}
@Override
public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
String encryptedValue = rs.getString(columnName);
if (encryptedValue != null) {
try {
String s = SM4Utils.decryptHex(encryptedValue, DbDataProperties.encryptKey);
return SM4Utils.decryptHex(encryptedValue, DbDataProperties.encryptKey);
} catch (Exception e) {
log.error("Error decrypting value", e);
}
}
return null;
}
@Override
public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String encryptedValue = rs.getString(columnIndex);
if (encryptedValue != null) {
try {
return SM4Utils.decryptHex(encryptedValue, DbDataProperties.encryptKey);
} catch (Exception e) {
log.error("Error decrypting value", e);
}
}
return null;
}
@Override
public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String encryptedValue = cs.getString(columnIndex);
if (encryptedValue != null) {
try {
return SM4Utils.decryptHex(encryptedValue, DbDataProperties.encryptKey);
} catch (Exception e) {
log.error("Error decrypting value", e);
}
}
return null;
}
}
加密工具类
public class SM4Utils {
static {
Security.addProvider(new BouncyCastleProvider());
}
private static final String ALGORITHM = "SM4/CBC/PKCS7Padding";
private static final byte[] IV = new byte[16]; // 初始化向量,此处为全零
//加密
public static String encryptHex(String plaintext, String key) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "SM4");
IvParameterSpec ivSpec = new IvParameterSpec(IV);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
return bytesToHex(encryptedBytes); // 将字节数组转换为十六进制字符串
}
//解密
public static String decryptHex(String ciphertext, String key) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "SM4");
IvParameterSpec ivSpec = new IvParameterSpec(IV);
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
byte[] encryptedBytes = hexToBytes(ciphertext); // 使用与加密对应的方法将十六进制字符串转换为字节数组
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
//字节数组转十六进制字符串和十六进制字符串转字节数组的方法
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b)); // 使用大写的十六进制字符
}
return sb.toString();
}
public static byte[] hexToBytes(String hexString) {
return DatatypeConverter.parseHexBinary(hexString);
}
}
用法
@TableField(value = "cert_type",typeHandler = SM4StringTypeHandler.class)
private String certType;
想要利用mybatis中的typeHandler实现sm4算法的自动加解密,如上即可。实际需求根据自己的业务进行改动。