Detailed explanation of DES encryption and decryption - Java,Python

DES introduction

Des (Data Encryption Standard) is by far the most widely used and popular block cipher algorithm in the world. Its packet length is 64 bits and the key length is 56 bits. It was developed by IBM in the United States. It is an early development and modification of Lucifer cipher. Every five years, the National Security Agency (NSA) evaluates and re approves whether it will continue to be a federal encryption standard. The last assessment was in January 1994. The United States has decided not to use des after December 1998. DES is the first generation of open and fully detailed commercial modern algorithm, which is recognized all over the world.

DES encryption is implemented based on Feistel structure, and its wheel structure is shown in the figure below:

DES encryption and decryption details

Encryption process of DES:

Encryption of plaintext binary:
Convert the plaintext data into binary, and then group the binary data into 64 bits in each group. If the group element is less than 64, it will be supplemented with 0 until it is full of 64. Then each set of 64bit data is initially replaced in the round function.

F operation is performed on the right 32bit in the round function, and then XOR is performed with the left 32bit. The obtained result is used as the right of the next round, and the right at the beginning is used as the left of the next round. It is cycled 16 times in turn. Finally, the inverse initial replacement is performed to obtain the ciphertext binary.

Generation of secret key:

Convert the plaintext secret key into binary, take 56bit as a group, fill 0 when it is less than 56bit, and then generate the secret key. Take the obtained secret key groups to participate in each round of F operation, that is, the first group of secret keys corresponds to the first round of F function, and the length of each group of generated secret keys is 48bit

Decryption process:

Encryption is the same as decryption. The difference is that the last set of secret keys corresponds to the first round of F function, that is, the secret key group is reversed.

After reading the general process, let's take a look at the specific code implementation, including java version and python version. For convenience, we will explain it in Python version. All the codes of Java and python will be attached at the end of the article.

DES encryption

We implement the process step by step according to the DES encryption process. (look at the flow chart step by step)

1. Clear text to binary
I think this step is more important. First of all, your plaintext may be Chinese + letters. In this way, if you convert to binary and then encrypt and decrypt, the results are different. Some strange characters (garbled code) will appear. If you only encrypt letters and numbers, they will not appear.

So we need another character form to replace it, and it only contains the composition of letters and numbers. Yes, it is converted into hexadecimal string. In DES, it is in hexadecimal conversion. See the figure below.

This is probably the process of hexadecimal conversion. Let's implement the first step to convert plaintext into hexadecimal.

Look at the Python code

# String to hexadecimal string
def str2hex(self, string: str):
        return bytes.hex(string.encode('utf8'))
# Hexadecimal string to string
def hex2str(self, hexstr):
        return bytes.fromhex(hexstr).decode()

Ah, is this very simple, that is, encode the plaintext into utf-8, get the bytes, and then convert them to hexadecimal, and vice versa. This is the case in python. Originally, we can see how to implement it in detail in the Java version of the code.

The results are as follows:

hello, world -- > 68656c6c6f2ce4b896e7958c
68656c6c6f2ce4b896e7958c -- > Hello, world

Next, convert to binary

Hexadecimal to binary, take out one by one, and then convert. Write two, and choose one. Note that each character corresponds to 4 binary bits, such as 6 - > 0110

# Hex to binary

    def hex2bin(self, hex):
        hex_to_bin_table = (
            '0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100',
            '1101',
            '1110', '1111')
        bin_string = ''
        for i in hex:
            i = int(i, 16)
            bin_string = bin_string + hex_to_bin_table[i]
        return bin_string

    def hex2bin1(self, hex):
        hex_table = "0123456789ABCDEF"
        s = ""
        for i in hex:
            k = str(bin(hex_table.find(i.upper()))[2:])
            if len(k) < 4:
                k = (4 - len(k)) * "0" + k
            s += k
        return s

# Binary to hexadecimal
    def bin2hex(self, bin):
        changed_str = ''
        while len(bin) > 0:
            temp = int(bin[:4], 2)
            changed_str += '%0x' % temp
            bin = bin[4:]
        return changed_str

    def bin2hex1(self, bin):
        hextable = "0123456789ABCDEF"
        binlist = re.findall(r".{4}", bin)
        s = ""
        for i in binlist:
            s += hextable[int(i, 2)].lower()
        return s

In this way, the binary form of plaintext is obtained. Next, just encrypt it

