package com.joker.utils; import java.io.UnsupportedEncodingException; public class DESedeTool { /***************************** 压缩替换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左补0 if (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); // 置换P ret = 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扩展�?8bit int[] expendR = expend(R);// 48bit // 与轮子密钥进行异或运�? temp = diffOr(expendR, K); // 压缩�?2bit dest = 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 ok for (int i = 1; i < 17; i++) { // 获取(48bit)的轮子密�? int[] key = subKey[i - 1]; // L1 = R0 left[i] = right[i - 1]; // R1 = L0 ^ f(R0,K1) int[] fTemp = f(right[i - 1], key);// 32bit right[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 ok for (int i = 16; i > 0; i--) { // 获取(48bit)的轮子密�? /********* 不同之处 **********/ int[] sKey = subKey[i - 1]; tmp = left; // R1 = L0 left = right; // L1 = R0 ^ f(L0,K1) int[] fTemp = f(right, sKey);// 32bit right = 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_new(String source, String key, int type) { String temp = ""; for(int i =0;i<source.length()/16;i++){ String str = source.substring(i*16,(i+1)*16); temp+=DES_3(str,key,type); } return temp; } 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]; // 装换�?4bit int[] temp = string2Binary(source); // �?6bit均分成两部分 int[] left = new int[28]; int[] right = new int[28]; // 经过PC-1�?4bit转换�?6bit int[] 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) { 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 Vector String I = xOr(D[0], vector); String O = null; for (int i = 1; i < arrLen; i++) { // System.out.println(i + "**************"); // System.out.println("I=" + I); O = DES_1(I, key, 0); // System.out.println("O=" + O); I = xOr(D[i], O); // System.out.println("I=" + I); } I = DES_1(I, key, 0); 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(); } /** * * 三重DES算法(双�?长密�?32byte)) * * 密钥K1和K2 * * 1、先用K1加密明文 * * 2、接�?��K2对上�?��的结果进行解�? * * 3、然后用K1对上�?��的结果进行加�? * * @param source * * @param key * * @param type * 0:encrypt 1:discrypt * * @return */ public static String DEDES_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; } public static void main(String[] args) throws Exception { //B2E8F2E11778F601 //7576242348C58915 System.out.println(DES_1("3630ADF459CB24DA", "87077F2FD88BD8B8", 0)); System.out.println(DES_1("3630ADF459CB24DA", "87077F2FD88BD8B87576242348C58915", 1)); } }