Module cryptanalysis.cryptanalysis
Module for performing cryptanalysis on Substitution Permutation Network cipher.
Classes: - Cryptanalysis: Abstract base class for cryptanalysis algorithms.
Usage:
Import the cryptanalysis
module to access the Cryptanalysis
class.
Expand source code
"""
Module for performing cryptanalysis on Substitution Permutation Network cipher.
Classes:
- Cryptanalysis: Abstract base class for cryptanalysis algorithms.
Usage:
Import the `cryptanalysis` module to access the `Cryptanalysis` class.
"""
from abc import ABC, abstractmethod
from .spn import SPN
from .characteristic_searcher import CharacteristicSearcher
__all__ = ["Cryptanalysis"]
class Cryptanalysis(SPN, ABC):
"""
Abstract base class for cryptanalysis algorithms.
Methods:
- __init__: Initialize the cryptanalysis class.
- dec_partial_last_noperm: Partially decrypt the ciphertext using last round without permutation.
- dec_partial_last_withperm: Partially decrypt the ciphertext using last round with permutation.
- update_encryptions: Update the encryption pairs used for analysis.
- batch_encrypt: Encrypt multiple plaintexts in batch mode.
- find_keybits: Find the key bits of the encryption algorithm.
- generate_encryption_pairs: Generate encryption pairs for cryptanalysis.
- find_last_roundkey: Find the last round key of the encryption algorithm.
"""
def __init__(self, sbox, pbox, num_rounds, mode='differential'):
"""
This method initializes the Cryptanalysis class by calling the __init__ method of the SPN class
(the parent class) and setting the mode and characteristic_searcher attributes. It also initializes
the encryptions dictionary.
Args:
sbox (list): A list of integers representing the S-box.
pbox (list): A list of integers representing the P-box.
num_rounds (int): The number of rounds in the block cipher.
mode (str, optional): The mode of the cryptanalysis. Defaults to 'differential'.
"""
super().__init__(sbox, pbox, 0, num_rounds)
self.mode = mode
self.characteristic_searcher = CharacteristicSearcher(
self.sbox, self.pbox, num_rounds - 1, mode)
self.encryptions = {} # store of the encryptions utilized by the cryptanalysis
def dec_partial_last_noperm(self, ciphertext, round_keys):
"""Performs partial decryption without permutation on the last round.
Args:
ciphertext (int): The ciphertext to decrypt.
round_keys (list): A list of round keys in reverse order.
Returns:
int: The partially decrypted ciphertext.
"""
# partial decryption
# round keys in reverse order
ciphertext = ciphertext ^ round_keys[0]
ciphertext = self.inv_sub(ciphertext)
for round_key in round_keys[1:self.rounds]:
ciphertext ^= round_key
ciphertext = self.inv_perm(ciphertext)
ciphertext = self.inv_sub(ciphertext)
if len(round_keys) == self.rounds + 1:
ciphertext ^= round_keys[-1]
return ciphertext
def dec_partial_last_withperm(self, ciphertext, round_keys):
"""Performs partial decryption with permutation on last round
Args:
ciphertext (int): The ciphertext to decrypt.
round_keys (list): A list of round keys.
Returns:
int: The partially decrypted ciphertext.
"""
for round_key in round_keys[:self.rounds]:
ciphertext ^= round_key
ciphertext = self.inv_perm(ciphertext)
ciphertext = self.inv_sub(ciphertext)
if len(round_keys) == self.rounds + 1:
ciphertext ^= round_keys[-1]
return ciphertext
def update_encryptions(self, multiple=10000):
"""Updates the encryptions dictionary.
This method updates the encryptions dictionary by encrypting the ciphertexts
that have not been encrypted yet. It encrypts the ciphertexts in batches to
improve performance.
Args:
multiple (int, optional): The number of ciphertexts to encrypt in each batch. Defaults to 10000.
"""
to_encrypt = [i for i, v in self.encryptions.items() if v is None]
for i in range(0, len(to_encrypt) + multiple, multiple):
current_batch = to_encrypt[i:i + multiple]
if current_batch == []:
break
for j, enc in zip(current_batch, self.batch_encrypt(current_batch)):
self.encryptions[j] = enc
def batch_encrypt(self, pt_list):
"""Encrypts a list of plaintexts.
This method takes a list of integers representing plaintexts and returns a
list of integers representing the corresponding ciphertexts.
Override this function in case oracle is remote and to get encryptions from it.
Args:
pt_list (list): A list of integers representing the plaintexts.
Returns:
list: A list of integers representing the ciphertexts.
"""
return [self.encrypt(i) for i in pt_list]
@abstractmethod
def find_keybits(self, in_mask, out_mask, encryption_pairs, known_keyblocks=()):
"""Finds the key bits based on input and output masks.
This abstract method is meant to be overridden by subclasses. It takes an input mask,
an output mask, a list of encryption pairs, and an optional list of known key blocks
as input. It should implement the logic to find the key bits based on the provided parameters.
Args:
in_mask (int): The input mask for the key search.
out_mask (int): The output mask for the key search.
encryption_pairs (list): A list of tuples of encryption pairs used for analysis.
known_keyblocks (list, optional): A list of known key blocks. Defaults to an empty list.
Returns:
list: A list of key bits that are determined based on the provided parameters.
"""
@abstractmethod
def generate_encryption_pairs(self, outmasks, cutoff, multiple):
"""Generates encryption pairs for analysis.
This abstract method is meant to be overridden by subclasses. It takes a list of output masks
and generates encryption pairs for analysis. The encryption pairs should be suitable for
cryptanalysis purposes.
Args:
outmasks (list): A list of tuples of (input, output masks, bias) for which
the last round key needs to be found.
cutoff (int, optional): The cutoff value used for the maximum number of encryptions
called from oracle in determining the last round key. Defaults to 10000.
multiple (int, optional): The multiple indicating the size of the batch of values to be
encrypted at once used for generating encryption pairs. Defaults to 1000.
Returns:
list: A list of encryption pairs suitable for cryptanalysis.
"""
@abstractmethod
def find_last_roundkey(self, outmasks, cutoff, multiple):
"""Finds the last round key based on output masks.
This abstract method is meant to be overridden by subclasses. It takes a list of output masks
and a cutoff value. It should implement the logic to find the last round key based on the output
masks and the specified cutoff value.
Args:
outmasks (list): A list of tuples of (input, output masks, bias) for which
the last round key needs to be found.
cutoff (int): The cutoff value used for determining the number of encryptions used to
determine the last round key
multiple (int): The multiple indicating the size of the batch of values to be
encrypted at once used for generating encryption pairs.
Returns:
int: The last round key determined based on the output masks and the cutoff value.
"""
Classes
class Cryptanalysis (sbox, pbox, num_rounds, mode='differential')
-
Abstract base class for cryptanalysis algorithms.
Methods: - init: Initialize the cryptanalysis class. - dec_partial_last_noperm: Partially decrypt the ciphertext using last round without permutation. - dec_partial_last_withperm: Partially decrypt the ciphertext using last round with permutation. - update_encryptions: Update the encryption pairs used for analysis. - batch_encrypt: Encrypt multiple plaintexts in batch mode. - find_keybits: Find the key bits of the encryption algorithm. - generate_encryption_pairs: Generate encryption pairs for cryptanalysis. - find_last_roundkey: Find the last round key of the encryption algorithm.
This method initializes the Cryptanalysis class by calling the init method of the SPN class (the parent class) and setting the mode and characteristic_searcher attributes. It also initializes the encryptions dictionary.
Args
sbox
:list
- A list of integers representing the S-box.
pbox
:list
- A list of integers representing the P-box.
num_rounds
:int
- The number of rounds in the block cipher.
mode
:str
, optional- The mode of the cryptanalysis. Defaults to 'differential'.
Expand source code
class Cryptanalysis(SPN, ABC): """ Abstract base class for cryptanalysis algorithms. Methods: - __init__: Initialize the cryptanalysis class. - dec_partial_last_noperm: Partially decrypt the ciphertext using last round without permutation. - dec_partial_last_withperm: Partially decrypt the ciphertext using last round with permutation. - update_encryptions: Update the encryption pairs used for analysis. - batch_encrypt: Encrypt multiple plaintexts in batch mode. - find_keybits: Find the key bits of the encryption algorithm. - generate_encryption_pairs: Generate encryption pairs for cryptanalysis. - find_last_roundkey: Find the last round key of the encryption algorithm. """ def __init__(self, sbox, pbox, num_rounds, mode='differential'): """ This method initializes the Cryptanalysis class by calling the __init__ method of the SPN class (the parent class) and setting the mode and characteristic_searcher attributes. It also initializes the encryptions dictionary. Args: sbox (list): A list of integers representing the S-box. pbox (list): A list of integers representing the P-box. num_rounds (int): The number of rounds in the block cipher. mode (str, optional): The mode of the cryptanalysis. Defaults to 'differential'. """ super().__init__(sbox, pbox, 0, num_rounds) self.mode = mode self.characteristic_searcher = CharacteristicSearcher( self.sbox, self.pbox, num_rounds - 1, mode) self.encryptions = {} # store of the encryptions utilized by the cryptanalysis def dec_partial_last_noperm(self, ciphertext, round_keys): """Performs partial decryption without permutation on the last round. Args: ciphertext (int): The ciphertext to decrypt. round_keys (list): A list of round keys in reverse order. Returns: int: The partially decrypted ciphertext. """ # partial decryption # round keys in reverse order ciphertext = ciphertext ^ round_keys[0] ciphertext = self.inv_sub(ciphertext) for round_key in round_keys[1:self.rounds]: ciphertext ^= round_key ciphertext = self.inv_perm(ciphertext) ciphertext = self.inv_sub(ciphertext) if len(round_keys) == self.rounds + 1: ciphertext ^= round_keys[-1] return ciphertext def dec_partial_last_withperm(self, ciphertext, round_keys): """Performs partial decryption with permutation on last round Args: ciphertext (int): The ciphertext to decrypt. round_keys (list): A list of round keys. Returns: int: The partially decrypted ciphertext. """ for round_key in round_keys[:self.rounds]: ciphertext ^= round_key ciphertext = self.inv_perm(ciphertext) ciphertext = self.inv_sub(ciphertext) if len(round_keys) == self.rounds + 1: ciphertext ^= round_keys[-1] return ciphertext def update_encryptions(self, multiple=10000): """Updates the encryptions dictionary. This method updates the encryptions dictionary by encrypting the ciphertexts that have not been encrypted yet. It encrypts the ciphertexts in batches to improve performance. Args: multiple (int, optional): The number of ciphertexts to encrypt in each batch. Defaults to 10000. """ to_encrypt = [i for i, v in self.encryptions.items() if v is None] for i in range(0, len(to_encrypt) + multiple, multiple): current_batch = to_encrypt[i:i + multiple] if current_batch == []: break for j, enc in zip(current_batch, self.batch_encrypt(current_batch)): self.encryptions[j] = enc def batch_encrypt(self, pt_list): """Encrypts a list of plaintexts. This method takes a list of integers representing plaintexts and returns a list of integers representing the corresponding ciphertexts. Override this function in case oracle is remote and to get encryptions from it. Args: pt_list (list): A list of integers representing the plaintexts. Returns: list: A list of integers representing the ciphertexts. """ return [self.encrypt(i) for i in pt_list] @abstractmethod def find_keybits(self, in_mask, out_mask, encryption_pairs, known_keyblocks=()): """Finds the key bits based on input and output masks. This abstract method is meant to be overridden by subclasses. It takes an input mask, an output mask, a list of encryption pairs, and an optional list of known key blocks as input. It should implement the logic to find the key bits based on the provided parameters. Args: in_mask (int): The input mask for the key search. out_mask (int): The output mask for the key search. encryption_pairs (list): A list of tuples of encryption pairs used for analysis. known_keyblocks (list, optional): A list of known key blocks. Defaults to an empty list. Returns: list: A list of key bits that are determined based on the provided parameters. """ @abstractmethod def generate_encryption_pairs(self, outmasks, cutoff, multiple): """Generates encryption pairs for analysis. This abstract method is meant to be overridden by subclasses. It takes a list of output masks and generates encryption pairs for analysis. The encryption pairs should be suitable for cryptanalysis purposes. Args: outmasks (list): A list of tuples of (input, output masks, bias) for which the last round key needs to be found. cutoff (int, optional): The cutoff value used for the maximum number of encryptions called from oracle in determining the last round key. Defaults to 10000. multiple (int, optional): The multiple indicating the size of the batch of values to be encrypted at once used for generating encryption pairs. Defaults to 1000. Returns: list: A list of encryption pairs suitable for cryptanalysis. """ @abstractmethod def find_last_roundkey(self, outmasks, cutoff, multiple): """Finds the last round key based on output masks. This abstract method is meant to be overridden by subclasses. It takes a list of output masks and a cutoff value. It should implement the logic to find the last round key based on the output masks and the specified cutoff value. Args: outmasks (list): A list of tuples of (input, output masks, bias) for which the last round key needs to be found. cutoff (int): The cutoff value used for determining the number of encryptions used to determine the last round key multiple (int): The multiple indicating the size of the batch of values to be encrypted at once used for generating encryption pairs. Returns: int: The last round key determined based on the output masks and the cutoff value. """
Ancestors
- SPN
- abc.ABC
Subclasses
Methods
def batch_encrypt(self, pt_list)
-
Encrypts a list of plaintexts.
This method takes a list of integers representing plaintexts and returns a list of integers representing the corresponding ciphertexts. Override this function in case oracle is remote and to get encryptions from it.
Args
pt_list
:list
- A list of integers representing the plaintexts.
Returns
list
- A list of integers representing the ciphertexts.
Expand source code
def batch_encrypt(self, pt_list): """Encrypts a list of plaintexts. This method takes a list of integers representing plaintexts and returns a list of integers representing the corresponding ciphertexts. Override this function in case oracle is remote and to get encryptions from it. Args: pt_list (list): A list of integers representing the plaintexts. Returns: list: A list of integers representing the ciphertexts. """ return [self.encrypt(i) for i in pt_list]
def dec_partial_last_noperm(self, ciphertext, round_keys)
-
Performs partial decryption without permutation on the last round.
Args
ciphertext
:int
- The ciphertext to decrypt.
round_keys
:list
- A list of round keys in reverse order.
Returns
int
- The partially decrypted ciphertext.
Expand source code
def dec_partial_last_noperm(self, ciphertext, round_keys): """Performs partial decryption without permutation on the last round. Args: ciphertext (int): The ciphertext to decrypt. round_keys (list): A list of round keys in reverse order. Returns: int: The partially decrypted ciphertext. """ # partial decryption # round keys in reverse order ciphertext = ciphertext ^ round_keys[0] ciphertext = self.inv_sub(ciphertext) for round_key in round_keys[1:self.rounds]: ciphertext ^= round_key ciphertext = self.inv_perm(ciphertext) ciphertext = self.inv_sub(ciphertext) if len(round_keys) == self.rounds + 1: ciphertext ^= round_keys[-1] return ciphertext
def dec_partial_last_withperm(self, ciphertext, round_keys)
-
Performs partial decryption with permutation on last round
Args
ciphertext
:int
- The ciphertext to decrypt.
round_keys
:list
- A list of round keys.
Returns
int
- The partially decrypted ciphertext.
Expand source code
def dec_partial_last_withperm(self, ciphertext, round_keys): """Performs partial decryption with permutation on last round Args: ciphertext (int): The ciphertext to decrypt. round_keys (list): A list of round keys. Returns: int: The partially decrypted ciphertext. """ for round_key in round_keys[:self.rounds]: ciphertext ^= round_key ciphertext = self.inv_perm(ciphertext) ciphertext = self.inv_sub(ciphertext) if len(round_keys) == self.rounds + 1: ciphertext ^= round_keys[-1] return ciphertext
def find_keybits(self, in_mask, out_mask, encryption_pairs, known_keyblocks=())
-
Finds the key bits based on input and output masks.
This abstract method is meant to be overridden by subclasses. It takes an input mask, an output mask, a list of encryption pairs, and an optional list of known key blocks as input. It should implement the logic to find the key bits based on the provided parameters.
Args
in_mask
:int
- The input mask for the key search.
out_mask
:int
- The output mask for the key search.
encryption_pairs
:list
- A list of tuples of encryption pairs used for analysis.
known_keyblocks
:list
, optional- A list of known key blocks. Defaults to an empty list.
Returns
list
- A list of key bits that are determined based on the provided parameters.
Expand source code
@abstractmethod def find_keybits(self, in_mask, out_mask, encryption_pairs, known_keyblocks=()): """Finds the key bits based on input and output masks. This abstract method is meant to be overridden by subclasses. It takes an input mask, an output mask, a list of encryption pairs, and an optional list of known key blocks as input. It should implement the logic to find the key bits based on the provided parameters. Args: in_mask (int): The input mask for the key search. out_mask (int): The output mask for the key search. encryption_pairs (list): A list of tuples of encryption pairs used for analysis. known_keyblocks (list, optional): A list of known key blocks. Defaults to an empty list. Returns: list: A list of key bits that are determined based on the provided parameters. """
def find_last_roundkey(self, outmasks, cutoff, multiple)
-
Finds the last round key based on output masks.
This abstract method is meant to be overridden by subclasses. It takes a list of output masks and a cutoff value. It should implement the logic to find the last round key based on the output masks and the specified cutoff value.
Args
outmasks
:list
- A list of tuples of (input, output masks, bias) for which the last round key needs to be found.
cutoff
:int
- The cutoff value used for determining the number of encryptions used to determine the last round key
multiple
:int
- The multiple indicating the size of the batch of values to be encrypted at once used for generating encryption pairs.
Returns
int
- The last round key determined based on the output masks and the cutoff value.
Expand source code
@abstractmethod def find_last_roundkey(self, outmasks, cutoff, multiple): """Finds the last round key based on output masks. This abstract method is meant to be overridden by subclasses. It takes a list of output masks and a cutoff value. It should implement the logic to find the last round key based on the output masks and the specified cutoff value. Args: outmasks (list): A list of tuples of (input, output masks, bias) for which the last round key needs to be found. cutoff (int): The cutoff value used for determining the number of encryptions used to determine the last round key multiple (int): The multiple indicating the size of the batch of values to be encrypted at once used for generating encryption pairs. Returns: int: The last round key determined based on the output masks and the cutoff value. """
def generate_encryption_pairs(self, outmasks, cutoff, multiple)
-
Generates encryption pairs for analysis.
This abstract method is meant to be overridden by subclasses. It takes a list of output masks and generates encryption pairs for analysis. The encryption pairs should be suitable for cryptanalysis purposes.
Args
outmasks
:list
- A list of tuples of (input, output masks, bias) for which the last round key needs to be found.
cutoff
:int
, optional- The cutoff value used for the maximum number of encryptions called from oracle in determining the last round key. Defaults to 10000.
multiple
:int
, optional- The multiple indicating the size of the batch of values to be encrypted at once used for generating encryption pairs. Defaults to 1000.
Returns
list
- A list of encryption pairs suitable for cryptanalysis.
Expand source code
@abstractmethod def generate_encryption_pairs(self, outmasks, cutoff, multiple): """Generates encryption pairs for analysis. This abstract method is meant to be overridden by subclasses. It takes a list of output masks and generates encryption pairs for analysis. The encryption pairs should be suitable for cryptanalysis purposes. Args: outmasks (list): A list of tuples of (input, output masks, bias) for which the last round key needs to be found. cutoff (int, optional): The cutoff value used for the maximum number of encryptions called from oracle in determining the last round key. Defaults to 10000. multiple (int, optional): The multiple indicating the size of the batch of values to be encrypted at once used for generating encryption pairs. Defaults to 1000. Returns: list: A list of encryption pairs suitable for cryptanalysis. """
def update_encryptions(self, multiple=10000)
-
Updates the encryptions dictionary.
This method updates the encryptions dictionary by encrypting the ciphertexts that have not been encrypted yet. It encrypts the ciphertexts in batches to improve performance.
Args
multiple
:int
, optional- The number of ciphertexts to encrypt in each batch. Defaults to 10000.
Expand source code
def update_encryptions(self, multiple=10000): """Updates the encryptions dictionary. This method updates the encryptions dictionary by encrypting the ciphertexts that have not been encrypted yet. It encrypts the ciphertexts in batches to improve performance. Args: multiple (int, optional): The number of ciphertexts to encrypt in each batch. Defaults to 10000. """ to_encrypt = [i for i, v in self.encryptions.items() if v is None] for i in range(0, len(to_encrypt) + multiple, multiple): current_batch = to_encrypt[i:i + multiple] if current_batch == []: break for j, enc in zip(current_batch, self.batch_encrypt(current_batch)): self.encryptions[j] = enc
Inherited members