zoukankan      html  css  js  c++  java
  • 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;
        }
    
    }
  • 相关阅读:
    家庭记账本(七+每周总结)
    家庭记账本(六)
    家庭记账本(五)
    家庭记账本(四)
    家庭记账本(三)
    家庭记账本(二)
    家庭记账本(一)
    2021.2.14(每周总结)
    2021.2.13
    文件上传时报错in a frame because it set 'X-Frame-Options' to 'deny'.
  • 原文地址:https://www.cnblogs.com/alsodzy/p/9324794.html
Copyright © 2011-2022 走看看