cascada.primitives.blockcipher module

Represent encryption functions and block ciphers.

Encryption

Represent encryption functions of block ciphers.

Cipher

Represent block ciphers.

get_random_cipher

Return a random Cipher with given shape.

class cascada.primitives.blockcipher.Encryption(*args, **options)[source]

Bases: object

Represent encryption functions of block ciphers.

An encryption function is a bit-vector function (see BvFunction) that takes the plaintext as input and returns the ciphertext for some fixed master key.

An encryption function together with a key-schedule function forms a Cipher.

The tuple of round keys (the outputs of the associated key-schedule function) are accessible through the class attribute round_keys.

The encryption function is not responsible for the creation of the round keys, and the eval method of Encryption can assume that round_keys is a tuple of bit-vectors with the bit-sizes given by Cipher.key_schedule.output_widths.

Note

The eval method of Encryption is meant to be called from the eval method of Cipher, and in the latter eval the round keys for the given master key are automatically created and temporarily stored in round_keys (until the end of eval).

To use the encryption function as a regular BvFunction, round_keys must be filled with a tuple of Constant or Variable objects. This can be easily done by Cipher.set_round_keys If round_keys contains Variable objects, the round keys are represented in the SSA of the encryption function as external variables.

To define an encryption function for a new Cipher, you must create a new class with two parent/base classes: Encryption and either BvFunction or RoundBasedFunction.

Note

Encryption must always be the first parent/base class so that the Encryption methods can override the BvFunction or RoundBasedFunction methods.

round_keys

the round keys as a tuple of Constant or Variable objects

class cascada.primitives.blockcipher.Cipher(plaintext, masterkey, **options)[source]

Bases: object

Represent block ciphers.

A block cipher is a pair of bit-vector functions (see BvFunction): the key schedule that computes the round keys from a master key, and the Encryption function.

