[aes] Add 2-share implementation of the cipher core for security hardening
This commit adds a first version of the first-order masked, 2-share
implementation of the AES cipher core. The masking can be enabled
via a design time parameter. If enabled, both the cipher datapath and
and key schedule are masked.
The generation of the masks is not part of this commit but future work.
At the moment, constant masks are used. This is of course not secure.
Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
diff --git a/hw/ip/aes/pre_dv/aes_sbox_tb/rtl/aes_sbox_tb.sv b/hw/ip/aes/pre_dv/aes_sbox_tb/rtl/aes_sbox_tb.sv
index e029bb8..8eceb85 100644
--- a/hw/ip/aes/pre_dv/aes_sbox_tb/rtl/aes_sbox_tb.sv
+++ b/hw/ip/aes/pre_dv/aes_sbox_tb/rtl/aes_sbox_tb.sv
@@ -38,17 +38,13 @@
assign stimulus = count_q[7:0];
// Instantiate SBox Implementations
- aes_sbox #(
- .SBoxImpl ( "lut" )
- ) aes_sbox_lut (
+ aes_sbox_lut aes_sbox_lut (
.op_i ( op ),
.data_i ( stimulus ),
.data_o ( responses[0] )
);
- aes_sbox #(
- .SBoxImpl ( "canright" )
- ) aes_sbox_canright (
+ aes_sbox_canright aes_sbox_canright (
.op_i ( op ),
.data_i ( stimulus ),
.data_o ( responses[1] )
diff --git a/hw/ip/aes/rtl/aes.sv b/hw/ip/aes/rtl/aes.sv
index 708de30..80fbdfc 100644
--- a/hw/ip/aes/rtl/aes.sv
+++ b/hw/ip/aes/rtl/aes.sv
@@ -6,12 +6,15 @@
`include "prim_assert.sv"
-module aes #(
- parameter bit AES192Enable = 1, // Can be 0 (disable), or 1 (enable).
- parameter SBoxImpl = "lut" // Can be "lut" (LUT-based SBox), "canright",
- // "canright_masked_noreuse", or "canright_masked".
- // Note: Currently, constant masks are used, this is
- // of course not secure.
+module aes import aes_pkg::*; #(
+ parameter bit AES192Enable = 1, // Can be 0 (disable), or 1 (enable).
+ parameter bit Masking = 0, // Can be 0 (no masking), or 1 (first-order masking) of the
+ // cipher core. Masking requires the use of a masked S-Box,
+ // see SBoxImpl parameter. Note: currently, constant masks
+ // are used, this is of course not secure.
+ parameter sbox_impl_e SBoxImpl = SBoxImplLut, // See aes_pkg.sv
+
+ localparam int NumShares = Masking ? 2 : 1 // derived parameter
) (
input clk_i,
input rst_ni,
@@ -31,12 +34,11 @@
output tlul_pkg::tl_d2h_t tl_o,
// Alerts
- input prim_alert_pkg::alert_rx_t [aes_pkg::NumAlerts-1:0] alert_rx_i,
- output prim_alert_pkg::alert_tx_t [aes_pkg::NumAlerts-1:0] alert_tx_o
+ input prim_alert_pkg::alert_rx_t [NumAlerts-1:0] alert_rx_i,
+ output prim_alert_pkg::alert_tx_t [NumAlerts-1:0] alert_tx_o
);
import aes_reg_pkg::*;
- import aes_pkg::*;
aes_reg2hw_t reg2hw;
aes_hw2reg_t hw2reg;
@@ -61,8 +63,9 @@
aes_core #(
.AES192Enable ( AES192Enable ),
+ .Masking ( Masking ),
.SBoxImpl ( SBoxImpl )
- ) aes_core (
+ ) u_aes_core (
.clk_i,
.rst_ni,
@@ -78,7 +81,7 @@
.hw2reg
);
- aes_prng aes_prng (
+ aes_prng u_aes_prng (
.clk_i,
.rst_ni,
@@ -100,7 +103,7 @@
for (genvar i = 0; i < NumAlerts; i++) begin : gen_alert_tx
prim_alert_sender #(
.AsyncOn(AlertAsyncOn[i])
- ) i_prim_alert_sender (
+ ) u_alert_sender_i (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.alert_i ( alert[i] ),
diff --git a/hw/ip/aes/rtl/aes_cipher_core.sv b/hw/ip/aes/rtl/aes_cipher_core.sv
index ed35dc5..20b07d2 100644
--- a/hw/ip/aes/rtl/aes_cipher_core.sv
+++ b/hw/ip/aes/rtl/aes_cipher_core.sv
@@ -6,12 +6,99 @@
//
// This module contains the AES cipher core including, state register, full key and decryption key
// registers as well as key expand module and control unit.
+//
+//
+// Masking
+// -------
+//
+// If the parameter "Masking" is set to one, first-order masking is applied to the entire
+// cipher core including key expand module. For details, see Rivain et al., "Provably secure
+// higher-order masking of AES" available at https://eprint.iacr.org/2010/441.pdf
+//
+//
+// Details on the data formats
+// ---------------------------
+//
+// This implementation uses 4-dimensional SystemVerilog arrays to represent the AES state:
+//
+// logic [3:0][3:0][7:0] state_q [NumShares];
+//
+// The fourth dimension (unpacked) corresponds to the different shares. The first element holds the
+// (masked) data share whereas the other elements hold the masks (masked implementation only).
+// The three packed dimensions correspond to the 128-bit state matrix per share. This
+// implementation uses the same encoding as the Advanced Encryption Standard (AES) FIPS Publication
+// 197 available at https://www.nist.gov/publications/advanced-encryption-standard-aes (see Section
+// 3.4). An input sequence of 16 bytes (128-bit, left most byte is the first one)
+//
+// b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15
+//
+// is mapped to the state matrix as
+//
+// [ b0 b4 b8 b12 ]
+// [ b1 b5 b9 b13 ]
+// [ b2 b6 b10 b14 ]
+// [ b3 b7 b11 b15 ] .
+//
+// This is mapped to three packed dimensions of SystemVerilog array as follows:
+// - The first dimension corresponds to the rows. Thus, state_q[0] gives
+// - The first row of the state matrix [ b0 b4 b8 b12 ], or
+// - A 32-bit packed SystemVerilog array 32h'{ b12, b8, b4, b0 }.
+//
+// - The second dimension corresponds to the columns. To access complete columns, the state matrix
+// must first be transposed first. Thus state_transposed = aes_pkg::aes_transpose(state_q)
+// and then state_transposed[1] gives
+// - The second column of the state matrix [ b4 b5 b6 b7 ], or
+// - A 32-bit packed SystemVerilog array 32h'{ b7, b6, b5, b4 }.
+//
+// - The third dimension corresponds to the bytes.
+//
+// Note that the CSRs are little-endian. The input sequence above is provided to 32-bit DATA_IN0 -
+// DATA_IN3 registers as
+// MSB LSB
+// - DATA_IN0 32h'{ b3 , b2 , b1 , b0 }
+// - DATA_IN1 32h'{ b7 , b6 , b4 , b4 }
+// - DATA_IN2 32h'{ b11, b10, b9 , b8 }
+// - DATA_IN3 32h'{ b15, b14, b13, b12 } .
+//
+// The input state can thus be obtained by transposing the content of the DATA_IN0 - DATA_IN3
+// registers.
+//
+// Similarly, the implementation uses a 3-dimensional array to represent the AES keys:
+//
+// logic [7:0][31:0] key_full_q [NumShares]
+//
+// The third dimension (unpacked) corresponds to the different shares. The first element holds the
+// (masked) key share whereas the other elements hold the masks (masked implementation only).
+// The two packed dimensions correspond to the 256-bit key per share. This implementation uses
+// the same encoding as the Advanced Encryption Standard (AES) FIPS Publication
+// 197 available at https://www.nist.gov/publications/advanced-encryption-standard-aes .
+//
+// The first packed dimension corresponds to the 8 key words. The second packed dimension
+// corresponds to the 32 bits per key word. A key sequence of 32 bytes (256-bit, left most byte is
+// the first one)
+//
+// b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 ... ... b28 b29 b30 b31
+//
+// is mapped to the key words and registers (little-endian) as
+// MSB LSB
+// - KEY0 32h'{ b3 , b2 , b1 , b0 }
+// - KEY1 32h'{ b7 , b6 , b4 , b4 }
+// - KEY2 32h'{ b11, b10, b9 , b8 }
+// - KEY3 32h'{ b15, b14, b13, b12 }
+// - KEY4 32h'{ . . . . }
+// - KEY5 32h'{ . . . . }
+// - KEY6 32h'{ . . . . }
+// - KEY7 32h'{ b31, b30, b29, b28 } .
`include "prim_assert.sv"
-module aes_cipher_core #(
- parameter bit AES192Enable = 1,
- parameter SBoxImpl = "lut"
+module aes_cipher_core import aes_pkg::*;
+#(
+ parameter bit AES192Enable = 1,
+ parameter bit Masking = 0,
+ parameter sbox_impl_e SBoxImpl = SBoxImplLut,
+
+ localparam int NumShares = Masking ? 2 : 1 // derived parameter
) (
input logic clk_i,
input logic rst_ni,
@@ -25,8 +112,8 @@
input logic out_ready_i,
// Control and sync signals
- input aes_pkg::ciph_op_e op_i,
- input aes_pkg::key_len_e key_len_i,
+ input ciph_op_e op_i,
+ input key_len_e key_len_i,
input logic crypt_i,
output logic crypt_o,
input logic dec_key_gen_i,
@@ -40,44 +127,45 @@
input logic [63:0] prng_data_i,
// I/O data & initial key
- input logic [3:0][3:0][7:0] state_init_i,
- input logic [7:0][31:0] key_init_i,
- output logic [3:0][3:0][7:0] state_o
+ input logic [3:0][3:0][7:0] state_init_i [NumShares],
+ input logic [7:0][31:0] key_init_i [NumShares],
+ output logic [3:0][3:0][7:0] state_o [NumShares]
);
- import aes_pkg::*;
-
// Signals
- logic [3:0][3:0][7:0] state_d;
- logic [3:0][3:0][7:0] state_q;
+ logic [3:0][3:0][7:0] state_d [NumShares];
+ logic [3:0][3:0][7:0] state_q [NumShares];
logic state_we;
state_sel_e state_sel;
logic [3:0][3:0][7:0] sub_bytes_out;
- logic [3:0][3:0][7:0] shift_rows_out;
- logic [3:0][3:0][7:0] mix_columns_out;
- logic [3:0][3:0][7:0] add_round_key_in;
- logic [3:0][3:0][7:0] add_round_key_out;
+ logic [3:0][3:0][7:0] sb_in_mask;
+ logic [3:0][3:0][7:0] sb_out_mask;
+ logic [3:0][3:0][7:0] shift_rows_in [NumShares];
+ logic [3:0][3:0][7:0] shift_rows_out [NumShares];
+ logic [3:0][3:0][7:0] mix_columns_out [NumShares];
+ logic [3:0][3:0][7:0] add_round_key_in [NumShares];
+ logic [3:0][3:0][7:0] add_round_key_out [NumShares];
add_rk_sel_e add_round_key_in_sel;
- logic [7:0][31:0] key_full_d;
- logic [7:0][31:0] key_full_q;
+ logic [7:0][31:0] key_full_d [NumShares];
+ logic [7:0][31:0] key_full_q [NumShares];
logic key_full_we;
key_full_sel_e key_full_sel;
- logic [7:0][31:0] key_dec_d;
- logic [7:0][31:0] key_dec_q;
+ logic [7:0][31:0] key_dec_d [NumShares];
+ logic [7:0][31:0] key_dec_q [NumShares];
logic key_dec_we;
key_dec_sel_e key_dec_sel;
- logic [7:0][31:0] key_expand_out;
+ logic [7:0][31:0] key_expand_out [NumShares];
ciph_op_e key_expand_op;
logic key_expand_step;
logic key_expand_clear;
logic [3:0] key_expand_round;
key_words_sel_e key_words_sel;
- logic [3:0][31:0] key_words;
- logic [3:0][3:0][7:0] key_bytes;
- logic [3:0][3:0][7:0] key_mix_columns_out;
- logic [3:0][3:0][7:0] round_key;
+ logic [3:0][31:0] key_words [NumShares];
+ logic [3:0][3:0][7:0] key_bytes [NumShares];
+ logic [3:0][3:0][7:0] key_mix_columns_out [NumShares];
+ logic [3:0][3:0][7:0] round_key [NumShares];
round_key_sel_e round_key_sel;
//////////
@@ -89,8 +177,8 @@
unique case (state_sel)
STATE_INIT: state_d = state_init_i;
STATE_ROUND: state_d = add_round_key_out;
- STATE_CLEAR: state_d = {prng_data_i, prng_data_i};
- default: state_d = {prng_data_i, prng_data_i};
+ STATE_CLEAR: state_d = '{default: {prng_data_i, prng_data_i}};
+ default: state_d = '{default: {prng_data_i, prng_data_i}};
endcase
end
@@ -100,26 +188,52 @@
end
end
+ // Masking
+ if (!Masking) begin : gen_no_sb_in_mask
+ // The mask is ignored anyway, it can be 0.
+ assign sb_in_mask = '0;
+ end else begin : gen_sb_in_mask
+ // The input mask is the mask share of the state.
+ assign sb_in_mask = state_q[1];
+ end
+
+ // TODO: Use non-constant output masks for SubBytes + remove corresponding comment in aes.sv.
+ // See https://github.com/lowRISC/opentitan/issues/1005
+ assign sb_out_mask = {8'h55, 8'h55, 8'h55, 8'h55, 8'h55, 8'h55, 8'h55, 8'h55,
+ 8'h55, 8'h55, 8'h55, 8'h55, 8'h55, 8'h55, 8'h55, 8'h55};
+
// Cipher data path
aes_sub_bytes #(
.SBoxImpl ( SBoxImpl )
- ) aes_sub_bytes (
- .op_i ( op_i ),
- .data_i ( state_q ),
- .data_o ( sub_bytes_out )
+ ) u_aes_sub_bytes (
+ .op_i ( op_i ),
+ .data_i ( state_q[0] ),
+ .in_mask_i ( sb_in_mask ),
+ .out_mask_i ( sb_out_mask ),
+ .data_o ( sub_bytes_out )
);
- aes_shift_rows aes_shift_rows (
- .op_i ( op_i ),
- .data_i ( sub_bytes_out ),
- .data_o ( shift_rows_out )
- );
+ for (genvar s = 0; s < NumShares; s++) begin : gen_shares_shift_mix
+ if (s == 0) begin : gen_shift_in_data
+ // The (masked) data share
+ assign shift_rows_in[s] = sub_bytes_out;
+ end else begin : gen_shift_in_mask
+ // The mask share
+ assign shift_rows_in[s] = sb_out_mask;
+ end
- aes_mix_columns aes_mix_columns (
- .op_i ( op_i ),
- .data_i ( shift_rows_out ),
- .data_o ( mix_columns_out )
- );
+ aes_shift_rows u_aes_shift_rows (
+ .op_i ( op_i ),
+ .data_i ( shift_rows_in[s] ),
+ .data_o ( shift_rows_out[s] )
+ );
+
+ aes_mix_columns u_aes_mix_columns (
+ .op_i ( op_i ),
+ .data_i ( shift_rows_out[s] ),
+ .data_o ( mix_columns_out[s] )
+ );
+ end
always_comb begin : add_round_key_in_mux
unique case (add_round_key_in_sel)
@@ -130,7 +244,9 @@
endcase
end
- assign add_round_key_out = add_round_key_in ^ round_key;
+ for (genvar s = 0; s < NumShares; s++) begin : gen_shares_add_round_key
+ assign add_round_key_out[s] = add_round_key_in[s] ^ round_key[s];
+ end
/////////
// Key //
@@ -142,8 +258,8 @@
KEY_FULL_ENC_INIT: key_full_d = key_init_i;
KEY_FULL_DEC_INIT: key_full_d = key_dec_q;
KEY_FULL_ROUND: key_full_d = key_expand_out;
- KEY_FULL_CLEAR: key_full_d = {prng_data_i, prng_data_i, prng_data_i, prng_data_i};
- default: key_full_d = {prng_data_i, prng_data_i, prng_data_i, prng_data_i};
+ KEY_FULL_CLEAR: key_full_d ='{default: {prng_data_i, prng_data_i, prng_data_i, prng_data_i}};
+ default: key_full_d ='{default: {prng_data_i, prng_data_i, prng_data_i, prng_data_i}};
endcase
end
@@ -157,8 +273,8 @@
always_comb begin : key_dec_mux
unique case (key_dec_sel)
KEY_DEC_EXPAND: key_dec_d = key_expand_out;
- KEY_DEC_CLEAR: key_dec_d = {prng_data_i, prng_data_i, prng_data_i, prng_data_i};
- default: key_dec_d = {prng_data_i, prng_data_i, prng_data_i, prng_data_i};
+ KEY_DEC_CLEAR: key_dec_d = '{default: {prng_data_i, prng_data_i, prng_data_i, prng_data_i}};
+ default: key_dec_d = '{default: {prng_data_i, prng_data_i, prng_data_i, prng_data_i}};
endcase
end
@@ -171,8 +287,9 @@
// Key expand data path
aes_key_expand #(
.AES192Enable ( AES192Enable ),
+ .Masking ( Masking ),
.SBoxImpl ( SBoxImpl )
- ) aes_key_expand (
+ ) u_aes_key_expand (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.op_i ( key_expand_op ),
@@ -184,25 +301,27 @@
.key_o ( key_expand_out )
);
- always_comb begin : key_words_mux
- unique case (key_words_sel)
- KEY_WORDS_0123: key_words = key_full_q[3:0];
- KEY_WORDS_2345: key_words = AES192Enable ? key_full_q[5:2] : '0;
- KEY_WORDS_4567: key_words = key_full_q[7:4];
- KEY_WORDS_ZERO: key_words = '0;
- default: key_words = '0;
- endcase
+ for (genvar s = 0; s < NumShares; s++) begin : gen_shares_round_key
+ always_comb begin : key_words_mux
+ unique case (key_words_sel)
+ KEY_WORDS_0123: key_words[s] = key_full_q[s][3:0];
+ KEY_WORDS_2345: key_words[s] = AES192Enable ? key_full_q[s][5:2] : '0;
+ KEY_WORDS_4567: key_words[s] = key_full_q[s][7:4];
+ KEY_WORDS_ZERO: key_words[s] = '0;
+ default: key_words[s] = '0;
+ endcase
+ end
+
+ // Convert words to bytes (every key word contains one column).
+ assign key_bytes[s] = aes_transpose(key_words[s]);
+
+ aes_mix_columns u_aes_key_mix_columns (
+ .op_i ( CIPH_INV ),
+ .data_i ( key_bytes[s] ),
+ .data_o ( key_mix_columns_out[s] )
+ );
end
- // Convert words to bytes (every key word contains one column)
- assign key_bytes = aes_transpose(key_words);
-
- aes_mix_columns aes_key_mix_columns (
- .op_i ( CIPH_INV ),
- .data_i ( key_bytes ),
- .data_o ( key_mix_columns_out )
- );
-
always_comb begin : round_key_mux
unique case (round_key_sel)
ROUND_KEY_DIRECT: round_key = key_bytes;
@@ -216,7 +335,7 @@
/////////////
// Control
- aes_cipher_control aes_cipher_control (
+ aes_cipher_control u_aes_cipher_control (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@@ -261,6 +380,15 @@
// Assertions //
////////////////
+ // Cipher core masking requires a masked SBox and vice versa.
+ `ASSERT_INIT(AesMaskedCoreAndSBox,
+ (Masking &&
+ (SBoxImpl == SBoxImplCanrightMasked ||
+ SBoxImpl == SBoxImplCanrightMaskedNoreuse)) ||
+ (!Masking &&
+ (SBoxImpl == SBoxImplLut ||
+ SBoxImpl == SBoxImplCanright)))
+
// Selectors must be known/valid
`ASSERT(AesStateSelValid, state_sel inside {
STATE_INIT,
diff --git a/hw/ip/aes/rtl/aes_core.sv b/hw/ip/aes/rtl/aes_core.sv
index 1edcab1..ee4ddcf 100644
--- a/hw/ip/aes/rtl/aes_core.sv
+++ b/hw/ip/aes/rtl/aes_core.sv
@@ -6,9 +6,13 @@
`include "prim_assert.sv"
-module aes_core #(
- parameter bit AES192Enable = 1,
- parameter SBoxImpl = "lut"
+module aes_core import aes_pkg::*;
+#(
+ parameter bit AES192Enable = 1,
+ parameter bit Masking = 0,
+ parameter sbox_impl_e SBoxImpl = SBoxImplLut,
+
+ localparam int NumShares = Masking ? 2 : 1 // derived parameter
) (
input logic clk_i,
input logic rst_ni,
@@ -30,7 +34,6 @@
);
import aes_reg_pkg::*;
- import aes_pkg::*;
// Signals
logic ctrl_re;
@@ -51,13 +54,15 @@
logic [3:0][3:0][7:0] add_state_in;
add_si_sel_e add_state_in_sel;
- logic [3:0][3:0][7:0] state_init;
- logic [3:0][3:0][7:0] state_done;
+ logic [3:0][3:0][7:0] state_init [NumShares];
+ logic [3:0][3:0][7:0] state_done [NumShares];
+ logic [3:0][3:0][7:0] state_out;
logic [7:0][31:0] key_init;
logic [7:0] key_init_qe;
logic [7:0][31:0] key_init_d;
logic [7:0][31:0] key_init_q;
+ logic [7:0][31:0] key_init_cipher [NumShares];
logic [7:0] key_init_we;
key_init_sel_e key_init_sel;
@@ -165,7 +170,7 @@
unique case (iv_sel)
IV_INPUT: iv_d = iv;
IV_DATA_OUT: iv_d = data_out_d;
- IV_DATA_OUT_RAW: iv_d = aes_transpose(state_done);
+ IV_DATA_OUT_RAW: iv_d = aes_transpose(state_out);
IV_DATA_IN_PREV: iv_d = data_in_prev_q;
IV_CTR: iv_d = ctr;
IV_CLEAR: iv_d = {prng_data_i, prng_data_i};
@@ -200,7 +205,7 @@
// Counter //
/////////////
- aes_ctr aes_ctr (
+ aes_ctr u_aes_ctr (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@@ -225,6 +230,7 @@
(aes_mode_q == AES_OFB) ? CIPH_FWD :
(aes_mode_q == AES_CTR) ? CIPH_FWD : CIPH_FWD;
+ // Convert input data/IV to state format (every word corresponds to one state column).
// Mux for state input
always_comb begin : state_in_mux
unique case (state_in_sel)
@@ -243,14 +249,40 @@
endcase
end
- // Convert input data to state format (every input data word contains one state column)
- assign state_init = state_in ^ add_state_in;
+ if (!Masking) begin : gen_state_init_unmasked
+ assign state_init[0] = state_in ^ add_state_in;
+
+ end else begin : gen_state_init_masked
+ // TODO: Use non-constant input masks + remove corresponding comment in aes.sv.
+ // See https://github.com/lowRISC/opentitan/issues/1005
+ logic [3:0][3:0][7:0] state_mask;
+ assign state_mask = {8'hAA, 8'hAA, 8'hAA, 8'hAA, 8'hAA, 8'hAA, 8'hAA, 8'hAA,
+ 8'hAA, 8'hAA, 8'hAA, 8'hAA, 8'hAA, 8'hAA, 8'hAA, 8'hAA};
+
+ assign state_init[0] = (state_in ^ add_state_in) ^ state_mask; // Masked data share
+ assign state_init[1] = state_mask; // Mask share
+ end
+
+ if (!Masking) begin : gen_key_init_unmasked
+ assign key_init_cipher[0] = key_init_q;
+
+ end else begin : gen_key_init_masked
+ // TODO: Use non-constant input masks + remove corresponding comment in aes.sv.
+ // See https://github.com/lowRISC/opentitan/issues/1005
+ logic [7:0][31:0] key_mask;
+ assign key_mask = {32'h0000_1111, 32'h2222_3333, 32'h4444_5555, 32'h6666_7777,
+ 32'h8888_9999, 32'hAAAA_BBBB, 32'hCCCC_DDDD, 32'hEEEE_FFFF};
+
+ assign key_init_cipher[0] = key_init_q ^ key_mask; // Masked key share
+ assign key_init_cipher[1] = key_mask; // Mask share
+ end
// Cipher core
aes_cipher_core #(
.AES192Enable ( AES192Enable ),
+ .Masking ( Masking ),
.SBoxImpl ( SBoxImpl )
- ) aes_cipher_core (
+ ) u_aes_cipher_core (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
@@ -272,10 +304,18 @@
.prng_data_i ( prng_data_i ),
.state_init_i ( state_init ),
- .key_init_i ( key_init_q ),
+ .key_init_i ( key_init_cipher ),
.state_o ( state_done )
);
+ if (!Masking) begin : gen_state_out_unmasked
+ assign state_out = state_done[0];
+ end else begin : gen_state_out_masked
+ // Unmask the cipher core output. This causes SCA leakage and should thus be avoided. This will
+ // be reworked in the future when masking the counter and feedback path through the IV regs.
+ assign state_out = state_done[0] ^ state_done[1];
+ end
+
// Mux for addition to state output
always_comb begin : add_state_out_mux
unique case (add_state_out_sel)
@@ -286,9 +326,8 @@
endcase
end
- // Convert output state to output data format (every state column corresponds to one output word)
- assign data_out_d = aes_transpose(state_done ^ add_state_out);
-
+ // Convert output state to output data format (every column corresponds to one output word).
+ assign data_out_d = aes_transpose(state_out ^ add_state_out);
//////////////////////
// Control Register //
@@ -332,7 +371,7 @@
.DW ( $bits(ctrl_reg_t) ),
.SWACCESS ( "WO" ),
.RESVAL ( CTRL_RESET )
- ) ctrl_shadowed_reg (
+ ) u_ctrl_reg_shadowed (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.re ( ctrl_re ),
@@ -360,7 +399,7 @@
/////////////
// Control
- aes_control aes_control (
+ aes_control u_aes_control (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
diff --git a/hw/ip/aes/rtl/aes_key_expand.sv b/hw/ip/aes/rtl/aes_key_expand.sv
index c030089..59dd00f 100644
--- a/hw/ip/aes/rtl/aes_key_expand.sv
+++ b/hw/ip/aes/rtl/aes_key_expand.sv
@@ -6,23 +6,25 @@
`include "prim_assert.sv"
-module aes_key_expand #(
- parameter bit AES192Enable = 1,
- parameter SBoxImpl = "lut"
+module aes_key_expand import aes_pkg::*;
+#(
+ parameter bit AES192Enable = 1,
+ parameter bit Masking = 0,
+ parameter sbox_impl_e SBoxImpl = SBoxImplLut,
+
+ localparam int NumShares = Masking ? 2 : 1 // derived parameter
) (
input logic clk_i,
input logic rst_ni,
- input aes_pkg::ciph_op_e op_i,
+ input ciph_op_e op_i,
input logic step_i,
input logic clear_i,
input logic [3:0] round_i,
- input aes_pkg::key_len_e key_len_i,
- input logic [7:0][31:0] key_i,
- output logic [7:0][31:0] key_o
+ input key_len_e key_len_i,
+ input logic [7:0][31:0] key_i [NumShares],
+ output logic [7:0][31:0] key_o [NumShares]
);
- import aes_pkg::*;
-
logic [7:0] rcon_d, rcon_q;
logic rcon_we;
logic use_rcon;
@@ -30,15 +32,18 @@
logic [3:0] rnd;
logic [3:0] rnd_type;
- logic [31:0] spec_in_128, spec_in_192;
- logic [31:0] rot_word_in, rot_word_out;
+ logic [31:0] spec_in_128 [NumShares];
+ logic [31:0] spec_in_192 [NumShares];
+ logic [31:0] rot_word_in [NumShares];
+ logic [31:0] rot_word_out [NumShares];
logic use_rot_word;
logic [31:0] sub_word_in, sub_word_out;
+ logic [31:0] sw_in_mask, sw_out_mask;
logic [7:0] rcon_add_in, rcon_add_out;
logic [31:0] rcon_added;
- logic [31:0] irregular;
- logic [7:0][31:0] regular;
+ logic [31:0] irregular [NumShares];
+ logic [7:0][31:0] regular [NumShares];
assign rnd = round_i;
@@ -104,76 +109,93 @@
end
end
- // Special input, equivalent to key_o[3] in the used cases
- assign spec_in_128 = key_i[3] ^ key_i[2];
- assign spec_in_192 = AES192Enable ? key_i[5] ^ key_i[1] ^ key_i[0] : '0;
+ for (genvar s = 0; s < NumShares; s++) begin : gen_shares_rot_word_out
+ // Special input, equivalent to key_o[3] in the used cases
+ assign spec_in_128[s] = key_i[s][3] ^ key_i[s][2];
+ assign spec_in_192[s] = AES192Enable ? key_i[s][5] ^ key_i[s][1] ^ key_i[s][0] : '0;
- // Select input
- always_comb begin : rot_word_in_mux
- unique case (key_len_i)
+ // Select input
+ always_comb begin : rot_word_in_mux
+ unique case (key_len_i)
- /////////////
- // AES-128 //
- /////////////
- AES_128: begin
- unique case (op_i)
- CIPH_FWD: rot_word_in = key_i[3];
- CIPH_INV: rot_word_in = spec_in_128;
- default: rot_word_in = key_i[3];
- endcase
- end
-
- /////////////
- // AES-192 //
- /////////////
- AES_192: begin
- if (AES192Enable) begin
+ /////////////
+ // AES-128 //
+ /////////////
+ AES_128: begin
unique case (op_i)
- CIPH_FWD: begin
- rot_word_in = rnd_type[0] ? key_i[5] :
- rnd_type[2] ? key_i[5] :
- rnd_type[3] ? spec_in_192 : key_i[3];
- end
- CIPH_INV: begin
- rot_word_in = rnd_type[1] ? key_i[3] :
- rnd_type[2] ? key_i[1] : key_i[3];
- end
- default: rot_word_in = key_i[3];
+ CIPH_FWD: rot_word_in[s] = key_i[s][3];
+ CIPH_INV: rot_word_in[s] = spec_in_128[s];
+ default: rot_word_in[s] = key_i[s][3];
endcase
- end else begin
- rot_word_in = key_i[3];
end
- end
- /////////////
- // AES-256 //
- /////////////
- AES_256: begin
- unique case (op_i)
- CIPH_FWD: rot_word_in = key_i[7];
- CIPH_INV: rot_word_in = key_i[3];
- default: rot_word_in = key_i[7];
- endcase
- end
+ /////////////
+ // AES-192 //
+ /////////////
+ AES_192: begin
+ if (AES192Enable) begin
+ unique case (op_i)
+ CIPH_FWD: begin
+ rot_word_in[s] = rnd_type[0] ? key_i[s][5] :
+ rnd_type[2] ? key_i[s][5] :
+ rnd_type[3] ? spec_in_192[s] : key_i[s][3];
+ end
+ CIPH_INV: begin
+ rot_word_in[s] = rnd_type[1] ? key_i[s][3] :
+ rnd_type[2] ? key_i[s][1] : key_i[s][3];
+ end
+ default: rot_word_in[s] = key_i[s][3];
+ endcase
+ end else begin
+ rot_word_in[s] = key_i[s][3];
+ end
+ end
- default: rot_word_in = key_i[3];
- endcase
+ /////////////
+ // AES-256 //
+ /////////////
+ AES_256: begin
+ unique case (op_i)
+ CIPH_FWD: rot_word_in[s] = key_i[s][7];
+ CIPH_INV: rot_word_in[s] = key_i[s][3];
+ default: rot_word_in[s] = key_i[s][7];
+ endcase
+ end
+
+ default: rot_word_in[s] = key_i[s][3];
+ endcase
+ end
+
+ // RotWord: cyclic byte shift
+ assign rot_word_out[s] = aes_circ_byte_shift(rot_word_in[s], 2'h3);
end
- // RotWord: cyclic byte shift
- assign rot_word_out = aes_circ_byte_shift(rot_word_in, 2'h3);
-
// Mux input for SubWord
- assign sub_word_in = use_rot_word ? rot_word_out : rot_word_in;
+ assign sub_word_in = use_rot_word ? rot_word_out[0] : rot_word_in[0];
+
+ // Masking
+ if (!Masking) begin : gen_no_sw_in_mask
+ // The mask share is ignored anyway, it can be 0.
+ assign sw_in_mask = '0;
+ end else begin : gen_sw_in_mask
+ // The input mask is the mask share of rot_word_in/out.
+ assign sw_in_mask = use_rot_word ? rot_word_out[1] : rot_word_in[1];
+ end
+
+ // TODO: Use non-constant output masks for SubWord + remove corresponding comment in aes.sv.
+ // See https://github.com/lowRISC/opentitan/issues/1005
+ assign sw_out_mask = 32'h5555_5555;
// SubWord - individually substitute bytes
for (genvar i = 0; i < 4; i++) begin : gen_sbox
aes_sbox #(
.SBoxImpl ( SBoxImpl )
- ) aes_sbox_i (
- .op_i ( CIPH_FWD ),
- .data_i ( sub_word_in[8*i +: 8] ),
- .data_o ( sub_word_out[8*i +: 8] )
+ ) u_aes_sbox_i (
+ .op_i ( CIPH_FWD ),
+ .data_i ( sub_word_in[8*i +: 8] ),
+ .in_mask_i ( sw_in_mask[8*i +: 8] ),
+ .out_mask_i ( sw_out_mask[8*i +: 8] ),
+ .data_o ( sub_word_out[8*i +: 8] )
);
end
@@ -183,7 +205,15 @@
assign rcon_added = {sub_word_out[31:8], rcon_add_out};
// Mux output coming from Rcon & SubWord
- assign irregular = use_rcon ? rcon_added : sub_word_out;
+ for (genvar s = 0; s < NumShares; s++) begin : gen_shares_irregular
+ if (s == 0) begin : gen_irregular_rcon
+ // The (masked) key share
+ assign irregular[s] = use_rcon ? rcon_added : sub_word_out;
+ end else begin : gen_irregular_no_rcon
+ // The mask share
+ assign irregular[s] = sw_out_mask;
+ end
+ end
///////////////////////////
// The more regular part //
@@ -191,144 +221,159 @@
// To reduce muxing resources, we re-use existing
// connections for unused words and default cases.
- always_comb begin : drive_regular
- unique case (key_len_i)
+ for (genvar s = 0; s < NumShares; s++) begin : gen_shares_regular
+ always_comb begin : drive_regular
+ unique case (key_len_i)
- /////////////
- // AES-128 //
- /////////////
- AES_128: begin
- // key_o[7:4] not used
- regular[7:4] = key_i[3:0];
+ /////////////
+ // AES-128 //
+ /////////////
+ AES_128: begin
+ // key_o[7:4] not used
+ regular[s][7:4] = key_i[s][3:0];
- regular[0] = irregular ^ key_i[0];
- unique case (op_i)
- CIPH_FWD: begin
- for (int i=1; i<4; i++) begin
- regular[i] = regular[i-1] ^ key_i[i];
- end
- end
-
- CIPH_INV: begin
- for (int i=1; i<4; i++) begin
- regular[i] = key_i[i-1] ^ key_i[i];
- end
- end
-
- default: regular = {key_i[3:0], key_i[7:4]};
- endcase
- end
-
- /////////////
- // AES-192 //
- /////////////
- AES_192: begin
- // key_o[7:6] not used
- regular[7:6] = key_i[3:2];
-
- if (AES192Enable) begin
+ regular[s][0] = irregular[s] ^ key_i[s][0];
unique case (op_i)
CIPH_FWD: begin
- if (rnd_type[0]) begin
- // Shift down four upper most words
- regular[3:0] = key_i[5:2];
- // Generate Words 6 and 7
- regular[4] = irregular ^ key_i[0];
- regular[5] = regular[4] ^ key_i[1];
- end else begin
- // Shift down two upper most words
- regular[1:0] = key_i[5:4];
- // Generate new upper four words
- for (int i=0; i<4; i++) begin
- if ((i == 0 && rnd_type[2]) ||
- (i == 2 && rnd_type[3])) begin
- regular[i+2] = irregular ^ key_i[i];
- end else begin
- regular[i+2] = regular[i+1] ^ key_i[i];
- end
- end
- end // rnd_type[0]
+ for (int i=1; i<4; i++) begin
+ regular[s][i] = regular[s][i-1] ^ key_i[s][i];
+ end
end
CIPH_INV: begin
- if (rnd_type[0]) begin
- // Shift up four lowest words
- regular[5:2] = key_i[3:0];
- // Generate Word 44 and 45
- for (int i=0; i<2; i++) begin
- regular[i] = key_i[3+i] ^ key_i[3+i+1];
- end
- end else begin
- // Shift up two lowest words
- regular[5:4] = key_i[1:0];
- // Generate new lower four words
- for (int i=0; i<4; i++) begin
- if ((i == 2 && rnd_type[1]) ||
- (i == 0 && rnd_type[2])) begin
- regular[i] = irregular ^ key_i[i+2];
- end else begin
- regular[i] = key_i[i+1] ^ key_i[i+2];
- end
- end
- end // rnd_type[0]
+ for (int i=1; i<4; i++) begin
+ regular[s][i] = key_i[s][i-1] ^ key_i[s][i];
+ end
end
- default: regular = {key_i[3:0], key_i[7:4]};
+ default: regular[s] = {key_i[s][3:0], key_i[s][7:4]};
endcase
+ end
- end else begin
- regular = {key_i[3:0], key_i[7:4]};
- end // AES192Enable
- end
+ /////////////
+ // AES-192 //
+ /////////////
+ AES_192: begin
+ // key_o[7:6] not used
+ regular[s][7:6] = key_i[s][3:2];
- /////////////
- // AES-256 //
- /////////////
- AES_256: begin
- unique case (op_i)
- CIPH_FWD: begin
- if (rnd == 0) begin
- // Round 0: Nothing to be done
- // The Full Key registers are not updated
- regular = {key_i[3:0], key_i[7:4]};
- end else begin
- // Shift down old upper half
- regular[3:0] = key_i[7:4];
- // Generate new upper half
- regular[4] = irregular ^ key_i[0];
- for (int i=1; i<4; i++) begin
- regular[i+4] = regular[i+4-1] ^ key_i[i];
+ if (AES192Enable) begin
+ unique case (op_i)
+ CIPH_FWD: begin
+ if (rnd_type[0]) begin
+ // Shift down four upper most words
+ regular[s][3:0] = key_i[s][5:2];
+ // Generate Words 6 and 7
+ regular[s][4] = irregular[s] ^ key_i[s][0];
+ regular[s][5] = regular[s][4] ^ key_i[s][1];
+ end else begin
+ // Shift down two upper most words
+ regular[s][1:0] = key_i[s][5:4];
+ // Generate new upper four words
+ for (int i=0; i<4; i++) begin
+ if ((i == 0 && rnd_type[2]) ||
+ (i == 2 && rnd_type[3])) begin
+ regular[s][i+2] = irregular[s] ^ key_i[s][i];
+ end else begin
+ regular[s][i+2] = regular[s][i+1] ^ key_i[s][i];
+ end
+ end
+ end // rnd_type[0]
end
- end // rnd == 0
- end
- CIPH_INV: begin
- if (rnd == 0) begin
- // Round 0: Nothing to be done
- // The Full Key registers are not updated
- regular = {key_i[3:0], key_i[7:4]};
- end else begin
- // Shift up old lower half
- regular[7:4] = key_i[3:0];
- // Generate new lower half
- regular[0] = irregular ^ key_i[4];
- for (int i=0; i<3; i++) begin
- regular[i+1] = key_i[4+i] ^ key_i[4+i+1];
+ CIPH_INV: begin
+ if (rnd_type[0]) begin
+ // Shift up four lowest words
+ regular[s][5:2] = key_i[s][3:0];
+ // Generate Word 44 and 45
+ for (int i=0; i<2; i++) begin
+ regular[s][i] = key_i[s][3+i] ^ key_i[s][3+i+1];
+ end
+ end else begin
+ // Shift up two lowest words
+ regular[s][5:4] = key_i[s][1:0];
+ // Generate new lower four words
+ for (int i=0; i<4; i++) begin
+ if ((i == 2 && rnd_type[1]) ||
+ (i == 0 && rnd_type[2])) begin
+ regular[s][i] = irregular[s] ^ key_i[s][i+2];
+ end else begin
+ regular[s][i] = key_i[s][i+1] ^ key_i[s][i+2];
+ end
+ end
+ end // rnd_type[0]
end
- end // rnd == 0
- end
- default: regular = {key_i[3:0], key_i[7:4]};
- endcase
- end
+ default: regular[s] = {key_i[s][3:0], key_i[s][7:4]};
+ endcase
- default: regular = {key_i[3:0], key_i[7:4]};
- endcase // key_len_i
- end
+ end else begin
+ regular[s] = {key_i[s][3:0], key_i[s][7:4]};
+ end // AES192Enable
+ end
+
+ /////////////
+ // AES-256 //
+ /////////////
+ AES_256: begin
+ unique case (op_i)
+ CIPH_FWD: begin
+ if (rnd == 0) begin
+ // Round 0: Nothing to be done
+ // The Full Key registers are not updated
+ regular[s] = {key_i[s][3:0], key_i[s][7:4]};
+ end else begin
+ // Shift down old upper half
+ regular[s][3:0] = key_i[s][7:4];
+ // Generate new upper half
+ regular[s][4] = irregular[s] ^ key_i[s][0];
+ for (int i=1; i<4; i++) begin
+ regular[s][i+4] = regular[s][i+4-1] ^ key_i[s][i];
+ end
+ end // rnd == 0
+ end
+
+ CIPH_INV: begin
+ if (rnd == 0) begin
+ // Round 0: Nothing to be done
+ // The Full Key registers are not updated
+ regular[s] = {key_i[s][3:0], key_i[s][7:4]};
+ end else begin
+ // Shift up old lower half
+ regular[s][7:4] = key_i[s][3:0];
+ // Generate new lower half
+ regular[s][0] = irregular[s] ^ key_i[s][4];
+ for (int i=0; i<3; i++) begin
+ regular[s][i+1] = key_i[s][4+i] ^ key_i[s][4+i+1];
+ end
+ end // rnd == 0
+ end
+
+ default: regular[s] = {key_i[s][3:0], key_i[s][7:4]};
+ endcase
+ end
+
+ default: regular[s] = {key_i[s][3:0], key_i[s][7:4]};
+ endcase // key_len_i
+ end // drive_regular
+ end // gen_shares_regular
// Drive output
assign key_o = regular;
+ ////////////////
+ // Assertions //
+ ////////////////
+
+ // Cipher core masking requires a masked SBox and vice versa.
+ `ASSERT_INIT(AesMaskedCoreAndSBox,
+ (Masking &&
+ (SBoxImpl == SBoxImplCanrightMasked ||
+ SBoxImpl == SBoxImplCanrightMaskedNoreuse)) ||
+ (!Masking &&
+ (SBoxImpl == SBoxImplLut ||
+ SBoxImpl == SBoxImplCanright)))
+
// Selectors must be known/valid
`ASSERT_KNOWN(AesCiphOpKnown, op_i)
`ASSERT(AesKeyLenValid, key_len_i inside {
diff --git a/hw/ip/aes/rtl/aes_mix_columns.sv b/hw/ip/aes/rtl/aes_mix_columns.sv
index 3aee014..b4c121e 100644
--- a/hw/ip/aes/rtl/aes_mix_columns.sv
+++ b/hw/ip/aes/rtl/aes_mix_columns.sv
@@ -20,7 +20,7 @@
// Individually mix columns
for (genvar i = 0; i < 4; i++) begin : gen_mix_column
- aes_mix_single_column aes_mix_column_i (
+ aes_mix_single_column u_aes_mix_column_i (
.op_i ( op_i ),
.data_i ( data_i_transposed[i] ),
.data_o ( data_o_transposed[i] )
diff --git a/hw/ip/aes/rtl/aes_pkg.sv b/hw/ip/aes/rtl/aes_pkg.sv
index bb2f6f6..2f855e2 100644
--- a/hw/ip/aes/rtl/aes_pkg.sv
+++ b/hw/ip/aes/rtl/aes_pkg.sv
@@ -9,6 +9,15 @@
parameter int NumAlerts = 1;
parameter logic [NumAlerts-1:0] AlertAsyncOn = NumAlerts'(1'b1);
+typedef enum integer {
+ SBoxImplLut, // Unmasked LUT-based S-Box
+ SBoxImplCanright, // Unmasked Canright S-Box, see aes_sbox_canright.sv
+ SBoxImplCanrightMasked, // First-order masked Canright S-Box
+ // see aes_sbox_canright_masked.sv
+ SBoxImplCanrightMaskedNoreuse // First-order masked Canright S-Box without mask reuse,
+ // see aes_sbox_canright_masked_noreuse.sv
+} sbox_impl_e;
+
typedef enum logic {
AES_ENC = 1'b0,
AES_DEC = 1'b1
diff --git a/hw/ip/aes/rtl/aes_prng.sv b/hw/ip/aes/rtl/aes_prng.sv
index 08e2a94..43f9193 100644
--- a/hw/ip/aes/rtl/aes_prng.sv
+++ b/hw/ip/aes/rtl/aes_prng.sv
@@ -47,7 +47,7 @@
.LfsrType ( "GAL_XOR" ),
.LfsrDw ( DATA_WIDTH ),
.StateOutDw ( DATA_WIDTH )
- ) aes_prng_lfsr (
+ ) u_aes_prng_lfsr (
.clk_i ( clk_i ),
.rst_ni ( rst_ni ),
.seed_en_i ( seed_en ),
diff --git a/hw/ip/aes/rtl/aes_sbox.sv b/hw/ip/aes/rtl/aes_sbox.sv
index a2bbcf6..6fd58e9 100644
--- a/hw/ip/aes/rtl/aes_sbox.sv
+++ b/hw/ip/aes/rtl/aes_sbox.sv
@@ -4,55 +4,58 @@
//
// AES SBox
-module aes_sbox #(
- parameter SBoxImpl = "lut"
+module aes_sbox import aes_pkg::*;
+#(
+ parameter sbox_impl_e SBoxImpl = SBoxImplLut
) (
- input aes_pkg::ciph_op_e op_i,
- input logic [7:0] data_i,
- output logic [7:0] data_o
+ input ciph_op_e op_i,
+ input logic [7:0] data_i,
+ input logic [7:0] in_mask_i,
+ input logic [7:0] out_mask_i,
+ output logic [7:0] data_o
);
- if (SBoxImpl == "lut") begin : gen_sbox_lut
- aes_sbox_lut aes_sbox (
- .op_i,
- .data_i,
- .data_o
- );
- end else if (SBoxImpl == "canright") begin : gen_sbox_canright
- aes_sbox_canright aes_sbox (
- .op_i,
- .data_i,
- .data_o
- );
- end else begin : gen_sbox_masked
- // TODO: Use non-constant masks + remove corresponding comment in aes.sv.
- // See https://github.com/lowRISC/opentitan/issues/1005
- logic [7:0] in_data_m, out_data_m;
- logic [7:0] in_mask, out_mask;
- assign in_mask = 8'hAA;
- assign out_mask = 8'h55;
+ import aes_pkg::*;
+ localparam bit SBoxMasked = (SBoxImpl == SBoxImplCanrightMasked ||
+ SBoxImpl == SBoxImplCanrightMaskedNoreuse) ? 1'b1 : 1'b0;
- // Mask input data
- assign in_data_m = data_i ^ in_mask;
- if (SBoxImpl == "canright_masked_noreuse") begin : gen_sbox_canright_masked_noreuse
- aes_sbox_canright_masked_noreuse aes_sbox (
+ if (!SBoxMasked) begin : gen_sbox_unmasked
+ // Tie off unused mask inputs.
+ logic [15:0] unused_masks;
+ assign unused_masks = {in_mask_i, out_mask_i};
+
+ if (SBoxImpl == SBoxImplCanright) begin : gen_sbox_canright
+ aes_sbox_canright u_aes_sbox (
.op_i,
- .data_i ( in_data_m ),
- .in_mask_i ( in_mask ),
- .out_mask_i ( out_mask ),
- .data_o ( out_data_m )
+ .data_i,
+ .data_o
);
- end else if (SBoxImpl == "canright_masked") begin : gen_sbox_canright_masked
- aes_sbox_canright_masked aes_sbox (
+ end else begin : gen_sbox_lut // SBoxImpl == SBoxImplLut
+ aes_sbox_lut u_aes_sbox (
.op_i,
- .data_i ( in_data_m ),
- .in_mask_i ( in_mask ),
- .out_mask_i ( out_mask ),
- .data_o ( out_data_m )
+ .data_i,
+ .data_o
);
end
- // Unmask output data
- assign data_o = out_data_m ^ out_mask;
+ end else begin : gen_sbox_masked
+
+ if (SBoxImpl == SBoxImplCanrightMaskedNoreuse) begin : gen_sbox_canright_masked_noreuse
+ aes_sbox_canright_masked_noreuse u_aes_sbox (
+ .op_i,
+ .data_i,
+ .in_mask_i,
+ .out_mask_i,
+ .data_o
+ );
+ end else begin : gen_sbox_canright_masked // SBoxImpl == SBoxImplCanrightMasked
+ aes_sbox_canright_masked u_aes_sbox (
+ .op_i,
+ .data_i,
+ .in_mask_i,
+ .out_mask_i,
+ .data_o
+ );
+ end
end
endmodule
diff --git a/hw/ip/aes/rtl/aes_sub_bytes.sv b/hw/ip/aes/rtl/aes_sub_bytes.sv
index 1d3e5c3..fa588bf 100644
--- a/hw/ip/aes/rtl/aes_sub_bytes.sv
+++ b/hw/ip/aes/rtl/aes_sub_bytes.sv
@@ -4,11 +4,14 @@
//
// AES SubBytes
-module aes_sub_bytes #(
- parameter SBoxImpl = "lut"
+module aes_sub_bytes import aes_pkg::*;
+#(
+ parameter sbox_impl_e SBoxImpl = SBoxImplLut
) (
- input aes_pkg::ciph_op_e op_i,
+ input ciph_op_e op_i,
input logic [3:0][3:0][7:0] data_i,
+ input logic [3:0][3:0][7:0] in_mask_i,
+ input logic [3:0][3:0][7:0] out_mask_i,
output logic [3:0][3:0][7:0] data_o
);
@@ -17,10 +20,12 @@
for (genvar i = 0; i < 4; i++) begin : gen_sbox_i
aes_sbox #(
.SBoxImpl ( SBoxImpl )
- ) aes_sbox_ij (
- .op_i ( op_i ),
- .data_i ( data_i[i][j] ),
- .data_o ( data_o[i][j] )
+ ) u_aes_sbox_ij (
+ .op_i ( op_i ),
+ .data_i ( data_i[i][j] ),
+ .in_mask_i ( in_mask_i[i][j] ),
+ .out_mask_i ( out_mask_i[i][j] ),
+ .data_o ( data_o[i][j] )
);
end
end