We convert plaintext to binary into a function and check whether it is full of 64 bits:

 def text2Bin(self, txt: str) -> str:
        """
        Will plaintext or The secret key is converted to a binary stream, and%64=0
        :param txt: Enter the plaintext or secret key
        :return: Binary stream of operations
        """
        txt = self.str2hex(txt)  # String to hexadecimal string
        bintxt = self.hex2bin(txt)  # Hexadecimal string to binary string
        k = len(bintxt) % 64
        if k != 0:
            bintxt += "0" * (64 - k)
        return bintxt

2. Secret key group generation

Schematic diagram of generating 16 rounds of secret key group

All substitution tables in the code are in the final code at the end of the text

Generate secret key: accept a binary secret key stream of 64bit, perform PC1 replacement, take the first 56 bits, and then divide them into two, each 28bit, and then perform cyclic shift, that is, according to the shift table, the number 2: means to connect the left 2 of the binary string to the back of the right, and shift it

C0 and D0 are spliced together, PC2 is replaced to obtain the sub secret key, and then the result of the last cyclic shift is continued to cyclic shift to generate 16 groups in turn

    def generateKeyTo16(self, binKey: str):
        """
        Generate 16 sets of secret keys
        :param binKey: Initial secret key
        :return: 16 Group key list
        """
        keyList = []
        # Replacement selection PC-1
        z1 = ""
        for i in self.PC_1:
            z1 += binKey[i - 1]
        # 28 bit key
        leftKey = z1[:28]
        rightKey = z1[28:]

        def leftShift(m, s):  # Shift function s: how much
            return m[s:] + m[:s]

        for shift in self.SHIFT:
            leftKey = leftShift(leftKey, shift)
            rightKey = leftShift(rightKey, shift)
            # Replacement selection PC-2
            zh = leftKey + rightKey
            ans = ""
            for i in self.PC_2:
                ans += zh[i - 1]
            keyList.append(ans)  # Add secret key
        return keyList

3. Implementation of F function


Function input analysis: 1. A 32 bit binary stream 2. A 48 bit binary secret key

E table replacement: expand 32bit to 48bit (repeat some bits)

XOR: XOR table E results and secret keys

S-box substitution: S-box substitution of XOR result (48bit)

Divide 48bit into 8 parts, each with 6bit, and then change 6bit to 4bit. How do you change it?

First, combine one character at the beginning and end of 6bit into two as the line number, and the rest remains unchanged as the column number, such as: 010011 - > line: 01, column: 1001. Then, the line number and column number are converted to decimal numbers. Go to the s box to query the value corresponding to the row and column, and then convert this value to binary. (note that the first group of 6 bits corresponds to the first group of S boxes)


If 010011 is replaced according to the S-box table in the above figure, the row: 01 column 1001 decimal system is 1 and 9 respectively. The result of the first row and the ninth column is 6 and binary is 0110.

Then put all the results in box S together

, replace the P table to get the output of the F function

  # XOR XOR operation
    def msgXorKey(self, left, right) -> str:
        xor = ""
        for i in range(len(left)):
            xor += str(int(left[i]) ^ int(right[i]))
        return xor

    # f function
    def FFunction(self, binText: str, binKey: str) -> str:
        # Define several functions
        # E table extension
        def e_Extend(bintxt) -> str:
            e = ""
            for i in self.E:
                e += bintxt[i - 1]
            return e

        # S-box processing
        def S_Box(bintxt: str) -> str:
            ans = ""
            bit6list = re.findall(r".{6}", bintxt)
            flag = 0
            for b in bit6list:
                k = int(b[0] + b[len(b) - 1], 2)  # Get row
                v = int(b[1:5], 2)  # Get column
                sValue = bin(self.S[flag][k * 16 + v])[2:]  # The result of S-box query is converted to binary
                if len(sValue) < 4:
                    sValue = "0" * (4 - len(sValue)) + sValue
                flag += 1
                ans += sValue
            return ans

        # P replacement
        def P_Swap(bintxt: str) -> str:
            ans = ""
            for i in self.P:
                ans += bintxt[i - 1]
            return ans

        # Start processing E table - > XOR - > s Box - > P replacement
        return P_Swap(S_Box(self.msgXorKey(e_Extend(binText), binKey)))

4-round function implementation


Parameters: 1. 64bit binary to be encrypted 2. Secret key group (the secret key in the secret key group is used for F function)

