需要用到的工具类,代码如下:

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<String, String> getSubElement(byte[] message) {
// Map<String, String> map = new HashMap<String, String>();
// 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;
} }

DES算法总结,代码如下:

import java.security.GeneralSecurityException;
import java.security.SecureRandom; import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec; public final class DesUtils { private static final byte[] ZERO_IVC = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; /**
* 生成秘钥
* @return 16字节3des秘钥
* @throws GeneralSecurityException
*/
public static byte[] create3DESKey() throws GeneralSecurityException {
KeyGenerator kg = KeyGenerator.getInstance("DESede");
kg.init(112);//must be equal to 112 or 168
byte[] key24 = kg.generateKey().getEncoded();
byte[] result = new byte[16];
System.arraycopy(key24, 0, result, 0, 16);
return result;
} /**
* 3DES加密cbc模式
* @param content 待加密数据
* @param key 秘钥
* @param ivb 向量
* @return 加密结果
* @throws GeneralSecurityException
*/
public static byte[] encryptBy3DesCbc(byte[] content, byte[] key, byte[] ivb) throws GeneralSecurityException {
byte[] _3deskey = new byte[24];
System.arraycopy(key, 0, _3deskey, 0, 16);
System.arraycopy(key, 0, _3deskey, 16, 8); Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
SecretKey secureKey = new SecretKeySpec(_3deskey, "DESede");
IvParameterSpec iv = new IvParameterSpec(ivb);
cipher.init(Cipher.ENCRYPT_MODE, secureKey, iv);
return cipher.doFinal(content);
}
/**
* 3DES解密cbc模式
* @param content 待解密数据
* @param key 秘钥
* @param ivb 向量
* @return 解密结果
* @throws GeneralSecurityException
*/
public static byte[] decryptBy3DesCbc(byte[] content, byte[] key, byte[] ivb) throws GeneralSecurityException {
byte[] _3deskey = new byte[24];
System.arraycopy(key, 0, _3deskey, 0, 16);
System.arraycopy(key, 0, _3deskey, 16, 8); Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
SecretKey secureKey = new SecretKeySpec(_3deskey, "DESede");
IvParameterSpec iv = new IvParameterSpec(ivb);
cipher.init(Cipher.DECRYPT_MODE, secureKey, iv);
long start = System.currentTimeMillis();
System.out.println(start);
return cipher.doFinal(content);
}
/**
* 3DES加密cbc模式,默认向量
* @param content 待加密数据
* @param key 秘钥
* @return 加密结果
* @throws GeneralSecurityException
*/
public static byte[] encryptBy3DesCbc(byte[] content, byte[] key) throws GeneralSecurityException {
return encryptBy3DesCbc(content, key, ZERO_IVC);
} /**
* 3DES解密cbc模式,默认向量
* @param content 带解密数据
* @param key 秘钥
* @return 解密结果
* @throws GeneralSecurityException
*/
public static byte[] decryptBy3DesCbc(byte[] content, byte[] key) throws GeneralSecurityException {
return decryptBy3DesCbc(content, key, ZERO_IVC);
} /**
* 3DES加密Ecb模式
* @param content 待加密数据
* @param key 加密秘钥
* @return 加密结果
* @throws GeneralSecurityException
*/
public static byte[] encryptBy3DesEcb(byte[] content, byte[] key) throws GeneralSecurityException {
byte[] _3deskey = new byte[24];
System.arraycopy(key, 0, _3deskey, 0, 16);
System.arraycopy(key, 0, _3deskey, 16, 8); Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
SecretKey secureKey = new SecretKeySpec(_3deskey, "DESede");
cipher.init(Cipher.ENCRYPT_MODE, secureKey);
return cipher.doFinal(content);
} /**
* 3DES解密Ecb模式
* @param content 待解密数据
* @param key 秘钥
* @return 解密结果
* @throws GeneralSecurityException
*/
public static byte[] decryptBy3DesEcb(byte[] content, byte[] key) throws GeneralSecurityException {
byte[] _3deskey = new byte[24];
System.arraycopy(key, 0, _3deskey, 0, 16);
System.arraycopy(key, 0, _3deskey, 16, 8); Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
SecretKey secureKey = new SecretKeySpec(_3deskey, "DESede");
cipher.init(Cipher.DECRYPT_MODE, secureKey);
return cipher.doFinal(content);
} /**
* 3DES加密Ecb模式(3倍密钥长)
* @param content 待加密数据
* @param key 加密秘钥
* @return 加密结果
* @throws GeneralSecurityException
*/
public static byte[] encryptBy3DesEcbThreeThreeTimes(byte[] content, byte[] key) throws GeneralSecurityException {
if (key.length != 24) {
throw new RuntimeException("密钥长度不是24.");
} Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
SecretKey secureKey = new SecretKeySpec(key, "DESede");
cipher.init(Cipher.ENCRYPT_MODE, secureKey);
return cipher.doFinal(content);
} /**
* 3DES解密Ecb模式((3倍密钥长))
* @param content 待解密数据
* @param key 秘钥
* @return 解密结果
* @throws GeneralSecurityException
*/
public static byte[] decryptBy3DesEcbThreeThreeTimes(byte[] content, byte[] key) throws GeneralSecurityException {
if (key.length != 24) {
throw new RuntimeException("密钥长度不是24.");
} Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
SecretKey secureKey = new SecretKeySpec(key, "DESede");
cipher.init(Cipher.DECRYPT_MODE, secureKey);
return cipher.doFinal(content);
} /**
* des的cbc模式加密算法
* @param content 待加密数据
* @param key 密钥
* @return 加密结果
* @throws GeneralSecurityException
*/
public static byte[] encryptByDesCbc(byte[] content, byte[] key) throws GeneralSecurityException {
return encryptByDesCbc(content, key, ZERO_IVC);
}
/**
* des的cbc模式解密算法
* @param content 待解密数据
* @param key 密钥
* @return 解密结果
* @throws GeneralSecurityException
*/
public static byte[] decryptByDesCbc(byte[] content, byte[] key) throws GeneralSecurityException {
return decryptByDesCbc(content, key, ZERO_IVC);
} /**
* des的cbc模式加密算法
* @param content 待加密数据
* @param key 加密密钥
* @return 加密结果
* @throws GeneralSecurityException
*/
public static byte[] encryptByDesCbc(byte[] content, byte[] key, byte[] icv) throws GeneralSecurityException {
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
IvParameterSpec iv = new IvParameterSpec(icv); cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv, sr); return cipher.doFinal(content);
} /**
* des的cbc模式解密算法
* @param content 待解密数据
* @param key 密钥
* @return 解密结果
* @throws GeneralSecurityException
*/
public static byte[] decryptByDesCbc(byte[] content, byte[] key, byte[] icv) throws GeneralSecurityException {
SecureRandom sr = new SecureRandom();
DESKeySpec dks = new DESKeySpec(key);
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding");
IvParameterSpec iv = new IvParameterSpec(icv); cipher.init(Cipher.DECRYPT_MODE, secretKey, iv, sr); return cipher.doFinal(content);
} /**
* des加密算法,ECB方式,NoPadding模式,数据字节必须是8的整数倍
* @param content 数据字节必须是8的整数倍
* @param key 密钥
* @return 加密结果
* @throws GeneralSecurityException
*/
public static byte[] encryptByDesEcb(byte[] content, byte[] key) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(new DESKeySpec(key));
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(content);
} /**
* des解密算法,ECB方式,NoPadding模式,数据字节必须是8的整数倍
* @param content 数据字节必须是8的整数倍
* @param key 密钥
* @throws GeneralSecurityException
* @return
*/
public static byte[] decryptByDesEcb(byte[] content, byte[] key) throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
SecretKey secretKey = keyFactory.generateSecret(new DESKeySpec(key));
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(content);
} /**
* 本项目用于生成外部设备认证码和校验卡认证码(javacard GP规范 SCP02安全通道)(cardCryptogram)
* B.1.2.1 Full Triple DES MAC
* The full triple DES MAC is as defined in [ISO 9797-1] as MAC Algorithm 1 with output transformation 3,
* without truncation, and with triple DES taking the place of the block cipher.
* @param content 待加密数据
* @param key 加密密钥
* @return 加密结果后8字节
* @throws Exception
*/
public static byte[] encryptBy3DesCbcLast8Mac(byte[] content, byte[] key) throws GeneralSecurityException {
byte[] edata = encryptBy3DesCbc(content, key); byte[] result = new byte[8];
System.arraycopy(edata, edata.length - 8, result, 0, 8);
return result;
}
/**
* 将b1和b2做异或,然后返回
* @param b1
* @param b2
* @return 异或结果
*/
public static byte[] xOr(byte[] b1, byte[] b2) {
byte[] tXor = new byte[Math.min(b1.length, b2.length)];
for (int i = 0; i < tXor.length; i++)
tXor[i] = (byte) (b1[i] ^ b2[i]); // 异或(Xor)
return tXor;
} /**
* 整形转字节
* @param n 整形数值
* @param buf 结果字节数组
* @param offset 填充开始位置
*/
public static void int2byte(int n, byte buf[], int offset){
buf[offset] = (byte)(n >> 24);
buf[offset + 1] = (byte)(n >> 16);
buf[offset + 2] = (byte)(n >> 8);
buf[offset + 3] = (byte)n;
} /**
* 长整形转字节
* @param n 长整形数值
* @param buf 结果字节数组
* @param offset 填充开始位置
*/
public static void long2byte(long n, byte buf[], int offset){
buf[offset] = (byte)(int)(n >> 56);
buf[offset + 1] = (byte)(int)(n >> 48);
buf[offset + 2] = (byte)(int)(n >> 40);
buf[offset + 3] = (byte)(int)(n >> 32);
buf[offset + 4] = (byte)(int)(n >> 24);
buf[offset + 5] = (byte)(int)(n >> 16);
buf[offset + 6] = (byte)(int)(n >> 8);
buf[offset + 7] = (byte)(int)n;
}
/**
* @Title: hexString2byte
* @Description: 16进制字符串转字节数组
* @since: 0.0.1
* @param hexString 16进制字符串 如:"33d20046" 转换为 0x33 0xD2 0x00 0x46
* @return
*/
public static byte[] hexString2byte(String hexString) {
if (null == hexString || hexString.length() % 2 != 0) {
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;
} /**
* @Title: byte2hexString
* @Description: 字节数组转换为16进制字符串 //0x33 0xD2 0x00 0x46 转换为 "33d20046" 转换和打印报文用
* @since: 0.0.1
* @param bytes 字节数组
* @return
*/
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();
} /**
* 3DES加密Ecb模式
* @param data 待加密数据
* @param key 加密秘钥
* @return 加密结果
* @throws GeneralSecurityException
*/
public static String encryptBy3DesEcb(String data, String key) {
byte[] content = hexString2byte(data);
byte[] deskey = hexString2byte(key);
String hex2S = "";
try {
byte[] doFinal = encryptBy3DesEcb(content, deskey);
hex2S = byte2hexString(doFinal);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
return hex2S;
} /**
* 分散算法
* @param data 数据(卡号)
* @param key 根密钥
* @return
*/
public static String getHashProtectKey(String data, String key) {
String tempKey, protect_key;
tempKey =byte2hexString(xOr(hexString2byte(data),hexString2byte("FFFFFFFFFFFFFFFF")));
protect_key = encryptBy3DesEcb(data, key);
protect_key = protect_key + encryptBy3DesEcb(tempKey, key);
return protect_key;
} /**
* 分散密钥
* @param data 数据(卡号)
* @param key 根密钥
* @return
* @throws GeneralSecurityException
*/
public static String getHashProtectKey(byte[] data, byte[] key) throws GeneralSecurityException {
byte[] tempKeyBytes = xOr(data, hexString2byte("FFFFFFFFFFFFFFFF"));
byte[] key1 = encryptBy3DesEcb(data, key);
byte[] key2 = encryptBy3DesEcb(tempKeyBytes, key);
byte[] disperKeyBytes = CommonUtils.byteMerger(key1, key2);
String disperKey = CommonUtils.byte2hexString(disperKeyBytes);
return disperKey;
} }