Similar to BvFunction, Cipher is evaluated with the operator () that is, Cipher(plaintext, masterkey) returns the ciphertext. The arguments plaintext and masterkey are both lists of Constant objects or integers (integers are automatically converted to Constant objects using the bit-sizes given by Cipher.key_schedule.input_widths and Cipher.encryption.input_widths.

An iterated block cipher is a Cipher where both the key-schedule and the encryption functions are RoundBasedFunction objects.

This class is not meant to be instantiated but to provide a base class for block ciphers. To define a block cipher, subclass Cipher and set the class attributes key_schedule and encryption. For an iterated block cipher, the method set_num_rounds must be implemented.

Note

The method set_num_rounds must set the number of rounds of encryption to the given number of rounds, but the number of rounds of key_schedule might differ.

For an iterated block cipher C where the key_schedule and the encryption share the number of rounds (i.e., C.key_schedule.num_rounds == C.encryption.num_rounds), the usual implement of set_num_rounds is

@classmethod
def set_num_rounds(cls, encryption_new_num_rounds):
    cls.key_schedule.set_num_rounds(encryption_new_num_rounds)
    cls.encryption.set_num_rounds(encryption_new_num_rounds)

However, an iterated block cipher can also contain a key_schedule with a different number of rounds than the encryption. An example of set_num_rounds for an iterated cipher where the key_schedule has one less round that the encryption is

@classmethod
def set_num_rounds(cls, encryption_new_num_rounds):
    cls.key_schedule.set_num_rounds(encryption_new_num_rounds - 1)
    cls.encryption.set_num_rounds(encryption_new_num_rounds)
>>> from cascada.primitives.blockcipher import Cipher
>>> from cascada.primitives import speck
>>> Speck32 = speck.get_Speck_instance(speck.SpeckInstance.speck_32_64)
>>> issubclass(Speck32, Cipher)
True
>>> Speck32(plaintext=[0, 0], masterkey=[0, 0, 0, 0])  # Automatic Constant Conversion
(0x2bb9, 0xc642)
>>> Speck32.get_name()
'SpeckCipher_22R'
>>> Speck32.vrepr()
'SpeckCipher.set_num_rounds_and_return(22)'
>>> Speck32.set_round_keys(masterkey=[0, 0, 0, 0])
>>> Speck32.encryption.round_keys  
(0x0000, 0x0000, 0x0001, 0x0007, 0x0018, 0x027c, 0x0189, 0x0fab, 0x7904, 0x8f0d, 0x911f,
0xa5da, 0x49d1, 0xba62, 0xeda2, 0xd3da, 0x6c70, 0x0da9, 0x86c6, 0xa604, 0xef7d, 0x093e)
>>> Speck32.set_num_rounds(2)
>>> Speck32(plaintext=[0, 0], masterkey=[0, 0])  # masterkey is now a 2-word list
(0x0000, 0x0000)
>>> Speck32.get_name()
'SpeckCipher_2R'
>>> Speck32.vrepr()
'SpeckCipher.set_num_rounds_and_return(2)'
>>> Speck32.set_round_keys(symbolic_prefix="k")
>>> for v in Speck32.encryption.round_keys: print(v.vrepr())
Variable('k0', width=16)
Variable('k1', width=16)
key_schedule

the key-schedule function (a subclass of BvFunction)

encryption

the encryption function (a subclass of Encryption and BvFunction)

class property num_rounds

The number of rounds of encryption if iterated, otherwise None

classmethod get_name()[source]

Return the class name and the current number of rounds (if iterated).

classmethod vrepr()[source]

Return an executable string representation.

This method returns a string so that eval(cls.vrepr()) returns a new Cipher object with the same content.

classmethod set_num_rounds(encryption_new_num_rounds)[source]

Call RoundBasedFunction.set_num_rounds of key_schedule and encryption (if iterated).

classmethod set_num_rounds_and_return(new_num_rounds)[source]

Call set_num_rounds and return cls (if iterated).

classmethod set_round_keys(masterkey=None, symbolic_prefix=None)[source]

Set cls.encryption.round_keys.

If masterkey is given, set the round keys as the output of cls.key_schedule(*masterkey).

If symbolic_prefix is given, set the round keys as a tuple of Variable objects with prefix name symbolic_prefix and with bit-sizes given by cls.key_schedule.output_widths.

Parameters
  • masterkey – (optional) a list of Constant objects or integers

  • symbolic_prefix – (optional) a string

cascada.primitives.blockcipher.get_random_cipher(width, key_num_inputs, key_num_assignments, enc_num_inputs, enc_num_outputs, enc_num_assignments, seed, external_variable_prefix, operation_set_index=0, num_rounds=None, extra_operations=None)[source]

Return a random Cipher with given shape.

Parameters
  • width – the common bitsize of the input and output variables of the function

  • key_num_inputs – the number of inputs of the key schedule

  • key_num_assignments – an estimation of the number of operations within the key schedule

  • enc_num_inputs – the number of inputs of the encryption

  • enc_num_assignments – an estimation of the number of operations within the encryption

  • enc_num_outputs – the number of outputs of the encryption

  • seed – the seed used when sampling

  • operation_set_index – four set of operations to choose indexed by 0, 1, 2 and 3

  • num_rounds – if not None, sample the key-schedule and the encryption functions as random RoundBasedFunction objects with the given number of rounds

  • extra_operations – an optional tuple containing Operation subclasses to add to the list of operations to choose

>>> from cascada.bitvector.core import Variable
>>> from cascada.primitives.blockcipher import get_random_cipher
>>> my_cipher = get_random_cipher(4, 1, 1, 2, 2, 4, seed=1, external_variable_prefix="rk")
>>> my_cipher.key_schedule.to_ssa(["mk0"], "k")
SSA(input_vars=[mk0], output_vars=[k0_out], assignments=[(k0, mk0 & 0x5), (k0_out, Id(k0))])
>>> my_cipher.encryption.round_keys = [Variable(f"rk{i}", 4) for i in range(1)]
>>> my_cipher.encryption.to_ssa(["p0", "p1"], "x")  
SSA(input_vars=[p0, p1], output_vars=[x2_out, x3_out], external_vars=[rk0],
    assignments=[(x0, p0 ^ rk0), (x1, x0 - p1), (x2, p0 + p1), (x3, -x1), (x2_out, Id(x2)), (x3_out, Id(x3))])

See also get_random_bvfunction.