上次介绍了一下DES算法的整体流程,那么下面展开讲讲DES算法中16轮密钥获取的部分
话不多说,先上代码
package common;
import java.math.BigInteger;
/**
* 进制转换类
* @author zygswo
*
*/
public class EncodeUtil {
/**
* 转2进制(字符串转成二进制)
* @param text 要转的文本
* @param length 字符长度
* @return
*/
public static String strtoBinary(String text, int length) {
StringBuilder result = new StringBuilder("");
//取每一位上的数字
for(char ch : text.toCharArray()) {
int res = ch, pre = ch;
String res1 = "";
while(res > 0) {
res = res >> 1 << 1;
res1 = ((pre ^ res) == 0 ? "0" : "1") + res1; //异或判断当前位上数字是否为1
res = res >> 1;
pre = pre >> 1;
}
//扩充至8位
while (res1.length() < length) {
res1 = "0" + res1;
}
// System.out.println("res1 = " + res1);
result.append(res1);
}
return result.toString();
}
}
package des;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import common.EncodeUtil;
/**
* 子密钥生成为置换选择,因为不仅有位的置换还有位的筛选
* 而des明文加密中的为初始置换,因为没有位的筛选。
*/
/**
* des加解密密钥生成工具类
* @author zygswo
*
*/
public class KeyUtil {
/**
* 循环移动
*/
public static final int[] SHIFT = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
/**
* 置换选择PC-1表
*/
private static int[][] transferTable = {
{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}
};
/**
* 置换选择PC-2表
*/
private static int[][] transferTwoTable = {
{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}
};
/**
* leftpart and rightPart
*/
private char[] leftPart,rightPart;
/**
* keylist
*/
private List<String> keylist = Collections.synchronizedList(new ArrayList<>());
/**
* 密钥初始化
*/
public KeyUtil init() {
String randomStr = "12345678";
String str64bit = EncodeUtil.strtoBinary(randomStr,8);
leftPart = new char[28]; //左半部分
rightPart = new char[28]; //右半部分
//置换选择(pc-1)
for (int i=0; i< 28;i++) {
leftPart[i] = str64bit.charAt(transferTable[i/8][i%8] - 1);
}
for (int i=28; i< 56;i++) {
rightPart[i-28] = str64bit.charAt(transferTable[i/8][i%8] - 1);
}
return this;
}
/**
* 加密生成子密钥
* @param round 循环次数
* @return
*/
public List<String> generateKey() {
if (leftPart == null || rightPart == null) {
throw new RuntimeException("请先进行密钥初始化");
}
for (int i : SHIFT) {
//循环左移,1,2,9,16移动一位,其他移动2位
String leftRotateResult = leftRotate(leftPart, rightPart, i);
char[] temp = leftRotateResult.toCharArray();
char[] result = new char[48];
for (int k=0; k<48; k++) {
result[k] = temp[transferTwoTable[k/8][k%8] - 1];
}
keylist.add(new String(result));
}
System.out.println(keylist.toString());
return keylist;
}
/**
* 循环左移
* @param leftPart 左边28位
* @param rightPart 右边28位
* @return 循环后的结果
*/
private String leftRotate(char[] leftPart, char[] rightPart, int i) {
String leftValue = new String(leftPart);
String rightValue = new String(rightPart);
leftValue = leftValue.substring(i) + leftValue.substring(0,i);
rightValue = rightValue.substring(i) + rightValue.substring(0,i);
this.leftPart = leftValue.toCharArray();
this.rightPart = rightValue.toCharArray();
return leftValue + rightValue;
}
public static void main(String[] args) {
new KeyUtil().init().generateKey();
}
}
整体流程:
设计思路:
将整个16轮循环左移的偏移量放入shift数组中,之后通过for循环遍历shift数组获取16轮的密钥获取输出结果再通过返回结果List的方式完成输出。
--------------------------------小尾巴--------------------------------------------------------------------
DES算法会持续更新