PSUT: 25347 (Cryptography) Fall 2022 Assignment 4 (Simple DES) Overview: In this assignment, you will implement the Simplified DES (SDES) cryptographic scheme. The implementation will use the Electronic Book (ECB) and Cipher Block Chaining (CBC) modes. General Instructions: 1. Create a python project called: "A4" 2. Rename the file: A4_template.py to sdes.py. This is the only file that you are expected to edit and will contain your entire solution to this assignment. 3. Add the mod class to the bottom of the sdes.py file. 4. Insert your credentials on top of the sdes.py file. 5. When you are done, submit only one file: sdes.py. DO NOT submit a zip file. 6. Compare your results to the A4_output.txt file. Use the free online tool: https://text-compare.com/. Your results should EXACTLY match the output of the output file. 7. Your program SHOULD NEVER crash. If it crashes for any reason, then you lose 25% of the assignment grade. If the grader was not able to fix your error in a short time, a grade of 0 is assigned. 8. Deadline: Thursday, Jan 19th at midnight. You can submit one day late with 50% late penalty. Submissions are not accepted after that. 9. The instructor will ask you to run your code and present your solution for grading purposes. © Qutaiba Albluwi PSUT: 25347 (Cryptography) Fall 2022 General Notes: The implementation of SDES is not complex. However, having a full implementation that handles all exceptions is quite lengthy. Therefore, our focus will be on being practical by handling the most common operations and errors. Therefore, you might notice that the implementation is not comprehensive. For error checking, in newly created methods in this assignment, you will either be instructed to return an empty string, or print an error message and return an empty string. For most cases, the former (which is returning empty string with no error msg printing) will be used. Because we are dealing with binary numbers, tracing the algorithm can be challenging. Therefore, insert as many print statements (for debugging purposes) as possible. Remember to remove these prints before submission. In this assignment, you will use many functions in the utilities library. You might need to use the following functions: is_binary, xor, dec_to_bin, bin_to_dec, get_base, get_positions, clean_text, decode, shift_string, insert_positions. encode, Assignment Structure: The assignment can be broken into 8 steps: 12345678- Implementation of PRNG Implementation of SBOX General outline of SDES focusing on parameter handling SDES key handling Feistel Network Encryption and Decryption Dispatcher ECB mode (encryption and decryption) CBC mode (encryption and decryption) We will present a short overview of each step. [1] Implementation of PRNG: In this course, we have learned two Pseudo Random Number Generator (PRNG) algorithms: LFSR and Blum Blum Shub (BBS). We will only implement BBS. © Qutaiba Albluwi PSUT: 25347 (Cryptography) Fall 2022 The PRNG class has one static methods: BBS. The method returns a stream of binary bits. The number of bits is determined by the bits parameter. Whenever there is an issue in the input parameters, the function returns an error message (does not print). Three values are passed to the method: p, q and bits. The function validates inputs by insuring that bits is a positive integer and both p and q are positive integers congruent to 3 mod 4. The seed is computed as the nth prime number, where n = p*q. The prime number can be obtained from the PRIMES_FILE which contains the first million primes. If the seed is not relatively prime with n, then the function should pick the next prime number and continue until a valid number is found. Below is the output for testing PRNG.BBS: ---------------------------------------Start of PRNG Testing Testing Blum Blum Shub: PRNG.BBS(383,503,8) = 01110011 PRNG.BBS(11,19,4) = 1110 PRNG.BBS(27691,11,16) = 1111110111000011 PRNG.BBS(383,503,0) = Error(PRNG.BBS): invalid bits PRNG.BBS(383,503,1) = Error(PRNG.BBS): invalid q PRNG.BBS(384,503,1) = Error(PRNG.BBS): invalid p End of PRNG Testing ---------------------------------------- [2] SBox Implementation: SBOX is an integral part of the Feistel Network. It is also integrated in many other ciphers like AES. Therefore, we will have a separate class for it. The class has the following layout: class SBOX: def __init__(self,filename = '') def is_empty(self): def get_box(self): def get_size(self): def set_box(self,filename): def substitute(self,value): def __str__(self): © Qutaiba Albluwi PSUT: 25347 (Cryptography) Fall 2022 Each SBOX has a size. If the size is n, then the input binary number should be nbits, and the output is (n-1) bits. Also, each SBOX table should have a substitution table. The table is normally loaded from a file, which can be performed using the __init__ and/or the set_box methods. The box should be stored in a 2D list _box. Below is a sample file: 101-010-001-110-011-100-111-000 001-100-110-010-000-111-101-011 If the input is 1010, then MSB is 1 which represent the row number, and 010 represent the column number. In the above table, this corresponds to: 110. Below is the output of testing the SBOX class: ---------------------------------------Start of SBOX class testing Creating an empty SBOX: SBOX(0): [] [] sbox.substitute(1000) = sbox.is_empty() = True sbox.get_size() = 0 sbox.get_box() = [[], []] Loading sbox1.txt: sbox.set_box('sbox1.txt'): None SBOX(4): ['101', '010', '001', '110', '011', '100', '111', '000'] ['001', '100', '110', '010', '000', '111', '101', '011'] sbox.is_empty() = False sbox.get_size() = 4 sbox.get_box() = [['101', '010', '001', '110', '011', '100', '111', '000'], ['001', '100', '110', '010', '000', '111', '101', '011']] sbox.substitute(1101) = 111 sbox.substitute(0010) = 001 sbox.substitute(0111) = 000 sbox.substitute(0000) = 101 sbox.substitute(010) = sbox.substitute(1010) = sbox.set_box('sbox2.txt'): None SBOX(4): ['100', '000', '110', '101', '111', '001', '011', '010'] ['101', '011', '000', '111', '110', '010', '001', '100'] sbox.substitute(1101) = 010 sbox.substitute(0010) = 110 sbox.substitute(0111) = 010 sbox.substitute(0000) = 100 sbox.substitute(010) = sbox.substitute(1010) = © Qutaiba Albluwi PSUT: 25347 (Cryptography) Fall 2022 End of SBOX class Testing ---------------------------------------- [3] SDES Basic Implementation: The SDES class has 9 data members: 123456789- _encoding: The default value of 'B6' will be always used _rounds: number of Feistel network rounds. By default set to 2 _block_size: By default set to 12 bits _key_length: By default set to 9 bits _p: an integer value to be used in key generation _q: an integer value to be used in key generation _sbox1: An SBOX object to be used in Feistel Network _sbox2: An SBOX object to be used in Feistel Network _pad: a padding character to be used whenever necessary. The __init__ method initializes the above data parameters, called SDES parameters, to the to the default values. The method get_value(parameter) receives a parameter name and returns the corresponding value, as defined in the SDES object. The defined parameter names are: encoding, rounds, block_size, key_length, p, q, sbox1, sbox2 and pad. If an invalid parameter name is passed, the method prints an error message and returns an empty string. Note for sbox1 and sbox2, the method returns a copy (not a reference) of the relevant SBOX object. The method set_parameter(parameter, value) receives a parameter name and a corresponding value and sets the parameter accordingly. The parameter names are defined as in the get_value method. Below are some restrictions: - The encoding parameter can only be set to 'B6'. The rounds should be an integer larger than 1 The p and q should be integers congruent to 3 mod 4 The sbox1 and sbox2 should be non-empty SBOX objects The block_size should be a power of 2, greater than or equal to 4 © Qutaiba Albluwi PSUT: 25347 (Cryptography) Fall 2022 The key_length parameter can be set. However, when setting the block_size, the key_length is automatically set to πππππ_π ππ§π 2 + 3 . (The 3 comes from 2 for expand function, and 1 for key generation function). Whenever the set operation is successful, the method updates the relevant data member and returns True. If an invalid parameter name is passed, an error message is printed and False is returned. If an invalid value is passed, the function returns False. Running the SDES test will produce: ---------------------------------------Start of SDES basics testing Testing default values (get_value): sdes.get_value(rounds) = 2 sdes.get_value(key_length) = 9 sdes.get_value(block_size) = 12 sdes.get_value(encoding) = B6 sdes.get_value(sbox1) = SBOX(4): ['101', '010', '001', '110', '011', '100', '111', '000'] ['001', '100', '110', '010', '000', '111', '101', '011'] sdes.get_value(sbox2) = SBOX(4): ['100', '000', '110', '101', '111', '001', '011', '010'] ['101', '011', '000', '111', '110', '010', '001', '100'] sdes.get_value(p) = 103 sdes.get_value(q) = 199 sdes.get_value(pad) = Q sdes.get_value(size) = Error(SDES.get_value): undefined parameter Testing set_parameter: sdes.set_parameter(rounds,5) = True sdes.set_parameter(rounds,1) = False sdes.set_parameter(rounds,4.3) = False sdes.set_parameter(p,683) = True sdes.set_parameter(p,899) = False sdes.set_parameter(q,684) = False sdes.set_parameter(q,13.2) = False sdes.set_parameter(pad,r) = True sdes.set_parameter(pad,ab) = False sdes.set_parameter(pad,1) = False sdes.set_parameter(pad,?) = False sdes.set_parameter(encoding,B6) = True sdes.set_parameter(encoding,ascii) = False sdes.set_parameter(block_size,1024) = False sdes.set_parameter(block_size,243) = False sdes.set_parameter(block_size,512.0) = False Error(SDES.set_parameter): undefined operation sdes.set_parameter(key_length,64) = False Error(SDES.set_parameter): undefined operation sdes.set_parameter(sbox_size,128) = False End of SDES basics Testing © Qutaiba Albluwi PSUT: 25347 (Cryptography) Fall 2022 [4] SDES Keys: An SDES key is generated using the Blum Blum Shub, defined in the PRNG class. The parameters p and q are passed to the BBS method to generate key_length bits. This is done by the method get_key(). The method get_subkey(i) generates the ith subkey, which is the key_length bits starting at key index i, using circular method if necessary. Note that there is no set_key method. Instead, a key can be set by setting the p and q parameters. Running the testing function would give: ---------------------------------------Start of SDES keys testing Testing get_key: p = 103, q = 199 sdes.get_key() = 100011001 p = 683, q = 199 sdes.get_key() = 010111101 p = 683, q = 503 sdes.get_key() = 101111010 Testing get_subkey: key = 101111010 subkey(0) = subkey(1) = 10111101 subkey(2) = 01111010 subkey(3) = 11110101 subkey(4) = 11101010 subkey(5) = 11010101 subkey(6) = 10101011 subkey(7) = 01010111 subkey(8) = 10101111 subkey(9) = 01011110 subkey(10) = 10111101 subkey(11) = 01111010 End of SDES keys Testing ---------------------------------------- [5] Feistel Network: Building the Feistel Network requires implementing three methods: First, the expand function which takes the right block side R, of size block_size/2, and expands it by adding two extra bits. © Qutaiba Albluwi PSUT: 25347 (Cryptography) Fall 2022 If the size of R is 6 bits, the output is of size 8 bits. The function swaps and repeats the two middle bits, while keeping the other bits unchanged. For example, if R = [R1R2R3R4R5R6] → [R1R2R4R3R4R3R5R6] R = [R1R2R3R4R5R6R7R8] → [R1R2R3R5R4R5R4R6R7 R8] The second is the F(Ri, ki), which receives an R block along with the corresponding subkey, both at round i. The function performs five things: 12345- Pass the Ri block to the expander function XOR the output of [1] with ki Divide the output of [2] into two equal sub-blocks Pass the most significant bits of [3] to Sbox1 and least significant bits to sbox2 Concatenate the output of [4] as [sbox1][sbox2] The third method is the feistel(Ri, ki), applies one round of Feistel Cipher. This is represented as: πΏπ = π π−1 π π = πΏπ−1 ⊕ πΉ(π π−1 , ππ ) Running the testing function would give: ---------------------------------------Start of Feistel Network testing Testing expand: sdes.expand(011001) = 01010101 sdes.expand(00001111) = 0001010111 sdes.expand(0011) = 010101 sdes.expand() = sdes.expand(1011) = Testing F function: F(111000,00011010) = 000001 F(100110,01100101) = 000100 F(10011,01100101) = F(100110,0110010) = Testing feistel: feistel(011100100110,01100101) = 100110011000 feistel(010001100101,11000001) = 100101101100 feistel(01110010011,01100101) = feistel(011100100110,0110010) = End of Feistel Network Testing ---------------------------------------- © Qutaiba Albluwi PSUT: 25347 (Cryptography) Fall 2022 [6] Encryption/Decryption Dispatcher: Now that the inner workings of the SDES cipher are ready, we can implement the encrypt and decrypt methods. The methods have the following prototypes: - encrypt(plaintext,mode) - decrypt(ciphertext,mode) The defined modes are: ECB and CBC. If one of these modes is passed, then the appropriate encryption/decryption method is called. Otherwise, an empty string is returned. [7] ECB Mode: Implement the two methods: - _encrypt_ECB(plaintext) - _decrypt_ECB(ciphertext) The two methods use the ECB mode to encrypt/decrypt a given text. The feistel network is called as many as rounds. For the last round, the two sides (R and L) are swapped. Only characters defined in the B6 base are encrypted/decrypted. This requires cleaning the text and preserving their positions for the undefined characters before processing, and restoring that before providing the output. Since the B6 encoding is used, for the standard block_size of 12, every two characters in the input text will correspond to one block. If the last block contains one character, then it needs to be padded. Watch out for the main difference between encryption and decryption which is the subkeys used in each round. In decryption, the reverse order is used. Below is the testing result for the ECB mode: ---------------------------------------Start of SDES ECB Mode testing key = 111001101 plaintext = OK ciphertext = kX plaintext2 = OK key = 000100011 plaintext = Sit © Qutaiba Albluwi PSUT: 25347 (Cryptography) Fall 2022 ciphertext = GfRt plaintext2 = Sit key = 111111011 plaintext = beet ciphertext = i41v plaintext2 = beet key = 101111010 plaintext = welcome ciphertext = K3RFOg E plaintext2 = welcome key = 111100100 plaintext = "Cryptography" is power ciphertext = "jjzAevJtKc20"gul4wjKUP plaintext2 = "Cryptography" is power key = 110010001 plaintext = go-go ciphertext = GD-GD plaintext2 = go-go End of SDES ECB Mode Testing ---------------------------------------- [8] CBC Mode: Implement the two methods: - _encrypt_CBC(plaintext) - _decrypt_CBC(ciphertext) You would need to implement _get_IV() to generate the initial vector (IV) for the first round. The length of the IV is the same as the block size. The function returns a string representing a binary number, which is generated as: One 1, two 0's, three 1's, four 0's, five 1's, six 0's and so forth For a block size of 12, the output will be: 100111 000011 Remember that CBC uses padding if necessary. Running the testing function would give: ---------------------------------------Start of SDES CBC Mode testing key = 111001101 plaintext = go ciphertext = yE plaintext2 = go © Qutaiba Albluwi PSUT: 25347 (Cryptography) Fall 2022 key = 110011101 plaintext = CAT ciphertext = XCpt plaintext2 = CAT key = 111111011 plaintext = seed ciphertext = go1g plaintext2 = seed key = 101111010 plaintext = go-go ciphertext = pT-s4 plaintext2 = go-go End of SDES CBC Mode Testing ---------------------------------------- © Qutaiba Albluwi