MAC算法总结,代码如下:

import java.security.GeneralSecurityException;

/**
* 计算MAC的工具类
*/
public class MacUtils { private static final byte[] ZERO_IVC = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 }; /**
* PBOC-3DES-MAC算法
*
* 计算MAC(hex) PBOC_3DES_MAC(符合ISO9797Alg3Mac标准) (16的整数补8000000000000000)
* 前n-1组使用单长密钥DES 使用密钥是密钥的左8字节) 最后1组使用双长密钥3DES (使用全部16字节密钥)
*
* 算法步骤:初始数据为D,初始向量为I,3DES秘钥为K0,秘钥低8字节DES秘钥K1;
* 1、数据D分组并且填充:将字节数组D进行分组,每组8个字节,分组编号从0开始,分别为D0...Dn;最后一个分组不满8字节的,先填充一个字节80,
* 后续全部填充00,满8字节的,新增一个8字节分组(80000000 00000000);
* 2、进行des循环加密:(1)D0和初始向量I进行按位异或得到结果O0;(2)使用秘钥K1,DES加密结果O0得到结果I1,
* 将I1和D1按位异或得到结果D1;(3)循环第二步骤得到结果Dn; 3、将Dn使用16字节秘钥K0进行3DES加密,得到的结果就是我们要的MAC。
* @param data
* @param key
* @param icv
* @return
* @throws Exception
*/
public static byte[] calculatePboc3desMAC(byte[] data, byte[] key, byte[] icv) throws Exception { if (key == null || data == null)
throw new RuntimeException("data or key is null.");
if (key.length != 16)
throw new RuntimeException("key length is not 16 byte."); byte[] leftKey = new byte[8];
System.arraycopy(key, 0, leftKey, 0, 8); // 拆分数据(8字节块/Block)
final int dataLength = data.length;
final int blockCount = dataLength / 8 + 1;
final int lastBlockLength = dataLength % 8; byte[][] dataBlock = new byte[blockCount][8];
for (int i = 0; i < blockCount; i++) {
int copyLength = i == blockCount - 1 ? lastBlockLength : 8;
System.arraycopy(data, i * 8, dataBlock[i], 0, copyLength);
}
dataBlock[blockCount - 1][lastBlockLength] = (byte) 0x80; byte[] desXor = DesUtils.xOr(dataBlock[0], icv);
for (int i = 1; i < blockCount; i++) {
byte[] des = DesUtils.encryptByDesCbc(desXor, leftKey);
desXor = DesUtils.xOr(dataBlock[i], des);
}
desXor = DesUtils.encryptBy3DesCbc(desXor, key);
return desXor;
} /**
* PBOC-DES-MAC算法
* @param data
* @param key
* @param icv
* @return
* @throws Exception
*/
public static byte[] calculatePbocdesMAC(byte[] data, byte[] key, byte[] icv) throws Exception { if (key == null || data == null)
throw new RuntimeException("data or key is null.");
if (key.length != 8)
throw new RuntimeException("key length is not 16 byte."); // 拆分数据(8字节块/Block)
final int dataLength = data.length;
final int blockCount = dataLength / 8 + 1;
final int lastBlockLength = dataLength % 8; byte[][] dataBlock = new byte[blockCount][8];
for (int i = 0; i < blockCount; i++) {
int copyLength = i == blockCount - 1 ? lastBlockLength : 8;
System.arraycopy(data, i * 8, dataBlock[i], 0, copyLength);
}
dataBlock[blockCount - 1][lastBlockLength] = (byte) 0x80; byte[] desXor = DesUtils.xOr(dataBlock[0], icv);
for (int i = 1; i < blockCount; i++) {
byte[] des = DesUtils.encryptByDesCbc(desXor, key);
desXor = DesUtils.xOr(dataBlock[i], des);
}
desXor = DesUtils.encryptByDesCbc(desXor, key);
return desXor;
} /**
* ANSI X9.9MAC算法 <br/>
* (1) ANSI X9.9MAC算法只使用单倍长密钥。 <br/>
* (2) MAC数据先按8字节分组,表示为D0~Dn,如果Dn不足8字节时,尾部以字节00补齐。 <br/>
* (3) 用MAC密钥加密D0,加密结果与D1异或作为下一次的输入。 <br/>
* (4) 将上一步的加密结果与下一分组异或,然后再用MAC密钥加密。<br/>
* (5) 直至所有分组结束,取最后结果的左半部作为MAC。<br/>
* 采用x9.9算法计算MAC (Count MAC by ANSI-x9.9).
*
* @param key 8字节密钥数据
* @param data 待计算的缓冲区
* @throws GeneralSecurityException
*/
public static byte[] calculateANSIX9_9MAC(byte[] key, byte[] data) throws GeneralSecurityException { final int dataLength = data.length;
final int lastLength = dataLength % 8;
final int lastBlockLength = lastLength == 0 ? 8 : lastLength;
final int blockCount = dataLength / 8 + (lastLength > 0 ? 1 : 0); // 拆分数据(8字节块/Block)
byte[][] dataBlock = new byte[blockCount][8];
for (int i = 0; i < blockCount; i++) {
int copyLength = i == blockCount - 1 ? lastBlockLength : 8;
System.arraycopy(data, i * 8, dataBlock[i], 0, copyLength);
} byte[] desXor = new byte[8];
for (int i = 0; i < blockCount; i++) {
byte[] tXor = DesUtils.xOr(desXor, dataBlock[i]);
desXor = DesUtils.encryptByDesEcb(tXor, key); // DES加密
}
return desXor;
} /**
* 采用ANSI x9.19算法计算MAC (Count MAC by ANSI-x9.19).<br/>
* 将ANSI X9.9的结果做如下计算<br/>
* (6) 用MAC密钥右半部解密(5)的结果。 <br/>
* (7) 用MAC密钥左半部加密(6)的结果。<br/>
* (8) 取(7)的结果的左半部作为MAC。<br/>
* @param key 16字节密钥数据
* @param data 待计算的缓冲区
* @throws GeneralSecurityException
*/
public static byte[] calculateANSIX9_19MAC(byte[] key, byte[] data) throws GeneralSecurityException {
if (key == null || data == null)
return null; if (key.length != 16) {
throw new RuntimeException("秘钥长度错误.");
} byte[] keyLeft = new byte[8];
byte[] keyRight = new byte[8];
System.arraycopy(key, 0, keyLeft, 0, 8);
System.arraycopy(key, 8, keyRight, 0, 8); byte[] result99 = calculateANSIX9_9MAC(keyLeft, data); byte[] resultTemp = DesUtils.decryptByDesEcb(result99, keyRight);
return DesUtils.encryptByDesEcb(resultTemp, keyLeft);
} }

