[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