Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[aes] Masked GHASH implementation #8

Merged
merged 7 commits into from
Nov 19, 2024
37 changes: 13 additions & 24 deletions hw/ip/aes/rtl/aes_control_fsm.sv
Original file line number Diff line number Diff line change
Expand Up @@ -463,33 +463,19 @@ module aes_control_fsm
aes_ctrl_ns = CTRL_GHASH_READY;
end

end else if (start_gcm_restore) begin
// We don't have work for the AES cipher core but for the GHASH block only.
// Mask the input data and load it into the GHASH block.
state_in_sel_o = SI_DATA;
add_state_in_sel_o = ADD_SI_ZERO;

// Perform handshake and advance to the loading state where the input data is marked as
// used.
ghash_in_valid_o = 1'b1;
if (ghash_in_ready_i) begin
doing_gcm_restore_d = 1'b1;
start_we = 1'b1;
aes_ctrl_ns = CTRL_LOAD;
end

end else if (start_gcm_aad || start_gcm_tag) begin
end else if (start_gcm_restore || start_gcm_aad || start_gcm_tag) begin
// We don't have work for the AES cipher core but for the GHASH block only. Load the
// input data into the previous input data register such that it can be loaded into
// the GHASH block in unmasked form.
data_in_prev_sel_o = DIP_DATA_IN;
data_in_prev_we_o = 1'b1;

// Advance to the loading state where the input data is marked as used.
doing_gcm_aad_d = start_gcm_aad;
doing_gcm_tag_d = start_gcm_tag;
start_we = 1'b1;
aes_ctrl_ns = CTRL_LOAD;
doing_gcm_restore_d = start_gcm_restore;
doing_gcm_aad_d = start_gcm_aad;
doing_gcm_tag_d = start_gcm_tag;
start_we = 1'b1;
aes_ctrl_ns = CTRL_LOAD;

end else if (start_gcm_save) begin
// We don't have work for the AES cipher core but for the GHASH block only. Update the
Expand Down Expand Up @@ -610,10 +596,13 @@ module aes_control_fsm
end

end else if (doing_gcm_restore_q) begin
// We're actually already done: The input data has already been forwarded to the GHASH
// block. We ended up here because we had to go through the loading state.
doing_gcm_restore_d = 1'b0;
aes_ctrl_ns = CTRL_IDLE;
// Pass the previously saved GHASH state to the GHASH block. We're done after the input
// handshake.
ghash_in_valid_o = 1'b1;
if (ghash_in_ready_i) begin
doing_gcm_restore_d = 1'b0;
aes_ctrl_ns = CTRL_IDLE;
end

end else if (doing_gcm_aad_q) begin
// Pass the AAD to the GHASH block. We're done after the input handshake.
Expand Down
21 changes: 14 additions & 7 deletions hw/ip/aes/rtl/aes_core.sv
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ module aes_core
sp2v_e ghash_out_valid;
sp2v_e ghash_out_ready;
sp2v_e ghash_load_hash_subkey;
logic ghash_first_block;
logic ghash_alert;

// Pseudo-random data for clearing purposes
Expand Down Expand Up @@ -584,10 +585,14 @@ module aes_core
logic ghash_clear;
assign ghash_clear = cipher_key_clear | cipher_key_clear_busy;

// The number of cycles must be a power of two and ideally matches the minimum latency of the
// cipher core which is 56 clock cycles (masked) or 12 clock cycles (unmasked) for AES-128.
localparam int unsigned GhashGFMultCycles = (SecSBoxImpl == SBoxImplDom) ? 32 : 8;

