SM4加解密

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;
	}

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值