package tools;
import java.io.UnsupportedEncodingException;
/**
* @author liyan
*
*/
public class DES {
/*****************************压缩替换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
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
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
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
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
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
temp = source[0];
for(int j=0; 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
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
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
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
//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
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 static void main(String[] args) throws Exception {
System.out.println("/*************Tripe-DES*************/");
//主密�?
String masterKey = "11111111111111112222222222222222";
//数据
String data = "1111111111111111";
System.out.println(DES_3(data, masterKey, 0));
String dpk = getDPK("1111111111111111","1111111111111111","11111111111111111111111111111111");
System.out.println(dpk);
}
}
标签: