Skip to content

Commit

Permalink
[aes/rtl] Correct manual operation mode for GCM
Browse files Browse the repository at this point in the history
This commit cleans up the generation of GCM specific start signals
and properly handles manual operation mode for GCM. Previously, some
GCM phases (especially the ones not using the AES cipher core) would
start automatically despite the module being configured in manual
operation mode.

Signed-off-by: Pirmin Vogel <[email protected]>
  • Loading branch information
vogelpi committed Jan 13, 2025
1 parent 0cd8a2a commit 2721e79
Showing 1 changed file with 78 additions and 46 deletions.
124 changes: 78 additions & 46 deletions hw/ip/aes/rtl/aes_control_fsm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,8 @@ module aes_control_fsm
logic input_ready_we;

logic gcm_init, gcm_restore, gcm_aad, gcm_txt, gcm_save, gcm_tag;
logic start_common_gcm, start_gcm;
logic start_gcm_init, start_gcm_hash_subkey, start_gcm_s;
logic start_common_gcm, start_ghash;
logic start_gcm_init, start_gcm_hsk, start_gcm_s;
logic start_gcm_restore, start_gcm_aad, start_gcm_txt, start_gcm_save;
logic start_gcm_tag;
logic doing_gcm_hsk, doing_gcm_s, doing_gcm_txt;
Expand Down Expand Up @@ -230,41 +230,6 @@ module aes_control_fsm
assign start_ofb = (mode_i == AES_OFB) & iv_ready;
assign start_ctr = (mode_i == AES_CTR) & iv_ready & ctr_ready_i;

// For the initial GCM phase, we need key and IV but then encrypt two blocks. The input data
// is not required.
assign gcm_init = (mode_i == AES_GCM) & (gcm_phase_i == GCM_INIT);
assign start_common_gcm = key_init_ready & (sideload_i ? key_sideload_valid_i : 1'b1);
assign start_gcm_hash_subkey = gcm_init & ~hash_subkey_ready_q & iv_ready & ctr_ready_i;
assign start_gcm_s = gcm_init & ~s_ready_q & iv_ready & ctr_ready_i;
assign start_gcm_init = (start_gcm_hash_subkey | start_gcm_s) & start_common_gcm;

// For the restore phase of GCM, we need key, IV and input data.
assign gcm_restore = (mode_i == AES_GCM) & (gcm_phase_i == GCM_RESTORE);
assign start_gcm_restore = gcm_restore & iv_ready & ctr_ready_i & data_in_new & start_common_gcm;

// For the AAD and ciphertext/plaintext phases of GCM, we need key, IV and input data. But for
// the AAD phase, only the input data is really used and marked as used.
assign gcm_aad = (mode_i == AES_GCM) & (gcm_phase_i == GCM_AAD);
assign gcm_txt = (mode_i == AES_GCM) & (gcm_phase_i == GCM_TEXT);
assign start_gcm_aad = gcm_aad & iv_ready & ctr_ready_i & data_in_new;
assign start_gcm_txt = gcm_txt & iv_ready & ctr_ready_i & data_in_new;
assign start_gcm = start_gcm_aad | start_gcm_txt;

// For the save phase of GCM, we need no inputs.
assign gcm_save = (mode_i == AES_GCM) & (gcm_phase_i == GCM_SAVE);
assign start_gcm_save = gcm_save & hash_subkey_ready_q & s_ready_q;

// For the tag phase of GCM, we just need the input data.
assign gcm_tag = (mode_i == AES_GCM) & (gcm_phase_i == GCM_TAG);
assign start_gcm_tag = gcm_tag & data_in_new;

// The GHASH block is idle whenever it's ready to receive inputs and where not about to start
// a GCM related operation.
assign ghash_idle = ghash_in_ready_i & ~(start_gcm_init | start_gcm | start_gcm_tag);

// In GCM, the counter performs inc32() instead of inc128(), i.e., the counter wraps at 32 bits.
assign ctr_inc32_o = (mode_i == AES_GCM);

// If set to start manually, we just wait for the trigger. Otherwise, check common as well as
// mode-specific start conditions.
assign start = cfg_valid & no_alert &
Expand All @@ -275,12 +240,11 @@ module aes_control_fsm
start_cbc |
start_cfb |
start_ofb |
start_ctr |
start_gcm) & start_common) |
start_gcm_init |
start_gcm_restore |
start_gcm_save |
start_gcm_tag);
start_ctr) & start_common) |
// Only the initial as well as the ciphertext/plaintext phases of GCM require operating
// the AES cipher core. Common start conditions are already factored into these signals.
(start_gcm_init |
start_gcm_txt));

// If not set to overwrite data, we wait for any previous output data to be read. data_out_read
// synchronously clears output_valid_q, unless new output data is written in the exact same
Expand All @@ -291,6 +255,72 @@ module aes_control_fsm
// Make sure previous output data has been read.
(~output_valid_q | data_out_read));