MAC1Utils工具类:

/**
* 计算MAC1的工具类,是CPU卡在充值过程中要计算MAC1,然后通卡公司返回MAC2
*/
public class Mac1Utils { /**
*
* @param walletSequence 钱包交易流水(16进制)
* @param beforeAmt 充值前金额(10进制)
* @param txnAmt 充值金额(10进制)
* @param tradeType 交易类型
* @param psamTerminalCode 终端机编号
* @param random 伪随机数
* @param rechargeKey 充值密钥密文
* @param protectKey 充值密钥保护密钥
* @return
* @throws Exception
*/
public static String getMac1(String walletSequence, long beforeAmt, long txnAmt, String tradeType, String psamTerminalCode, String random, String rechargeKey, String protectKey) throws Exception {
//获取充值密钥明文
byte[] rechargeKeyBytes = DesUtils.hexString2byte(rechargeKey);
byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
byte[] rechargeKeyClearTextBytes = DesUtils.decryptBy3DesEcb(rechargeKeyBytes, protectKeyBytes); // System.out.println("rechargeKeyClearText:" + DesUtils.byte2hexString(rechargeKeyClearTextBytes)); // if (walletSequence.length() == 6) {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
// } else {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
// }
// walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4); // System.out.println("walletSequence:" + walletSequence); //过程密钥由 DATA中第一字节即密钥标识符指定的圈存密钥对(4 字节随机数+2 字节电子存折或电子钱包联机交易序号+8000)数据加密生成
String calcProcessKeyData = CustomStringUtils.append(random, walletSequence, "8000");
System.out.println("calcProcessKeyData:" + calcProcessKeyData); //获取过程密钥
byte[] calcProcessKeyDataBytes = DesUtils.hexString2byte(calcProcessKeyData);
byte[] processKeyBytes = DesUtils.encryptBy3DesEcb(calcProcessKeyDataBytes, rechargeKeyClearTextBytes); // System.out.println("processKey:" + DesUtils.byte2hexString(processKeyBytes)); String balance = CustomStringUtils.leftFill(Long.toHexString(beforeAmt), '0', 8);
String chargeFee = CustomStringUtils.leftFill(Long.toHexString(txnAmt), '0', 8); String macData = CustomStringUtils.append(balance, chargeFee, tradeType, psamTerminalCode);
byte[] macDataBytes = DesUtils.hexString2byte(macData); byte[] icv = DesUtils.hexString2byte("0000000000000000");
byte[] calcPbocDesMacBytes = MacUtils.calculatePbocdesMAC(macDataBytes, processKeyBytes, icv);
String calcPbocDesMac = DesUtils.byte2hexString(calcPbocDesMacBytes); String mac1 = calcPbocDesMac.substring(0, 8);
return mac1;
} /**
*
* @param walletSequence 钱包交易流水(16进制)
* @param beforeBalanceHex 充值前金额(16进制)
* @param rechargeFeeHex 充值金额(16进制)
* @param tradeType 交易类型
* @param psamTerminalCode 终端机编号
* @param random 伪随机数
* @param rechargeKey 充值密钥密文
* @param protectKey 充值密钥保护密钥
* @return
* @throws Exception
*/
public static String getMac1(String walletSequence, String beforeBalanceHex, String rechargeFeeHex, String tradeType, String psamTerminalCode, String random, String rechargeKey, String protectKey) throws Exception {
//获取充值密钥明文
byte[] rechargeKeyBytes = DesUtils.hexString2byte(rechargeKey);
byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
byte[] rechargeKeyClearTextBytes = DesUtils.decryptBy3DesEcb(rechargeKeyBytes, protectKeyBytes); System.out.println("rechargeKeyClearText:" + DesUtils.byte2hexString(rechargeKeyClearTextBytes)); // if (walletSequence.length() == 6) {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
// } else {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
// }
// walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4); // System.out.println("walletSequence:" + walletSequence); //过程密钥由 DATA中第一字节即密钥标识符指定的圈存密钥对(4 字节随机数+2 字节电子存折或电子钱包联机交易序号+8000)数据加密生成
String calcProcessKeyData = CustomStringUtils.append(random, walletSequence, "8000"); //获取过程密钥
byte[] calcProcessKeyDataBytes = DesUtils.hexString2byte(calcProcessKeyData);
byte[] processKeyBytes = DesUtils.encryptBy3DesEcb(calcProcessKeyDataBytes, rechargeKeyClearTextBytes); System.out.println("processKey:" + DesUtils.byte2hexString(processKeyBytes)); String balance = CustomStringUtils.leftFill(beforeBalanceHex, '0', 8);
String chargeFee = CustomStringUtils.leftFill(rechargeFeeHex, '0', 8); String macData = CustomStringUtils.append(balance, chargeFee, tradeType, psamTerminalCode);
byte[] macDataBytes = DesUtils.hexString2byte(macData);
System.out.println("macData:" + macData); byte[] icv = DesUtils.hexString2byte("0000000000000000");
byte[] calcPbocDesMacBytes = MacUtils.calculatePbocdesMAC(macDataBytes, processKeyBytes, icv);
String calcPbocDesMac = DesUtils.byte2hexString(calcPbocDesMacBytes); String mac1 = calcPbocDesMac.substring(0, 8);
return mac1;
} /**
*
* @param walletSequence 电子钱包联机交易序号(16进制)
* @param rechargeFee 充值金额(10进制)
* @param tradeType 交易类型
* @param psamTerminalCode 终端机编号
* @param tradeDateTime 主机交易日期时间
* @param random 随机数
* @param rechargeKey 充值密钥密文
* @param protectKey 保护密钥
* @return
* @throws Exception
*/
public static String getMac2(String walletSequence, long rechargeFee, String tradeType, String psamTerminalCode, String tradeDateTime, String random, String rechargeKey, String protectKey) throws Exception { //获取充值密钥明文
byte[] rechargeKeyBytes = DesUtils.hexString2byte(rechargeKey);
byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
byte[] rechargeKeyClearTextBytes = DesUtils.decryptBy3DesEcb(rechargeKeyBytes, protectKeyBytes); System.out.println("rechargeKeyClearText:" + DesUtils.byte2hexString(rechargeKeyClearTextBytes)); // if (walletSequence.length() == 6) {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
// } else {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
// }
// walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4); //过程密钥由 DATA中第一字节即密钥标识符指定的圈存密钥对(4 字节随机数+2 字节电子存折或电子钱包联机交易序号+8000)数据加密生成
String calcProcessKeyData = CustomStringUtils.append(random, walletSequence, "8000"); //获取过程密钥
byte[] calcProcessKeyDataBytes = DesUtils.hexString2byte(calcProcessKeyData);
byte[] processKeyBytes = DesUtils.encryptBy3DesEcb(calcProcessKeyDataBytes, rechargeKeyClearTextBytes); //充值金额
String chargeFee = CustomStringUtils.leftFill(Long.toHexString(rechargeFee), '0', 8);
String mac2Data = CustomStringUtils.append(chargeFee, tradeType,psamTerminalCode, tradeDateTime); byte[] icv = DesUtils.hexString2byte("0000000000000000");
byte[] mac2DataBytes = DesUtils.hexString2byte(mac2Data); byte[] calcPbocdesMACBytes = MacUtils.calculatePbocdesMAC(mac2DataBytes, processKeyBytes, icv);
String calcPbocdesMac = DesUtils.byte2hexString(calcPbocdesMACBytes); String mac2 = calcPbocdesMac.substring(0, 8);
return mac2;
} /**
*
* @param walletSequence 电子钱包联机交易序号(16进制)
* @param rechargeFee 充值金额(16进制)
* @param tradeType 交易类型
* @param psamTerminalCode 终端机编号
* @param tradeDateTime 主机交易日期时间
* @param random 随机数
* @param rechargeKey 充值密钥密文
* @param protectKey 保护密钥
* @return
* @throws Exception
*/
public static String getMac2(String walletSequence, String rechargeFee, String tradeType, String psamTerminalCode, String tradeDateTime, String random, String rechargeKey, String protectKey) throws Exception { //获取充值密钥明文
byte[] rechargeKeyBytes = DesUtils.hexString2byte(rechargeKey);
byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
byte[] rechargeKeyClearTextBytes = DesUtils.decryptBy3DesEcb(rechargeKeyBytes, protectKeyBytes); System.out.println("rechargeKeyClearText:" + DesUtils.byte2hexString(rechargeKeyClearTextBytes)); // if (walletSequence.length() == 6) {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
// } else {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
// }
// walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4); //过程密钥由 DATA中第一字节即密钥标识符指定的圈存密钥对(4 字节随机数+2 字节电子存折或电子钱包联机交易序号+8000)数据加密生成
String calcProcessKeyData = CustomStringUtils.append(random, walletSequence, "8000"); //获取过程密钥
byte[] calcProcessKeyDataBytes = DesUtils.hexString2byte(calcProcessKeyData);
byte[] processKeyBytes = DesUtils.encryptBy3DesEcb(calcProcessKeyDataBytes, rechargeKeyClearTextBytes); //充值金额
String chargeFee = CustomStringUtils.leftFill(rechargeFee, '0', 8);
String mac2Data = CustomStringUtils.append(chargeFee, tradeType,psamTerminalCode, tradeDateTime); byte[] icv = DesUtils.hexString2byte("0000000000000000");
byte[] mac2DataBytes = DesUtils.hexString2byte(mac2Data); byte[] calcPbocdesMACBytes = MacUtils.calculatePbocdesMAC(mac2DataBytes, processKeyBytes, icv);
String calcPbocdesMac = DesUtils.byte2hexString(calcPbocdesMACBytes); String mac2 = calcPbocdesMac.substring(0, 8);
return mac2;
} /**
* 计算MAC2
* @param rechargeFee 充值金额
* @param tradeType 交易类型
* @param psamTerminalCode 终端机编号
* @param tradeDateTime 交易日期时间
* @param processKey 过程密钥
* @return
* @throws Exception
*/
public static String getMac2(String rechargeFee, String tradeType, String psamTerminalCode, String tradeDateTime, String processKey) throws Exception { byte[] processKeyBytes = DesUtils.hexString2byte(processKey); //4字节交易金额+1字节交易类型+6字节终端机编号+4字节主机交易日期+3字节主机交易时间
String chargeFee = CustomStringUtils.leftFill(rechargeFee, '0', 8);
String mac2Data = CustomStringUtils.append(chargeFee, tradeType,psamTerminalCode, tradeDateTime); byte[] icv = DesUtils.hexString2byte("0000000000000000");
byte[] mac2DataBytes = DesUtils.hexString2byte(mac2Data); byte[] calcPbocdesMACBytes = MacUtils.calculatePbocdesMAC(mac2DataBytes, processKeyBytes, icv);
String calcPbocdesMac = DesUtils.byte2hexString(calcPbocdesMACBytes); String mac2 = calcPbocdesMac.substring(0, 8);
return mac2;
} }

