ciphers.des_ecb =============== .. py:module:: ciphers.des_ecb .. autoapi-nested-parse:: Python program for DES (Data Encryption Standard) using Electronic Codebook (ECB) mode. DES is a symmetric-key block cipher that encrypts data in fixed-size blocks (64 bits). In ECB mode, the plaintext is divided into 64-bit blocks, and each block is encrypted independently using the same key. This makes ECB the simplest block cipher mode, but also one of the least secure, as identical plaintext blocks will produce identical ciphertext blocks. This implementation of DES includes key scheduling, encryption, and decryption. It uses standard DES operations such as initial and final permutations, expansion, permutation, and S-box lookups. Padding is applied to ensure the plaintext length is a multiple of 64 bits. Warning: ECB mode is not secure for most use cases due to its vulnerability to block repetition analysis. Consider using a more secure mode of operation, such as CBC (Cipher Block Chaining), for sensitive data encryption. References: - Handbook of Applied Cryptography (Algorithm 7.82) - Handbook of Applied Cryptography (Algorithm 7.83) - Handbook of Applied Cryptography (Algorithm 9.29) - https://en.wikipedia.org/wiki/Data_Encryption_Standard Attributes ---------- .. autoapisummary:: ciphers.des_ecb.E ciphers.des_ecb.IP ciphers.des_ecb.IP_INV ciphers.des_ecb.P ciphers.des_ecb.PC1 ciphers.des_ecb.PC2 ciphers.des_ecb.S_BOXES ciphers.des_ecb.mode Classes ------- .. autoapisummary:: ciphers.des_ecb.Des ciphers.des_ecb.Operations Module Contents --------------- .. py:class:: Des .. py:method:: decrypt(key: str, cipher_text: str) -> str :staticmethod: Decrypts the given cipher text using DES decryption. Args: key (str): A 16-character hexadecimal string representing a 64-bit key. cipher_text (str): A hexadecimal string representing the encrypted data. Returns: str: The decrypted plain text string. Examples: >>> key = '133457799BBCDFF1' >>> encrypted_string = 'c84e3c8fb646872720b224896db4f60' >>> decrypted = Des.decrypt(key, encrypted_string) >>> decrypted # Checking the cipher to ensure consistency 'Test string' .. py:method:: des(keys: list, plain_bitset: list) -> list :staticmethod: Encrypts a plain bitset using the provided subkeys with DES encryption algorithm. Args: keys (list): A list of 16 subkeys, each 48 bits long. plain_bitset (list): A bitset representing the plain text, which should be divisible into 64-bit blocks. Returns: list: The encrypted bitset. Examples: >>> plain_bitset = Operations.string_to_bitset("Test string") >>> plain_bitset = Operations.pad_right_to_multiple_of_n(plain_bitset, 64) >>> keys = Des.key_schedule(Des.generate_key()) >>> cipher_bitset = Des.des(keys, plain_bitset) >>> # The output length should be the same as the input >>> len(cipher_bitset) == len(plain_bitset) True >>> # Decryption should be the inverse of encryption >>> plain_bitset == Des.des(keys[::-1], cipher_bitset) True .. py:method:: encrypt(key: str, input_string: str) -> str :staticmethod: Encrypts a given input string using the DES encryption algorithm. Args: key (str): A 16-character hexadecimal string representing a 64-bit key. input_string (str): The plain text string to be encrypted. Returns: str: A hexadecimal string representing the encrypted data. Examples: >>> key = '133457799BBCDFF1' >>> input_string = 'Test string' >>> encrypted = Des.encrypt(key, input_string) >>> encrypted # Checking the cipher to ensure consistency 'c84e3c8fb646872720b224896db4f60' .. py:method:: generate_key() -> str :staticmethod: Generates a random hexadecimal key of 16 characters (64 bits). Returns: str: A random hexadecimal key. Examples: >>> key = Des.generate_key() >>> len(key) # Check if the key length is correct 16 >>> # Ensure key only contains valid hex characters >>> all(c in "0123456789abcdef" for c in key) True .. py:method:: key_schedule(key: str) -> list :staticmethod: Generates 16 subkeys (round keys) from a given 64-bit hexadecimal key using the DES key schedule. Args: key (str): A 16-character hexadecimal string representing a 64-bit key. Returns: list: A list of 16 subkeys, each of which is a permuted bitset. Examples: >>> subkeys = Des.key_schedule('133457799BBCDFF1') >>> len(subkeys) # Check that 16 subkeys are generated 16 >>> # Ensure each subkey is 48 bits long >>> all(len(subkey) == 48 for subkey in subkeys) True .. py:class:: Operations .. py:method:: bitset_to_hex(bitset: list) -> str :staticmethod: Converts a list of binary digits into its 16 digit hexadecimal representation. Args: bitset (list): A list of binary digits (as strings) representing a binary number. Returns: str: The 16 digit hexadecimal representation of the binary number. Examples: >>> Operations.bitset_to_hex(['1', '0', '1', '0', '1', '1', '1', '0']) '00000000000000ae' >>> Operations.bitset_to_hex(['1', '1', '1', '1'] * 16) 'ffffffffffffffff' >>> Operations.bitset_to_hex(['0'] * 64) '0000000000000000' .. py:method:: bitset_to_string(bitset: list) -> str :staticmethod: Converts a bitset into a string by interpreting every 8 bits as a character. Args: bitset (list): The list of binary digits (bitset). Returns: str: The decoded string. Examples: >>> Operations.bitset_to_string(['0', '1', '0', '0', '0', '0', '0', '1']) 'A' >>> Operations.bitset_to_string(['0', '1', '0', '0', '0', '1','0', '0', '0', '1', '0', '1', '0', '1', '1', '0']) 'DV' .. py:method:: hex_to_bitset(hex_string: str, left_pad: int) -> list :staticmethod: Converts a hexadecimal string to a bitset and pads the bitset to a specified length. Args: hex_string (str): The hexadecimal string to convert. left_pad (int): The length to pad the bitset on the left. Returns: list: The padded bitset. Examples: >>> Operations.hex_to_bitset('ae', 8) ['1', '0', '1', '0', '1', '1', '1', '0'] >>> Operations.hex_to_bitset('1f', 10) ['0', '0', '0', '0', '0', '1', '1', '1', '1', '1'] .. py:method:: pad_left_to_multiple_of_n(bitset: list, length: int) -> list :staticmethod: Pads the bitset with zeros on the left until its length is a multiple of length. Args: bitset (list): A list of binary digits (as strings) to be padded. Returns: list: The padded bitset, with a length that is a multiple of n. Examples: >>> Operations.pad_left_to_multiple_of_n(['1', '0', '1'], 4) ['0', '1', '0', '1'] >>> len(Operations.pad_left_to_multiple_of_n(['1'] * 64, 64)) % 64 0 >>> len(Operations.pad_left_to_multiple_of_n(['0'] * 63, 64)) % 64 0 .. py:method:: pad_right_to_multiple_of_n(bitset: list, length: int) -> list :staticmethod: Pads the bitset with zeros on the right until its length is a multiple of `length`. Args: bitset (list): A list of binary digits (as strings) to be padded. Returns: list: The padded bitset, with a length that is a multiple of n. Examples: >>> Operations.pad_right_to_multiple_of_n(['1', '0', '1'], 4) ['1', '0', '1', '0'] >>> len(Operations.pad_right_to_multiple_of_n(['1'] * 64, 64)) % 64 0 >>> len(Operations.pad_right_to_multiple_of_n(['0'] * 63, 64)) % 64 0 .. py:method:: permute(bitset: list, permutation: list) -> list :staticmethod: Permutes a bitset according to a given permutation table. Args: bitset (list): The bitset to be permuted. permutation (list): The permutation table specifying the new order. Returns: list: The permuted bitset. Examples: >>> Operations.permute(['1', '0', '1', '0', '1', '1'], [6, 5, 4, 3, 2, 1]) ['1', '1', '0', '1', '0', '1'] >>> Operations.permute(['0', '1', '1', '0', '1', '0'], [3, 1, 6, 5, 4, 2]) ['1', '0', '0', '1', '0', '1'] >>> Operations.permute(['0', '1', '1', '0', '1', '0'], [3, 1, 6, 5, 4, 2, 7]) Traceback (most recent call last): ... ValueError: Permutation values must be within the range of the bitset .. py:method:: shift_left(bitset: list, position: int) -> list :staticmethod: Performs a rotated left shift on a bitset by `position` positions. Args: bitset (list): The bitset to be shifted. n (int): The number of positions to shift. Returns: list: The left-shifted bitset. Examples: >>> Operations.shift_left(['1', '0', '0', '1'], 2) ['0', '1', '1', '0'] >>> Operations.shift_left(['0', '1', '1', '1'], 1) ['1', '1', '1', '0'] >>> Operations.shift_left(['0', '1', '1', '1'], 7) ['1', '0', '1', '1'] .. py:method:: string_to_bitset(string: str) -> list :staticmethod: Converts a string into a list of binary digits (bitset). Args: string (str): The input string to be converted. Returns: list: A list of binary digits representing the string. Examples: >>> Operations.string_to_bitset('A') ['0', '1', '0', '0', '0', '0', '0', '1'] >>> len(Operations.string_to_bitset('ab')) 16 >>> Operations.string_to_bitset(' ') ['0', '0', '1', '0', '0', '0', '0', '0'] .. py:method:: xor(bitset1: list, bitset2: list) -> list :staticmethod: Applies a bitwise XOR operation between two bitsets of the same length. Args: bitset1 (list): The first bitset. bitset2 (list): The second bitset. Returns: list: The result of the XOR operation as a new bitset. Examples: >>> Operations.xor(['0', '1', '0', '1'], ['1', '0', '1', '1']) ['1', '1', '1', '0'] >>> Operations.xor(['1', '0', '1', '0'], ['0', '0', '0', '1']) ['1', '0', '1', '1'] >>> Operations.xor(['1', '0', '1', '0', '1'], ['0', '0', '0', '1']) Traceback (most recent call last): ... ValueError: Bitsets must be of the same length >>> Operations.xor(['1', '0', '1', '0'], ['0', '0', '0', '1', '1']) Traceback (most recent call last): ... ValueError: Bitsets must be of the same length .. py:data:: E :value: [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,... .. py:data:: IP :value: [58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6,... .. py:data:: IP_INV :value: [40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22, 62, 30,... .. py:data:: P :value: [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,... .. py:data:: PC1 :value: [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,... .. py:data:: PC2 :value: [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,... .. py:data:: S_BOXES .. py:data:: mode