import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
SecretKey key = null;
/**
* 生成用于内部密钥加解密的临时密钥对象
*/
public FMSYS() {
try{
KeyGenerator skg = KeyGenerator.getInstance("SM4", "FishermanJCE");
skg.init(128);
key = skg.generateKey();
}catch(Exception e){
//logger.error("gen SM4 key fail");
e.printStackTrace();
}
}
public String SYSEncAndDec (String str , boolean action){
//通过生成随机数生成初始化向量iv
byte [] iv = {1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8};
if(action){
//转换byte类型
byte[] indata = str.getBytes(StandardCharsets.UTF_8);
/*********内部SM4加密**************/
//数据加密
byte[]cipherData = InternalSM4Enc(1, "CBC", true, indata, iv);
if(cipherData==null){//加密失败返回原字符串
return str;
}else{//加密成功返回
BASE64Encoder enc=new BASE64Encoder();
String srtCipherData = enc.encode(cipherData);
return srtCipherData;
}
}else {
byte[] plainData = {0x01, 0x23, 0x45, 0x67, (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef,
(byte)0xfe, (byte)0xdc, (byte)0xba, (byte)0x98, 0x76, 0x54, 0x32, 0x10};
try {
/*********内部SM4解密**************/
//CBC打补丁模式解密
BASE64Decoder dec=new BASE64Decoder();
byte[] indata = dec.decodeBuffer(str);
//byte[] indata = str.getBytes();
//indata = plainData;
byte[] tmpdata = InternalSM4Dec(1, "CBC", true, indata, iv);
String str1 = new String(tmpdata, "utf-8");
return new String(tmpdata,"utf-8");
} catch (Exception e) {
// TODO Auto-generated catch block
return str;
}
}
}
/**
* 内部对称密钥加密运算
* @param keyid 密钥号
* @param mode "CBC"或者"ECB"
* @param ispad true为内部打补丁,即输入数据可为任意长度;false为上层打补丁,即输入数据必须为密钥模长的整数倍
* @param indata 待加密数据
* @param iv
* @return 加密后的数据
*/
public byte[] InternalSM4Enc(int keyid, String mode, boolean ispad, byte[] indata, byte[] iv)
{
String alg = "SM4" + "/" + mode + "/";
byte[] cipherdata = null;
byte[] tail = null;
IvParameterSpec ivspe = null;
if(ispad){
alg += "PKCS5PADDING";
}else{
alg += "NOPADDING";
}
String sysalg = "RandomSM4" + keyid;
try{
/*
* alg:参数格式"算法名称/模式/打补丁方式";
* 如"SM1/ECB/NOPADDING"为SM1算法,ECB模式,不打补丁
* "SM1/CBC/PKCS5PADDING"为SM1算法,CBC模式,打补丁
*/
SecureRandom ran = SecureRandom.getInstance(sysalg, "FishermanJCE");
Cipher cp = Cipher.getInstance(alg, "FishermanJCE");
if(mode.equalsIgnoreCase("CBC")){
ivspe = new IvParameterSpec(iv, 0, 16);
cp.init(Cipher.ENCRYPT_MODE, key, ivspe, ran);
}else{
cp.init(Cipher.ENCRYPT_MODE, key, ran);
}
cipherdata = cp.update(indata);
tail = cp.doFinal();
}catch(Exception e){
//logger.error(alg+" internal enc error");
e.printStackTrace();
return null;
}
byte[] ret = null;
if(tail != null){
if(cipherdata == null){
ret = new byte[tail.length];
System.arraycopy(tail, 0, ret, 0, tail.length);
}
else {
ret = new byte[cipherdata.length+tail.length];
System.arraycopy(cipherdata, 0, ret, 0, cipherdata.length);
System.arraycopy(tail, 0, ret, cipherdata.length, tail.length);
}
}else{
ret = new byte[cipherdata.length];
System.arraycopy(cipherdata, 0, ret, 0, cipherdata.length);
}
return ret;
}
/**
* 内部对称密钥解密运算
* @param keyid 密钥号
* @param mode "CBC"或者"ECB"
* @param ispad true为内部打补丁,即输入数据可为任意长度;false为上层打补丁,即输入数据必须为密钥模长的整数倍
* @param indata 待解密数据
* @param iv
* @return 解密后的数据
*/
public byte[] InternalSM4Dec(int keyid, String mode, boolean ispad, byte[] indata, byte[] iv)
{
String alg = "SM4" + "/" + mode + "/";
byte[] data = null;
byte[] tail = null;
IvParameterSpec ivspe = null;
if(ispad){
alg += "PKCS5PADDING";
}else{
alg += "NOPADDING";
}
String sysran = "RandomSM4" + keyid;
try{
/*
* alg:参数格式"算法名称/模式/打补丁方式";
* 如"SM1/ECB/NOPADDING"为SM1算法,ECB模式,不打补丁
* "SM1/CBC/PKCS5PADDING"为SM1算法,CBC模式,打补丁
*/
SecureRandom ran = SecureRandom.getInstance(sysran, "FishermanJCE");
Cipher cp = Cipher.getInstance(alg, "FishermanJCE");
if(mode.equalsIgnoreCase("CBC")){
ivspe = new IvParameterSpec(iv, 0, 16);
cp.init(Cipher.DECRYPT_MODE, key, ivspe, ran);
}else{
cp.init(Cipher.DECRYPT_MODE, key, ran);
}
data = cp.update(indata);
tail = cp.doFinal();
}catch(Exception e){
//logger.error(alg+" internal dec error");
e.printStackTrace();
return null;
}
byte[] ret = null;
if(tail != null){
if(data != null){
ret = new byte[data.length+tail.length];
System.arraycopy(data, 0, ret, 0, data.length);
System.arraycopy(tail, 0, ret, data.length, tail.length);
}else{
ret = new byte[tail.length];
System.arraycopy(tail, 0, ret, 0, tail.length);
}
}else{
ret = new byte[data.length];
System.arraycopy(data, 0, ret, 0, data.length);
}
return ret;
}