[aes] Clear internal registers with pseudo-random data
This commit adds an LFSR-based pseudo-random number generator to the AES
module that is used to clear various registers (input data, output data,
IV, key, internal state). The LFSR can be reseeded at runtime using a
bit in the TRIGGER register.
The reset for all these registers is removed. After a reset, the AES unit
first reseeds the LFSR and then clears all these registers with
pseudo-random data.
Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
diff --git a/hw/ip/aes/rtl/aes.sv b/hw/ip/aes/rtl/aes.sv
index 605bc6c..4040067 100644
--- a/hw/ip/aes/rtl/aes.sv
+++ b/hw/ip/aes/rtl/aes.sv
@@ -13,7 +13,14 @@
input clk_i,
input rst_ni,
- // Bus Interface
+ // Entropy source interface
+ // TODO: This still needs to be connected.
+ // See https://github.com/lowRISC/opentitan/issues/1005
+ //output logic entropy_req_o,
+ //input logic entropy_ack_i,
+ //input logic [63:0] entropy_i,
+
+ // Bus interface
input tlul_pkg::tl_h2d_t tl_i,
output tlul_pkg::tl_d2h_t tl_o
);
@@ -23,7 +30,13 @@
aes_reg2hw_t reg2hw;
aes_hw2reg_t hw2reg;
- aes_reg_top u_reg (
+ logic prng_data_req;
+ logic prng_data_ack;
+ logic [63:0] prng_data;
+ logic prng_reseed_req;
+ logic prng_reseed_ack;
+
+ aes_reg_top aes_reg_top (
.clk_i,
.rst_ni,
.tl_i,
@@ -39,10 +52,34 @@
) aes_core (
.clk_i,
.rst_ni,
+
+ .prng_data_req_o ( prng_data_req ),
+ .prng_data_ack_i ( prng_data_ack ),
+ .prng_data_i ( prng_data ),
+ .prng_reseed_req_o ( prng_reseed_req ),
+ .prng_reseed_ack_i ( prng_reseed_ack ),
+
.reg2hw,
.hw2reg
);
+ aes_prng aes_prng (
+ .clk_i,
+ .rst_ni,
+
+ .data_req_i ( prng_data_req ),
+ .data_ack_o ( prng_data_ack ),
+ .data_o ( prng_data ),
+ .reseed_req_i ( prng_reseed_req ),
+ .reseed_ack_o ( prng_reseed_ack ),
+
+ // TODO: This still needs to be connected to the entropy source.
+ // See https://github.com/lowRISC/opentitan/issues/1005
+ .entropy_req_o( ),
+ .entropy_ack_i( 1'b1 ),
+ .entropy_i ( 64'hFEDCBA9876543210 )
+ );
+
// All outputs should have a known value after reset
`ASSERT_KNOWN(TlODValidKnown, tl_o.d_valid)
`ASSERT_KNOWN(TlOAReadyKnown, tl_o.a_ready)
diff --git a/hw/ip/aes/rtl/aes_cipher_control.sv b/hw/ip/aes/rtl/aes_cipher_control.sv
index 9be1d92..d5287f9 100644
--- a/hw/ip/aes/rtl/aes_cipher_control.sv
+++ b/hw/ip/aes/rtl/aes_cipher_control.sv
@@ -23,7 +23,8 @@
// Control and sync signals
input aes_pkg::ciph_op_e op_i,
input aes_pkg::key_len_e key_len_i,
- input logic start_i,
+ input logic crypt_i,
+ output logic crypt_o,
input logic dec_key_gen_i,
output logic dec_key_gen_o,
input logic key_clear_i,
@@ -53,7 +54,7 @@
// Types
typedef enum logic [2:0] {
- IDLE, INIT, ROUND, FINISH, CLEAR
+ IDLE, INIT, ROUND, FINISH, CLEAR_S, CLEAR_KD
} aes_cipher_ctrl_e;
aes_cipher_ctrl_e aes_cipher_ctrl_ns, aes_cipher_ctrl_cs;
@@ -62,6 +63,7 @@
logic [3:0] round_d, round_q;
logic [3:0] num_rounds_d, num_rounds_q;
logic [3:0] num_rounds_regular;
+ logic crypt_d, crypt_q;
logic dec_key_gen_d, dec_key_gen_q;
logic key_clear_d, key_clear_q;
logic data_out_clear_d, data_out_clear_q;
@@ -92,6 +94,7 @@
aes_cipher_ctrl_ns = aes_cipher_ctrl_cs;
round_d = round_q;
num_rounds_d = num_rounds_q;
+ crypt_d = crypt_q;
dec_key_gen_d = dec_key_gen_q;
key_clear_d = key_clear_q;
data_out_clear_d = data_out_clear_q;
@@ -104,9 +107,19 @@
// Signal that we are ready, wait for handshake.
in_ready_o = 1'b1;
if (in_valid_i) begin
- if (start_i) begin
- // Start generation of start key for decryption.
- dec_key_gen_d = dec_key_gen_i;
+ if (key_clear_i || data_out_clear_i) begin
+ // Clear internal key registers. The cipher core muxes are used to clear the data
+ // output registers.
+ key_clear_d = key_clear_i;
+ data_out_clear_d = data_out_clear_i;
+
+ // To clear the data output registers, we must first clear the state.
+ aes_cipher_ctrl_ns = data_out_clear_i ? CLEAR_S : CLEAR_KD;
+
+ end else if (dec_key_gen_i || crypt_i) begin
+ // Start encryption/decryption or generation of start key for decryption.
+ crypt_d = ~dec_key_gen_i;
+ dec_key_gen_d = dec_key_gen_i;
// Load input data to state
state_sel_o = dec_key_gen_d ? STATE_CLEAR : STATE_INIT;
@@ -127,11 +140,6 @@
(key_len_i == AES_192) ? 4'd12 :
4'd14;
aes_cipher_ctrl_ns = INIT;
- end else if (key_clear_i || data_out_clear_i) begin
- key_clear_d = key_clear_i;
- data_out_clear_d = data_out_clear_i;
-
- aes_cipher_ctrl_ns = CLEAR;
end
end
end
@@ -221,6 +229,7 @@
// We don't need the state anymore, clear it.
state_we_o = 1'b1;
state_sel_o = STATE_CLEAR;
+ crypt_d = 1'b0;
// If we were generating the decryption key and didn't get the handshake in the last
// regular round, we should clear dec_key_gen now.
dec_key_gen_d = 1'b0;
@@ -228,7 +237,15 @@
end
end
- CLEAR: begin
+ CLEAR_S: begin
+ // Clear the state with pseudo-random data.
+ state_we_o = 1'b1;
+ state_sel_o = STATE_CLEAR;
+ aes_cipher_ctrl_ns = CLEAR_KD;
+ end
+
+ CLEAR_KD: begin
+ // Clear internal key registers and/or external data output registers.
if (key_clear_q) begin
key_full_sel_o = KEY_FULL_CLEAR;
key_full_we_o = 1'b1;
@@ -236,6 +253,7 @@
key_dec_we_o = 1'b1;
end
if (data_out_clear_q) begin
+ // Forward the state (previously cleared with psuedo-random data).
add_rk_sel_o = ADD_RK_INIT;
key_words_sel_o = KEY_WORDS_ZERO;
round_key_sel_o = ROUND_KEY_DIRECT;
@@ -258,6 +276,7 @@
aes_cipher_ctrl_cs <= IDLE;
round_q <= '0;
num_rounds_q <= '0;
+ crypt_q <= 1'b0;
dec_key_gen_q <= 1'b0;
key_clear_q <= 1'b0;
data_out_clear_q <= 1'b0;
@@ -265,6 +284,7 @@
aes_cipher_ctrl_cs <= aes_cipher_ctrl_ns;
round_q <= round_d;
num_rounds_q <= num_rounds_d;
+ crypt_q <= crypt_d;
dec_key_gen_q <= dec_key_gen_d;
key_clear_q <= key_clear_d;
data_out_clear_q <= data_out_clear_d;
@@ -279,6 +299,7 @@
assign key_expand_round_o = round_d;
// Let the main controller know whate we are doing.
+ assign crypt_o = crypt_q;
assign dec_key_gen_o = dec_key_gen_q;
assign key_clear_o = key_clear_q;
assign data_out_clear_o = data_out_clear_q;
@@ -299,7 +320,8 @@
INIT,
ROUND,
FINISH,
- CLEAR
+ CLEAR_S,
+ CLEAR_KD
})
endmodule
diff --git a/hw/ip/aes/rtl/aes_cipher_core.sv b/hw/ip/aes/rtl/aes_cipher_core.sv
index 913e044..ed35dc5 100644
--- a/hw/ip/aes/rtl/aes_cipher_core.sv
+++ b/hw/ip/aes/rtl/aes_cipher_core.sv
@@ -27,7 +27,8 @@
// Control and sync signals
input aes_pkg::ciph_op_e op_i,
input aes_pkg::key_len_e key_len_i,
- input logic start_i,
+ input logic crypt_i,
+ output logic crypt_o,
input logic dec_key_gen_i,
output logic dec_key_gen_o,
input logic key_clear_i,
@@ -35,6 +36,9 @@
input logic data_out_clear_i, // Re-use the cipher core muxes.
output logic data_out_clear_o,
+ // Pseudo-random data
+ 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,
@@ -85,15 +89,13 @@
unique case (state_sel)
STATE_INIT: state_d = state_init_i;
STATE_ROUND: state_d = add_round_key_out;
- STATE_CLEAR: state_d = '0;
- default: state_d = '0;
+ STATE_CLEAR: state_d = {prng_data_i, prng_data_i};
+ default: state_d = {prng_data_i, prng_data_i};
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin : state_reg
- if (!rst_ni) begin
- state_q <= '0;
- end else if (state_we) begin
+ always_ff @(posedge clk_i) begin : state_reg
+ if (state_we) begin
state_q <= state_d;
end
end
@@ -140,15 +142,13 @@
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 = '0;
- default: key_full_d = '0;
+ 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};
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin : key_full_reg
- if (!rst_ni) begin
- key_full_q <= '0;
- end else if (key_full_we) begin
+ always_ff @(posedge clk_i) begin : key_full_reg
+ if (key_full_we) begin
key_full_q <= key_full_d;
end
end
@@ -157,15 +157,13 @@
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 = '0;
- default: key_dec_d = '0;
+ 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};
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin : key_dec_reg
- if (!rst_ni) begin
- key_dec_q <= '0;
- end else if (key_dec_we) begin
+ always_ff @(posedge clk_i) begin : key_dec_reg
+ if (key_dec_we) begin
key_dec_q <= key_dec_d;
end
end
@@ -228,7 +226,8 @@
.out_ready_i ( out_ready_i ),
.op_i ( op_i ),
.key_len_i ( key_len_i ),
- .start_i ( start_i ),
+ .crypt_i ( crypt_i ),
+ .crypt_o ( crypt_o ),
.dec_key_gen_i ( dec_key_gen_i ),
.dec_key_gen_o ( dec_key_gen_o ),
.key_clear_i ( key_clear_i ),
diff --git a/hw/ip/aes/rtl/aes_control.sv b/hw/ip/aes/rtl/aes_control.sv
index 67adb02..177c7d9 100644
--- a/hw/ip/aes/rtl/aes_control.sv
+++ b/hw/ip/aes/rtl/aes_control.sv
@@ -22,6 +22,7 @@
input logic iv_clear_i,
input logic data_in_clear_i,
input logic data_out_clear_i,
+ input logic prng_reseed_i,
// I/O register read/write enables
input logic [7:0] key_init_qe_i,
@@ -50,7 +51,8 @@
input logic cipher_in_ready_i,
input logic cipher_out_valid_i,
output logic cipher_out_ready_o,
- output logic cipher_start_o,
+ output logic cipher_crypt_o,
+ input logic cipher_crypt_i,
output logic cipher_dec_key_gen_o,
input logic cipher_dec_key_gen_i,
output logic cipher_key_clear_o,
@@ -66,6 +68,12 @@
output aes_pkg::iv_sel_e iv_sel_o,
output logic [7:0] iv_we_o,
+ // Pseudo-random number generator interface
+ output logic prng_data_req_o,
+ input logic prng_data_ack_i,
+ output logic prng_reseed_req_o,
+ input logic prng_reseed_ack_i,
+
// Trigger register
output logic start_o,
output logic start_we_o,
@@ -77,6 +85,8 @@
output logic data_in_clear_we_o,
output logic data_out_clear_o,
output logic data_out_clear_we_o,
+ output logic prng_reseed_o,
+ output logic prng_reseed_we_o,
// Status register
output logic output_valid_o,
@@ -92,8 +102,8 @@
import aes_pkg::*;
// Types
- typedef enum logic [1:0] {
- IDLE, LOAD, FINISH, CLEAR
+ typedef enum logic [2:0] {
+ IDLE, LOAD, UPDATE_PRNG, FINISH, CLEAR
} aes_ctrl_e;
aes_ctrl_e aes_ctrl_ns, aes_ctrl_cs;
@@ -121,6 +131,8 @@
logic output_valid_q;
logic start, finish;
+ logic doing_cbc_enc, doing_cbc_dec;
+ logic doing_ctr;
// Software updates IV in chunks of 32 bits, the counter updates 16 bits at a time.
// Convert word write enable to internal half-word write enable.
@@ -140,6 +152,11 @@
// clock cycle.
assign finish = manual_operation_i ? 1'b1 : ~output_valid_q | data_out_read;
+ // Helper signals for FSM
+ assign doing_cbc_enc = (cipher_crypt_o | cipher_crypt_i) & (mode_i == AES_CBC) & (op_i == AES_ENC);
+ assign doing_cbc_dec = (cipher_crypt_o | cipher_crypt_i) & (mode_i == AES_CBC) & (op_i == AES_DEC);
+ assign doing_ctr = (cipher_crypt_o | cipher_crypt_i) & (mode_i == AES_CTR);
+
// FSM
always_comb begin : aes_ctrl_fsm
@@ -158,7 +175,7 @@
// Cipher core control
cipher_in_valid_o = 1'b0;
cipher_out_ready_o = 1'b0;
- cipher_start_o = 1'b0;
+ cipher_crypt_o = 1'b0;
cipher_dec_key_gen_o = 1'b0;
cipher_key_clear_o = 1'b0;
cipher_data_out_clear_o = 1'b0;
@@ -172,12 +189,17 @@
iv_we_o = 8'h00;
iv_load = 1'b0;
+ // Pseudo-random number generator control
+ prng_data_req_o = 1'b0;
+ prng_reseed_req_o = 1'b0;
+
// Trigger register control
start_we_o = 1'b0;
key_clear_we_o = 1'b0;
iv_clear_we_o = 1'b0;
data_in_clear_we_o = 1'b0;
data_out_clear_we_o = 1'b0;
+ prng_reseed_we_o = 1'b0;
// Status register
idle_o = 1'b0;
@@ -202,33 +224,45 @@
IDLE: begin
idle_o = (start || key_clear_i || iv_clear_i ||
- data_in_clear_i || data_out_clear_i) ? 1'b0 : 1'b1;
+ data_in_clear_i || data_out_clear_i || prng_reseed_i) ? 1'b0 : 1'b1;
idle_we_o = 1'b1;
// Initial key and IV updates are ignored if we are not idle.
key_init_we_o = idle_o ? key_init_qe_i : 8'h00;
iv_we_o = idle_o ? iv_qe : 8'h00;
- if (start) begin
+ if (prng_reseed_i) begin
+ // Request a reseed of the PRNG, perform handshake.
+ prng_reseed_req_o = 1'b1;
+ if (prng_reseed_ack_i) begin
+ // Clear the trigger.
+ prng_reseed_we_o = 1'b1;
+ end
+
+ end else if (key_clear_i || data_out_clear_i || iv_clear_i || data_in_clear_i) begin
+ // To clear registers, we must first request fresh pseudo-random data.
+ aes_ctrl_ns = UPDATE_PRNG;
+
+ end else if (start) begin
// Signal that we want to start encryption/decryption.
- cipher_start_o = 1'b1;
+ cipher_crypt_o = 1'b1;
// We got a new initial key, but want to do decryption. The cipher core must first
// generate the start key for decryption.
cipher_dec_key_gen_o = key_init_new & (cipher_op_i == CIPH_INV);
// Previous input data register control
- data_in_prev_sel_o = (mode_i == AES_CBC && op_i == AES_DEC) ? DIP_DATA_IN :
- (mode_i == AES_CTR) ? DIP_DATA_IN : DIP_CLEAR;
- data_in_prev_we_o = (mode_i == AES_CBC && op_i == AES_DEC) ? 1'b1 :
- (mode_i == AES_CTR) ? 1'b1 : 1'b0;
+ data_in_prev_sel_o = doing_cbc_dec ? DIP_DATA_IN :
+ doing_ctr ? DIP_DATA_IN : DIP_CLEAR;
+ data_in_prev_we_o = doing_cbc_dec ? 1'b1 :
+ doing_ctr ? 1'b1 : 1'b0;
// State input mux control
- state_in_sel_o = (mode_i == AES_CTR) ? SI_ZERO : SI_DATA;
+ state_in_sel_o = doing_ctr ? SI_ZERO : SI_DATA;
// State input additon mux control
- add_state_in_sel_o = (mode_i == AES_CBC && op_i == AES_ENC) ? ADD_SI_IV :
- (mode_i == AES_CTR) ? ADD_SI_IV : ADD_SI_ZERO;
+ add_state_in_sel_o = doing_cbc_enc ? ADD_SI_IV :
+ doing_ctr ? ADD_SI_IV : ADD_SI_ZERO;
// We have work for the cipher core, perform handshake.
cipher_in_valid_o = 1'b1;
@@ -238,21 +272,6 @@
start_we_o = ~cipher_dec_key_gen_o;
aes_ctrl_ns = LOAD;
end
- end else if (key_clear_i || data_out_clear_i) begin
- // To clear the output data registers, we re-use the muxing resources of the cipher core.
- // To clear all key material, some key registers inside the cipher core need to be
- // cleared.
- cipher_key_clear_o = key_clear_i;
- cipher_data_out_clear_o = data_out_clear_i;
-
- // We have work for the cipher core, perform handshake.
- cipher_in_valid_o = 1'b1;
- if (cipher_in_ready_i) begin
- aes_ctrl_ns = CLEAR;
- end
- end else if (iv_clear_i || data_in_clear_i) begin
- // To clear the IV or input data registers, no handshake with the cipher core is needed.
- aes_ctrl_ns = CLEAR;
end
end
@@ -263,9 +282,49 @@
data_in_load = ~cipher_dec_key_gen_i;
// Trigger counter increment.
- ctr_incr_o = (mode_i == AES_CTR) ? 1'b1 : 1'b0;
+ ctr_incr_o = doing_ctr ? 1'b1 : 1'b0;
- aes_ctrl_ns = FINISH;
+ // Unless we are just generating the start key for decryption, we must update the PRNG.
+ aes_ctrl_ns = ~cipher_dec_key_gen_i ? UPDATE_PRNG : FINISH;
+ end
+
+ UPDATE_PRNG: begin
+ // Fresh pseudo-random data is used to:
+ // - clear the state in the final cipher round,
+ // - clear any other registers in the CLEAR state.
+
+ // IV control in case of ongoing encryption/decryption
+ // - CTR: IV registers are updated by counter during cipher operation
+ iv_sel_o = doing_ctr ? IV_CTR : IV_INPUT;
+ iv_we_o = doing_ctr ? ctr_we_i : 8'h00;
+
+ // Request fresh pseudo-random data, perform handshake.
+ prng_data_req_o = 1'b1;
+ if (prng_data_ack_i) begin
+
+ // Ongoing encryption/decryption operations have the highest priority. The clear triggers
+ // might have become asserted after the handshake with the cipher core.
+ if (cipher_crypt_i) begin
+ aes_ctrl_ns = FINISH;
+
+ end else if (key_clear_i || data_out_clear_i) begin
+ // To clear the output data registers, we re-use the muxing resources of the cipher
+ // core. To clear all key material, some key registers inside the cipher core need to
+ // be cleared.
+ cipher_key_clear_o = key_clear_i;
+ cipher_data_out_clear_o = data_out_clear_i;
+
+ // We have work for the cipher core, perform handshake.
+ cipher_in_valid_o = 1'b1;
+ if (cipher_in_ready_i) begin
+ aes_ctrl_ns = CLEAR;
+ end
+ end else begin // (iv_clear_i || data_in_clear_i)
+ // To clear the IV or input data registers, no handshake with the cipher core is
+ // needed.
+ aes_ctrl_ns = CLEAR;
+ end
+ end
end
FINISH: begin
@@ -283,17 +342,17 @@
stall_we_o = 1'b1;
// State out addition mux control
- add_state_out_sel_o = (mode_i == AES_CBC && op_i == AES_DEC) ? ADD_SO_IV :
- (mode_i == AES_CTR) ? ADD_SO_DIP : ADD_SO_ZERO;
+ add_state_out_sel_o = doing_cbc_dec ? ADD_SO_IV :
+ doing_ctr ? ADD_SO_DIP : ADD_SO_ZERO;
// IV control
// - CBC: IV registers can only be updated when cipher finishes
// - CTR: IV registers are updated by counter during cipher operation
- iv_sel_o = (mode_i == AES_CBC && op_i == AES_ENC) ? IV_DATA_OUT :
- (mode_i == AES_CBC && op_i == AES_DEC) ? IV_DATA_IN_PREV :
- (mode_i == AES_CTR) ? IV_CTR : IV_INPUT;
- iv_we_o = (mode_i == AES_CBC) ? {8{finish & cipher_out_valid_i}} :
- (mode_i == AES_CTR) ? ctr_we_i : 8'h00;
+ iv_sel_o = doing_cbc_enc ? IV_DATA_OUT :
+ doing_cbc_dec ? IV_DATA_IN_PREV :
+ doing_ctr ? IV_CTR : IV_INPUT;
+ iv_we_o = (doing_cbc_enc || doing_cbc_dec) ? {8{finish & cipher_out_valid_i}} :
+ doing_ctr ? ctr_we_i : 8'h00;
// We are ready once the output data registers can be written.
cipher_out_ready_o = finish;
@@ -425,6 +484,7 @@
assign iv_clear_o = 1'b0;
assign data_in_clear_o = 1'b0;
assign data_out_clear_o = 1'b0;
+ assign prng_reseed_o = 1'b0;
// Selectors must be known/valid
`ASSERT(AesModeValid, mode_i inside {
diff --git a/hw/ip/aes/rtl/aes_core.sv b/hw/ip/aes/rtl/aes_core.sv
index 4022f85..148e2cc 100644
--- a/hw/ip/aes/rtl/aes_core.sv
+++ b/hw/ip/aes/rtl/aes_core.sv
@@ -10,8 +10,16 @@
parameter bit AES192Enable = 1,
parameter SBoxImpl = "lut"
) (
- input logic clk_i,
- input logic rst_ni,
+ input logic clk_i,
+ input logic rst_ni,
+
+ // PRNG Interface
+ output logic prng_data_req_o,
+ input logic prng_data_ack_i,
+ input logic [63:0] prng_data_i,
+
+ output logic prng_reseed_req_o,
+ input logic prng_reseed_ack_i,
// Bus Interface
input aes_reg_pkg::aes_reg2hw_t reg2hw,
@@ -80,7 +88,8 @@
logic cipher_in_ready;
logic cipher_out_valid;
logic cipher_out_ready;
- logic cipher_start;
+ logic cipher_crypt;
+ logic cipher_crypt_busy;
logic cipher_dec_key_gen;
logic cipher_dec_key_gen_busy;
logic cipher_key_clear;
@@ -157,19 +166,15 @@
always_comb begin : key_init_mux
unique case (key_init_sel)
KEY_INIT_INPUT: key_init_d = key_init;
- KEY_INIT_CLEAR: key_init_d = '0;
- default: key_init_d = '0;
+ KEY_INIT_CLEAR: key_init_d = {prng_data_i, prng_data_i, prng_data_i, prng_data_i};
+ default: key_init_d = {prng_data_i, prng_data_i, prng_data_i, prng_data_i};
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin : key_init_reg
- if (!rst_ni) begin
- key_init_q <= '0;
- end else begin
- for (int i=0; i<8; i++) begin
- if (key_init_we[i]) begin
- key_init_q[i] <= key_init_d[i];
- end
+ always_ff @(posedge clk_i) begin : key_init_reg
+ for (int i=0; i<8; i++) begin
+ if (key_init_we[i]) begin
+ key_init_q[i] <= key_init_d[i];
end
end
end
@@ -181,19 +186,15 @@
IV_DATA_OUT: iv_d = data_out_d;
IV_DATA_IN_PREV: iv_d = data_in_prev_q;
IV_CTR: iv_d = ctr;
- IV_CLEAR: iv_d = '0;
- default: iv_d = '0;
+ IV_CLEAR: iv_d = {prng_data_i, prng_data_i};
+ default: iv_d = {prng_data_i, prng_data_i};
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin : iv_reg
- if (!rst_ni) begin
- iv_q <= '0;
- end else begin
- for (int i=0; i<8; i++) begin
- if (iv_we[i]) begin
- iv_q[i] <= iv_d[i];
- end
+ always_ff @(posedge clk_i) begin : iv_reg
+ for (int i=0; i<8; i++) begin
+ if (iv_we[i]) begin
+ iv_q[i] <= iv_d[i];
end
end
end
@@ -202,18 +203,14 @@
always_comb begin : data_in_prev_mux
unique case (data_in_prev_sel)
DIP_DATA_IN: data_in_prev_d = data_in;
- DIP_CLEAR: data_in_prev_d = '0;
- default: data_in_prev_d = '0;
+ DIP_CLEAR: data_in_prev_d = {prng_data_i, prng_data_i};
+ default: data_in_prev_d = {prng_data_i, prng_data_i};
endcase
end
- always_ff @(posedge clk_i or negedge rst_ni) begin : data_in_prev_reg
- if (!rst_ni) begin
- data_in_prev_q <= '0;
- end else begin
- if (data_in_prev_we) begin
- data_in_prev_q <= data_in_prev_d;
- end
+ always_ff @(posedge clk_i) begin : data_in_prev_reg
+ if (data_in_prev_we) begin
+ data_in_prev_q <= data_in_prev_d;
end
end
@@ -279,7 +276,8 @@
.out_ready_i ( cipher_out_ready ),
.op_i ( cipher_op ),
.key_len_i ( key_len_q ),
- .start_i ( cipher_start ),
+ .crypt_i ( cipher_crypt ),
+ .crypt_o ( cipher_crypt_busy ),
.dec_key_gen_i ( cipher_dec_key_gen ),
.dec_key_gen_o ( cipher_dec_key_gen_busy ),
.key_clear_i ( cipher_key_clear ),
@@ -287,6 +285,8 @@
.data_out_clear_i ( cipher_data_out_clear ),
.data_out_clear_o ( cipher_data_out_clear_busy ),
+ .prng_data_i ( prng_data_i ),
+
.state_init_i ( state_init ),
.key_init_i ( key_init_q ),
.state_o ( state_done )
@@ -323,6 +323,7 @@
.iv_clear_i ( reg2hw.trigger.iv_clear.q ),
.data_in_clear_i ( reg2hw.trigger.data_in_clear.q ),
.data_out_clear_i ( reg2hw.trigger.data_out_clear.q ),
+ .prng_reseed_i ( reg2hw.trigger.prng_reseed.q ),
.key_init_qe_i ( key_init_qe ),
.iv_qe_i ( iv_qe ),
@@ -346,7 +347,8 @@
.cipher_in_ready_i ( cipher_in_ready ),
.cipher_out_valid_i ( cipher_out_valid ),
.cipher_out_ready_o ( cipher_out_ready ),
- .cipher_start_o ( cipher_start ),
+ .cipher_crypt_o ( cipher_crypt ),
+ .cipher_crypt_i ( cipher_crypt_busy ),
.cipher_dec_key_gen_o ( cipher_dec_key_gen ),
.cipher_dec_key_gen_i ( cipher_dec_key_gen_busy ),
.cipher_key_clear_o ( cipher_key_clear ),
@@ -359,6 +361,11 @@
.iv_sel_o ( iv_sel ),
.iv_we_o ( iv_we ),
+ .prng_data_req_o ( prng_data_req_o ),
+ .prng_data_ack_i ( prng_data_ack_i ),
+ .prng_reseed_req_o ( prng_reseed_req_o ),
+ .prng_reseed_ack_i ( prng_reseed_ack_i ),
+
.start_o ( hw2reg.trigger.start.d ),
.start_we_o ( hw2reg.trigger.start.de ),
.key_clear_o ( hw2reg.trigger.key_clear.d ),
@@ -369,6 +376,8 @@
.data_in_clear_we_o ( hw2reg.trigger.data_in_clear.de ),
.data_out_clear_o ( hw2reg.trigger.data_out_clear.d ),
.data_out_clear_we_o ( hw2reg.trigger.data_out_clear.de ),
+ .prng_reseed_o ( hw2reg.trigger.prng_reseed.d ),
+ .prng_reseed_we_o ( hw2reg.trigger.prng_reseed.de ),
.output_valid_o ( hw2reg.status.output_valid.d ),
.output_valid_we_o ( hw2reg.status.output_valid.de ),
@@ -409,10 +418,8 @@
// Outputs //
/////////////
- always_ff @(posedge clk_i or negedge rst_ni) begin : data_out_reg
- if (!rst_ni) begin
- data_out_q <= '0;
- end else if (data_out_we) begin
+ always_ff @(posedge clk_i) begin : data_out_reg
+ if (data_out_we) begin
data_out_q <= data_out_d;
end
end
diff --git a/hw/ip/aes/rtl/aes_prng.sv b/hw/ip/aes/rtl/aes_prng.sv
new file mode 100644
index 0000000..f0c7046
--- /dev/null
+++ b/hw/ip/aes/rtl/aes_prng.sv
@@ -0,0 +1,78 @@
+// Copyright lowRISC contributors.
+// Licensed under the Apache License, Version 2.0, see LICENSE for details.
+// SPDX-License-Identifier: Apache-2.0
+//
+// AES pseudo-random number generator
+//
+// This module uses an LFSR connected to a PRINCE S-Box to provide pseudo-random data to the AES
+// module primarily for clearing registers. The LFSR can be reseeded using an external interface.
+
+module aes_prng(
+ input logic clk_i,
+ input logic rst_ni,
+
+ // Connections to AES internals, PRNG consumers
+ input logic data_req_i,
+ output logic data_ack_o,
+ output logic [63:0] data_o,
+ input logic reseed_req_i,
+ output logic reseed_ack_o,
+
+ // Connections to outer world, LFSR re-seed
+ output logic entropy_req_o,
+ input logic entropy_ack_i,
+ input logic [63:0] entropy_i
+);
+
+ localparam int unsigned DATA_WIDTH = 64;
+
+ // The S-Box of the PRINCE cipher is used to "scramble" the LFSR output.
+ localparam logic[15:0][3:0] PRINCE_SBOX_FWD = {4'h4, 4'hD, 4'h5, 4'hE,
+ 4'h0, 4'h8, 4'h7, 4'h6,
+ 4'h1, 4'h9, 4'hC, 4'hA,
+ 4'h2, 4'h3, 4'hF, 4'hB};
+
+ // "Scramble" with PRINCE cipher S-Box.
+ function automatic logic [63:0] aes_prng_scramble(logic [63:0] in);
+ logic [63:0] out;
+ // The PRINCE cipher S-Box operates on 4-bit nibbles.
+ for (int i=0; i<16; i++) begin
+ out[i*4 +: 4] = PRINCE_SBOX_FWD[in[i*4 +: 4]];
+ end
+ return out;
+ endfunction
+
+ logic [DATA_WIDTH-1:0] lfsr_state;
+ logic lfsr_en;
+ logic seed_en;
+
+ // The data requests are fed from the LFSR, reseed requests have the highest priority.
+ assign data_ack_o = reseed_req_i ? 1'b0 : data_req_i;
+
+ // Reseed requests are directly forwarded to the external interface.
+ assign reseed_ack_o = entropy_ack_i;
+ assign entropy_req_o = reseed_req_i;
+
+ // LFSR control
+ assign lfsr_en = data_req_i & data_ack_o;
+ assign seed_en = entropy_req_o & entropy_ack_i;
+
+ // LFSR instance
+ prim_lfsr #(
+ .LfsrType ( "GAL_XOR" ),
+ .LfsrDw ( DATA_WIDTH ),
+ .StateOutDw ( DATA_WIDTH )
+ ) aes_prng_lfsr (
+ .clk_i ( clk_i ),
+ .rst_ni ( rst_ni ),
+ .seed_en_i ( seed_en ),
+ .seed_i ( entropy_i ),
+ .lfsr_en_i ( lfsr_en ),
+ .entropy_i ( '0 ),
+ .state_o ( lfsr_state )
+ );
+
+ // "Scramble" the LFSR state.
+ assign data_o = aes_prng_scramble(lfsr_state);
+
+endmodule
diff --git a/hw/ip/aes/rtl/aes_reg_pkg.sv b/hw/ip/aes/rtl/aes_reg_pkg.sv
index 57437d8..fdb809d 100644
--- a/hw/ip/aes/rtl/aes_reg_pkg.sv
+++ b/hw/ip/aes/rtl/aes_reg_pkg.sv
@@ -69,6 +69,9 @@
struct packed {
logic q;
} data_out_clear;
+ struct packed {
+ logic q;
+ } prng_reseed;
} aes_reg2hw_trigger_reg_t;
@@ -125,6 +128,10 @@
logic d;
logic de;
} data_out_clear;
+ struct packed {
+ logic d;
+ logic de;
+ } prng_reseed;
} aes_hw2reg_trigger_reg_t;
typedef struct packed {
@@ -151,25 +158,25 @@
// Register to internal design logic //
///////////////////////////////////////
typedef struct packed {
- aes_reg2hw_key_mreg_t [7:0] key; // [676:413]
- aes_reg2hw_iv_mreg_t [3:0] iv; // [412:281]
- aes_reg2hw_data_in_mreg_t [3:0] data_in; // [280:149]
- aes_reg2hw_data_out_mreg_t [3:0] data_out; // [148:17]
- aes_reg2hw_ctrl_reg_t ctrl; // [16:5]
- aes_reg2hw_trigger_reg_t trigger; // [4:0]
+ aes_reg2hw_key_mreg_t [7:0] key; // [677:414]
+ aes_reg2hw_iv_mreg_t [3:0] iv; // [413:282]
+ aes_reg2hw_data_in_mreg_t [3:0] data_in; // [281:150]
+ aes_reg2hw_data_out_mreg_t [3:0] data_out; // [149:18]
+ aes_reg2hw_ctrl_reg_t ctrl; // [17:6]
+ aes_reg2hw_trigger_reg_t trigger; // [5:0]
} aes_reg2hw_t;
///////////////////////////////////////
// Internal design logic to register //
///////////////////////////////////////
typedef struct packed {
- aes_hw2reg_key_mreg_t [7:0] key; // [669:414]
- aes_hw2reg_iv_mreg_t [3:0] iv; // [413:286]
- aes_hw2reg_data_in_mreg_t [3:0] data_in; // [285:154]
- aes_hw2reg_data_out_mreg_t [3:0] data_out; // [153:26]
- aes_hw2reg_ctrl_reg_t ctrl; // [25:14]
- aes_hw2reg_trigger_reg_t trigger; // [13:9]
- aes_hw2reg_status_reg_t status; // [8:9]
+ aes_hw2reg_key_mreg_t [7:0] key; // [671:416]
+ aes_hw2reg_iv_mreg_t [3:0] iv; // [415:288]
+ aes_hw2reg_data_in_mreg_t [3:0] data_in; // [287:156]
+ aes_hw2reg_data_out_mreg_t [3:0] data_out; // [155:28]
+ aes_hw2reg_ctrl_reg_t ctrl; // [27:16]
+ aes_hw2reg_trigger_reg_t trigger; // [15:10]
+ aes_hw2reg_status_reg_t status; // [9:10]
} aes_hw2reg_t;
// Register Address
diff --git a/hw/ip/aes/rtl/aes_reg_top.sv b/hw/ip/aes/rtl/aes_reg_top.sv
index eac8a94..3760ff6 100644
--- a/hw/ip/aes/rtl/aes_reg_top.sv
+++ b/hw/ip/aes/rtl/aes_reg_top.sv
@@ -137,6 +137,8 @@
logic trigger_data_in_clear_we;
logic trigger_data_out_clear_wd;
logic trigger_data_out_clear_we;
+ logic trigger_prng_reseed_wd;
+ logic trigger_prng_reseed_we;
logic status_idle_qs;
logic status_stall_qs;
logic status_output_valid_qs;
@@ -604,7 +606,7 @@
prim_subreg #(
.DW (1),
.SWACCESS("WO"),
- .RESVAL (1'h0)
+ .RESVAL (1'h1)
) u_trigger_key_clear (
.clk_i (clk_i ),
.rst_ni (rst_ni ),
@@ -629,7 +631,7 @@
prim_subreg #(
.DW (1),
.SWACCESS("WO"),
- .RESVAL (1'h0)
+ .RESVAL (1'h1)
) u_trigger_iv_clear (
.clk_i (clk_i ),
.rst_ni (rst_ni ),
@@ -654,7 +656,7 @@
prim_subreg #(
.DW (1),
.SWACCESS("WO"),
- .RESVAL (1'h0)
+ .RESVAL (1'h1)
) u_trigger_data_in_clear (
.clk_i (clk_i ),
.rst_ni (rst_ni ),
@@ -679,7 +681,7 @@
prim_subreg #(
.DW (1),
.SWACCESS("WO"),
- .RESVAL (1'h0)
+ .RESVAL (1'h1)
) u_trigger_data_out_clear (
.clk_i (clk_i ),
.rst_ni (rst_ni ),
@@ -700,6 +702,31 @@
);
+ // F[prng_reseed]: 5:5
+ prim_subreg #(
+ .DW (1),
+ .SWACCESS("WO"),
+ .RESVAL (1'h1)
+ ) u_trigger_prng_reseed (
+ .clk_i (clk_i ),
+ .rst_ni (rst_ni ),
+
+ // from register interface
+ .we (trigger_prng_reseed_we),
+ .wd (trigger_prng_reseed_wd),
+
+ // from internal hardware
+ .de (hw2reg.trigger.prng_reseed.de),
+ .d (hw2reg.trigger.prng_reseed.d ),
+
+ // to internal hardware
+ .qe (),
+ .q (reg2hw.trigger.prng_reseed.q ),
+
+ .qs ()
+ );
+
+
// R[status]: V(False)
// F[idle]: 0:0
@@ -949,6 +976,9 @@
assign trigger_data_out_clear_we = addr_hit[21] & reg_we & ~wr_err;
assign trigger_data_out_clear_wd = reg_wdata[4];
+ assign trigger_prng_reseed_we = addr_hit[21] & reg_we & ~wr_err;
+ assign trigger_prng_reseed_wd = reg_wdata[5];
+
@@ -1050,6 +1080,7 @@
reg_rdata_next[2] = '0;
reg_rdata_next[3] = '0;
reg_rdata_next[4] = '0;
+ reg_rdata_next[5] = '0;
end
addr_hit[22]: begin