TACUtils工具类:

public class TacUtils {

    /**
* 计算TAC
* @param afterAmt 新余额(充值后金额)(10进制)
* @param walletSequence 钱包交易序号
* @param txnAmt 充值金额(10进制)
* @param tradeType 交易类型
* @param psamTerminalCode 终端机编号
* @param tradeDateTime 交易日期时间
* @param tacKey tac密钥
* @param protectKey 保护密钥
* @return
* @throws Exception
*/
public static String getTac(long afterAmt, String walletSequence, long txnAmt, String tradeType, String psamTerminalCode, String tradeDateTime, String tacKey, String protectKey) throws Exception { //获取TAC密钥明文
byte[] tacKeyBytes = DesUtils.hexString2byte(tacKey);
byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
byte[] tacKeyClearTextBytes = DesUtils.decryptBy3DesEcb(tacKeyBytes, protectKeyBytes); int half = tacKeyClearTextBytes.length / 2;
byte[] b1 = new byte[half];
byte[] b2 = new byte[half]; System.arraycopy(tacKeyClearTextBytes, 0, b1, 0, half);
System.arraycopy(tacKeyClearTextBytes, half, b2, 0, half); //tac过程密钥
byte[] tacProcessKeyBytes = DesUtils.xOr(b1, b2); //4字节电子存折或电子钱包新余额
String newBalance = CustomStringUtils.leftFill(Long.toHexString(afterAmt), '0', 8);
String chargeFee = CustomStringUtils.leftFill(Long.toHexString(txnAmt), '0', 8); // if (walletSequence.length() == 6) {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
// } else {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
// }
// walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4); //4字节电子存折或电子钱包新余额 + 2字节电子存折或电子钱包联机交易序号(加1前) + 4字节交易金额 + 1字节交易类型标识 + 6字节终端机编号 + 4字节主机交易日期 + 3字节主机交易时间
String tacData = CustomStringUtils.append(newBalance, walletSequence, chargeFee, tradeType, psamTerminalCode, tradeDateTime); System.out.println("tacData:" + tacData);
System.out.println("tacProceessKey:" + DesUtils.byte2hexString(tacProcessKeyBytes)); byte[] tacDataBytes = DesUtils.hexString2byte(tacData);
byte[] icv = DesUtils.hexString2byte("0000000000000000"); byte[] calculatePbocdesMACBytes = MacUtils.calculatePbocdesMAC(tacDataBytes, tacProcessKeyBytes, icv);
String calculatePbocdesMAC = DesUtils.byte2hexString(calculatePbocdesMACBytes); String tac = calculatePbocdesMAC.substring(0, 8);
return tac;
} /**
* 计算TAC
* @param rechargeFeeHex 新余额(充值后金额)(16进制)
* @param walletSequence 钱包交易序号
* @param rechargeFeeHex 充值金额(16进制)
* @param tradeType 交易类型
* @param psamTerminalCode 终端机编号
* @param tradeDateTime 交易日期时间
* @param tacKey tac密钥
* @param protectKey 保护密钥
* @return
* @throws Exception
*/
public static String getTac(String afterBalanceHex, String walletSequence, String rechargeFeeHex, String tradeType, String psamTerminalCode, String tradeDateTime, String tacKey, String protectKey) throws Exception { //获取TAC密钥明文
byte[] tacKeyBytes = DesUtils.hexString2byte(tacKey);
byte[] protectKeyBytes = DesUtils.hexString2byte(protectKey);
byte[] tacKeyClearTextBytes = DesUtils.decryptBy3DesEcb(tacKeyBytes, protectKeyBytes); System.out.println("tacKeyClearText:" + DesUtils.byte2hexString(tacKeyClearTextBytes)); int half = tacKeyClearTextBytes.length / 2;
byte[] b1 = new byte[half];
byte[] b2 = new byte[half]; System.arraycopy(tacKeyClearTextBytes, 0, b1, 0, half);
System.arraycopy(tacKeyClearTextBytes, half, b2, 0, half); //tac过程密钥
byte[] tacProcessKeyBytes = DesUtils.xOr(b1, b2); //4字节电子存折或电子钱包新余额
String newBalance = CustomStringUtils.leftFill(afterBalanceHex, '0', 8);
String chargeFee = CustomStringUtils.leftFill(rechargeFeeHex, '0', 8); // if (walletSequence.length() == 6) {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence.substring(2)));
// } else {
// walletSequence = Integer.toHexString(Integer.parseInt(walletSequence));
// }
// walletSequence = CustomStringUtils.leftFill(walletSequence, '0', 4); //4字节电子存折或电子钱包新余额 + 2字节电子存折或电子钱包联机交易序号(加1前) + 4字节交易金额 + 1字节交易类型标识 + 6字节终端机编号 + 4字节主机交易日期 + 3字节主机交易时间
String tacData = CustomStringUtils.append(newBalance, walletSequence, chargeFee, tradeType, psamTerminalCode, tradeDateTime); System.out.println("tacData:" + tacData);
System.out.println("tacProceessKey:" + DesUtils.byte2hexString(tacProcessKeyBytes)); byte[] tacDataBytes = DesUtils.hexString2byte(tacData);
byte[] icv = DesUtils.hexString2byte("0000000000000000"); byte[] calculatePbocdesMACBytes = MacUtils.calculatePbocdesMAC(tacDataBytes, tacProcessKeyBytes, icv);
String calculatePbocdesMAC = DesUtils.byte2hexString(calculatePbocdesMACBytes); String tac = calculatePbocdesMAC.substring(0, 8);
return tac;
} }

