DES算法和MAC算法总结
需要用到的工具类,代码如下:
- 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算法总结的更多相关文章
- 最小生成树---Prim算法和Kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (gra ...
- mahout中kmeans算法和Canopy算法实现原理
本文讲一下mahout中kmeans算法和Canopy算法实现原理. 一. Kmeans是一个很经典的聚类算法,我想大家都非常熟悉.虽然算法较为简单,在实际应用中却可以有不错的效果:其算法原理也决定了 ...
- 使用Apriori算法和FP-growth算法进行关联分析
系列文章:<机器学习实战>学习笔记 最近看了<机器学习实战>中的第11章(使用Apriori算法进行关联分析)和第12章(使用FP-growth算法来高效发现频繁项集).正如章 ...
- 转载:最小生成树-Prim算法和Kruskal算法
本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算 ...
- 0-1背包的动态规划算法,部分背包的贪心算法和DP算法------算法导论
一.问题描述 0-1背包问题,部分背包问题.分别实现0-1背包的DP算法,部分背包的贪心算法和DP算法. 二.算法原理 (1)0-1背包的DP算法 0-1背包问题:有n件物品和一个容量为W的背包.第i ...
- 用Spark学习FP Tree算法和PrefixSpan算法
在FP Tree算法原理总结和PrefixSpan算法原理总结中,我们对FP Tree和PrefixSpan这两种关联算法的原理做了总结,这里就从实践的角度介绍如何使用这两个算法.由于scikit-l ...
- 字符串查找算法总结(暴力匹配、KMP 算法、Boyer-Moore 算法和 Sunday 算法)
字符串匹配是字符串的一种基本操作:给定一个长度为 M 的文本和一个长度为 N 的模式串,在文本中找到一个和该模式相符的子字符串,并返回该字字符串在文本中的位置. KMP 算法,全称是 Knuth-Mo ...
- 最小生成树之Prim算法和Kruskal算法
最小生成树算法 一个连通图可能有多棵生成树,而最小生成树是一副连通加权无向图中一颗权值最小的生成树,它可以根据Prim算法和Kruskal算法得出,这两个算法分别从点和边的角度来解决. Prim算法 ...
- java实现最小生成树的prim算法和kruskal算法
在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...
随机推荐
- 利用Tensorflow进行自然语言处理(NLP)系列之一Word2Vec
同步笔者CSDN博客(https://blog.csdn.net/qq_37608890/article/details/81513882). 一.概述 本文将要讨论NLP的一个重要话题:Word2V ...
- 使用qemu启动dd制作的img镜像
1. 准备工作 应用场景 在需要单机取证时,需要在不影响对象业务的情况下进行取证或分析,可以使用dd 对目标服务器进行镜像,生成img文件,镜像可以通过winhex进行静态分析.但是想要动态分析服务器 ...
- 工作在Amazon:为何晋升如此难?
英文原文:Why It's So Difficult to Climb Amazon's Corporate Ladder 本文作者 Brad Stone 的新书 The Everything Sto ...
- js操作对象属性值为字符串
今天在项目开发中遇到一个没遇到过的问题,这个问题是需要对比两个对象a和b,a是一个只有一个属性的对象,b是一个含有多个属性对象,如果b中包含和a一模一样的属性名和值,则把这个一样的属性和值从b中删除了 ...
- Phonegap 环境配置
目前要开发 Web App 还是有比较多的选择的 如 Phonegap.MUI.AppCan,接下来以 Web前端开发工程师 的角度来一个 Phonegap 的 First Blood 一.开发环境: ...
- 补充的css知识点
1.文字一行显示 超出的用...表示 .ellipsis{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
- sprint3最终演示及团队贡献分
团队名:在考虑 团队项目:复利计算 项目演示: 之前的功能都有演示过就不再一一截图,把我们新增加的功能说一下 首先用户进入我们的网页可以登录或者注册,注册的用户可以直接输入用户名及密码登录,没有注册的 ...
- Thunder团队第七周 - Scrum会议6
Scrum会议6 小组名称:Thunder 项目名称:i阅app Scrum Master:苗威 工作照片: 宋雨在照相,所以不在相片中. 参会成员: 王航:http://www.cnblogs.co ...
- struts2文件上传突破2M限制
struts配置文件 <action name="upload" class="strutsFileUpload"> <result name ...
- struts2 不返回result的做法
有时候 比如提交一个弹框的表单 提交成功后我们只是让表单关闭并不进行页面跳转,那么action 里面就returne null, 然后result 也不用配置了 版权声明:本文为博主原创文章,未经博主 ...