Class desfire::crypto_with_cmac

Inheritance Relationships

Base Type

Derived Types

Class Documentation

class crypto_with_cmac : public desfire::crypto

Abstract class that extends crypto providing CMAC capabilities.

This is the base class for modern 3K3DES and AES128 ciphers, and uses internally cmac_provider. Subclasses should

  1. Still provide the correct crypto_operation::mac implementation through crypto::do_crypto, as this is used as a subroutine of the more sophisticated do_cmac function.

  2. Correctly setup this class via the protected constructor crypto_with_cmac::crypto_with_cmac, since some information on the block size and a given magic number is required to correctly compute the CMAC.

  3. Avoid overriding setup_with_key, since the implementation provided by this class does also CMAC subkey derivation. Instead, they should implement setup_primitives_with_key, with the same effect and extents as crypto::setup_with_key.

Warning

It is not correct to use this class through its base interface crypto! Protocols and ciphers that use CMAC-enabled crypto should use directly do_cmac and this class. The reason is that these ciphers require the initialization vector to be in sync with the Desfire card throughout the session, and the IV is updated by a CMAC operation. Therefore, calling e.g. do_crypto naively with a crypto_operation::mac would throw the IV out of sync. Therefore, CMAC-enabled cryptographic implementation are supposed to be used as such and not through the lower abstraction layer.

Subclassed by desfire::crypto_3k3des_base, desfire::crypto_aes_base

Public Types

using mac_t = cmac_provider::mac_t

The type of the CMAC MAC code, which is a fixed 8 bytes sequence.

Public Functions

virtual mac_t do_cmac(range<std::uint8_t const*> data, range<std::uint8_t*> iv)

Computes the CMAC on data using the given initialization vector iv. The CMAC is nothing but the first 8 bytes of iv after crypto_operation::mac has been run on data.

Parameters:
  • data – Data sequence for which the CMAC has to be computed. Remains constant.

  • iv – Initialization vector to use. It is updated in place by this function.

Returns:

The first 8 bytes of iv after the cryptographic operation has been done.

std::size_t block_size() const

Block size for this cipher. This is specified upon construction and is cipher-specific.

Returns:

Size in bytes of the underlying block cipher.

virtual void setup_with_key(range<std::uint8_t const*> key) override

CMAC-enabled implementation of crypto::setup_with_key.

This method first of all calls setup_primitives_with_key and right afterwards generates CMAC subkeys for the internal cmac_provider.

Warning

Subclasses should leave this method alone and instead implement setup_primitives_with_key.

Parameters:

key – Range of bytes containing the key to use for the following operations. This is specified as a range on raw bytes for convenience, as the underlying cryptographic functions are likely low level.

inline cmac_provider const &provider() const

Access the internal CMAC provider.

Protected Functions

crypto_with_cmac(std::uint8_t block_size, std::uint8_t last_byte_xor)

Initializes the CMAC-enabled class.

Parameters:
  • block_size – Size of the cipher block. This is passed directly to cmac_provider::cmac_provider.

  • last_byte_xor – When deriving the key, if the MSB is 1, the last byte is XOR-ed with this value. I have no clue about why we have to do this, maybe some nice key pre-conditioning to resist certain attacks? I do not know, but it is a constant specific to the cipher used. This is passed directly to cmac_provider::cmac_provider.

virtual void setup_primitives_with_key(range<std::uint8_t const*> key) = 0

Subclasses should implement this instead of setup_with_key, to the same effect.

This method is called by the custom implementation of setup_with_key provided in this class, right before key derivation is performed, with the same parameters.

Parameters:

key – Range of bytes containing the key to use for the following operations. This is specified as a range on raw bytes for convenience, as the underlying cryptographic functions are likely low level.