//////////////////////////
// GCM Start Conditions //
//////////////////////////
// Note that only the initial as well as the ciphertext/plaintext phases of GCM require operating
// the AES cipher core. The start conditions for these phases are factored into the regular start
// signal above. In contrast, the restore, AAD, save and tag phases use the GHASH block only. The
// corresponding start conditions are handled separately by the FSM and we need to explicilty
// factor in manual operation below.

assign gcm_init = (mode_i == AES_GCM) & (gcm_phase_i == GCM_INIT);
assign gcm_restore = (mode_i == AES_GCM) & (gcm_phase_i == GCM_RESTORE);
assign gcm_aad = (mode_i == AES_GCM) & (gcm_phase_i == GCM_AAD);
assign gcm_txt = (mode_i == AES_GCM) & (gcm_phase_i == GCM_TEXT);
assign gcm_save = (mode_i == AES_GCM) & (gcm_phase_i == GCM_SAVE);
assign gcm_tag = (mode_i == AES_GCM) & (gcm_phase_i == GCM_TAG);

// The common start conditions for GCM don't include the input data.
assign start_common_gcm = key_init_ready &
// If key sideload is enabled, we only start if the key is valid.
(sideload_i ? key_sideload_valid_i : 1'b1);

// For the initial GCM phase, we need key and IV but then encrypt two blocks. The input data
// is not required. Requires operating the AES cipher core and thus factors into the regular
// start signal.
assign start_gcm_hsk = gcm_init & ~hash_subkey_ready_q & iv_ready & ctr_ready_i;
assign start_gcm_s = gcm_init & ~s_ready_q & iv_ready & ctr_ready_i;
assign start_gcm_init = (start_gcm_hsk | start_gcm_s) & start_common_gcm;

// For the restore phase of GCM, we need key, IV and input data. If set to start manually, we
// just wait for the trigger.
assign start_gcm_restore = gcm_restore & cfg_valid & no_alert &
// Manual operation has priority.
(manual_operation_i ? start_i : iv_ready & ctr_ready_i & data_in_new & start_common_gcm);

// For the AAD and ciphertext/plaintext phases of GCM, we need key, IV and input data. But for
// the AAD phase, only the input data is really used and marked as used. The start condition for
// the AAD phase is handled separately by the FSM and we need to factor in the manual operation
// mode here.
assign start_gcm_aad = gcm_aad & cfg_valid & no_alert &
// Manual operation has priority.
(manual_operation_i ? start_i : iv_ready & ctr_ready_i & start_common);
// The ciphertext/plaintext phase requires operating AES cipher core and thus factors into the
// regular start signal.
assign start_gcm_txt = gcm_txt & iv_ready & ctr_ready_i & start_common;

// For the save phase of GCM, we need no inputs. But the hash subkey and S must not yet have been
// cleared (happens upon saving the GHASH state).
assign start_gcm_save = gcm_save & cfg_valid & no_alert &
// Manual operation has priority.
(manual_operation_i ? start_i : hash_subkey_ready_q & s_ready_q);

// For the tag phase of GCM, we also need the input data.
assign start_gcm_tag = gcm_tag & cfg_valid & no_alert &
// Manual operation has priority.
(manual_operation_i ? start_i : hash_subkey_ready_q & s_ready_q & data_in_new);

// The restore, AAD, save and tag phases use the GHASH block only.
assign start_ghash = start_gcm_restore | start_gcm_aad | start_gcm_save | start_gcm_tag;

// The GHASH block is idle whenever it's ready to receive inputs and we're not about to start
// a GCM related operation.
assign ghash_idle = ghash_in_ready_i & ~start_ghash;

// In GCM, the counter performs inc32() instead of inc128(), i.e., the counter wraps at 32 bits.
assign ctr_inc32_o = (mode_i == AES_GCM);

// Helper signals for FSM
assign crypt = cipher_crypt_o | cipher_crypt_i;

Expand Down Expand Up @@ -417,10 +447,12 @@ module aes_control_fsm
// is enabled, software writes to the initial key registers are ignored.
key_init_we_o = sideload_i ? {NumSharesKey * NumRegsKey{key_sideload}} : key_init_qe_i;
iv_we_o = iv_qe;
end

// Updates to the main and GCM control registers are only allowed if the core is not
// about to start and there isn't a storage error. A storage error is unrecoverable and
// requires a reset.
if (!start_core && !start_ghash) begin
// Updates to the main and GCM control registers are only allowed if the cipher core and
// the GHASH block are not about to start and there isn't a storage error. A storage
// error is unrecoverable and requires a reset.
ctrl_we_o = !ctrl_err_storage_i ? ctrl_qe_i : 1'b0;
ctrl_gcm_we_o = !ctrl_err_storage_i ? ctrl_gcm_qe_i : 1'b0;

Expand Down

0 comments on commit 2721e79

Please sign in to comment.