标签:

公用类算法:

PCIKeyPair.java
/**
* @Author: dzy
* @Date: 2018/9/27 14:18
* @Describe: 公私钥对
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PCIKeyPair {
private String priKey; //私钥
private String pubKey; //公钥
}
CommonUtils.java
import org.apache.commons.lang3.StringUtils;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
/**
* @ClassName: CommonUtils
* @Description: 通用工具类
* @since: 0.0.1
* @author: dzy
* @date: 2017年2月22日 上午11:46:44
*/
public class CommonUtils {
/**
* @param date 日期
* @param pattern 模式 如:yyyyMMdd等
* @return
* @Title: formatDate
* @Description: 格式化日期
* @since: 0.0.1
*/
public static String formatDate(Date date, String pattern) {
SimpleDateFormat formatter = new SimpleDateFormat(pattern);
return formatter.format(date);
}
/**
* @param strDate String类型日期
* @param pattern 日期显示模式
* @return
* @Title: parseDate
* @Description: 将String日期转换为Date类型日期
* @since: 0.0.1
*/
public static Date parseDate(String strDate, String pattern) {
SimpleDateFormat formatter = null;
if (StringUtils.isBlank(strDate)) {
return null;
}
formatter = new SimpleDateFormat(pattern);
try {
return formatter.parse(strDate);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* @param date 操作前的日期
* @param field 日期的部分如:年,月,日
* @param amount 增加或减少的值(负数表示减少)
* @return
* @Title: dateAdd
* @Description: 日期的加减操作
* @since: 0.0.1
*/
public static Date dateAdd(Date date, int field, int amount) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(field, amount);
return calendar.getTime();
}
/**
* @param source 源字符串
* @param offset 填充开始的位置, 0-在左边, source.getBytes().length 在右边, 如果有中文时需小心位置
* @param c 用于填充的字符
* @param length 最后字符串的字节长度
* @return
* @Title: fill
* @Description: 填充字符串, 长度是按字节计算, 不是字符
* @since: 0.0.1
*/
public static String fill(String source, int offset, char c, int length) throws UnsupportedEncodingException {
if (null == source) {
source = "";
}
if (source.getBytes(CustomConstants.CHARSET_UTF8).length == length) {
return source;
}
byte[] buf = new byte[length];
byte[] src = source.getBytes(CustomConstants.CHARSET_UTF8);
if (src.length > length) {
System.arraycopy(src, src.length - length, buf, 0, length);
return new String(buf, CustomConstants.CHARSET_UTF8);
}
if (offset > src.length) {
offset = src.length;
} else if (offset < 0) {
offset = 0;
}
int n = length - src.length;
System.arraycopy(src, 0, buf, 0, offset);
for (int i = 0; i < n; i++) {
buf[i + offset] = (byte) c;
}
System.arraycopy(src, offset, buf, offset + n, src.length - offset);
return new String(buf, CustomConstants.CHARSET_UTF8);
}
/**
* @param original 原字符串
* @param offset 填充开始的位置, 0-在左边, original.getBytes().length 在右边, 如果有中文时需小心位置
* @param length 替换的字节数
* @param c 用于替换的字符
* @return
* @Title: replace
* @Description: 替换字符串, 长度是按字节计算, 不是字符
* @since: 0.0.1
*/
public static String replace(String original, int offset, int length, char c) throws UnsupportedEncodingException {
if (original == null) {
original = "";
}
if (original.getBytes(CustomConstants.CHARSET_UTF8).length <= offset) {
return original;
}
if (original.getBytes(CustomConstants.CHARSET_UTF8).length < offset + length) {
length = original.getBytes(CustomConstants.CHARSET_UTF8).length - offset;
}
byte[] buf = new byte[original.length()];
byte[] src = original.getBytes(CustomConstants.CHARSET_UTF8);
System.arraycopy(src, 0, buf, 0, offset);
for (int i = offset; i < offset + length; i++) {
buf[i] = (byte) c;
}
System.arraycopy(src, offset + length, buf, offset + length, src.length - offset - length);
return new String(buf, CustomConstants.CHARSET_UTF8);
}
/**
* @param s 16进制字符串
* @return
* @Title: hexToByte
* @Description: 16进制字符串转字节数组
* @since: 0.0.1
*/
public static byte[] hexToByte(String s) {
byte[] result = null;
try {
int i = s.length();
// if (i % 2 == 1) {
// throw new Exception("字符串长度不是偶数.");
// }
if (i % 2 != 0) {
throw new Exception("字符串长度不是偶数.");
}
result = new byte[i / 2];
for (int j = 0; j < result.length; j++) {
result[j] = (byte) Integer.parseInt(s.substring(j * 2, j * 2 + 2), 16);
}
} catch (Exception e) {
result = null;
e.printStackTrace();
// log.error("16进制字符串转字节数组时出现异常:", e);
}
return result;
}
/**
* @param bytes 字节数组
* @return
* @Title: byte2hexString
* @Description: 字节数组转换为16进制字符串 //0x33 0xD2 0x00 0x46 转换为 "33d20046" 转换和打印报文用
* @since: 0.0.1
*/
public static String byte2hexString(byte[] bytes) {
StringBuffer buf = new StringBuffer(bytes.length * 2);
for (int i = 0; i < bytes.length; i++) {
if (((int) bytes[i] & 0xff) < 0x10) {
buf.append("0");
}
buf.append(Long.toString((int) bytes[i] & 0xff, 16));
}
return buf.toString().toUpperCase();
}
/**
* @param hexString 16进制字符串 如:"33d20046" 转换为 0x33 0xD2 0x00 0x46
* @return
* @Title: hexString2byte
* @Description: 16进制字符串转字节数组
* @since: 0.0.1
*/
public static byte[] hexString2byte(String hexString) {
if (null == hexString || hexString.length() % 2 != 0 || hexString.contains("null")) {
return null;
}
byte[] bytes = new byte[hexString.length() / 2];
for (int i = 0; i < hexString.length(); i += 2) {
bytes[i / 2] = (byte) (Integer.parseInt(hexString.substring(i, i + 2), 16) & 0xff);
}
return bytes;
}
/**
* @param i 需要转的int类型数字
* @return
* @Title: byte1ToBcd2
* @Description: int类型转BCD码
* @since: 0.0.1
*/
public static String byte1ToBcd2(int i) {
// return (new Integer(i / 16).toString() + (new Integer(i % 16)).toString());
return Integer.toString(i / 16) + Integer.toString(i % 16);
}
/**
* @param b 字节数组
* @return
* @Title: byteToHex2
* @Description: 字节数组转换为16进制字符串 For example, byte[] {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF} will be changed to String "0123456789ABCDEF"
* @since: 0.0.1
*/
public static String byteToHex2(byte[] b) {
StringBuffer result = new StringBuffer();
String tmp = "";
for (int i = 0; i < b.length; i++) {
tmp = Integer.toHexString(b[i] & 0xff);
if (tmp.length() == 1) {
result.append("0" + tmp);
} else {
result.append(tmp);
}
}
return result.toString().toUpperCase();
}
/**
* @param num 数字
* @param len 字节数组长度
* @return
* @Title: intToHexBytes
* @Description: int类型转16进制字节数组
*/
public static byte[] intToHexBytes(int num, int len) {
byte[] bytes = null;
String hexString = Integer.toHexString(num);
if (len > 0) {
int length = len * 2;
hexString = CustomStringUtils.leftFill(hexString, '0', length);
bytes = CommonUtils.hexString2byte(hexString);
}
return bytes;
}
/*public static String byteToHex3(byte[] b) {
String result = "";
String tmp = "";
for (int n = 0; n < b.length; n++) {
tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (tmp.length() == 1) {
result = result + "0" + tmp;
} else {
result = result + tmp;
}
if (n < b.length - 1) {
result = result + "";
}
}
return result.toUpperCase();
}*/
/**
* @param str 需要转换编码的字符串
* @return
* @Title: iso2Gbk
* @Description: 将ISO-8859-1编码的字符串转成GBK编码的字符串
* @since: 0.0.1
*/
public static String iso2Gbk(String str) {
if (null == str) {
return str;
}
try {
return new String(str.getBytes("ISO-8859-1"), "GBK");
} catch (UnsupportedEncodingException e) {
// log.error("不支持的编码异常:", e);
e.printStackTrace();
return str;
}
}
// /**
// * @param message
// * @return
// * @Title: getSubElement
// * @Description: 分解各子域到HashMap
// * @since: 0.0.1
// */
// public static Map getSubElement(byte[] message) {
// Map map = new HashMap();
// String key = null;
// String value = null;
// int len = 0;
// int idx = 0;
// while (idx < message.length) {
// key = new String(message, idx, 2);
// idx += 2; //取了SE id 移2位
// len = Integer.parseInt(new String(message, idx, 2));
// idx += 2; //取了SE id的内容长度 移2位
// value = new String(message, idx, len);
// map.put(key, value);
// idx += len;
// }
// return map;
// }
//byte数组转成long
/**
* @param b 将字节数组转long类型 位置为小端
* @return
*/
public static long byteToLong(byte[] b) {
long s = 0;
long s0 = b[0] & 0xff;// 最低位
long s1 = b[1] & 0xff;
long s2 = b[2] & 0xff;
long s3 = b[3] & 0xff;
long s4 = b[4] & 0xff;// 最低位
long s5 = b[5] & 0xff;
long s6 = b[6] & 0xff;
long s7 = b[7] & 0xff;
// s0不变
s1 <<= 8;
s2 <<= 16;
s3 <<= 24;
s4 <<= 8 * 4;
s5 <<= 8 * 5;
s6 <<= 8 * 6;
s7 <<= 8 * 7;
s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7;
return s;
}
/**
* @param b 将字节数组转int类型 位置为小端
* @return
*/
public static int byteToInt(byte[] b) {
int s = 0;
int s0 = b[0] & 0xff;// 最低位
int s1 = b[1] & 0xff;
int s2 = b[2] & 0xff;
int s3 = b[3] & 0xff;
// s0不变
s1 <<= 8;
s2 <<= 16;
s3 <<= 24;
s = s0 | s1 | s2 | s3;
return s;
}
/**
* int类型转换小端的byte数组
* @param i
* @return
*/
public static byte[] intToLittleBytes(int i) {
ByteBuffer byteBuffer = ByteBuffer.allocate(4);
byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
byteBuffer.asIntBuffer().put(i);
byte[] littleBytes = byteBuffer.array();
return littleBytes;
}
/**
* 将一个字节转成10进制
* @param b
* @return
*/
public static int byteToInt(byte b) {
int value = b & 0xff;
return value;
}
/**
* 字节数组合并
* @param bt1 字节数组bt1
* @param bt2 字节数组bt2
* @return
*/
public static byte[] byteMerger(byte[] bt1, byte[] bt2){
byte[] bt3 = new byte[bt1.length+bt2.length];
System.arraycopy(bt1, 0, bt3, 0, bt1.length);
System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
return bt3;
}
}
SM2算法:
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.*;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.SimpleDateFormat;
import java.util.Calendar;
/**
* @Author: dzy
* @Date: 2018/9/28 15:53
* @Describe: SM2工具类
*/
public class SM2Util {
/**
* 生成SM2公私钥对
* @return
*/
private static AsymmetricCipherKeyPair genKeyPair0() {
//获取一条SM2曲线参数
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
//构造domain参数
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
sm2ECParameters.getG(), sm2ECParameters.getN());
//1.创建密钥生成器
ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
//2.初始化生成器,带上随机数
try {
keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
//3.生成密钥对
AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
return asymmetricCipherKeyPair;
}
/**
* 生成公私钥对(默认压缩公钥)
* @return
*/
public static PCIKeyPair genKeyPair() {
return genKeyPair(true);
}
/**
* 生成公私钥对
* @param compressedPubKey 是否压缩公钥
* @return
*/
public static PCIKeyPair genKeyPair(boolean compressedPubKey) {
AsymmetricCipherKeyPair asymmetricCipherKeyPair = genKeyPair0();
//提取公钥点
ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
//公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
String pubKey = Hex.toHexString(ecPoint.getEncoded(compressedPubKey));
BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
String priKey = privatekey.toString(16);
//TODO 删掉控制台输出
System.out.println("pubKey:" + pubKey);
System.out.println("sm2 private key = " + priKey);
System.out.println("sm2 public key = " + CommonUtils.byte2hexString(ecPoint.getEncoded(false)));
System.out.println("sm2 public key compressed = " + CommonUtils.byte2hexString(ecPoint.getEncoded(true)));
PCIKeyPair keyPair = new PCIKeyPair(priKey, pubKey);
return keyPair;
}
public static void main(String[] args) {
PCIKeyPair keyPair = genKeyPair();
System.out.println("keyPair:" + keyPair);
}
/**
* 私钥签名
* @param privateKey 私钥
* @param content 待签名内容
* @return
*/
public static String sign(String privateKey, String content) {
//待签名内容转为字节数组
byte[] message = Hex.decode(content);
//获取一条SM2曲线参数
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
//构造domain参数
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
sm2ECParameters.getG(), sm2ECParameters.getN());
BigInteger privateKeyD = new BigInteger(privateKey, 16);
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
//创建签名实例
SM2Signer sm2Signer = new SM2Signer();
//初始化签名实例,带上ID,国密的要求,ID默认值:1234567812345678
try {
sm2Signer.init(true, new ParametersWithID(new ParametersWithRandom(privateKeyParameters, SecureRandom.getInstance("SHA1PRNG")), Strings.toByteArray("1234567812345678")));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
//生成签名,签名分为两部分r和s,分别对应索引0和1的数组
BigInteger[] bigIntegers = sm2Signer.generateSignature(message);
String r = Hex.toHexString(bigIntegers[0].toByteArray());
r = r.substring(r.length() - 64);
String s = Hex.toHexString(bigIntegers[1].toByteArray());
s = s.substring(s.length() - 64);
String sign = CustomStringUtils.append(r, s);
//TODO 删掉控制台输出
System.out.println("Message signatrue = " + CommonUtils.byte2hexString(CommonUtils.byteMerger(bigIntegers[0].toByteArray(), bigIntegers[1].toByteArray())));
System.out.println("生成的签名(r+s) : " + sign);
return sign;
}
/**
* 验证签名
* @param publicKey 公钥
* @param content 待签名内容
* @param sign 签名值
* @return
*/
public static boolean verify(String publicKey, String content, String sign) {
//待签名内容
byte[] message = Hex.decode(content);
byte[] signData = Hex.decode(sign);
// 获取一条SM2曲线参数
X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
// 构造domain参数
ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
sm2ECParameters.getG(),
sm2ECParameters.getN());
//获取签名
BigInteger R = null;
BigInteger S = null;
byte[] rBy = new byte[33];
System.arraycopy(signData, 0, rBy, 1, 32);
rBy[0] = 0x00;
byte[] sBy = new byte[33];
System.arraycopy(signData, 32, sBy, 1, 32);
sBy[0] = 0x00;
R = new BigInteger(rBy);
S = new BigInteger(sBy);
//提取公钥点
ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(publicKey));
// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
//创建签名实例
SM2Signer sm2Signer = new SM2Signer();
ParametersWithID parametersWithID = new ParametersWithID(publicKeyParameters, Strings.toByteArray("1234567812345678"));
sm2Signer.init(false, parametersWithID);
//验证签名结果
boolean verify = sm2Signer.verifySignature(message, R, S);
return verify;
}
}
SM3算法:
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Hex;
import java.security.MessageDigest;
/**
* @Author: dzy
* @Date: 2018/10/19 16:36
* @Describe: SM3工具类(杂凑算法-hash算法)
*/
@Slf4j
public class SM3Util {
/**
* 16进制字符串SM3生成HASH签名值算法
* @param hexString 16进制字符串
* @return
*/
public static String hexEncrypt(String hexString) {
byte[] srcData = Hex.decode(hexString);
byte[] encrypt = encrypt(srcData);
String cipherStr = Hex.toHexString(encrypt);
return cipherStr;
}
/**
* 16进制字符串SM3生成HASH签名值算法
* @param hexKey 16进制密钥
* @param hexString 16进制字符串
* @return
*/
public static String hexEncrypt(String hexKey, String hexString) {
byte[] key = Hex.decode(hexKey);
byte[] srcData = Hex.decode(hexString);
byte[] encrypt = encrypt(key, srcData);
String cipherStr = Hex.toHexString(encrypt);
return cipherStr;
}
/**
* 普通文本SM3生成HASH签名算法
* @param plain 待签名数据
* @return
*/
public static String plainEncrypt(String plain) {
// 将返回的hash值转换成16进制字符串
String cipherStr = null;
try {
//将字符串转换成byte数组
byte[] srcData = plain.getBytes(CustomConstants.CHARSET_UTF8);
//调用encrypt计算hash
byte[] encrypt = encrypt(srcData);
//将返回的hash值转换成16进制字符串
cipherStr = Hex.toHexString(encrypt);
} catch (Exception e) {
log.error("将字符串转换为字节时出现异常:", e);
}
return cipherStr;
}
/**
* 普通文本SM3生成HASH签名算法
* @param hexKey 密钥
* @param plain 待签名数据
* @return
*/
public static String plainEncrypt(String hexKey, String plain) {
// 将返回的hash值转换成16进制字符串
String cipherStr = null;
try {
//将字符串转换成byte数组
byte[] srcData = plain.getBytes(CustomConstants.CHARSET_UTF8);
//密钥
byte[] key = Hex.decode(hexKey);
//调用encrypt计算hash
byte[] encrypt = encrypt(key, srcData);
//将返回的hash值转换成16进制字符串
cipherStr = Hex.toHexString(encrypt);
} catch (Exception e) {
log.error("将字符串转换为字节时出现异常:", e);
}
return cipherStr;
}
/**
* SM3计算hashCode
* @param srcData 待计算数据
* @return
*/
public static byte[] encrypt(byte[] srcData) {
SM3Digest sm3Digest = new SM3Digest();
sm3Digest.update(srcData, 0, srcData.length);
byte[] encrypt = new byte[sm3Digest.getDigestSize()];
sm3Digest.doFinal(encrypt, 0);
return encrypt;
}
/**
* 通过密钥进行加密
* @param key 密钥byte数组
* @param srcData 被加密的byte数组
* @return
*/
public static byte[] encrypt(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;
}
/**
* SM3计算hashCode
* @param srcData 待计算数据
* @return
* @throws Exception
*/
public static byte[] encrypt_0(byte[] srcData) throws Exception {
MessageDigest messageDigest = MessageDigest.getInstance("SM3", "BC");
byte[] digest = messageDigest.digest(srcData);
return digest;
}
}
SM4算法:
import org.bouncycastle.crypto.engines.SM4Engine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Hex;
/**
* @Author: dzy
* @Date: 2018/10/9 16:41
* @Describe: SM4算法
*/
public class SM4Util {
//加解密的字节快大小
public static final int BLOCK_SIZE = 16;
/**
* SM4ECB加密算法
* @param in 待加密内容
* @param keyBytes 密钥
* @return
*/
public static byte[] encryptByEcb0(byte[] in, byte[] keyBytes) {
SM4Engine sm4Engine = new SM4Engine();
sm4Engine.init(true, new KeyParameter(keyBytes));
int inLen = in.length;
byte[] out = new byte[inLen];
int times = inLen / BLOCK_SIZE;
for (int i = 0; i < times; i++) {
sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE);
}
return out;
}
/**
* SM4ECB加密算法
* @param in 待加密内容
* @param keyBytes 密钥
* @return
*/
public static String encryptByEcb(byte[] in, byte[] keyBytes) {
byte[] out = encryptByEcb0(in, keyBytes);
String cipher = Hex.toHexString(out);
return cipher;
}
/**
* SM4的ECB加密算法
* @param content 待加密内容
* @param key 密钥
* @return
*/
public static String encryptByEcb(String content, String key) {
byte[] in = Hex.decode(content);
byte[] keyBytes = Hex.decode(key);
String cipher = encryptByEcb(in, keyBytes);
return cipher;
}
/**
* SM4的ECB解密算法
* @param in 密文内容
* @param keyBytes 密钥
* @return
*/
public static byte[] decryptByEcb0(byte[] in, byte[] keyBytes) {
SM4Engine sm4Engine = new SM4Engine();
sm4Engine.init(false, new KeyParameter(keyBytes));
int inLen = in.length;
byte[] out = new byte[inLen];
int times = inLen / BLOCK_SIZE;
for (int i = 0; i < times; i++) {
sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE);
}
return out;
}
/**
* SM4的ECB解密算法
* @param in 密文内容
* @param keyBytes 密钥
* @return
*/
public static String decryptByEcb(byte[] in, byte[] keyBytes) {
byte[] out = decryptByEcb0(in, keyBytes);
String plain = Hex.toHexString(out);
return plain;
}
/**
* SM4的ECB解密算法
* @param cipher 密文内容
* @param key 密钥
* @return
*/
public static String decryptByEcb(String cipher, String key) {
byte[] in = Hex.decode(cipher);
byte[] keyBytes = Hex.decode(key);
String plain = decryptByEcb(in, keyBytes);
return plain;
}
}