DES算法和MAC算法总结的更多相关文章

  1. 最小生成树---Prim算法和Kruskal算法

    Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...

  2. mahout中kmeans算法和Canopy算法实现原理

    本文讲一下mahout中kmeans算法和Canopy算法实现原理. 一. Kmeans是一个很经典的聚类算法,我想大家都非常熟悉.虽然算法较为简单,在实际应用中却可以有不错的效果:其算法原理也决定了 ...

  3. 使用Apriori算法和FP-growth算法进行关联分析

    系列文章:<机器学习实战>学习笔记 最近看了<机器学习实战>中的第11章(使用Apriori算法进行关联分析)和第12章(使用FP-growth算法来高效发现频繁项集).正如章 ...

  4. 转载:最小生成树-Prim算法和Kruskal算法

    本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...

  5. 0-1背包的动态规划算法,部分背包的贪心算法和DP算法------算法导论

    一.问题描述 0-1背包问题,部分背包问题.分别实现0-1背包的DP算法,部分背包的贪心算法和DP算法. 二.算法原理 (1)0-1背包的DP算法 0-1背包问题:有n件物品和一个容量为W的背包.第i ...

  6. 用Spark学习FP Tree算法和PrefixSpan算法

    在FP Tree算法原理总结和PrefixSpan算法原理总结中,我们对FP Tree和PrefixSpan这两种关联算法的原理做了总结,这里就从实践的角度介绍如何使用这两个算法.由于scikit-l ...

  7. 字符串查找算法总结(暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法)

    字符串匹配是字符串的一种基本操作:给定一个长度为 M 的文本和一个长度为 N 的模式串,在文本中找到一个和该模式相符的子字符串,并返回该字字符串在文本中的位置. KMP 算法,全称是 Knuth-Mo ...

  8. 最小生成树之Prim算法和Kruskal算法

    最小生成树算法 一个连通图可能有多棵生成树,而最小生成树是一副连通加权无向图中一颗权值最小的生成树,它可以根据Prim算法和Kruskal算法得出,这两个算法分别从点和边的角度来解决. Prim算法 ...

  9. java实现最小生成树的prim算法和kruskal算法

    在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...

