blob: de26398641bbe181a311a61d3fc9669393a87a1a [file] [log] [blame]
// Copyright lowRISC contributors.
// 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 outbut 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 Input 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_