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]