// The actual GHASH module.
aes_ghash #(
.SecMasking ( SecMasking ),
.SecSBoxImpl ( SecSBoxImpl )
.SecMasking ( SecMasking ),
.GFMultCycles ( GhashGFMultCycles )
) u_aes_ghash (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
Expand All @@ -603,10 +608,10 @@ module aes_core
.num_valid_bytes_i ( num_valid_bytes_q ),
.load_hash_subkey_i ( ghash_load_hash_subkey ),
.clear_i ( ghash_clear ),
.first_block_o ( ghash_first_block ),
.alert_fatal_i ( alert_fatal_o ),
.alert_o ( ghash_alert ),

.cipher_state_init_i ( state_init ),
.data_in_prev_i ( data_in_prev_q ),
.data_out_i ( data_out_d ),
.cipher_state_done_i ( state_done ),
Expand All @@ -624,10 +629,11 @@ module aes_core

end else begin : gen_no_ghash
// GHASH isn't there and thus generates no back pressure / alerts / output to be muxed.
assign ghash_in_ready = SP2V_HIGH;
assign ghash_out_valid = SP2V_HIGH;
assign ghash_alert = 1'b0;
assign data_out_d = data_out;
assign ghash_in_ready = SP2V_HIGH;
assign ghash_out_valid = SP2V_HIGH;
assign ghash_first_block = 1'b0;
assign ghash_alert = 1'b0;
assign data_out_d = data_out;

// Tie-off unused signals.
sp2v_e unused_ghash_in_valid;
Expand Down Expand Up @@ -682,6 +688,7 @@ module aes_core
.rst_shadowed_ni ( rst_shadowed_ni ),
.qe_o ( ctrl_gcm_qe ),
.we_i ( ctrl_gcm_we ),
.first_block_i ( ghash_first_block ),
.gcm_phase_o ( gcm_phase_q ),
.num_valid_bytes_o ( num_valid_bytes_q ),
.err_update_o ( ctrl_gcm_reg_err_update ),
Expand Down
57 changes: 39 additions & 18 deletions hw/ip/aes/rtl/aes_ctrl_gcm_reg_shadowed.sv
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ module aes_ctrl_gcm_reg_shadowed
// Main control
output logic qe_o, // software wants to write
input logic we_i, // hardware grants software write
input logic first_block_i,
output gcm_phase_e gcm_phase_o,
output logic [4:0] num_valid_bytes_o,

Expand Down Expand Up @@ -67,24 +68,44 @@ module aes_ctrl_gcm_reg_shadowed

// Only a subset of next phase transitions are allowed.
unique case (gcm_phase_q)
GCM_INIT: gcm_phase_d = gcm_phase_d == GCM_RESTORE ||
gcm_phase_d == GCM_AAD ||
gcm_phase_d == GCM_TEXT ||
gcm_phase_d == GCM_TAG ? gcm_phase_d : gcm_phase_q;
GCM_RESTORE: gcm_phase_d = gcm_phase_d == GCM_INIT ||
gcm_phase_d == GCM_AAD ||
gcm_phase_d == GCM_TEXT ? gcm_phase_d : gcm_phase_q;
GCM_AAD: gcm_phase_d = gcm_phase_d == GCM_INIT ||
gcm_phase_d == GCM_TEXT ||
gcm_phase_d == GCM_SAVE ||
gcm_phase_d == GCM_TAG ? gcm_phase_d : gcm_phase_q;
GCM_TEXT: gcm_phase_d = gcm_phase_d == GCM_INIT ||
gcm_phase_d == GCM_SAVE ||
gcm_phase_d == GCM_TAG ? gcm_phase_d : gcm_phase_q;
GCM_SAVE: gcm_phase_d = gcm_phase_d == GCM_INIT ? gcm_phase_d : gcm_phase_q;
GCM_TAG: gcm_phase_d = gcm_phase_d == GCM_INIT ? gcm_phase_d : gcm_phase_q;
default: gcm_phase_d = gcm_phase_q; // If we end up in an unspported value (which
// should never happen), keep it.
GCM_INIT: begin
gcm_phase_d = gcm_phase_d == GCM_RESTORE ||
gcm_phase_d == GCM_AAD ||
gcm_phase_d == GCM_TEXT ||
gcm_phase_d == GCM_TAG ? gcm_phase_d : gcm_phase_q;
end

GCM_RESTORE: begin
gcm_phase_d = gcm_phase_d == GCM_INIT ||
gcm_phase_d == GCM_AAD ||
gcm_phase_d == GCM_TEXT ? gcm_phase_d : gcm_phase_q;
end

GCM_AAD: begin
gcm_phase_d = gcm_phase_d == GCM_INIT ||
gcm_phase_d == GCM_TEXT ||
gcm_phase_d == GCM_SAVE && !first_block_i ||
gcm_phase_d == GCM_TAG ? gcm_phase_d : gcm_phase_q;
end

GCM_TEXT: begin
gcm_phase_d = gcm_phase_d == GCM_INIT ||
gcm_phase_d == GCM_SAVE && !first_block_i ||
gcm_phase_d == GCM_TAG ? gcm_phase_d : gcm_phase_q;
end

GCM_SAVE: begin
gcm_phase_d = gcm_phase_d == GCM_INIT ? gcm_phase_d : gcm_phase_q;
end

GCM_TAG: begin
gcm_phase_d = gcm_phase_d == GCM_INIT ? gcm_phase_d : gcm_phase_q;
end

default: begin
gcm_phase_d = gcm_phase_q; // If we end up in an unspported value (which should never
// happen), keep it.
end
endcase
end
assign ctrl_gcm_wd.phase = gcm_phase_d;
Expand Down
Loading
Loading