Cryptography extra chapter on the growth path of programmers ----- Detailed explanation of DES algorithm key acquisition

Last time I introduced the overall process of the DES algorithm, so let's talk about the 16 rounds of key acquisition in the DES algorithm

Without further ado, let’s start with the code

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();
	}
}

The overall idea of ​​the code:

  1. Overall process:

    1. Replacement option PC-1: Convert the 64-bit initial value to 28 bits in the left half and 28 bits in the right half, that is, replace the 64-bit initial value with a 56-bit subkey, the purpose is to increase confusion and remove the parity bit.
    2. Circular left shift: the left half and the right half are circularly shifted to the left at the same time. Shift the previous one to the end. [ps: The substring function is used here]. Note that the 1st, 2nd, 9th, and 16th cycles are shifted to the left by 1 bit, and the rest are shifted to the left by 2 bits, for a total of 28 bits to the left.
    3. Replacement selection PC-2: Combine the left half and the right half into a 56-bit subkey and then perform replacement selection PC-2 to obtain a 48-bit result for subsequent f-function operations. PS: Because the input of the f function is half of the 64-bit plaintext (32 bits) for the expansion operation (48 bits) and the key generation result (48 bits).
  2. Design idea:
    put the offset of the entire 16 rounds of left shift into the shift array, and then use the for loop to traverse the shift array to obtain the 16 rounds of keys to obtain the output results, and then complete the output by returning the result List.

--------------------------------Little tail---------------- -------------------------------------------------- --
The DES algorithm will be continuously updated

Guess you like

Origin blog.csdn.net/qq_31236027/article/details/129224730