DES算法和MAC算法總結

須要用到的工具類,代碼以下:java

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;
     * 一、數據D分組而且填充:將字節數組D進行分組,每組8個字節,分組編號從0開始,分別爲D0...Dn;最後一個分組不滿8字節的,先填充一個字節80,
     * 後續所有填充00,滿8字節的,新增一個8字節分組(80000000 00000000);
     * 二、進行des循環加密:(1)D0和初始向量I進行按位異或獲得結果O0;(2)使用祕鑰K1,DES加密結果O0獲得結果I1,
     * 將I1和D1按位異或獲得結果D1;(3)循環第二步驟獲得結果Dn; 三、將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工具類:app

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

}
相關文章
相關標籤/搜索