[aes/dv/aes_model_dpi] Add DPI call to encrypt/decrypt entire messages

Signed-off-by: Pirmin Vogel <vogelpi@lowrisc.org>
diff --git a/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi.c b/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi.c
index d5bea92..c7984e9 100644
--- a/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi.c
+++ b/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi.c
@@ -2,6 +2,7 @@
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -12,10 +13,11 @@
 
 #include "aes_model_dpi.h"
 
-void c_dpi_aes_crypt(const unsigned char impl_i, const unsigned char op_i,
-                     const svBitVecVal *mode_i, const svBitVecVal *iv_i,
-                     const svBitVecVal *key_len_i, const svBitVecVal *key_i,
-                     const svBitVecVal *data_i, svBitVecVal *data_o) {
+void c_dpi_aes_crypt_block(const unsigned char impl_i, const unsigned char op_i,
+                           const svBitVecVal *mode_i, const svBitVecVal *iv_i,
+                           const svBitVecVal *key_len_i,
+                           const svBitVecVal *key_i, const svBitVecVal *data_i,
+                           svBitVecVal *data_o) {
   // get input data from simulator
   unsigned char *key = aes_key_get(key_i);
   unsigned char *ref_in = aes_data_get(data_i);
@@ -37,20 +39,13 @@
   if (mode != kCryptoAesEcb) {
     iv = aes_data_get(iv_i);
   } else {
-    iv = (unsigned char *)malloc(16 * sizeof(unsigned char));
-    if (!iv) {
-      printf("ERROR: malloc() for c_dpi_aes_crypt failed");
-      return;
-    }
-    memset(iv, 0, 16);
+    iv = (unsigned char *)calloc(16, sizeof(unsigned char));
+    assert(iv);
   }
 
   // allocate memory
   unsigned char *ref_out = (unsigned char *)malloc(16 * sizeof(unsigned char));
-  if (!ref_out) {
-    printf("ERROR: malloc() for c_dpi_aes_crypt failed");
-    return;
-  }
+  assert(ref_out);
 
   if (impl_i == 0) {
     // The C model does ECB only. We "emulate" other modes here.
@@ -106,6 +101,92 @@
   return;
 }
 
+void c_dpi_aes_crypt_message(unsigned char impl_i, unsigned char op_i,
+                             const svBitVecVal *mode_i, const svBitVecVal *iv_i,
+                             const svBitVecVal *key_len_i,
+                             const svBitVecVal *key_i,
+                             const svOpenArrayHandle data_i,
+                             svOpenArrayHandle data_o) {
+  if (impl_i == 0) {
+    // The C model is currently not supported.
+    printf(
+        "ERROR: c_dpi_aes_crypt_message() currently supports OpenSSL/BoringSSL "
+        "only\n");
+    return;
+  }
+
+  // Get key from simulator.
+  unsigned char *key = aes_key_get(key_i);
+
+  // key_len_i is one-hot encoded.
+  int key_len;
+  if (*key_len_i == 0x1) {
+    key_len = 16;
+  } else if (*key_len_i == 0x2) {
+    key_len = 24;
+  } else {  // 0x4
+    key_len = 32;
+  }
+
+  crypto_mode_t mode = (crypto_mode_t)*mode_i;
+
+  // Modes other than ECB require an IV from the simulator.
+  unsigned char *iv = (unsigned char *)malloc(16 * sizeof(unsigned char));
+  assert(iv);
+  if (mode != kCryptoAesEcb) {
+    // iv_i is a 1D array of words (4x32bit), but we need 16 bytes.
+    svBitVecVal value;
+    for (int i = 0; i < 4; ++i) {
+      value = iv_i[i];
+      iv[4 * i + 0] = (unsigned char)(value >> 0);
+      iv[4 * i + 1] = (unsigned char)(value >> 8);
+      iv[4 * i + 2] = (unsigned char)(value >> 16);
+      iv[4 * i + 3] = (unsigned char)(value >> 24);
+    }
+  } else {
+    memset(iv, 0, 16);
+  }
+
+  // Get message length.
+  int data_len = svSize(data_i, 1);
+
+  // Get input data from simulator.
+  unsigned char *ref_in = aes_data_unpacked_get(data_i);
+
+  // Allocate output buffer.
+  unsigned char *ref_out =
+      (unsigned char *)malloc(data_len * sizeof(unsigned char));
+  assert(ref_out);
+
+  // OpenSSL/BoringSSL
+  if ((int)data_len % 16) {
+    printf(
+        "ERROR: Message length must be a multiple of 16 bytes (the block "
+        "size).\n");
+    return;
+  }
+
+  if (impl_i == 0) {
+    // The C model is currently not supported.
+    printf(
+        "ERROR: c_dpi_aes_crypt_message() currently supports OpenSSL/BoringSSL "
+        "only\n");
+  } else {  // OpenSSL/BoringSSL
+    if (!op_i) {
+      crypto_encrypt(ref_out, iv, ref_in, data_len, key, key_len, mode);
+    } else {
+      crypto_decrypt(ref_out, iv, ref_in, data_len, key, key_len, mode);
+    }
+  }
+
+  // Write output data back to simulator, free ref_out.
+  aes_data_unpacked_put(data_o, ref_out);
+
+  // Free memory.
+  free(iv);
+  free(key);
+}
+
 void c_dpi_aes_sub_bytes(const unsigned char op_i, const svBitVecVal *data_i,
                          svBitVecVal *data_o) {
   // get input data from simulator
@@ -202,10 +283,7 @@
 
   // alloc data buffer
   data = (unsigned char *)malloc(16 * sizeof(unsigned char));
-  if (!data) {
-    printf("ERROR: malloc() for aes_data_get failed");
-    return 0;
-  }
+  assert(data);
 
   // get data from simulator, convert from 2D to 1D
   for (int i = 0; i < 4; i++) {
@@ -244,10 +322,7 @@
   // alloc data buffer
   len = svSize(data_i, 1);
   data = (unsigned char *)malloc(len * sizeof(unsigned char));
-  if (!data) {
-    printf("ERROR: malloc() for aes_data_unpacked_get failed");
-    return 0;
-  }
+  assert(data);
 
   // get data from simulator
   for (int i = 0; i < len; i++) {
@@ -284,10 +359,7 @@
 
   // alloc data buffer
   key = (unsigned char *)malloc(32 * sizeof(unsigned char));
-  if (!key) {
-    printf("ERROR: malloc() for aes_key_get failed");
-    return 0;
-  }
+  assert(key);
 
   // get data from simulator
   for (int i = 0; i < 8; i++) {
diff --git a/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi.h b/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi.h
index 874235f..513eafa 100644
--- a/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi.h
+++ b/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi.h
@@ -2,8 +2,8 @@
 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
 // SPDX-License-Identifier: Apache-2.0
 
-#ifndef _AES_MODEL_DPI_H_
-#define _AES_MODEL_DPI_H_
+#ifndef OPENTITAN_HW_IP_AES_DV_AES_MODEL_DPI_AES_MODEL_DPI_H_
+#define OPENTITAN_HW_IP_AES_DV_AES_MODEL_DPI_AES_MODEL_DPI_H_
 
 #include "svdpi.h"
 
@@ -19,14 +19,35 @@
  * @param  mode_i    Cipher mode: 3'b001 = ECB, 3'b010 = CBC, 3'b100 = CTR
  * @param  iv_i      Initialization vector: 2D matrix (3D packed array in SV)
  * @param  key_len_i Key length: 3'b001 = 128b, 3'b010 = 192b, 3'b100 = 256b
- * @param  key_i     Full input key
+ * @param  key_i     Full input key, 1D array of words (2D packed array in SV)
  * @param  data_i    Input data, 2D state matrix (3D packed array in SV)
  * @param  data_o    Output data, 2D state matrix (3D packed array in SV)
  */
-void c_dpi_aes_crypt(const unsigned char impl_i, const unsigned char op_i,
-                     const svBitVecVal *mode_i, const svBitVecVal *iv_i,
-                     const svBitVecVal *key_len_i, const svBitVecVal *key_i,
-                     const svBitVecVal *data_i, svBitVecVal *data_o);
+void c_dpi_aes_crypt_block(const unsigned char impl_i, const unsigned char op_i,
+                           const svBitVecVal *mode_i, const svBitVecVal *iv_i,
+                           const svBitVecVal *key_len_i,
+                           const svBitVecVal *key_i, const svBitVecVal *data_i,
+                           svBitVecVal *data_o);
+
+/**
+ * Perform encryption/decryption of an entire message using OpenSSL/BoringSSL.
+ *
+ * @param  impl_i    Select reference impl.: 0 = C model, 1 = OpenSSL/BoringSSL
+ * @param  op_i      Operation: 0 = encrypt, 1 = decrypt
+ * @param  mode_i    Cipher mode: 3'b001 = ECB, 3'b010 = CBC, 3'b100 = CTR
+ * @param  iv_i      Initialization vector: 1D array of words (2D packed array
+ *                   in SV)
+ * @param  key_len_i Key length: 3'b001 = 128b, 3'b010 = 192b, 3'b100 = 256b
+ * @param  key_i     Full input key, 1D array of words (2D packed array in SV)
+ * @param  data_i    Input data, 1D byte array (open array in SV)
+ * @param  data_o    Output data, 1D byte array (open array in SV)
+ */
+void c_dpi_aes_crypt_message(unsigned char impl_i, unsigned char op_i,
+                             const svBitVecVal *mode_i, const svBitVecVal *iv_i,
+                             const svBitVecVal *key_len_i,
+                             const svBitVecVal *key_i,
+                             const svOpenArrayHandle data_i,
+                             svOpenArrayHandle data_o);
 
 /**
  * Perform sub bytes operation for forward/inverse cipher operation.
@@ -90,7 +111,7 @@
 void aes_data_put(svBitVecVal *data_o, unsigned char *data);
 
 /**
- * Get unpacked data block from simulation.
+ * Get unpacked data from simulation.
  *
  * @param  data_i Input data from simulation
  * @return Pointer to data copied to memory, 0 in case of an error
@@ -98,7 +119,7 @@
 unsigned char *aes_data_unpacked_get(const svOpenArrayHandle data_i);
 
 /**
- * Write unpacked data block to simulation and free the source buffer
+ * Write unpacked data to simulation and free the source buffer
  * afterwards.
  *
  * @param  data_o Output data for simulation
@@ -125,4 +146,4 @@
 #ifdef __cplusplus
 }  // extern "C"
 #endif
-#endif  // _AES_MODEL_DPI_H_
+#endif  // OPENTITAN_HW_IP_AES_DV_AES_MODEL_DPI_AES_MODEL_DPI_H_
diff --git a/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi_pkg.sv b/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi_pkg.sv
index a8343c4..15ca238 100644
--- a/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi_pkg.sv
+++ b/hw/ip/aes/dv/aes_model_dpi/aes_model_dpi_pkg.sv
@@ -6,40 +6,51 @@
   import aes_pkg::*;
 
   // DPI-C imports
-  import "DPI-C" context function void c_dpi_aes_crypt(
-    input  bit                impl_i,
-    input  bit                op_i,
-    input  bit          [2:0] mode_i,
+  import "DPI-C" context function void c_dpi_aes_crypt_block(
+    input  bit                impl_i,    // 0 = C model, 1 = OpenSSL/BoringSSL
+    input  bit                op_i,      // 0 = encrypt, 1 = decrypt
+    input  bit          [2:0] mode_i,    // 3'b001 = ECB, 3'b010 = CBC, 3'b100 = CTR
     input  bit[3:0][3:0][7:0] iv_i,
-    input  bit          [2:0] key_len_i,
+    input  bit          [2:0] key_len_i, // 3'b001 = 128b, 3'b010 = 192b, 3'b100 = 256b
     input  bit    [7:0][31:0] key_i,
     input  bit[3:0][3:0][7:0] data_i,
     output bit[3:0][3:0][7:0] data_o
   );
 
+  import "DPI-C" context function void c_dpi_aes_crypt_message(
+    input  bit              impl_i,    // 0 = C model, 1 = OpenSSL/BoringSSL
+    input  bit              op_i,      // 0 = encrypt, 1 = decrypt
+    input  bit        [2:0] mode_i,    // 3'b001 = ECB, 3'b010 = CBC, 3'b100 = CTR
+    input  bit  [3:0][31:0] iv_i,
+    input  bit        [2:0] key_len_i, // 3'b001 = 128b, 3'b010 = 192b, 3'b100 = 256b
+    input  bit  [7:0][31:0] key_i,
+    input  bit        [7:0] data_i[],
+    output bit        [7:0] data_o[]
+  );
+
   import "DPI-C" context function void c_dpi_aes_sub_bytes(
-    input  bit                op_i,
+    input  bit                op_i, // 0 = encrypt, 1 = decrypt
     input  bit[3:0][3:0][7:0] data_i,
     output bit[3:0][3:0][7:0] data_o
   );
 
   import "DPI-C" context function void c_dpi_aes_shift_rows(
-    input  bit                op_i,
+    input  bit                op_i, // 0 = encrypt, 1 = decrypt
     input  bit[3:0][3:0][7:0] data_i,
     output bit[3:0][3:0][7:0] data_o
   );
 
   import "DPI-C" context function void c_dpi_aes_mix_columns(
-    input  bit                op_i,
+    input  bit                op_i, // 0 = encrypt, 1 = decrypt
     input  bit[3:0][3:0][7:0] data_i,
     output bit[3:0][3:0][7:0] data_o
   );
 
   import "DPI-C" context function void c_dpi_aes_key_expand(
-    input  bit            op_i,
+    input  bit            op_i,      // 0 = encrypt, 1 = decrypt
     input  bit      [7:0] rcon_i,
     input  bit      [3:0] round_i,
-    input  bit      [2:0] key_len_i,
+    input  bit      [2:0] key_len_i, // 3'b001 = 128b, 3'b010 = 192b, 3'b100 = 256b
     input  bit[7:0][31:0] key_i,
     output bit[7:0][31:0] key_o
   );
@@ -47,12 +58,12 @@
   // wrapper function that converts from register format (4x32bit)
   // to the 4x4x8 format of the c functions and back
   // this ensures that RTL and refence models have same input and output format.
-  function automatic void sv_dpi_aes_crypt(
-    input  bit             impl_i,
-    input  bit             op_i,
-    input  bit       [2:0] mode_i,
+  function automatic void sv_dpi_aes_crypt_block(
+    input  bit             impl_i,    // 0 = C model, 1 = OpenSSL/BoringSSL
+    input  bit             op_i,      // 0 = encrypt, 1 = decrypt
+    input  bit       [2:0] mode_i,    // 3'b001 = ECB, 3'b010 = CBC, 3'b100 = CTR
     input  bit [3:0][31:0] iv_i,
-    input  bit       [2:0] key_len_i,
+    input  bit       [2:0] key_len_i, // 3'b001 = 128b, 3'b010 = 192b, 3'b100 = 256b
     input  bit [7:0][31:0] key_i,
     input  bit [3:0][31:0] data_i,
     output bit [3:0][31:0] data_o);
@@ -60,7 +71,7 @@
     bit [3:0][3:0][7:0] iv_in, data_in, data_out;
     data_in = aes_transpose(data_i);
     iv_in   = aes_transpose(iv_i);
-    c_dpi_aes_crypt(impl_i, op_i, mode_i, iv_in, key_len_i, key_i, data_in, data_out);
+    c_dpi_aes_crypt_block(impl_i, op_i, mode_i, iv_in, key_len_i, key_i, data_in, data_out);
     data_o  = aes_transpose(data_out);
     return;
   endfunction
diff --git a/hw/ip/aes/dv/env/aes_scoreboard.sv b/hw/ip/aes/dv/env/aes_scoreboard.sv
index bc37080..6735f4e 100644
--- a/hw/ip/aes/dv/env/aes_scoreboard.sv
+++ b/hw/ip/aes/dv/env/aes_scoreboard.sv
@@ -192,7 +192,7 @@
       ref_fifo.get(c_item );
       `uvm_info(`gfn, $sformatf("\n\t ----| GOT item "), UVM_HIGH)
 
-      sv_dpi_aes_crypt(1'b0, c_item.operation, 3'b001, 128'b0, c_item.key_size, c_item.key,
+      sv_dpi_aes_crypt_block(1'b0, c_item.operation, 3'b001, 128'b0, c_item.key_size, c_item.key,
           c_item.data_in, c_item.data_out);
       `uvm_info(`gfn, $sformatf("\n\t ----| printing C MODEL %s", c_item.convert2string() )
           , UVM_HIGH)