dif_aes.h

To use this DIF, include the following C header:

#include "/workspace/sw/device/lib/dif/dif_aes.h"

This header provides the following device interface functions:

Generated from dif_aes.h
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

#ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_AES_H_
#define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_AES_H_

#include <stdbool.h>
#include <stdint.h>

#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_base.h"

#include "sw/device/lib/dif/autogen/dif_aes_autogen.h"

#ifdef __cplusplus
extern "C" {
#endif  // __cplusplus

/**
 *
 * @file
 * @brief <a href="/hw/ip/aes/doc/">AES</a> Device Interface Functions
 *
 * This API assumes transactional nature of work, where the peripheral is
 * configured once per message (data consisting of 1..N 128-bit blocks), and
 * then "de-initialised" when this message has been fully encrypted/decrypted.
 *
 * The peripheral is configured through one of the cipher mode "start"
 * functions:
 * `dif_aes_start_ecb`, `dif_aes_start_cbc`, ... .
 *
 * Then the encryption/decryption data is fed one 128-bit block at the
 * time through `dif_aes_load_data` function. The cipher mode operation details
 * are described in the description of above mentioned "start" functions. When
 * configured in "automatic" operation mode, every "load data" call, will
 * trigger encryption/decryption. This is not true when in "manual" operation
 * mode, where encryption/decryption is triggered by explicitly setting the
 * `aes.TRIGGER.START` flag through `dif_aes_trigger` call.
 *
 * When an entire requested message has been processed the internal state of
 * AES registers must be securely cleared, by calling `dif_aes_end`.
 *
 * Please see the following documentation for further information:
 * https://docs.opentitan.org/hw/ip/aes/doc/
 * https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf
 * https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
 */

/**
 * A typed representation of the AES key share.
 *
 * Two part masked AES key, where XOR operation of these two parts results in
 * the actual key.
 */
typedef struct dif_aes_key_share {
  /**
   * One share of the key that when XORed with `share1` results in the actual
   * key.
   */
  uint32_t share0[8];
  /**
   * One share of the key that when XORed with `share0` results in the actual
   * key.
   */
  uint32_t share1[8];
} dif_aes_key_share_t;

/**
 * A typed representation of the AES Initialisation Vector (IV).
 */
typedef struct dif_aes_iv {
  uint32_t iv[4];
} dif_aes_iv_t;

/**
 * A typed representation of the AES data.
 */
typedef struct dif_aes_data {
  uint32_t data[4];
} dif_aes_data_t;

/**
 * AES operation.
 */
typedef enum dif_aes_operation {
  /**
   * AES encryption.
   */
  kDifAesOperationEncrypt = 1,
  /**
   * AES decryption.
   */
  kDifAesOperationDecrypt = 2,
} dif_aes_operation_t;

/**
 * AES block cipher mode of operation.
 */
typedef enum dif_aes_mode {
  /**
   * The Electronic Codebook Mode.
   * In ECB cipher mode the key must be changed for every new block of data.
   * This is the only secure way to use ECB cipher mode.
   *
   * Note: The ECB cipher mode doesn't use the iv parameter of the
   * `dif_aes_start` function.
   *
   * Note: it is discouraged to use this cipher mode, due to impractical amount
   *       of different keys required to encrypt/decrypt multi-block messages.
   */
  kDifAesModeEcb = 1,

  /**
   * The Cipher Block Chaining Mode.
   *
   * In CBC cipher mode, the same key can be used for all messages, however
   * new Initialisation Vector (IV) must be generated for any new message. The
   * following condition must be true:
   *     The IV must be unpredictable (it must not be possible to predict the IV
   *     that will be associated to the plaintext in advance of the generation
   * of the IV).
   *
   * With key length less than 256 bits, the excess portion of the `key` can be
   * written with any data (preferably random).
   */
  kDifAesModeCbc = (1 << 1),

  /**
   * The Cipher Feedback Mode.
   *
   * In CFB cipher mode, the same key can be used for all messages, however
   * new Initialisation Vector (IV) must be generated for any new message. The
   * following condition must be true:
   *     The IV must be unpredictable (it must not be possible to predict the IV
   *     that will be associated to the plaintext in advance of the generation
   * of the IV).
   *
   * With key length less than 256 bits, the excess portion of the `key` can be
   * written with any data (preferably random).
   */
  kDifAesModeCfb = (1 << 2),

  /**
   * The Output Feedback Mode.
   *
   * In OFB cipher mode, the same key can be used for all messages, and the
   * Initialization Vector (IV) need NOT be unpredictable. The following
   * conditions must be true:
   *     OFB mode requires a unique initialization vector for every message that
   *     is ever encrypted under a given key, across all messages.
   *
   * With key length less than 256 bits, the excess portion of the `key` can be
   * written with any data (preferably random).
   */
  kDifAesModeOfb = (1 << 3),

  /**
   * The Counter Mode.
   *
   * In CTR cipher mode, the same key can be used for all messages, if the
   * following condition is true:
   *     CTR mode requires a unique counter block for each plaintext block that
   *     is ever encrypted under a given key, across all messages.
   *
   * With key length less than 256 bits, the excess portion of the `key` can be
   * written with any data (preferably random).
   */
  kDifAesModeCtr = (1 << 4),
} dif_aes_mode_t;

/**
 * AES key length in bits.
 */
typedef enum dif_aes_key_length {
  /**
   * 128 bit wide AES key.
   */
  kDifAesKey128 = 1,
  /**
   * 192 bit wide AES key.
   */
  kDifAesKey192 = (1 << 1),
  /**
   * 256 bit wide AES key.
   */
  kDifAesKey256 = (1 << 2)
} dif_aes_key_length_t;

/**
 * AES manual operation.
 */
typedef enum dif_aes_manual_operation {
  /**
   * AES operates in automatic mode - which means that the encryption/decryption
   * is automatically triggered on every successful `dif_aes_*_load_data()`.
   */
  kDifAesManualOperationAuto = 0,
  /**
   * AES operates in manual mode - which means that the encryption/decryption
   * is manually triggered by `dif_aes_trigger(kDifAesTriggerStart)`.
   */
  kDifAesManualOperationManual,
} dif_aes_manual_operation_t;

/**
 * AES key sideloaded.
 *
 * Controls whether the AES uses the key provided by the key manager or
 * software.
 */
typedef enum dif_aes_key_provider {
  /**
   * The key is provided by software via `dif_aes_key_share_t`.
   */
  kDifAesKeySoftwareProvided = 0,
  /**
   * The key be provided by the key manager.
   */
  kDifAesKeySideload,
} dif_aes_key_provider_t;

/**
 * AES reseeding rate
 *
 * Controls the reseeding rate of the internal pseudo-random number generator
 * (PRNG) used for masking.
 */
typedef enum dif_aes_mask_reseeding {
  /**
   * The masking PRNG will be reseed every block.
   */
  kDifAesReseedPerBlock = 1 << 0,
  /**
   * The masking PRNG will be reseed every 64 blocks.
   */
  kDifAesReseedPer64Block = 1 << 1,
  /**
   * The masking PRNG will be reseed every 8192 blocks.
   */
  kDifAesReseedPer8kBlock = 1 << 2,
} dif_aes_mask_reseeding_t;

/**
 * Parameters for an AES transaction.
 */
typedef struct dif_aes_transaction {
  dif_aes_operation_t operation;
  dif_aes_mode_t mode;
  dif_aes_key_length_t key_len;
  dif_aes_manual_operation_t manual_operation;
  dif_aes_key_provider_t key_provider;
  dif_aes_mask_reseeding_t mask_reseeding;
  /**
   * If true the internal pseudo-random number generators used for clearing and
   * masking will be reseeded every time the key changes.
   */
  bool reseed_on_key_change;
  /**
   * If true, the internal pseudo-random number generator used for masking is
   * not advancing leading to constant masks.
   *
   * NOTE: This should only be used for development purpose (SCA), and is
   * expected to be removed for the production version.
   */
  bool force_masks;
  /**
   * If true `reseed_on_key_change` and `force_masks` will be locked until the
   * device is reset.
   */
  bool ctrl_aux_lock;
} dif_aes_transaction_t;

/**
 * Resets an instance of AES.
 *
 * Clears the internal state along with the interface registers.
 *
 * @param aes AES state data.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_aes_reset(const dif_aes_t *aes);

/**
 * Begins an AES transaction in the mode selected by the `transaction->mode`.
 *
 * Each call to this function should be sequenced with a call to
 * `dif_aes_end()`.
 *
 * The peripheral must be in IDLE state for this operation to take effect, and
 * will return `kDifAesBusy` if this condition is not met.
 *
 * @param aes AES state data.
 * @param transaction Configuration data.
 * @param key Encryption/decryption key when `kDifAesKeySoftwareProvided`, can
 * be `NULL` otherwise.
 * @param iv Initialization vector when the mode isn't `kDifAesModeEcb`, can be
 * `NULL` otherwise.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_aes_start(const dif_aes_t *aes,
                           const dif_aes_transaction_t *transaction,
                           const dif_aes_key_share_t *key,
                           const dif_aes_iv_t *iv);
/**
 * Ends an AES transaction.
 *
 * This function must be called at the end of every `dif_aes_<mode>_start`
 * operation.
 *
 * The peripheral must be in IDLE state for this operation to take effect, and
 * will return `kDifAesEndBusy` if this condition is not met.
 *
 * @param aes AES state data.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_aes_end(const dif_aes_t *aes);

/**
 * Loads AES Input Data.
 *
 * This function will trigger encryption/decryption when configured in
 * the automatic operation mode.
 *
 * The peripheral must be able to accept the input (INPUT_READY set), and
 * will return `kDifAesLoadDataBusy` if this condition is not met.
 *
 * @param aes AES state data.
 * @param data AES Input Data.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_aes_load_data(const dif_aes_t *aes, const dif_aes_data_t data);

/**
 * Reads AES Output Data.
 *
 * The peripheral must have finished previous encryption/decryption operation,
 * and have valid data in the output registers (OUTPUT_VALID set), and will
 * return `kDifAesReadOutputInvalid` if this condition is not met.
 *
 * @param aes AES state data.
 * @param data AES Output Data.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_aes_read_output(const dif_aes_t *aes, dif_aes_data_t *data);

/**
 * Process a stream of data containing the plain text and output a stream of
 * data with the cipher text.
 *
 * This function should be used when performance is desired. It requires the
 * automatic operation mode activated.
 *
 * The peripheral must be able to accept the input (INPUT_READY set), and
 * will return `kDifAesLoadDataBusy` if this condition is not met.
 *
 * @param aes AES handle.
 * @param plain_text AES Input Data.
 * @param cipher_text AES Output Data.
 * @param block_amount The amount of blocks to be encrypted.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_aes_process_data(const dif_aes_t *aes,
                                  const dif_aes_data_t *plain_text,
                                  dif_aes_data_t *cipher_text,
                                  size_t block_amount);

/**
 * AES Trigger flags.
 */
typedef enum dif_aes_trigger {
  /**
   * Trigger encrypt/decrypt.
   */
  kDifAesTriggerStart = 0,
  /**
   * Clear key, Initialisation Vector/Initial Counter Value and input data.
   */
  kDifAesTriggerKeyIvDataInClear,
  /**
   * Clear Output Data registers.
   */
  kDifAesTriggerDataOutClear,
  /**
   * Perform reseed of the internal state.
   */
  kDifAesTriggerPrngReseed,
} dif_aes_trigger_t;

/**
 * Triggers one of `dif_aes_trigger_t` operations.
 *
 * All the triggers are applicable to both (automatic and manual) modes, with
 * the exception of `kDifAesTriggerStart`, which is ignored in automatic mode.
 *
 * @param aes AES state data.
 * @param trigger AES trigger.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_aes_trigger(const dif_aes_t *aes, dif_aes_trigger_t trigger);

/**
 * AES Status flags.
 */
typedef enum dif_aes_status {
  /**
   * Device is idle.
   */
  kDifAesStatusIdle = 0,
  /**
   * Device has stalled (only relevant in automatic
   * operation mode). Output data overwrite
   * protection.
   */
  kDifAesStatusStall,
  /**
   * Output data has been overwritten by the AES unit before the processor
   * could fully read it. This bit is "sticky" for the entire duration of
   * the current transaction.
   */
  kDifAesStatusOutputLost,
  /**
   * Device output is valid/ready. Denotes a
   * successful encrypt or decrypt operation.
   */
  kDifAesStatusOutputValid,
  /**
   * Device Input Data registers can be written to
   * (ready to accept new input data).
   */
  kDifAesStatusInputReady,
  /**
   * Fatal alert conditions include i) storage errors in the Control Register,
   * and ii) if any internal FSM enters an invalid state.
   */
  kDifAesStatusAlertFatalFault,
  /**
   * Recoverable alert conditions include update errors in the Control Register.
   */
  kDifAesStatusAlertRecovCtrlUpdateErr,
} dif_aes_status_t;

/**
 * Queries the AES status flags.
 *
 * @param aes AES state data.
 * @param flag Status flag to query.
 * @param[out] set Flag state (set/unset).
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_aes_get_status(const dif_aes_t *aes, dif_aes_status_t flag,
                                bool *set);

/**
 * Read the current initialization vector from its register.
 *
 * @param aes AES handle.
 * @param iv The pointer to receive the initialization vector.
 * @return The result of the operation.
 */
OT_WARN_UNUSED_RESULT
dif_result_t dif_aes_read_iv(const dif_aes_t *aes, dif_aes_iv_t *iv);

#ifdef __cplusplus
}  // extern "C"
#endif  // __cplusplus

#endif  // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_AES_H_