随机推荐

  1. realstudio 粒子特效问题总结

    ParticleEmitter._inner_material.flags.depth_write = true;ParticleEmitter._inner_material.flags.depth ...

  2. 列出连通集(mooc)

    给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集.假设顶点从0到N−1编号.进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点. 输入格式: 输入第1 ...

  3. Python基础入门(迭代器和生成器)

    1 Python迭代器 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束. 迭代器只能往前不会后退. 迭代器有两个基本的方法:iter() 和 ...

  4. python常用快捷键

    最重要的快捷键1. ctrl+shift+A:万能命令行2. shift两次:查看资源文件 新建工程第一步操作1. module设置把空包分层去掉,compact empty middle packa ...

  5. Your funds transfer has been delayed

    Hello from Amazon. Your funds transfer in the amount of 9,422.88 USD has been delayed because the cr ...

  6. Scrum立会报告+燃尽图(十月二十八日总第十九次)

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2288 项目地址:https://git.coding.net/zhang ...

  7. 关于解决MySort

    关于解决MySort 那天老师教给我们关于sort的用法以及String类中的split方法.在一定程度上告诉我们sort用法的原理和一些特别的用法后,老师叫我们用JAVA尝试去设计一个"M ...

  8. iOS开发 常见错误

    一.NSAppTransportSecurity 错误提示:NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL ...

  9. 超级迷宫需求分析与建议-NABCD模型

    超级迷宫需求分析与建议-NABCD模型 制作者-姜中希 1N-Need 需求  首先这是一个手机游戏风靡的时代,随着智能手机不断的更新问世,4G网络的不断扩大普及,越来越多的手机游戏受到广大玩家的追捧 ...

  10. ASP.NET MVC5 学习系列之表单和HTML辅助方法

    一.表单 (一)Action和Method特性 Action特性用以告知浏览器信息发往何处,因此,Action特性后面需要包含一个Url地址.这里的Url地址可以是相对的,也可以是绝对的.如下Form ...