[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/aes.core b/hw/ip/aes/aes.core
index 723d25b..da2a4f1 100644
--- a/hw/ip/aes/aes.core
+++ b/hw/ip/aes/aes.core
@@ -14,6 +14,7 @@
       - rtl/aes_reg_pkg.sv
       - rtl/aes_reg_top.sv
       - rtl/aes_core.sv
+      - rtl/aes_prng.sv
       - rtl/aes_ctr.sv
       - rtl/aes_control.sv
       - rtl/aes_cipher_core.sv
diff --git a/hw/ip/aes/data/aes.hjson b/hw/ip/aes/data/aes.hjson
index 588d09d..c507ae6 100644
--- a/hw/ip/aes/data/aes.hjson
+++ b/hw/ip/aes/data/aes.hjson
@@ -121,8 +121,10 @@
       fields: [
         { bits: "31:0", name: "data_out", desc: "Output Data" }
       ]
-      tags: [// Updated by the hw. Exclude from write-checks.
-             "excl:CsrNonInitTests:CsrExclWriteCheck"]
+      tags: [// Updated by the HW.
+             // No reset but sync clear with random data.
+             // Exclude from init and write checks.
+             "excl:CsrAllTests:CsrExclCheck"]
       }
     },
 ##############################################################################
@@ -181,6 +183,7 @@
     desc: '''
       Trigger Register.
       Each bit is individually cleared to zero when executing the corresponding trigger.
+
     '''
     swaccess: "wo",
     hwaccess: "hrw",
@@ -194,32 +197,45 @@
       }
       { bits: "1",
         name: "KEY_CLEAR",
+        resval: "1"
         desc:  '''
           Keep current values in Initial Key, internal Full Key and Decryption Key registers (0)
-          or clear those registers to zero (1).
+          or clear those registers with pseudo-random data (1).
         '''
       }
       { bits: "2",
         name: "IV_CLEAR",
+        resval: "1"
         desc:  '''
-          Keep current values in IV registers (0) or clear those registers to zero (1).
+          Keep current values in IV registers (0) or clear those registers with pseudo-random data (1).
         '''
       }
       { bits: "3",
         name: "DATA_IN_CLEAR",
+        resval: "1"
         desc:  '''
-          Keep current values in input registers (0) or clear those registers to zero (1).
+          Keep current values in input registers (0) or clear those registers with pseudo-random data (1).
         '''
       }
       { bits: "4",
         name: "DATA_OUT_CLEAR",
+        resval: "1"
         desc:  '''
-          Keep current values in output registers (0) or clear those registers to zero (1).
+          Keep current values in output registers (0) or clear those registers with pseudo-random data (1).
+        '''
+      }
+      { bits: "5",
+        name: "PRNG_RESEED",
+        resval: "1"
+        desc:  '''
+          Keep continuing with the current internal state of the internal pseudo-random number generator (0) or perform a reseed of the internal state from the connected entropy source (1).
         '''
       }
     ]
-    tags: [// Updated by hw. Exclude from write-checks.
-           "excl:CsrNonInitTests:CsrExclWriteCheck"]
+    tags: [// Updated by the HW.
+           // Reset value cleared to zero.
+           // Exclude from init and write checks.
+           "excl:CsrAllTests:CsrExclCheck"]
   },
   { name: "STATUS",
     desc: "Status Register",
diff --git a/hw/ip/aes/doc/_index.md b/hw/ip/aes/doc/_index.md
index 8f46597..d3f1d91 100644
--- a/hw/ip/aes/doc/_index.md
+++ b/hw/ip/aes/doc/_index.md
@@ -183,7 +183,7 @@
     Since the counter value is used in the first round only, and since the encryption/decryption of a single block takes 12/14/16 cycles, the iterative counter implementation does not affect the throughput of the AES unit._
 1. Finally, the AES cipher core performs the final encryption/decryption round in which the MixColumns operation is skipped.
    The output is forwarded to the output register in the CSRs but not stored back into the State register.
-   The internal State register is cleared to zero.
+   The internal State register is cleared with pseudo-random data.
 
    _Depending on the cipher mode, the output of the final round is potentially XORed with either the value in the IV registers (CBC decryption) or the value stored in the previous input data register (CTR mode), before being forwarded to the output register in the CSRs.
    If running in CBC mode, the IV registers are updated with the output data (encryption) or the value stored in the previous input data register (decryption)._
@@ -411,7 +411,7 @@
 
 After finishing operation, software must:
 1. Disable the AES unit to no longer automatically start encryption/decryption by setting the MANUAL_OPERATION bit in {{< regref "CTRL" >}} to `1`.
-1. Clear all key registers, IV registers as well as the Input Data and the Output Data registers by setting the KEY_CLEAR, IV_CLEAR, DATA_IN_CLEAR and DATA_OUT_CLEAR bits in {{< regref "TRIGGER" >}} to `1`.
+1. Clear all key registers with pseudo-random data, IV registers as well as the Input Data and the Output Data registers by setting the KEY_CLEAR, IV_CLEAR, DATA_IN_CLEAR and DATA_OUT_CLEAR bits in {{< regref "TRIGGER" >}} to `1`.
 
 The code snippet below shows how to perform this task.
 
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