At first, 64bit is initially replaced, and then divided into 32bit and 32bit. The 32bit on the right is F-function, and then the result obtained by XOR with the 32bit on the left is taken as the right of the next round, and the 32bit on the right at the beginning is taken as the left of the next round. 16 times in turn

After that, the results are exchanged left and right, and then the inverse initial replacement is carried out to obtain the ciphertext.

# ip permutation and inverse permutation
    def ip_Swap(self, bit, reTable=False):
        n = ""
        if reTable is True:
            for i in self.IP_re_table:
                n += bit[i - 1]
        else:
            for i in self.IP_table:
                n += bit[i - 1]
        return n

    # Wheel function
    def WheelFunction(self, bitTo64: str, keyList: list):
        # Initial replacement (IP replacement)
        n = self.ip_Swap(bitTo64)
        leftBit = n[:32]
        rightBit = n[32:]
        # Get 16 rounds of secret keys
        for rot in keyList:  # 16 round encryption
            temp = rightBit
            k32 = self.FFunction(rightBit, rot)
            rightBit = self.msgXorKey(leftBit, k32)  # XOR
            leftBit = temp
        # Left-right exchange
        swapValue = rightBit + leftBit
        # Inverse initial permutation
        Ciphertext = self.ip_Swap(swapValue, True)
        return Ciphertext

5. Encryption function

Integrate the above to achieve encryption

Parameters: 1. Plaintext 2. Secret key

    def encryption(self, msg: str, key: str):
        """
        DES encryption
        :param msg: Plaintext message
        :param key: Plaintext secret key
        :return: ciphertext
        """
        binMsgList = re.findall(r".{64}", self.text2Bin(msg))  # 64bit civilization binary list
        k64 = re.findall(r".{64}", self.text2Bin(key))[0]  # Secret key binary stream
        binKeyList = self.generateKeyTo16(k64) #Generate secret key group
        binaryCipher = ""
        for bitTo64 in binMsgList: # Encrypt the binary stream and secret key in turn
            binaryCipher += self.WheelFunction(bitTo64, binKeyList)
        return self.bin2hex(binaryCipher) # Binary result to hexadecimal

6. Decryption function

Receiving parameters: 1. Hexadecimal ciphertext 2. Secret key

Note: the decrypted secret key group should be reversed

  def decryption(self, msg: str, key: str):
        """
        DES decrypt
        :param msg: ciphertext
        :param key: Secret key
        :return: Plaintext
        """
        binMsgList = re.findall(r".{64}", self.hex2bin(msg))  # 64bit binary list
        k64 = re.findall(r".{64}", self.text2Bin(key))[0]  # Secret key binary stream m
        binKeyList = self.generateKeyTo16(k64)
        binaryCipher = ""
        for bitTo64 in binMsgList:
            binaryCipher += self.WheelFunction(bitTo64, binKeyList[::-1]) # [:: - 1] reverse the list, that is, reverse the secret key group
        return self.hex2str(self.bin2hex(binaryCipher))

7. Test

des = DesUtil()
s = des.encryption("How do you do,world", "lightr.cn")
print(f"Encryption results:{s}")
print(f"{s}Decryption result of:{des.decryption(s, 'lightr.cn')}")

Encryption result:

bea987772587d33d80f57b15ec011c57
Decryption result of bea987772587d33d80f57b15ec011c57: Hello, world

All codes

