java版 MAC ANSI x 9.9 算法

来源:互联网 发布:优盘格式化恢复软件 编辑:程序博客网 时间:2024/05/29 07:55

网上通过查找DES算法,无意间发现了这个算法,因为对算法不是很了解,暂时未对注释中的乱码进行修改


package fuck.this.world;import java.io.UnsupportedEncodingException;/** *  * @author someone *  * desType 1:单倍长 2:3DES(双倍长)3:3DES(三倍长) *  */public class MAC_ANSI_x9_9 {/** ***************************压缩替换S-Box�?************************************************* */private static final int[][] s1 = {{ 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },{ 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },{ 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },{ 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 } };private static final int[][] s2 = {{ 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },{ 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },{ 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },{ 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 } };private static final int[][] s3 = {{ 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },{ 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },{ 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },{ 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 } };private static final int[][] s4 = {{ 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },{ 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },// erorr{ 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },{ 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } };private static final int[][] s5 = {{ 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },{ 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },{ 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },{ 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 } };private static final int[][] s6 = {{ 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },{ 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },{ 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },{ 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 } };private static final int[][] s7 = {{ 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },{ 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },{ 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },{ 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 } };private static final int[][] s8 = {{ 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },{ 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },{ 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },{ 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } };private static final int[] ip = { 58, 50, 42, 34, 26, 18, 10, 2,60, 52, 44, 36, 28, 20, 12, 4,62, 54, 46, 38, 30, 22, 14, 6,64, 56, 48, 40, 32, 24, 16, 8,57, 49, 41, 33, 25, 17, 9, 1,59, 51, 43, 35, 27, 19, 11, 3,61, 53, 45, 37, 29, 21, 13, 5,63, 55, 47, 39, 31, 23, 15, 7 };private static final int[] _ip = { 40, 8, 48, 16, 56, 24, 64, 32,39, 7, 47, 15, 55, 23, 63, 31,38, 6, 46, 14, 54, 22, 62, 30,37, 5, 45, 13, 53, 21, 61, 29,36, 4, 44, 12, 52, 20, 60, 28,35, 3, 43, 11, 51, 19, 59, 27,34, 2, 42, 10, 50, 18, 58, 26,33, 1, 41, 9, 49, 17, 57, 25 };// 每次密钥循环左移位数private static final int[] LS = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2,2, 1 };private static int[][] subKey = new int[16][48];private static int HEX = 0;private static int ASC = 1;/** *  * 将十六进制A--F转换成对应数�? *  * @param ch *  * @return *  * @throws Exception *  */public static int getIntByChar(char ch) throws Exception {char t = Character.toUpperCase(ch);int i = 0;switch (t) {case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9':i = Integer.parseInt(Character.toString(t));break;case 'A':i = 10;break;case 'B':i = 11;break;case 'C':i = 12;break;case 'D':i = 13;break;case 'E':i = 14;break;case 'F':i = 15;break;default:throw new Exception("getIntByChar was wrong");}return i;}/** *  * 将字符串转换成二进制数组 *  * @param source : *            16字节 *  * @return *  */public static int[] string2Binary(String source) {int len = source.length();int[] dest = new int[len * 4];char[] arr = source.toCharArray();for (int i = 0; i < len; i++) {int t = 0;try {t = getIntByChar(arr[i]);// System.out.println(arr[i]);} catch (Exception e) {e.printStackTrace();}String[] str = Integer.toBinaryString(t).split("");int k = i * 4 + 3;for (int j = str.length - 1; j > 0; j--) {dest[k] = Integer.parseInt(str[j]);k--;}}return dest;}/** *  * 返回x的y次方 *  * @param x *  * @param y *  * @return *  */public static int getXY(int x, int y) {int temp = x;if (y == 0)x = 1;for (int i = 2; i <= y; i++) {x *= temp;}return x;}/** *  * s�?位长度的二进制字符串 *  * @param s *  * @return *  */public static String binary2Hex(String s) {int len = s.length();int result = 0;int k = 0;if (len > 4)return null;for (int i = len; i > 0; i--) {result += Integer.parseInt(s.substring(i - 1, i)) * getXY(2, k);k++;}switch (result) {case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9:return "" + result;case 10:return "A";case 11:return "B";case 12:return "C";case 13:return "D";case 14:return "E";case 15:return "F";default:return null;}}/** *  * 将int转换成Hex *  * @param i *  * @return *  * @throws Exception *  */public static String int2Hex(int i) {switch (i) {case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:case 8:case 9:return "" + i;case 10:return "A";case 11:return "B";case 12:return "C";case 13:return "D";case 14:return "E";case 15:return "F";default:return null;}}/** *  * 将二进制字符串转换成十六进制字符�? *  * @param s *  * @return *  */public static String binary2ASC(String s) {String str = "";int ii = 0;int len = s.length();// 不够4bit左补0if (len % 4 != 0) {while (ii < 4 - len % 4) {s = "0" + s;}}for (int i = 0; i < len / 4; i++) {str += binary2Hex(s.substring(i * 4, i * 4 + 4));}return str;}/** *  * IP初始置换 *  * @param source *  * @return *  */public static int[] changeIP(int[] source) {int[] dest = new int[64];for (int i = 0; i < 64; i++) {dest[i] = source[ip[i] - 1];}return dest;}/** *  * IP-1逆置�? *  * @param source *  * @return *  */public static int[] changeInverseIP(int[] source) {int[] dest = new int[64];for (int i = 0; i < 64; i++) {dest[i] = source[_ip[i] - 1];}return dest;}/** *  * �?2bit扩展�?8bit *  * @param source *  * @return *  */public static int[] expend(int[] source) {int[] ret = new int[48];int[] temp = { 32, 1, 2, 3, 4, 5,4, 5, 6, 7, 8, 9,8, 9, 10, 11, 12, 13,12, 13, 14, 15, 16, 17,16, 17, 18, 19, 20, 21,20, 21, 22, 23, 24, 25,24, 25, 26, 27, 28, 29,28, 29, 30, 31, 32, 1 };for (int i = 0; i < 48; i++) {ret[i] = source[temp[i] - 1];}return ret;}/** *  * �?8bit压缩�?2bit *  * @param source(48bit) *  * @return R(32bit) *  * B=E(R)⊕K,将48 位的B 分成8 个分组,B=B1B2B3B4B5B6B7B8 *  */public static int[] press(int[] source) {int[] ret = new int[32];int[][] temp = new int[8][6];int[][][] s = { s1, s2, s3, s4, s5, s6, s7, s8 };StringBuffer str = new StringBuffer();for (int i = 0; i < 8; i++) {for (int j = 0; j < 6; j++) {temp[i][j] = source[i * 6 + j];}}for (int i = 0; i < 8; i++) {// (16)int x = temp[i][0] * 2 + temp[i][5];// (2345)int y = temp[i][1] * 8 + temp[i][2] * 4 + temp[i][3] * 2+ temp[i][4];int val = s[i][x][y];String ch = int2Hex(val);// System.out.println("x=" + x + ",y=" + y + "-->" + ch);// String ch = Integer.toBinaryString(val);str.append(ch);}// System.out.println(str.toString());ret = string2Binary(str.toString());// printArr(ret);// 置换Pret = dataP(ret);return ret;}/** *  * 置换P(32bit) *  * @param source *  * @return *  */public static int[] dataP(int[] source) {int[] dest = new int[32];int[] temp = { 16, 7, 20, 21,29, 12, 28, 17,1, 15, 23, 26,5, 18, 31, 10,2, 8, 24, 14,32, 27, 3, 9,19, 13, 30, 6,22, 11, 4, 25 };int len = source.length;for (int i = 0; i < len; i++) {dest[i] = source[temp[i] - 1];}return dest;}/** *  * @param R(�?2bit) *  * @param K(48bit的轮子密�? *  * @return 32bit *  */public static int[] f(int[] R, int[] K) {int[] dest = new int[32];int[] temp = new int[48];// 先将输入32bit扩展�?8bitint[] expendR = expend(R);// 48bit// 与轮子密钥进行异或运�?temp = diffOr(expendR, K);// 压缩�?2bitdest = press(temp);// System.out.println("need press data----->");// printArr(temp);return dest;}/** *  * 两个等长的数组做异或 *  * @param source1 *  * @param source2 *  * @return *  */public static int[] diffOr(int[] source1, int[] source2) {int len = source1.length;int[] dest = new int[len];for (int i = 0; i < len; i++) {dest[i] = source1[i] ^ source2[i];}return dest;}/** *  * DES加密--->对称密钥 *  * D = Ln(32bit)+Rn(32bit) *  * 经过16轮置�? *  * @param D(16byte)明文 *  * @param K(16byte)轮子密钥 *  * @return (16byte)密文 *  */public static String encryption(String D, String K) {String str = "";int[] temp = new int[64];int[] data = string2Binary(D);// printArr(data);// 第一步初始置�?data = changeIP(data);// printArr(data);int[][] left = new int[17][32];int[][] right = new int[17][32];for (int j = 0; j < 32; j++) {left[0][j] = data[j];right[0][j] = data[j + 32];}// printArr(left[0]);// printArr(right[0]);setKey(K);// sub key okfor (int i = 1; i < 17; i++) {// 获取(48bit)的轮子密�?int[] key = subKey[i - 1];// L1 = R0left[i] = right[i - 1];// R1 = L0 ^ f(R0,K1)int[] fTemp = f(right[i - 1], key);// 32bitright[i] = diffOr(left[i - 1], fTemp);}// �?��组合的时候,左右调换**************************************************for (int i = 0; i < 32; i++) {temp[i] = right[16][i];temp[32 + i] = left[16][i];}temp = changeInverseIP(temp);str = binary2ASC(intArr2Str(temp));return str;}/** *  * DES解密--->对称密钥 *  * 解密算法与加密算法基本相同,不同之处仅在于轮子密钥的使用顺序逆序,即解密的第1 *  * 轮子密钥为加密的�?6 轮子密钥,解密的�? 轮子密钥为加密的�?5 轮子密钥,�?…, *  * 解密的第16 轮子密钥为加密的�? 轮子密钥�? *  * @param source密文 *  * @param key密钥 *  * @return *  */public static String discryption(String source, String key) {String str = "";int[] data = string2Binary(source);// 64bit// 第一步初始置�?data = changeIP(data);int[] left = new int[32];int[] right = new int[32];int[] tmp = new int[32];for (int j = 0; j < 32; j++) {left[j] = data[j];right[j] = data[j + 32];}setKey(key);// sub key okfor (int i = 16; i > 0; i--) {// 获取(48bit)的轮子密�?/** *******不同之处********* */int[] sKey = subKey[i - 1];tmp = left;// R1 = L0left = right;// L1 = R0 ^ f(L0,K1)int[] fTemp = f(right, sKey);// 32bitright = diffOr(tmp, fTemp);}// �?��组合的时候,左右调换**************************************************for (int i = 0; i < 32; i++) {data[i] = right[i];data[32 + i] = left[i];}data = changeInverseIP(data);for (int i = 0; i < data.length; i++) {str += data[i];}str = binary2ASC(str);return str;}/** *  * 单�?长密钥DES(16byte) *  * @param source *  * @param key *  * @param type *            0:encrypt 1:discrypt *  * @return *  */public static String DES_1(String source, String key, int type) {if (source.length() != 16 || key.length() != 16)return null;if (type == 0) {return encryption(source, key);}if (type == 1) {return discryption(source, key);}return null;}/** *  *  *  * @param source *  * @param key *  * @param type *            0:encrypt 1:discrypt *  * @return *  */public static String DES_2(String source, String key, int type) {return null;}/** *  * 三重DES算法(双�?长密�?32byte)) *  * 密钥K1和K2 *  * 1、先用K1加密明文 *  * 2、接�?��K2对上�?��的结果进行解�? *  * 3、然后用K1对上�?��的结果进行加�? *  * @param source *  * @param key *  * @param type *            0:encrypt 1:discrypt *  * @return *  */public static String DES_3(String source, String key, int type) {if (key.length() != 32 || source.length() != 16)return null;String temp = null;String K1 = key.substring(0, key.length() / 2);String K2 = key.substring(key.length() / 2);System.out.println("K1--->" + K1);System.out.println("K2--->" + K2);if (type == 0) {temp = encryption(source, K1);System.out.println("step1--->" + temp);temp = discryption(temp, K2);System.out.println("step2--->" + temp);return encryption(temp, K1);}if (type == 1) {temp = discryption(source, K1);temp = encryption(temp, K2);return discryption(temp, K1);}return null;}/** **********************************48bit的轮子密钥的生成********************************************************* *//** *  * �?4bit的密钥转换成56bit *  * @param source *  * @return *  */public static int[] keyPC_1(int[] source) {int[] dest = new int[56];int[] temp = { 57, 49, 41, 33, 25, 17, 9,1, 58, 50, 42, 34, 26, 18,10, 2, 59, 51, 43, 35, 27,19, 11, 3, 60, 52, 44, 36,63, 55, 47, 39, 31, 23, 15,7, 62, 54, 46, 38, 30, 22,14, 6, 61, 53, 45, 37, 29,21, 13, 5, 28, 20, 12, 4 };for (int i = 0; i < 56; i++) {dest[i] = source[temp[i] - 1];}return dest;}/** *  * 将密钥循环左移i�? *  * @param source *            二进制密钥数�? *  * @param i *            循环左移位数 *  * @return *  */public static int[] keyLeftMove(int[] source, int i) {int temp = 0;int len = source.length;int ls = LS[i];// System.out.println("len" + len + ",LS[" + i + "]=" + ls);for (int k = 0; k < ls; k++) {temp = source[0];for (int j = 0; j < len - 1; j++) {source[j] = source[j + 1];}source[len - 1] = temp;}return source;}/** *  * �?6bit的密钥转换成48bit *  * @param source *  * @return *  */public static int[] keyPC_2(int[] source) {int[] dest = new int[48];int[] temp = { 14, 17, 11, 24, 1, 5,3, 28, 15, 6, 21, 10,23, 19, 12, 4, 26, 8,16, 7, 27, 20, 13, 2,41, 52, 31, 37, 47, 55,30, 40, 51, 45, 33, 48,44, 49, 39, 56, 34, 53,46, 42, 50, 36, 29, 32 };for (int i = 0; i < 48; i++) {dest[i] = source[temp[i] - 1];}return dest;}/** *  * 获取轮子密钥(48bit) *  * @param source *  * @return *  */public static void setKey(String source) {if (subKey.length > 0)subKey = new int[16][48];// 装换�?4bitint[] temp = string2Binary(source);// �?6bit均分成两部分int[] left = new int[28];int[] right = new int[28];// 经过PC-1�?4bit转换�?6bitint[] temp1 = new int[56];temp1 = keyPC_1(temp);// printArr(temp1);// 将经过转换的temp1均分成两部分for (int i = 0; i < 28; i++) {left[i] = temp1[i];right[i] = temp1[i + 28];}// 经过16次循环左移,然后PC-2置换for (int i = 0; i < 16; i++) {left = keyLeftMove(left, LS[i]);right = keyLeftMove(right, LS[i]);for (int j = 0; j < 28; j++) {temp1[j] = left[j];temp1[j + 28] = right[j];}// printArr(temp1);subKey[i] = keyPC_2(temp1);}}public static void printArr(int[] source) {int len = source.length;for (int i = 0; i < len; i++) {System.out.print(source[i]);}System.out.println();}/** *  * 将ASC字符串转�?6进制字符�? *  * @param asc *  * @return *  */public static String ASC_2_HEX(String asc) {StringBuffer hex = new StringBuffer();try {byte[] bs = asc.toUpperCase().getBytes("UTF-8");for (byte b : bs) {hex.append(Integer.toHexString(new Byte(b).intValue()));}} catch (UnsupportedEncodingException e) {e.printStackTrace();}return hex.toString();}/** *  * �?6进制的字符串转换成ASC的字符串 *  * �?6进制的字符串压缩成BCD�?30313233343536373839414243444546)-->(0123456789ABCDEF) *  * @param hex *  * @return *  */public static String HEX_2_ASC(String hex) {String asc = null;int len = hex.length();byte[] bs = new byte[len / 2];for (int i = 0; i < len / 2; i++) {bs[i] = Byte.parseByte(hex.substring(i * 2, i * 2 + 2), 16);}try {asc = new String(bs, "UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}return asc;}/** *  * 计算MAC(hex) *  * ANSI-X9.9-MAC(16的整数�?不补) *  * PBOC-DES-MAC(16的整数�?�?000000000000000) *  * 使用单�?长密钥DES算法 *  * @param key密钥(16byte) *  * @param vector初始向量0000000000000000 *  * @param data数据 *  * @return mac *  */public static String MAC(String key, String vector, String data, int type, int desType) {if (type == ASC) {data = ASC_2_HEX(data);}int len = data.length();int arrLen = len / 16 + 1;String[] D = new String[arrLen];if (vector == null)vector = "0000000000000000";if (len % 16 == 0) {data += "8000000000000000";} else {data += "80";for (int i = 0; i < 15 - len % 16; i++) {data += "00";}}for (int i = 0; i < arrLen; i++) {D[i] = data.substring(i * 16, i * 16 + 16);System.out.println("D[" + i + "]=" + D[i]);}// D0 Xor VectorString I = xOr(D[0], vector);String O = null;for (int i = 1; i < arrLen; i++) {// System.out.println(i + "**************");// System.out.println("I=" + I);switch (desType) {case 1:O = DES_1(I, key, 0);break;case 2:O = DES_2(I, key, 0);break;case 3:O = DES_3(I, key, 0);break;default:break;}// System.out.println("O=" + O);I = xOr(D[i], O);// System.out.println("I=" + I);}switch (desType) {case 1:O = DES_1(I, key, 0);break;case 2:O = DES_2(I, key, 0);break;case 3:O = DES_3(I, key, 0);break;default:break;}return I;}/** *  * 将s1和s2做异或,然后返回 *  * @param s1 *  * @param s2 *  * @return *  */public static String xOr(String s1, String s2) {int[] iArr = diffOr(string2Binary(s1), string2Binary(s2));return binary2ASC(intArr2Str(iArr));}/** *  * 将int类型数组拼接成字符串 *  * @param arr *  * @return *  */public static String intArr2Str(int[] arr) {StringBuffer sb = new StringBuffer();for (int i = 0; i < arr.length; i++) {sb.append(arr[i]);}return sb.toString();}/** *  * 将data分散 *  * @param data *  * @param key *  * @param type *  * @return *  */public static String divData(String data, String key, int type) {String left = null;String right = null;if (type == HEX) {left = key.substring(0, 16);right = key.substring(16, 32);}if (type == ASC) {left = ASC_2_HEX(key.substring(0, 8));right = ASC_2_HEX(key.substring(8, 16));}// 加密data = DES_1(data, left, 0);// 解密data = DES_1(data, right, 1);// 加密data = DES_1(data, left, 0);return data;}/** *  * 取反(10001)--->(01110) *  * @param source *  * @return *  */public static String reverse(String source) {int[] data = string2Binary(source);int j = 0;for (int i : data) {data[j++] = 1 - i;}return binary2ASC(intArr2Str(data));}/** *  * 主密钥需要经过两次分散获得IC卡中的子密钥 *  * @param issuerFlag发卡方标识符 *  * @param appNo应用序列号即卡号 *  * @param mpk主密钥 *  * @return *  */public static String getDPK(String issuerFlag, String appNo, String mpk) {// 第一次分散StringBuffer issuerMPK = new StringBuffer();// 获取Issuer MPK左半边issuerMPK.append(divData(issuerFlag, mpk, 0));// 获取Issuer MPK右半边issuerMPK.append(divData(reverse(issuerFlag), mpk, 0));// 第二次分散StringBuffer dpk = new StringBuffer();// 获取DPK左半边dpk.append(divData(appNo, issuerMPK.toString(), 0));// 获取DPK右半边dpk.append(divData(reverse(appNo), issuerMPK.toString(), 0));return dpk.toString();}public String getMac(String key, String data, int desType) {String macCode = "";macCode = MAC(key, "0000000000000000", data, HEX, desType);return macCode == null ? "" : macCode;}public static void main(String[] args) throws Exception {System.out.println("/*************Tripe-MAC*************/");String masterKey = "1111111111111111";String data = "1212122343243543554645756666666666633333333333333333332111aa";String macCode = MAC(masterKey, "0000000000000000", data, HEX, 1);System.out.println(macCode);}}