DES加解密过程详解:
代码实现细节如下,DES加解密是对合运算,直接使用一个方法完成
import java.util.InputMismatchException;
import java.util.Scanner;
public class DES {
private static byte 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 byte 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 byte 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 byte 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, 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 byte 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 byte 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 byte 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 byte 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};
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入明文:");
String message = sc.nextLine(); // 明文
//填充明文,使其长度为8的整数倍
message = paddingMess(message);
System.out.println("请输入加密密钥(8个字符):");
String inputKey = sc.nextLine(); // 密钥
char inputKeyArr[] = inputKey.toCharArray();
char inputKeyBin[][] = new char[8][8];
// 加密密钥的二进制存放
keyStrTokeyBin(inputKeyArr, inputKeyBin);
String cypher = Encrypt(message, inputKeyBin, 1);
String cypherHex = binToHex(cypher);
System.out.println("DES加密结果:" + cypher);
System.out.println("十六DES加密结果:" + cypherHex);
//加解密分割线---------------
System.out.println("请输入解密密钥(8个字符):");
inputKey = sc.nextLine(); // 解密密钥
inputKeyArr = inputKey.toCharArray(); //解密密钥字符串
keyStrTokeyBin(inputKeyArr, inputKeyBin); //解密密钥的二进制数组,8列
// 解密密钥的二进制存放
keyStrTokeyBin(inputKeyArr, inputKeyBin);
String messDec = Encrypt(cypher, inputKeyBin, -1);
String messDecHex = binToHex(messDec);
message = hexMessToString(messDec);
System.out.println("DES解密结果:" + messDec);
System.out.println("十六DES解密结果:" + messDecHex);
System.out.println("解密结果:" + message);
}
/**
* @param message 该参数是传入的明文或者密文信息
* @param inputKey 该参数是二进制二维密钥数组,密钥长度行,8列
* @param flag 因为DES是对合运算,所以该函数同时可以进行加密和解密,flag位即加密解密标记位,1为加密,0为解密
* @return 返回加密或者解密后的二进制数组
*/
public static String Encrypt(String message, char inputKey[][], int flag) {
char masterKeyLeft[] = new char[28];
char masterKeyRight[] = new char[28];
byte keyRevLft[] = {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};
byte keyRevRight[] = {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};
// 对左28位和右28位赋值
for (int i = 0; i < masterKeyLeft.length; i++) {
masterKeyLeft[i] = inputKey[keyRevLft[i] / 8][keyRevLft[i] % 8 - 1];
}
for (int i = 0; i < masterKeyRight.length; i++) {
masterKeyRight[i] = inputKey[keyRevRight[i] / 8][keyRevRight[i] % 8 - 1];
}
// 定义左移位数的数组
byte moveArr[] = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
// 定义子密钥数组并且移为选择赋值
char subKey[][] = new char[16][48];
for (int i = 0; i < subKey.length; i++) {
subKey[i] = getSubKey(masterKeyLeft, masterKeyRight, moveArr[i]);
}
// 得到子密钥,开始加密
// 创建明文或者密文二进制数组及赋值
char messageBin[][];
if (flag == 1) {
messageBin = new char[message.length() / 8][64];
messageBin = messageToBin(message);
}
else {
messageBin = new char[message.length() / 64][64];
for (int i = 0; i < messageBin.length; i++) {
messageBin[i] = message.substring(64 * i,64 * (i + 1)).toCharArray();
}
}
// 开始循环对每个64位进行加密或者解密
String cypher = "";
cypher = interater(subKey,messageBin,flag);
return cypher;
}
public static void innerInterater(char L0[], char R0[], char subKey[]) {
char tempResult[] = new char[32];
//选择扩展数组
byte selectE[] = {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};
//R0经过运算得到48位的中间变量
char tempR0[] = new char[48];
for (int i = 0; i < tempR0.length; i++) {
tempR0[i] = R0[selectE[i] - 1];
}
//得到选择结果
//中间变量与子密钥亦或,结果中间变量中覆盖原有数据
for (int i = 0; i < tempR0.length; i++) {
if (tempR0[i] == subKey[i])
tempR0[i] = '0';
else
tempR0[i] = '1';
}
//48位选择出32位
for (int i = 0; i < tempR0.length - 5; i += 6) {
String temp = "";
temp += tempR0[i];
temp += tempR0[i + 5];
int column = Integer.parseInt(temp, 2);
temp = "";
temp += tempR0[i + 1];
temp += tempR0[i + 2];
temp += tempR0[i + 3];
temp += tempR0[i + 4];
int row = Integer.parseInt(temp, 2);
byte ret = 0;
switch (i / 6) {
case 0:
ret = S1[column * 16 + row];
break;
case 1:
ret = S2[column * 16 + row];
break;
case 2:
ret = S3[column * 16 + row];
break;
case 3:
ret = S4[column * 16 + row];
break;
case 4:
ret = S5[column * 16 + row];
break;
case 5:
ret = S6[column * 16 + row];
break;
case 6:
ret = S7[column * 16 + row];
break;
case 7:
ret = S8[column * 16 + row];
break;
}
String retStr = Integer.toBinaryString(ret);
while (retStr.length() != 4)
retStr = '0' + retStr;
char retArr[] = retStr.toCharArray();
for (int j = (i / 6) * 4, t = 0; j < 4 * (i / 6 + 1); j++, t++) {
tempResult[j] = retArr[t];
}
}
//置换运算P,打乱顺序
byte selectP[] = {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};
//这里tempResult中存放的是经过S盒选择的32位数据
//下面开始执行P置换,再与L0亦或运算得到R0,暂时继续存放到tempResult中
//48位选择32位结束,得到经过F运算的结果,存放在tempResult中,f函数结果与L0亦或重新赋值
char result[] = new char[tempResult.length];
for (int j = 0; j < tempResult.length; j++) {
if (tempResult[selectP[j] - 1] == L0[j])
result[j] = '0';
else
result[j] = '1';
}
for (int i = 0; i < result.length; i++) {
L0[i] = R0[i];
R0[i] = result[i];
}
}
public static String Decrypt(String cypher, char inputKey[][]) {
String messageDec = "";
return messageDec;
}
public static char[] getSubKey(char masterKeyLeft[], char masterKeyRight[], byte num) {
char subKey[] = new char[48];
char tempArrL[] = new char[num]; // 临时数组,存放移位溢出的数据
char tempArrR[] = new char[num]; // 临时数组,存放移位溢出的数据
// 移位
for (int i = 0; i < num; i++) {
tempArrL[i] = masterKeyLeft[i];
tempArrR[i] = masterKeyRight[i];
}
for (int i = 0; i < masterKeyLeft.length - num; i++) {
masterKeyLeft[i] = masterKeyLeft[i + num];
masterKeyRight[i] = masterKeyRight[i + num];
}
for (int i = num; i > 0; i--) {
masterKeyLeft[masterKeyLeft.length - i] = tempArrL[num - i];
masterKeyRight[masterKeyRight.length - i] = tempArrR[num - i];
}
// 移位完成,对两个数组选择,结果赋值给subKey
// 定义置换选择2的矩阵
byte selectArr[] = {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 < selectArr.length; i++) {
if (selectArr[i] > 28) {
subKey[i] = masterKeyRight[selectArr[i] - 29];
} else {
subKey[i] = masterKeyLeft[selectArr[i] - 1];
}
}
return subKey;
}
/**
* 该方法有两个参数
*
* @param inputKeyArr 该参数是密钥数组
* @param inputKeyBin 该参数是密钥数组的二进制存放
* 两个参数都是修改后返回
*/
public static void keyStrTokeyBin(char inputKeyArr[], char inputKeyBin[][]) {
for (int i = 0; i < inputKeyBin.length; i++) {
String inputKeyBlock = Integer.toBinaryString(inputKeyArr[i]);
int t = 8 - inputKeyBlock.length();
while (t != 0) {
inputKeyBlock = "0" + inputKeyBlock;
t = 8 - inputKeyBlock.length();
}
inputKeyBin[i] = inputKeyBlock.toCharArray();
}
return;
}
/**
* @param message 传入的参数是二进制字符串 this parament is a binary String waited to be Hex String
* @return 返回的参数是二进制字符串转化出的十六进制字符串 this method retun the Hex String of parament Binary String
*/
public static String binToHex(String message) {
char messageArr[] = message.toCharArray();
String hexTemp = "";
String retStr = "";
for (int i = 0; i < message.length(); i += 8) {
hexTemp = "";
for (int j = 0; j < 8; j++) {
hexTemp += messageArr[i + j];
}
hexTemp = Integer.toHexString(Integer.parseInt(hexTemp, 2));
if (hexTemp.length() != 2)
hexTemp = "0" + hexTemp;
retStr += hexTemp;
}
return retStr;
}
/**
* @param message 该参数是传入的明文信息
* @return 返回值是使用=字符填充后的明文,其长度为8的整数倍
*/
public static String paddingMess(String message) {
StringBuilder strBud = new StringBuilder(message);
if (message.length() % 8 != 0) { // 用等号=将明文填充够8的整数倍
while (strBud.length() % 8 != 0) {
strBud.append("=");
}
}
return strBud.toString();
}
public static char[][] messageToBin(String message) {
char messageBin[][] = new char[message.length() / 8][64];
char messageCha[] = message.toCharArray();
// 明文二进制数组赋值
String bin = ""; // 明文的二进制字符串
for (int i = 0; i < messageCha.length; i++) {
int t = 8 - Integer.toBinaryString(messageCha[i]).length();
while (t != 0) {
bin += '0';
t--;
}
bin += Integer.toBinaryString(messageCha[i]);
}
for (int i = 0; i < messageBin.length; i++) {
if (i == messageBin.length - 1) {
messageBin[i] = bin.substring(64 * i, bin.length()).toCharArray();
} else {
messageBin[i] = bin.substring(64 * i, 64 * (i + 1)).toCharArray();
}
}
return messageBin;
}
public static String interater(char subKey[][],char messageBin[][],int flag) {
char L0[] = new char[32];
char R0[] = new char[32];
byte 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};
String cypher = "";
for (int i = 0; i < messageBin.length; i++) {
//对L0 R0 赋值
for (int j = 0; j < messageBin[i].length; j++) {
if (j >= 32)
R0[j - 32] = messageBin[i][ip[j] - 1];
else
L0[j] = messageBin[i][ip[j] - 1];
}
//开始对当前分组进行16轮迭代
for (int j = 0; j < 16; j++) {
if (flag == 1) //加密
innerInterater(L0, R0, subKey[j]);
else if(flag == -1) //解密
innerInterater(L0, R0, subKey[15-j]);
else
throw new InputMismatchException();
}
//最后一轮迭代不交换左右L0 和 R0,但是循环里交换了,循环外再次交换回来
char tempR0;
for (int j = 0; j < L0.length; j++) {
tempR0 = L0[j];
L0[j] = R0[j];
R0[j] = tempR0;
}
//逆初始置换IPRev
String tempCry = "";
for (int j = 0; j < L0.length; j++) {
tempCry += L0[j];
}
for (int j = 0; j < R0.length; j++) {
tempCry += R0[j];
}
char tempCryArr[] = tempCry.toCharArray();
byte ipRev[] = {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};
char cryRevArr[] = new char[tempCryArr.length];
for (int j = 0; j < cryRevArr.length; j++)
cryRevArr[j] = tempCryArr[ipRev[j] - 1];
cypher += new String(cryRevArr);
}
return cypher;
}
public static String hexMessToString(String message) {
StringBuilder messageCha = new StringBuilder();
char arr[] = new char[8];
for (int i = 0; i < message.length() / 8; i++) {
arr = message.substring(8 * i,8 * (i + 1)).toCharArray();
messageCha.append((char)Integer.parseInt(new String(arr),2));
}
return messageCha.toString();
}
}
代码细节有任何问题欢迎评论私聊提问