Java version

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DesUtil {
    /**
     * DES encryption
     * @param msg Plaintext message
     * @param key Plaintext secret key
     * @return 16 Binary ciphertext string
     */
    public String encryption(String msg, String key){
        String msgbin = Check64(hex2Bin(str2Hex(msg)));
        String keybin = Check64(hex2Bin(str2Hex(key)));
        String[] msgs = regex(msgbin, ".{64}");
        String k = regex(keybin, ".{64}")[0];
        String[] keys = generateKey(k);
        StringBuilder mm = new StringBuilder();
        for (String binmsg : msgs) {
            mm.append(Wheel(binmsg, keys));
        }
        return bin2Hex(mm.toString().trim()).toLowerCase();
    }

    /**
     * DES decrypt
     * @param cipher 16 Binary ciphertext
     * @param key Decryption / encryption key
     * @return Plaintext string
     */
    public String decryption(String cipher, String key){
        String msgbin = hex2Bin(cipher);
        key = Check64(hex2Bin(str2Hex(key)));
        String[] cpbin = regex(msgbin, ".{64}");
        String k = regex(key, ".{64}")[0];
        String[] keys = generateKey(k);
        Collections.reverse(Arrays.asList(keys)); //Invert array
        StringBuilder mm = new StringBuilder();
        for (String binmsg : cpbin) {
            mm.append(Wheel(binmsg, keys));
        }
        return hex2Str(bin2Hex(mm.toString().trim())).trim();

    }
    // =========Binary conversion===============

    /**
     * String to hexadecimal string
     *
     * @param str String
     * @return HexString
     */
    public  String str2Hex(String str) {
        char[] chars = "0123456789ABCDEF".toCharArray();
        StringBuilder stringBuilder = new StringBuilder();
        byte[] bytes = str.getBytes();
        int bt;
        for (byte b : bytes) {
            bt = (b & 0x0f0) >> 4;
            stringBuilder.append(chars[bt]);
            stringBuilder.append(chars[(b & 0x00f)]);
        }
        return stringBuilder.toString().trim().toLowerCase();
    }

    /**
     * Hexadecimal string to string
     *
     * @param hexStr
     * @return
     */
    public  String hex2Str(String hexStr) {
        String str16 = "0123456789ABCDEF";
        char[] chars = str16.toCharArray();
        byte[] bytes = new byte[hexStr.length() / 2];
        char[] hex = hexStr.toUpperCase().toCharArray();
        int i;
        for (int j = 0; j < bytes.length; j++) {
            i = str16.indexOf(hex[j * 2]) << 4;
            i += str16.indexOf(hex[j * 2 + 1]);
            bytes[j] = (byte) i;
        }
        return new String(bytes);
    }

    public  String hex2Bin(String hexStr) {
        char[] hexchr = hexStr.toLowerCase().toCharArray();
        String binStr = "";
        for (char i : hexchr) {
            String bin = Integer.toBinaryString(Integer.parseInt(String.valueOf(i),16));
            if (bin.length() < 4) {
                bin = String.join("", Collections.nCopies(4 - bin.length(), "0")) + bin;
            }
            binStr += bin;
        }
        return binStr;
    }
    public String bin2Hex(String bin){
        char[] chars = "0123456789ABCDEF".toCharArray();
        String[] h4 = regex(bin, ".{4}");
        StringBuilder hexstr = new StringBuilder();
        for (String s : h4) {
            hexstr.append(chars[Integer.parseInt(s,2)]);
        }
        return hexstr.toString().trim();
    }

    /**
     * Check whether the binary string is 64 bit
     * @param binStr str
     * @return str64
     */
    public String Check64(String binStr) {
        int num = binStr.length() % 64;
        if (num != 0) {
            binStr += String.join("", Collections.nCopies(64 - num, "0"));
        }
        return binStr;
    }

    /**
     * Regular get matching values
     * @param str character string
     * @param regex regular expression 
     * @return String[]
     */
    public String[] regex(String str,String regex){
        Matcher matcher = Pattern.compile(regex).matcher(str);
        List<String> list = new ArrayList<>();
        while (matcher.find()){
            list.add(matcher.group(0));
        }
        String[] strings = new String[list.size()];
        list.toArray(strings);
        return  strings;
    }

    /**
     * 0 1 XOR of
     * @param left Binary string
     * @param right Binary string
     * @return xor
     */
    public String xor(String left,String right){
        StringBuilder str = new StringBuilder();
        char[] leftchr = left.toCharArray();
        char[] rightchr = right.toCharArray();
        for (int i = 0; i < leftchr.length; i++) {
            str.append(leftchr[i] ^rightchr[i]);
        }
        return str.toString().trim();
    }

    /**
     * F Function implementation
     * @param bin32 64 32 bits to the right of bit plaintext
     * @param key  Encryption key of the current round
     * @return
     */
    public String f_function(String bin32,String key){
        //E table replacement
        bin32 = Swap(bin32,E);
        // XOR
        String xor = xor(bin32, key);
        //S-box substitution
        String[] slist = regex(xor, ".{6}");
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < slist.length; i++) {
            String s = slist[i];
            int h = Integer.parseInt(s.substring(0,1) + s.substring(5),2);
            int l = Integer.parseInt(s.substring(1,5) ,2);
            String i1 = Integer.toBinaryString(S[i][h * 16 + l]);
            if (i1.length()<4){
                i1 = String.join("",Collections.nCopies(4-i1.length(),"0"))+i1;
            }
            builder.append(i1);
        }
        //P replacement
        String trim = builder.toString().trim();
        return Swap(trim,P);
    }

    /**
     * Wheel function
     * @param bin64 64 Bit plaintext binary
     * @param keys 16 Group key
     * @return
     */
    public String Wheel(String bin64,String[] keys){
        bin64 = Swap(bin64,IP_table); // Initial replacement
        String leftbin = bin64.substring(0,32);
        String rightbin = bin64.substring(32);
        for (String key : keys) {
            String temp = rightbin;
            String f_function = f_function(rightbin, key);
            rightbin = xor(leftbin, f_function);
            leftbin = temp;
        }
        return Swap(rightbin+leftbin,IP_re_table);
    }

    /**
     * Generate 16 sets of secret keys
     * @param binKey Binary of initial secret key
     * @return keys[]
     */
    public String[] generateKey(String binKey) {
        List<String> list = new ArrayList<>();
        String leftbin, rightbin;
        binKey = Swap(binKey,PC_1);
        leftbin = binKey.substring(0,28);
        rightbin = binKey.substring(28,56);
        for (int i : SHIFT) {
            leftbin = leftbin.substring(i) + leftbin.substring(0,i);
            rightbin = rightbin.substring(i) + rightbin.substring(0,i);
            list.add(Swap(leftbin+rightbin,PC_2));
        }
        return  list.toArray(new String[list.size()]);
    }

    /**
     * Permutation operation
     * @param swap String to be replaced
     * @param table Replacement table
     * @return Replaced string
     */
    public static String Swap(String swap, int[] table) {
        char[] array = swap.toCharArray();
        StringBuilder string = new StringBuilder();
        for (int i = 0; i < table.length; i++) {
            string.append(array[table[i]-1]);
        }
        return string.toString().trim();
    }


    public static final int[] PC_1 = {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};
    public static final int[] PC_2 = {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};
    public static final int[] SHIFT = {1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1};
    public static final int[][] S = {
            {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},

            {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},

            {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},

            {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},

            {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},

            {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},

            {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},

            {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 final int[] P = {
            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};
    public static final int[] E = {
            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};
    public static final int[] IP_table = {
            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};
    public static final int[] IP_re_table = {
            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};

}

Python version

import re


class DesUtil:
    """
    use:
    des = DesUtil()
    print(des.encryption("Encrypted plaintext", "Secret key"))
    print(des.decryption("ciphertext", "Secret key"))
    """

    # ==============Binary conversion====================

    def bin2hex(self, bin):
        hextable = "0123456789ABCDEF"
        binlist = re.findall(r".{4}", bin)
        s = ""
        for i in binlist:
            s += hextable[int(i, 2)].lower()
        return s

    def hex2bin(self, hex):
        hex_table = "0123456789ABCDEF"
        s = ""
        for i in hex:
            k = str(bin(hex_table.find(i.upper()))[2:])
            if len(k) < 4:
                k = (4 - len(k)) * "0" + k
            s += k
        return s

    def str2hex(self, string: str):
        return bytes.hex(string.encode('utf8'))

    def hex2str(self, hexstr):
        return bytes.fromhex(hexstr).decode().replace(b"\x00".decode(), "") # Remove spaces

    def encryption(self, msg: str, key: str):
        """
        DES encryption
        :param msg: Plaintext message
        :param key: Plaintext secret key
        :return: ciphertext
        """
        binMsgList = re.findall(r".{64}", self.text2Bin(msg))  # 64bit civilization binary list
        k64 = re.findall(r".{64}", self.text2Bin(key))[0]  # Secret key binary stream
        binKeyList = self.generateKeyTo16(k64)
        binaryCipher = ""
        for bitTo64 in binMsgList:
            binaryCipher += self.WheelFunction(bitTo64, binKeyList)
        return self.bin2hex(binaryCipher)

    def decryption(self, msg: str, key: str):
        """
        DES decrypt
        :param msg: ciphertext
        :param key: Secret key
        :return: Plaintext
        """
        binMsgList = re.findall(r".{64}", self.hex2bin(msg))  # 64bit civilization binary list
        k64 = re.findall(r".{64}", self.text2Bin(key))[0]  # Secret key binary stream m
        binKeyList = self.generateKeyTo16(k64)
        binaryCipher = ""
        for bitTo64 in binMsgList:
            binaryCipher += self.WheelFunction(bitTo64, binKeyList[::-1])
        return self.hex2str(self.bin2hex(binaryCipher))

    def text2Bin(self, txt: str) -> str:
        """
        Will plaintext or The secret key is converted to a binary stream, and%64=0
        :param txt: Enter the plaintext or secret key
        :return: Binary stream of operations
        """
        txt = self.str2hex(txt)  # String to hexadecimal string
        bintxt = self.hex2bin(txt)  # Hexadecimal string to binary string
        k = len(bintxt) % 64
        if k != 0:
            bintxt += "0" * (64 - k)
        return bintxt

    def generateKeyTo16(self, binKey: str):
        """
        Generate 16 sets of secret keys
        :param binKey: Initial secret key
        :return: 16 Group key list
        """
        keyList = []
        # Replacement selection PC-1
        z1 = ""
        for i in self.PC_1:
            z1 += binKey[i - 1]
        # 28 bit key
        leftKey = z1[:28]
        rightKey = z1[28:]

        def leftShift(m, s):  # Shift function s: how much
            return m[s:] + m[:s]

        for shift in self.SHIFT:
            leftKey = leftShift(leftKey, shift)
            rightKey = leftShift(rightKey, shift)
            # Replacement selection PC-2
            zh = leftKey + rightKey
            ans = ""
            for i in self.PC_2:
                ans += zh[i - 1]
            keyList.append(ans)  # Add secret key
        return keyList

    # XOR XOR operation
    def msgXorKey(self, left, right) -> str:
        xor = ""
        for i in range(len(left)):
            xor += str(int(left[i]) ^ int(right[i]))
        return xor

    # f function
    def FFunction(self, binText: str, binKey: str) -> str:
        # Define several functions
        # E table extension
        def e_Extend(bintxt) -> str:
            e = ""
            for i in self.E:
                e += bintxt[i - 1]
            return e

        # S-box processing
        def S_Box(bintxt: str) -> str:
            ans = ""
            bit6list = re.findall(r".{6}", bintxt)
            flag = 0
            for b in bit6list:
                k = int(b[0] + b[len(b) - 1], 2)  # Get row
                v = int(b[1:5], 2)  # Get column
                sValue = bin(self.S[flag][k * 16 + v])[2:]  # The result of S-box query is converted to binary
                if len(sValue) < 4:
                    sValue = "0" * (4 - len(sValue)) + sValue
                flag += 1
                ans += sValue
            return ans

        # P replacement
        def P_Swap(bintxt: str) -> str:
            ans = ""
            for i in self.P:
                ans += bintxt[i - 1]
            return ans

        # Start processing E table - > XOR - > s Box - > P replacement
        return P_Swap(S_Box(self.msgXorKey(e_Extend(binText), binKey)))

    # ip permutation and inverse permutation
    def ip_Swap(self, bit, reTable=False):
        n = ""
        if reTable is True:
            for i in self.IP_re_table:
                n += bit[i - 1]
        else:
            for i in self.IP_table:
                n += bit[i - 1]
        return n

    # Wheel function
    def WheelFunction(self, bitTo64: str, keyList: list):
        # Initial replacement (IP replacement)
        n = self.ip_Swap(bitTo64)
        leftBit = n[:32]
        rightBit = n[32:]
        # Get 16 rounds of secret keys
        for rot in keyList:  # 16 round encryption
            temp = rightBit
            k32 = self.FFunction(rightBit, rot)
            rightBit = self.msgXorKey(leftBit, k32)  # XOR
            leftBit = temp
        # Left-right exchange
        swapValue = rightBit + leftBit
        # Inverse initial permutation
        Ciphertext = self.ip_Swap(swapValue, True)
        return Ciphertext

    IP_table = [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]

    IP_re_table = [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]

    E = [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]

    P = [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]

    S = [
        [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],

        [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],

        [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],

        [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],

        [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],

        [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],

        [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],

        [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],

    ]
    # key
    PC_1 = [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 = [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]

    SHIFT = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1]

Tags: Python Java Windows cryptology

Posted on Wed, 01 Dec 2021 09:34:48 -0500 by kykin