diff --git a/hw/ip/aes/aes.core b/hw/ip/aes/aes.core index 5c19412af405f..aad7700452f3c 100644 --- a/hw/ip/aes/aes.core +++ b/hw/ip/aes/aes.core @@ -8,6 +8,7 @@ filesets: files_rtl: depend: - lowrisc:prim:all + - lowrisc:prim:gf_mult - lowrisc:prim:lc_sync - lowrisc:prim:lfsr - lowrisc:prim:sparse_fsm @@ -22,6 +23,7 @@ filesets: - rtl/aes_pkg.sv - rtl/aes_reg_top.sv - rtl/aes_ctrl_reg_shadowed.sv + - rtl/aes_ctrl_gcm_reg_shadowed.sv - rtl/aes_core.sv - rtl/aes_ctr.sv - rtl/aes_ctr_fsm.sv @@ -52,6 +54,7 @@ filesets: - rtl/aes_key_expand.sv - rtl/aes_prng_clearing.sv - rtl/aes_prng_masking.sv + - rtl/aes_ghash.sv - rtl/aes.sv file_type: systemVerilogSource diff --git a/hw/ip/aes/data/aes.hjson b/hw/ip/aes/data/aes.hjson index 457b594e7f291..c21467cf77eb5 100644 --- a/hw/ip/aes/data/aes.hjson +++ b/hw/ip/aes/data/aes.hjson @@ -22,10 +22,10 @@ dv_doc: "../doc/dv", hw_checklist: "../doc/checklist", sw_checklist: "/sw/device/lib/dif/dif_aes", - version: "1.0.1", + version: "1.1.0", life_stage: "L1", - design_stage: "D2S", - verification_stage: "V2S", + design_stage: "D1", + verification_stage: "V1", dif_stage: "S2", clocking: [ {clock: "clk_i", reset: "rst_ni", idle: "idle_o", primary: true}, @@ -275,6 +275,10 @@ name: "AES.MODE.CTR", desc: "AES can perform both operations (encryption and decryption) in Counter (CTR) Mode for all three key lengths (128/192/256)." } + { + name: "AES.MODE.GCM", + desc: "AES can perform both operations (encryption and decryption) in Galois/Counter Mode (GCM) for all three key lengths (128/192/256)." + } { name: "AES.KEY.SIDELOAD", desc: "The key can be loaded directly from the keymgr." @@ -631,11 +635,11 @@ } { bits: "7:2", name: "MODE", - resval: "0x20", + resval: "0x3f", hwaccess: "hrw", desc: ''' 6-bit one-hot field to select AES block cipher mode. - Invalid input values, i.e., values with multiple bits set and value 6'b00_0000, are mapped to AES_NONE (6'b10_0000). + Invalid input values, i.e., values with multiple bits set and value 6'b00_0000, are mapped to AES_NONE (6'b11_1111). ''' enum: [ { value: "1", @@ -669,9 +673,16 @@ ''' }, { value: "32", + name: "AES_GCM", + desc: ''' + 6'b10_0000: Galois/Counter Mode (GCM). + In case support for GCM has been disabled at compile time, setting this value results in configuring AES_NONE (6'b11_1111). + ''' + }, + { value: "63", name: "AES_NONE", desc: ''' - 6'b10_0000: Invalid input values, i.e., value with multiple bits set and value 6'b00_0000, are mapped to AES_NONE. + 6'b11_1111: Invalid input values, i.e., value with multiple bits set, value 6'b00_0000, and value 6'b10_0000 in case GCM is not supported (because disabled at compile time) are mapped to AES_NONE. ''' } ] @@ -966,5 +977,109 @@ } ] }, + { name: "CTRL_GCM_SHADOWED", + desc: ''' + Galois/Counter Mode (GCM) Control Register. + + Can only be updated when the AES unit is idle. + If the AES unit is non-idle, writes to this register are ignored. + This register is shadowed, meaning two subsequent write operations are required to change its content. + If the two write operations try to set a different value, a recoverable alert is triggered (See Status Register). + A read operation clears the internal phase tracking: The next write operation is always considered a first write operation of an update sequence. + ''' + swaccess: "rw", + hwaccess: "hrw", + hwext: "true", + hwqe: "true", + shadowed: "true", + update_err_alert: "recov_ctrl_update_err", + storage_err_alert: "fatal_fault", + fields: [ + { bits: "5:0", + name: "PHASE", + resval: "0x01", + hwaccess: "hrw", + desc: ''' + 6-bit one-hot field to select the phase of the Galois/Counter Mode (GCM) of operation. + Invalid input values, i.e., values with multiple bits set and value 6'b00_0000, are mapped to GCM_INIT (6'b00_0001). + In case support for GCM has been disabled at compile time, this field is not writable and always reads as GCM_INIT (6'b00_0001). + ''' + enum: [ + { value: "1", + name: "GCM_INIT", + desc: ''' + 6'b00_0001: Initialization phase. + Software configures the Initial Key and IV Registers. + The hardware then performs two encryption operations to 1) generate the hash subkey and 2) encrypt the IV. + Both results are loaded into the internal GHASH block. + Once the AES unit is idle again, software can advance to the next phase. + Possible next phases are GCM_RESTORE, GCM_AAD, GCM_TEXT, and GCM_TAG. + Invalid input values, i.e., values with multiple bits set, value 6'b00_0000, and all other values in case GCM is not supported (because disabled at compile time) are mapped to GCM_INIT. + ''' + }, + { value: "2", + name: "GCM_RESTORE", + desc: ''' + 6'b00_0010: Optional context restore phase. + Software configures the IV and Input Data Registers to restore a previously saved AES-GCM context (IV and GHASH state). + Possible next phases are GCM_INIT, GCM_AAD and GCM_TEXT. + ''' + }, + { value: "4", + name: "GCM_AAD", + desc: ''' + 6'b00_0100: Optional additional authenticated data phase (AAD). + Software inputs the AAD via Input Data Registers block by block via Input Data Registers. + Possible next phases are GCM_INIT, GCM_TEXT, GCM_SAVE and GCM_TAG. + ''' + }, + { value: "8", + name: "GCM_TEXT", + desc: ''' + 6'b00_1000: Optional plaintext/ciphertext phase. + Software inputs the plaintext/ciphertext block by block via Input Data Registers, and retrieves the output ciphertext/plaintext block by block via Output Data Registers. + Possible next phases are GCM_INIT, GCM_SAVE and GCM_TAG. + ''' + }, + { value: "16", + name: "GCM_SAVE", + desc: ''' + 6'b01_0000: Optional context save phase. + The hardware stops accepting inputs. + Software reads the current GHASH state and IV via Output Data and IV Registers, respectively. + The only possible next phase is GCM_INIT. + ''' + }, + { value: "32", + name: "GCM_TAG", + desc: ''' + 6'b10_0000: Tag phase. + Software inputs a single data block containing the length of the AAD and the ciphertext via Input Data Registers. + The hardware then produces the final integrity tag. + Once the AES unit is idle again, software reads the final integrity tag via Data Out Registers. + The only possible next phase is GCM_INIT. + ''' + }, + ] + tags: ["shadowed_reg_path:u_aes_core.u_ctrl_gcm_reg_shadowed.u_ctrl_gcm_reg_shadowed_phase"] + } + { bits: "10:6", + name: "NUM_VALID_BYTES", + resval: "16", + hwaccess: "hrw", + desc: ''' + Number of valid bytes of the current input block. + Only the last block in the GCM_AAD and GCM_TEXT phases are expected to have not all bytes marked as valid. + For all other blocks, the number of valid bytes should be set to 16. + Invalid input values, i.e., the value 5'b0_0000, and all other values different from 5'b1_0000 in case GCM is not supported (because disabled at compile time) are mapped to 5'b1_0000. + ''' + tags: ["shadowed_reg_path:u_aes_core.u_ctrl_gcm_reg_shadowed.u_ctrl_gcm_reg_shadowed_num_valid_bytes"] + } + ] + tags: [// Updated by the HW. + // Updates based on writes to this reg (reset test possible). + // Exclude from write-read checks. + "excl:CsrNonInitTests:CsrExclWriteCheck"] + }, ], } diff --git a/hw/ip/aes/doc/registers.md b/hw/ip/aes/doc/registers.md index 07d250d2a9880..c1d5752018293 100644 --- a/hw/ip/aes/doc/registers.md +++ b/hw/ip/aes/doc/registers.md @@ -15,42 +15,43 @@ For a detailed overview of the register tool, please refer to the [Register Tool ## Summary -| Name | Offset | Length | Description | -|:----------------------------------------------|:---------|---------:|:-----------------------------------------| -| aes.[`ALERT_TEST`](#alert_test) | 0x0 | 4 | Alert Test Register | -| aes.[`KEY_SHARE0_0`](#key_share0) | 0x4 | 4 | Initial Key Registers Share 0. | -| aes.[`KEY_SHARE0_1`](#key_share0) | 0x8 | 4 | Initial Key Registers Share 0. | -| aes.[`KEY_SHARE0_2`](#key_share0) | 0xc | 4 | Initial Key Registers Share 0. | -| aes.[`KEY_SHARE0_3`](#key_share0) | 0x10 | 4 | Initial Key Registers Share 0. | -| aes.[`KEY_SHARE0_4`](#key_share0) | 0x14 | 4 | Initial Key Registers Share 0. | -| aes.[`KEY_SHARE0_5`](#key_share0) | 0x18 | 4 | Initial Key Registers Share 0. | -| aes.[`KEY_SHARE0_6`](#key_share0) | 0x1c | 4 | Initial Key Registers Share 0. | -| aes.[`KEY_SHARE0_7`](#key_share0) | 0x20 | 4 | Initial Key Registers Share 0. | -| aes.[`KEY_SHARE1_0`](#key_share1) | 0x24 | 4 | Initial Key Registers Share 1. | -| aes.[`KEY_SHARE1_1`](#key_share1) | 0x28 | 4 | Initial Key Registers Share 1. | -| aes.[`KEY_SHARE1_2`](#key_share1) | 0x2c | 4 | Initial Key Registers Share 1. | -| aes.[`KEY_SHARE1_3`](#key_share1) | 0x30 | 4 | Initial Key Registers Share 1. | -| aes.[`KEY_SHARE1_4`](#key_share1) | 0x34 | 4 | Initial Key Registers Share 1. | -| aes.[`KEY_SHARE1_5`](#key_share1) | 0x38 | 4 | Initial Key Registers Share 1. | -| aes.[`KEY_SHARE1_6`](#key_share1) | 0x3c | 4 | Initial Key Registers Share 1. | -| aes.[`KEY_SHARE1_7`](#key_share1) | 0x40 | 4 | Initial Key Registers Share 1. | -| aes.[`IV_0`](#iv) | 0x44 | 4 | Initialization Vector Registers. | -| aes.[`IV_1`](#iv) | 0x48 | 4 | Initialization Vector Registers. | -| aes.[`IV_2`](#iv) | 0x4c | 4 | Initialization Vector Registers. | -| aes.[`IV_3`](#iv) | 0x50 | 4 | Initialization Vector Registers. | -| aes.[`DATA_IN_0`](#data_in) | 0x54 | 4 | Input Data Registers. | -| aes.[`DATA_IN_1`](#data_in) | 0x58 | 4 | Input Data Registers. | -| aes.[`DATA_IN_2`](#data_in) | 0x5c | 4 | Input Data Registers. | -| aes.[`DATA_IN_3`](#data_in) | 0x60 | 4 | Input Data Registers. | -| aes.[`DATA_OUT_0`](#data_out) | 0x64 | 4 | Output Data Register. | -| aes.[`DATA_OUT_1`](#data_out) | 0x68 | 4 | Output Data Register. | -| aes.[`DATA_OUT_2`](#data_out) | 0x6c | 4 | Output Data Register. | -| aes.[`DATA_OUT_3`](#data_out) | 0x70 | 4 | Output Data Register. | -| aes.[`CTRL_SHADOWED`](#ctrl_shadowed) | 0x74 | 4 | Control Register. | -| aes.[`CTRL_AUX_SHADOWED`](#ctrl_aux_shadowed) | 0x78 | 4 | Auxiliary Control Register. | -| aes.[`CTRL_AUX_REGWEN`](#ctrl_aux_regwen) | 0x7c | 4 | Lock bit for Auxiliary Control Register. | -| aes.[`TRIGGER`](#trigger) | 0x80 | 4 | Trigger Register. | -| aes.[`STATUS`](#status) | 0x84 | 4 | Status Register | +| Name | Offset | Length | Description | +|:----------------------------------------------|:---------|---------:|:--------------------------------------------| +| aes.[`ALERT_TEST`](#alert_test) | 0x0 | 4 | Alert Test Register | +| aes.[`KEY_SHARE0_0`](#key_share0) | 0x4 | 4 | Initial Key Registers Share 0. | +| aes.[`KEY_SHARE0_1`](#key_share0) | 0x8 | 4 | Initial Key Registers Share 0. | +| aes.[`KEY_SHARE0_2`](#key_share0) | 0xc | 4 | Initial Key Registers Share 0. | +| aes.[`KEY_SHARE0_3`](#key_share0) | 0x10 | 4 | Initial Key Registers Share 0. | +| aes.[`KEY_SHARE0_4`](#key_share0) | 0x14 | 4 | Initial Key Registers Share 0. | +| aes.[`KEY_SHARE0_5`](#key_share0) | 0x18 | 4 | Initial Key Registers Share 0. | +| aes.[`KEY_SHARE0_6`](#key_share0) | 0x1c | 4 | Initial Key Registers Share 0. | +| aes.[`KEY_SHARE0_7`](#key_share0) | 0x20 | 4 | Initial Key Registers Share 0. | +| aes.[`KEY_SHARE1_0`](#key_share1) | 0x24 | 4 | Initial Key Registers Share 1. | +| aes.[`KEY_SHARE1_1`](#key_share1) | 0x28 | 4 | Initial Key Registers Share 1. | +| aes.[`KEY_SHARE1_2`](#key_share1) | 0x2c | 4 | Initial Key Registers Share 1. | +| aes.[`KEY_SHARE1_3`](#key_share1) | 0x30 | 4 | Initial Key Registers Share 1. | +| aes.[`KEY_SHARE1_4`](#key_share1) | 0x34 | 4 | Initial Key Registers Share 1. | +| aes.[`KEY_SHARE1_5`](#key_share1) | 0x38 | 4 | Initial Key Registers Share 1. | +| aes.[`KEY_SHARE1_6`](#key_share1) | 0x3c | 4 | Initial Key Registers Share 1. | +| aes.[`KEY_SHARE1_7`](#key_share1) | 0x40 | 4 | Initial Key Registers Share 1. | +| aes.[`IV_0`](#iv) | 0x44 | 4 | Initialization Vector Registers. | +| aes.[`IV_1`](#iv) | 0x48 | 4 | Initialization Vector Registers. | +| aes.[`IV_2`](#iv) | 0x4c | 4 | Initialization Vector Registers. | +| aes.[`IV_3`](#iv) | 0x50 | 4 | Initialization Vector Registers. | +| aes.[`DATA_IN_0`](#data_in) | 0x54 | 4 | Input Data Registers. | +| aes.[`DATA_IN_1`](#data_in) | 0x58 | 4 | Input Data Registers. | +| aes.[`DATA_IN_2`](#data_in) | 0x5c | 4 | Input Data Registers. | +| aes.[`DATA_IN_3`](#data_in) | 0x60 | 4 | Input Data Registers. | +| aes.[`DATA_OUT_0`](#data_out) | 0x64 | 4 | Output Data Register. | +| aes.[`DATA_OUT_1`](#data_out) | 0x68 | 4 | Output Data Register. | +| aes.[`DATA_OUT_2`](#data_out) | 0x6c | 4 | Output Data Register. | +| aes.[`DATA_OUT_3`](#data_out) | 0x70 | 4 | Output Data Register. | +| aes.[`CTRL_SHADOWED`](#ctrl_shadowed) | 0x74 | 4 | Control Register. | +| aes.[`CTRL_AUX_SHADOWED`](#ctrl_aux_shadowed) | 0x78 | 4 | Auxiliary Control Register. | +| aes.[`CTRL_AUX_REGWEN`](#ctrl_aux_regwen) | 0x7c | 4 | Lock bit for Auxiliary Control Register. | +| aes.[`TRIGGER`](#trigger) | 0x80 | 4 | Trigger Register. | +| aes.[`STATUS`](#status) | 0x84 | 4 | Status Register | +| aes.[`CTRL_GCM_SHADOWED`](#ctrl_gcm_shadowed) | 0x88 | 4 | Galois/Counter Mode (GCM) Control Register. | ## ALERT_TEST Alert Test Register @@ -254,7 +255,7 @@ Any write operation to this register will clear the status tracking required for A write to the Control Register is considered the start of a new message. Hence, software needs to provide new key, IV and input data afterwards. - Offset: `0x74` -- Reset default: `0x1181` +- Reset default: `0x11fd` - Reset mask: `0xffff` ### Fields @@ -270,7 +271,7 @@ Hence, software needs to provide new key, IV and input data afterwards. | 14:12 | rw | 0x1 | [PRNG_RESEED_RATE](#ctrl_shadowed--prng_reseed_rate) | | 11 | rw | 0x0 | [SIDELOAD](#ctrl_shadowed--sideload) | | 10:8 | rw | 0x1 | [KEY_LEN](#ctrl_shadowed--key_len) | -| 7:2 | rw | 0x20 | [MODE](#ctrl_shadowed--mode) | +| 7:2 | rw | 0x3f | [MODE](#ctrl_shadowed--mode) | | 1:0 | rw | 0x1 | [OPERATION](#ctrl_shadowed--operation) | ### CTRL_SHADOWED . MANUAL_OPERATION @@ -310,16 +311,17 @@ Other values are reserved. ### CTRL_SHADOWED . MODE 6-bit one-hot field to select AES block cipher mode. -Invalid input values, i.e., values with multiple bits set and value 6'b00_0000, are mapped to AES_NONE (6'b10_0000). - -| Value | Name | Description | -|:--------|:---------|:-------------------------------------------------------------------------------------------------------------------| -| 0x01 | AES_ECB | 6'b00_0001: Electronic Codebook (ECB) mode. | -| 0x02 | AES_CBC | 6'b00_0010: Cipher Block Chaining (CBC) mode. | -| 0x04 | AES_CFB | 6'b00_0100: Cipher Feedback (CFB) mode. | -| 0x08 | AES_OFB | 6'b00_1000: Output Feedback (OFB) mode. | -| 0x10 | AES_CTR | 6'b01_0000: Counter (CTR) mode. | -| 0x20 | AES_NONE | 6'b10_0000: Invalid input values, i.e., value with multiple bits set and value 6'b00_0000, are mapped to AES_NONE. | +Invalid input values, i.e., values with multiple bits set and value 6'b00_0000, are mapped to AES_NONE (6'b11_1111). + +| Value | Name | Description | +|:--------|:---------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x01 | AES_ECB | 6'b00_0001: Electronic Codebook (ECB) mode. | +| 0x02 | AES_CBC | 6'b00_0010: Cipher Block Chaining (CBC) mode. | +| 0x04 | AES_CFB | 6'b00_0100: Cipher Feedback (CFB) mode. | +| 0x08 | AES_OFB | 6'b00_1000: Output Feedback (OFB) mode. | +| 0x10 | AES_CTR | 6'b01_0000: Counter (CTR) mode. | +| 0x20 | AES_GCM | 6'b10_0000: Galois/Counter Mode (GCM). In case support for GCM has been disabled at compile time, setting this value results in configuring AES_NONE (6'b11_1111). | +| 0x3f | AES_NONE | 6'b11_1111: Invalid input values, i.e., value with multiple bits set, value 6'b00_0000, and value 6'b10_0000 in case GCM is not supported (because disabled at compile time) are mapped to AES_NONE. | Other values are reserved. @@ -488,5 +490,51 @@ The AES unit is idle (1) or busy (0). This flag is `0` if one of the following operations is currently running: i) encryption/decryption, ii) register clearing or iii) PRNG reseeding. This flag is also `0` if an encryption/decryption is running but the AES unit is stalled. +## CTRL_GCM_SHADOWED +Galois/Counter Mode (GCM) Control Register. + +Can only be updated when the AES unit is idle. +If the AES unit is non-idle, writes to this register are ignored. +This register is shadowed, meaning two subsequent write operations are required to change its content. +If the two write operations try to set a different value, a recoverable alert is triggered (See Status Register). +A read operation clears the internal phase tracking: The next write operation is always considered a first write operation of an update sequence. +- Offset: `0x88` +- Reset default: `0x401` +- Reset mask: `0x7ff` + +### Fields + +```wavejson +{"reg": [{"name": "PHASE", "bits": 6, "attr": ["rw"], "rotate": 0}, {"name": "NUM_VALID_BYTES", "bits": 5, "attr": ["rw"], "rotate": -90}, {"bits": 21}], "config": {"lanes": 1, "fontsize": 10, "vspace": 170}} +``` + +| Bits | Type | Reset | Name | +|:------:|:------:|:-------:|:-------------------------------------------------------| +| 31:11 | | | Reserved | +| 10:6 | rw | 0x10 | [NUM_VALID_BYTES](#ctrl_gcm_shadowed--num_valid_bytes) | +| 5:0 | rw | 0x1 | [PHASE](#ctrl_gcm_shadowed--phase) | + +### CTRL_GCM_SHADOWED . NUM_VALID_BYTES +Number of valid bytes of the current input block. +Only the last block in the GCM_AAD and GCM_TEXT phases are expected to have not all bytes marked as valid. +For all other blocks, the number of valid bytes should be set to 16. +Invalid input values, i.e., the value 5'b0_0000, and all other values different from 5'b1_0000 in case GCM is not supported (because disabled at compile time) are mapped to 5'b1_0000. + +### CTRL_GCM_SHADOWED . PHASE +6-bit one-hot field to select the phase of the Galois/Counter Mode (GCM) of operation. +Invalid input values, i.e., values with multiple bits set and value 6'b00_0000, are mapped to GCM_INIT (6'b00_0001). +In case support for GCM has been disabled at compile time, this field is not writable and always reads as GCM_INIT (6'b00_0001). + +| Value | Name | Description | +|:--------|:------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| 0x01 | GCM_INIT | 6'b00_0001: Initialization phase. Software configures the Initial Key and IV Registers. The hardware then performs two encryption operations to 1) generate the hash subkey and 2) encrypt the IV. Both results are loaded into the internal GHASH block. Once the AES unit is idle again, software can advance to the next phase. Possible next phases are GCM_RESTORE, GCM_AAD, GCM_TEXT, and GCM_TAG. Invalid input values, i.e., values with multiple bits set, value 6'b00_0000, and all other values in case GCM is not supported (because disabled at compile time) are mapped to GCM_INIT. | +| 0x02 | GCM_RESTORE | 6'b00_0010: Optional context restore phase. Software configures the IV and Input Data Registers to restore a previously saved AES-GCM context (IV and GHASH state). Possible next phases are GCM_INIT, GCM_AAD and GCM_TEXT. | +| 0x04 | GCM_AAD | 6'b00_0100: Optional additional authenticated data phase (AAD). Software inputs the AAD via Input Data Registers block by block via Input Data Registers. Possible next phases are GCM_INIT, GCM_TEXT, GCM_SAVE and GCM_TAG. | +| 0x08 | GCM_TEXT | 6'b00_1000: Optional plaintext/ciphertext phase. Software inputs the plaintext/ciphertext block by block via Input Data Registers, and retrieves the output ciphertext/plaintext block by block via Output Data Registers. Possible next phases are GCM_INIT, GCM_SAVE and GCM_TAG. | +| 0x10 | GCM_SAVE | 6'b01_0000: Optional context save phase. The hardware stops accepting inputs. Software reads the current GHASH state and IV via Output Data and IV Registers, respectively. The only possible next phase is GCM_INIT. | +| 0x20 | GCM_TAG | 6'b10_0000: Tag phase. Software inputs a single data block containing the length of the AAD and the ciphertext via Input Data Registers. The hardware then produces the final integrity tag. Once the AES unit is idle again, software reads the final integrity tag via Data Out Registers. The only possible next phase is GCM_INIT. | + +Other values are reserved. + diff --git a/hw/ip/aes/dv/env/seq_lib/aes_control_fi_vseq.sv b/hw/ip/aes/dv/env/seq_lib/aes_control_fi_vseq.sv index 10795a62beccc..ecaf7a5c88bf5 100644 --- a/hw/ip/aes/dv/env/seq_lib/aes_control_fi_vseq.sv +++ b/hw/ip/aes/dv/env/seq_lib/aes_control_fi_vseq.sv @@ -53,10 +53,10 @@ class aes_control_fi_vseq extends aes_base_vseq; `uvm_fatal(`gfn, $sformatf("Randomization failed")) end `DV_CHECK_STD_RANDOMIZE_FATAL(await_state) - if (await_state inside {aes_pkg::CTRL_PRNG_UPDATE, aes_pkg::CTRL_CLEAR_I, + if (await_state inside {aes_pkg::CTRL_GHASH_READY, aes_pkg::CTRL_CLEAR_I, aes_pkg::CTRL_CLEAR_CO}) begin - // The PRNG Update state and the Clear states are difficult to hit with a random - // delay. This writes the clear register to bring the FSM to the PRNG Update and then + // The GHASH Ready state and the Clear states are difficult to hit with a random + // delay. This writes the clear register to bring the FSM to the GHASH Ready and then // the Clear states, and it waits until the FSM has reached the required state. clear_regs('{dataout: 1'b1, key_iv_data_in: 1'b1, default: 1'b0}); `DV_WAIT(cfg.aes_control_fi_vif[if_num].aes_ctrl_cs == await_state) diff --git a/hw/ip/aes/dv/env/seq_lib/aes_core_fi_vseq.sv b/hw/ip/aes/dv/env/seq_lib/aes_core_fi_vseq.sv index ac08c30f291ae..9bbb8f71924fd 100644 --- a/hw/ip/aes/dv/env/seq_lib/aes_core_fi_vseq.sv +++ b/hw/ip/aes/dv/env/seq_lib/aes_core_fi_vseq.sv @@ -57,10 +57,10 @@ class aes_core_fi_vseq extends aes_base_vseq; end // Wait and apply force. - if (await_state inside {aes_pkg::CTRL_PRNG_UPDATE, aes_pkg::CTRL_CLEAR_I, + if (await_state inside {aes_pkg::CTRL_GHASH_READY, aes_pkg::CTRL_CLEAR_I, aes_pkg::CTRL_CLEAR_CO}) begin - // The PRNG Update state and the Clear states are difficult to hit with a random - // delay. This writes the clear register to bring the FSM to the PRNG Update and then + // The GHASH Ready state and the Clear states are difficult to hit with a random + // delay. This writes the clear register to bring the FSM to the GHASH ready and then // the Clear states, and it waits until the FSM has reached the required state. clear_regs('{dataout: 1'b1, key_iv_data_in: 1'b1, default: 1'b0}); `DV_WAIT(cfg.aes_core_fi_vif.aes_ctrl_cs == await_state) diff --git a/hw/ip/aes/lint/aes.waiver b/hw/ip/aes/lint/aes.waiver index fe9c5072dc2e2..8fd6b952a38b9 100644 --- a/hw/ip/aes/lint/aes.waiver +++ b/hw/ip/aes/lint/aes.waiver @@ -68,3 +68,9 @@ waive -rules {RESET_USE} -location {aes_ctr.sv} -regexp {'rst_ni' is connected t waive -rules {ONE_BRANCH} -location {aes_sel_buf_chk.sv} -regexp {unique case statement has only one branch} \ -comment "check for legal combinations only, assert error signal otherwise" + +waive -rules {CLOCK_USE} -location {aes_core.sv} -regexp {clk_i' is connected to 'aes_ctrl_gcm_reg_shadowed' port} \ + -comment "when disabling GCM support, no clock is used inside aes_ctrl_gcm_reg_shadowed" + +waive -rules {RESET_USE} -location {aes_core.sv} -regexp {rst_[a-z]*_*ni' is connected to 'aes_ctrl_gcm_reg_shadowed' port} \ + -comment "when disabling GCM support, no resets are used inside aes_ctrl_gcm_reg_shadowed" diff --git a/hw/ip/aes/pre_syn/syn_yosys.sh b/hw/ip/aes/pre_syn/syn_yosys.sh index 8027434422ec0..d263d56a9f078 100755 --- a/hw/ip/aes/pre_syn/syn_yosys.sh +++ b/hw/ip/aes/pre_syn/syn_yosys.sh @@ -70,6 +70,7 @@ OT_DEP_SOURCES=( "$LR_SYNTH_SRC_DIR"/../prim/rtl/prim_cdc_rand_delay.sv "$LR_SYNTH_SRC_DIR"/../prim/rtl/prim_reg_we_check.sv "$LR_SYNTH_SRC_DIR"/../prim/rtl/prim_onehot_check.sv + "$LR_SYNTH_SRC_DIR"/../prim/rtl/prim_gf_mult.sv "$LR_SYNTH_SRC_DIR"/../prim_generic/rtl/prim_generic_flop.sv "$LR_SYNTH_SRC_DIR"/../prim_generic/rtl/prim_generic_flop_2sync.sv "$LR_SYNTH_SRC_DIR"/../prim_xilinx/rtl/prim_xilinx_flop.sv diff --git a/hw/ip/aes/rtl/aes.sv b/hw/ip/aes/rtl/aes.sv index b104713abeded..9f66d1380cd75 100644 --- a/hw/ip/aes/rtl/aes.sv +++ b/hw/ip/aes/rtl/aes.sv @@ -11,6 +11,7 @@ module aes import aes_reg_pkg::*; #( parameter bit AES192Enable = 1, // Can be 0 (disable), or 1 (enable). + parameter bit AESGCMEnable = 1, // Can be 0 (disable), or 1 (enable). parameter bit SecMasking = 1, // Can be 0 (no masking), or // 1 (first-order masking) of the cipher // core. Masking requires the use of a @@ -174,6 +175,7 @@ module aes // AES core aes_core #( .AES192Enable ( AES192Enable ), + .AESGCMEnable ( AESGCMEnable ), .SecMasking ( SecMasking ), .SecSBoxImpl ( SecSBoxImpl ), .SecStartTriggerDelay ( SecStartTriggerDelay ), diff --git a/hw/ip/aes/rtl/aes_control.sv b/hw/ip/aes/rtl/aes_control.sv index fe752436890df..f84f161419d72 100644 --- a/hw/ip/aes/rtl/aes_control.sv +++ b/hw/ip/aes/rtl/aes_control.sv @@ -12,6 +12,7 @@ module aes_control import aes_pkg::*; import aes_reg_pkg::*; #( + parameter bit AESGCMEnable = 0, parameter bit SecMasking = 0, parameter int unsigned SecStartTriggerDelay = 0 ) ( @@ -30,6 +31,9 @@ module aes_control input prs_rate_e prng_reseed_rate_i, input logic manual_operation_i, input logic key_touch_forces_reseed_i, + input logic ctrl_gcm_qe_i, + output logic ctrl_gcm_we_o, + input gcm_phase_e gcm_phase_i, input logic start_i, input logic key_iv_data_in_clear_i, input logic data_out_clear_i, @@ -47,6 +51,7 @@ module aes_control input logic [NumRegsData-1:0] data_in_qe_i, input logic [NumRegsData-1:0] data_out_re_i, output logic data_in_we_o, + output data_out_sel_e data_out_sel_o, output sp2v_e data_out_we_o, // Previous input data register @@ -59,6 +64,7 @@ module aes_control output add_so_sel_e add_state_out_sel_o, // Counter + output sp2v_e ctr_inc32_o, output sp2v_e ctr_incr_o, input sp2v_e ctr_ready_i, input sp2v_e [NumSlicesCtr-1:0] ctr_we_i, @@ -79,6 +85,13 @@ module aes_control output logic cipher_data_out_clear_o, input logic cipher_data_out_clear_i, + // GHASH control and sync + output sp2v_e ghash_in_valid_o, + input sp2v_e ghash_in_ready_i, + input sp2v_e ghash_out_valid_i, + output sp2v_e ghash_out_ready_o, + output sp2v_e ghash_load_hash_subkey_o, + // Initial key registers output key_init_sel_e key_init_sel_o, output sp2v_e [NumRegsKey-1:0] key_init_we_o [NumSharesKey], @@ -88,8 +101,7 @@ module aes_control output sp2v_e [NumSlicesCtr-1:0] iv_we_o, // Pseudo-random number generator interface - output logic prng_data_req_o, - input logic prng_data_ack_i, + output logic prng_update_o, output logic prng_reseed_req_o, input logic prng_reseed_ack_i, @@ -153,6 +165,8 @@ module aes_control sp2v_e cipher_out_valid; sp2v_e cipher_crypt; sp2v_e cipher_dec_key_gen; + sp2v_e ghash_in_ready; + sp2v_e ghash_out_valid; logic mux_sel_err; logic mr_err; logic sp_enc_err; @@ -161,6 +175,7 @@ module aes_control // signals to the single-rail FSMs. logic [Sp2VWidth-1:0] sp_data_out_we; logic [Sp2VWidth-1:0] sp_data_in_prev_we; + logic [Sp2VWidth-1:0] sp_ctr_inc32; logic [Sp2VWidth-1:0] sp_ctr_incr; logic [Sp2VWidth-1:0] sp_ctr_ready; logic [Sp2VWidth-1:0] sp_cipher_in_valid; @@ -171,11 +186,18 @@ module aes_control logic [Sp2VWidth-1:0] sp_out_cipher_crypt; logic [Sp2VWidth-1:0] sp_in_cipher_dec_key_gen; logic [Sp2VWidth-1:0] sp_out_cipher_dec_key_gen; + logic [Sp2VWidth-1:0] sp_ghash_in_valid; + logic [Sp2VWidth-1:0] sp_ghash_in_ready; + logic [Sp2VWidth-1:0] sp_ghash_out_valid; + logic [Sp2VWidth-1:0] sp_ghash_out_ready; + logic [Sp2VWidth-1:0] sp_ghash_load_hash_subkey; // Multi-rail signals. These are outputs of the single-rail FSMs and need combining. logic [Sp2VWidth-1:0] mr_ctrl_we; + logic [Sp2VWidth-1:0] mr_ctrl_gcm_we; logic [Sp2VWidth-1:0] mr_alert; logic [Sp2VWidth-1:0] mr_data_in_we; + data_out_sel_e [Sp2VWidth-1:0] mr_data_out_sel; dip_sel_e [Sp2VWidth-1:0] mr_data_in_prev_sel; si_sel_e [Sp2VWidth-1:0] mr_state_in_sel; add_si_sel_e [Sp2VWidth-1:0] mr_add_state_in_sel; @@ -185,7 +207,7 @@ module aes_control logic [Sp2VWidth-1:0] mr_cipher_data_out_clear; key_init_sel_e [Sp2VWidth-1:0] mr_key_init_sel; iv_sel_e [Sp2VWidth-1:0] mr_iv_sel; - logic [Sp2VWidth-1:0] mr_prng_data_req; + logic [Sp2VWidth-1:0] mr_prng_update; logic [Sp2VWidth-1:0] mr_prng_reseed_req; logic [Sp2VWidth-1:0] mr_start_we; logic [Sp2VWidth-1:0] mr_key_iv_data_in_clear_we; @@ -240,6 +262,8 @@ module aes_control assign sp_cipher_out_valid = {cipher_out_valid}; assign sp_in_cipher_crypt = {cipher_crypt}; assign sp_in_cipher_dec_key_gen = {cipher_dec_key_gen}; + assign sp_ghash_in_ready = {ghash_in_ready}; + assign sp_ghash_out_valid = {ghash_out_valid}; // SEC_CM: MAIN.FSM.REDUN // For every bit in the Sp2V signals, one separate rail is instantiated. The inputs and outputs @@ -247,7 +271,8 @@ module aes_control for (genvar i = 0; i < Sp2VWidth; i++) begin : gen_fsm if (SP2V_LOGIC_HIGH[i] == 1'b1) begin : gen_fsm_p aes_control_fsm_p #( - .SecMasking ( SecMasking ) + .AESGCMEnable ( AESGCMEnable ), + .SecMasking ( SecMasking ) ) u_aes_control_fsm_i ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -263,6 +288,9 @@ module aes_control .prng_reseed_rate_i ( prng_reseed_rate_i ), .manual_operation_i ( manual_operation_i ), .key_touch_forces_reseed_i ( key_touch_forces_reseed_i ), + .ctrl_gcm_qe_i ( ctrl_gcm_qe_i ), + .ctrl_gcm_we_o ( mr_ctrl_gcm_we[i] ), // AND-combine + .gcm_phase_i ( gcm_phase_i ), .start_i ( start_trigger ), .key_iv_data_in_clear_i ( key_iv_data_in_clear_i ), .data_out_clear_i ( data_out_clear_i ), @@ -279,6 +307,7 @@ module aes_control .data_in_qe_i ( data_in_qe_i ), .data_out_re_i ( data_out_re_i ), .data_in_we_o ( mr_data_in_we[i] ), // AND-combine + .data_out_sel_o ( mr_data_out_sel[i] ), // OR-combine .data_out_we_o ( sp_data_out_we[i] ), // Sparsified .data_in_prev_sel_o ( mr_data_in_prev_sel[i] ), // OR-combine @@ -288,6 +317,7 @@ module aes_control .add_state_in_sel_o ( mr_add_state_in_sel[i] ), // OR-combine .add_state_out_sel_o ( mr_add_state_out_sel[i] ), // OR-combine + .ctr_inc32_o ( sp_ctr_inc32[i] ), // Sparsified .ctr_incr_o ( sp_ctr_incr[i] ), // Sparsified .ctr_ready_i ( sp_ctr_ready[i] ), // Sparsified .ctr_we_i ( int_ctr_we[i] ), // Sparsified @@ -307,14 +337,19 @@ module aes_control .cipher_data_out_clear_o ( mr_cipher_data_out_clear[i] ), // OR-combine .cipher_data_out_clear_i ( cipher_data_out_clear_i ), + .ghash_in_valid_o ( sp_ghash_in_valid[i] ), // Sparsified + .ghash_in_ready_i ( sp_ghash_in_ready[i] ), // Sparsified + .ghash_out_valid_i ( sp_ghash_out_valid[i] ), // Sparsified + .ghash_out_ready_o ( sp_ghash_out_ready[i] ), // Sparsified + .ghash_load_hash_subkey_o ( sp_ghash_load_hash_subkey[i] ), // Sparsified + .key_init_sel_o ( mr_key_init_sel[i] ), // OR-combine .key_init_we_o ( int_key_init_we[i] ), // Sparsified .iv_sel_o ( mr_iv_sel[i] ), // OR-combine .iv_we_o ( int_iv_we[i] ), // Sparsified - .prng_data_req_o ( mr_prng_data_req[i] ), // OR-combine - .prng_data_ack_i ( prng_data_ack_i ), + .prng_update_o ( mr_prng_update[i] ), // OR-combine .prng_reseed_req_o ( mr_prng_reseed_req[i] ), // OR-combine .prng_reseed_ack_i ( prng_reseed_ack_i ), @@ -338,7 +373,8 @@ module aes_control ); end else begin : gen_fsm_n aes_control_fsm_n #( - .SecMasking ( SecMasking ) + .AESGCMEnable ( AESGCMEnable ), + .SecMasking ( SecMasking ) ) u_aes_control_fsm_i ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -354,6 +390,9 @@ module aes_control .prng_reseed_rate_i ( prng_reseed_rate_i ), .manual_operation_i ( manual_operation_i ), .key_touch_forces_reseed_i ( key_touch_forces_reseed_i ), + .ctrl_gcm_qe_i ( ctrl_gcm_qe_i ), + .ctrl_gcm_we_o ( mr_ctrl_gcm_we[i] ), // AND-combine + .gcm_phase_i ( gcm_phase_i ), .start_i ( start_trigger ), .key_iv_data_in_clear_i ( key_iv_data_in_clear_i ), .data_out_clear_i ( data_out_clear_i ), @@ -370,6 +409,7 @@ module aes_control .data_in_qe_i ( data_in_qe_i ), .data_out_re_i ( data_out_re_i ), .data_in_we_o ( mr_data_in_we[i] ), // AND-combine + .data_out_sel_o ( mr_data_out_sel[i] ), // OR-combine .data_out_we_no ( sp_data_out_we[i] ), // Sparsified .data_in_prev_sel_o ( mr_data_in_prev_sel[i] ), // OR-combine @@ -379,6 +419,7 @@ module aes_control .add_state_in_sel_o ( mr_add_state_in_sel[i] ), // OR-combine .add_state_out_sel_o ( mr_add_state_out_sel[i] ), // OR-combine + .ctr_inc32_no ( sp_ctr_inc32[i] ), // Sparsified .ctr_incr_no ( sp_ctr_incr[i] ), // Sparsified .ctr_ready_ni ( sp_ctr_ready[i] ), // Sparsified .ctr_we_ni ( int_ctr_we[i] ), // Sparsified @@ -398,14 +439,19 @@ module aes_control .cipher_data_out_clear_o ( mr_cipher_data_out_clear[i] ), // OR-combine .cipher_data_out_clear_i ( cipher_data_out_clear_i ), + .ghash_in_valid_no ( sp_ghash_in_valid[i] ), // Sparsified + .ghash_in_ready_ni ( sp_ghash_in_ready[i] ), // Sparsified + .ghash_out_valid_ni ( sp_ghash_out_valid[i] ), // Sparsified + .ghash_out_ready_no ( sp_ghash_out_ready[i] ), // Sparsified + .ghash_load_hash_subkey_no ( sp_ghash_load_hash_subkey[i] ), // Sparsified + .key_init_sel_o ( mr_key_init_sel[i] ), // OR-combine .key_init_we_no ( int_key_init_we[i] ), // Sparsified .iv_sel_o ( mr_iv_sel[i] ), // OR-combine .iv_we_no ( int_iv_we[i] ), // Sparsified - .prng_data_req_o ( mr_prng_data_req[i] ), // OR-combine - .prng_data_ack_i ( prng_data_ack_i ), + .prng_update_o ( mr_prng_update[i] ), // OR-combine .prng_reseed_req_o ( mr_prng_reseed_req[i] ), // OR-combine .prng_reseed_ack_i ( prng_reseed_ack_i ), @@ -431,13 +477,17 @@ module aes_control end // Convert sparsified outputs to sp2v_e type. - assign data_out_we_o = sp2v_e'(sp_data_out_we); - assign data_in_prev_we_o = sp2v_e'(sp_data_in_prev_we); - assign ctr_incr_o = sp2v_e'(sp_ctr_incr); - assign cipher_in_valid_o = sp2v_e'(sp_cipher_in_valid); - assign cipher_out_ready_o = sp2v_e'(sp_cipher_out_ready); - assign cipher_crypt_o = sp2v_e'(sp_out_cipher_crypt); - assign cipher_dec_key_gen_o = sp2v_e'(sp_out_cipher_dec_key_gen); + assign data_out_we_o = sp2v_e'(sp_data_out_we); + assign data_in_prev_we_o = sp2v_e'(sp_data_in_prev_we); + assign ctr_inc32_o = sp2v_e'(sp_ctr_inc32); + assign ctr_incr_o = sp2v_e'(sp_ctr_incr); + assign cipher_in_valid_o = sp2v_e'(sp_cipher_in_valid); + assign cipher_out_ready_o = sp2v_e'(sp_cipher_out_ready); + assign cipher_crypt_o = sp2v_e'(sp_out_cipher_crypt); + assign cipher_dec_key_gen_o = sp2v_e'(sp_out_cipher_dec_key_gen); + assign ghash_in_valid_o = sp2v_e'(sp_ghash_in_valid); + assign ghash_out_ready_o = sp2v_e'(sp_ghash_out_ready); + assign ghash_load_hash_subkey_o = sp2v_e'(sp_ghash_load_hash_subkey); // Combine single-bit FSM outputs. // OR: One bit is sufficient to drive the corresponding output bit high. @@ -445,7 +495,7 @@ module aes_control assign cipher_prng_reseed_o = |mr_cipher_prng_reseed; assign cipher_key_clear_o = |mr_cipher_key_clear; assign cipher_data_out_clear_o = |mr_cipher_data_out_clear; - assign prng_data_req_o = |mr_prng_data_req; + assign prng_update_o = |mr_prng_update; assign prng_reseed_req_o = |mr_prng_reseed_req; assign start_we_o = |mr_start_we; assign prng_reseed_o = |mr_prng_reseed; @@ -453,6 +503,7 @@ module aes_control // AND: Only if all bits are high, the corresponding action should be triggered. assign ctrl_we_o = &mr_ctrl_we; + assign ctrl_gcm_we_o = &mr_ctrl_gcm_we; assign data_in_we_o = &mr_data_in_we; assign key_iv_data_in_clear_we_o = &mr_key_iv_data_in_clear_we; assign data_out_clear_we_o = &mr_data_out_clear_we; @@ -472,6 +523,7 @@ module aes_control // - An invalid encoding results: A downstream checker will fire, see mux_sel_err_i. // - A valid encoding results: The outputs are compared below to cover this case, see mr_err; always_comb begin : combine_sparse_signals + data_out_sel_o = data_out_sel_e'({DataOutSelWidth{1'b0}}); data_in_prev_sel_o = dip_sel_e'({DIPSelWidth{1'b0}}); state_in_sel_o = si_sel_e'({SISelWidth{1'b0}}); add_state_in_sel_o = add_si_sel_e'({AddSISelWidth{1'b0}}); @@ -481,6 +533,7 @@ module aes_control mr_err = 1'b0; for (int i = 0; i < Sp2VWidth; i++) begin + data_out_sel_o = data_out_sel_e'({data_out_sel_o} | {mr_data_out_sel[i]}); data_in_prev_sel_o = dip_sel_e'({data_in_prev_sel_o} | {mr_data_in_prev_sel[i]}); state_in_sel_o = si_sel_e'({state_in_sel_o} | {mr_state_in_sel[i]}); add_state_in_sel_o = add_si_sel_e'({add_state_in_sel_o} | {mr_add_state_in_sel[i]}); @@ -490,7 +543,8 @@ module aes_control end for (int i = 0; i < Sp2VWidth; i++) begin - if (data_in_prev_sel_o != mr_data_in_prev_sel[i] || + if (data_out_sel_o != mr_data_out_sel[i] || + data_in_prev_sel_o != mr_data_in_prev_sel[i] || state_in_sel_o != mr_state_in_sel[i] || add_state_in_sel_o != mr_add_state_in_sel[i] || add_state_out_sel_o != mr_add_state_out_sel[i] || @@ -521,7 +575,7 @@ module aes_control // data_out_we_o and other write-enable signals to prevent any data from being released. // We use vectors of sparsely encoded signals to reduce code duplication. - localparam int unsigned NumSp2VSig = 5 + NumSlicesCtr; + localparam int unsigned NumSp2VSig = 7 + NumSlicesCtr; sp2v_e [NumSp2VSig-1:0] sp2v_sig; sp2v_e [NumSp2VSig-1:0] sp2v_sig_chk; logic [NumSp2VSig-1:0][Sp2VWidth-1:0] sp2v_sig_chk_raw; @@ -531,9 +585,11 @@ module aes_control assign sp2v_sig[1] = cipher_out_valid_i; assign sp2v_sig[2] = cipher_crypt_i; assign sp2v_sig[3] = cipher_dec_key_gen_i; - assign sp2v_sig[4] = ctr_ready_i; + assign sp2v_sig[4] = ghash_in_ready_i; + assign sp2v_sig[5] = ghash_out_valid_i; + assign sp2v_sig[6] = ctr_ready_i; for (genvar i = 0; i < NumSlicesCtr; i++) begin : gen_use_ctr_we_i - assign sp2v_sig[5+i] = ctr_we_i[i]; + assign sp2v_sig[7+i] = ctr_we_i[i]; end // All signals inside sp2v_sig are driven and consumed by multi-rail FSMs. @@ -559,9 +615,11 @@ module aes_control assign cipher_out_valid = sp2v_sig_chk[1]; assign cipher_crypt = sp2v_sig_chk[2]; assign cipher_dec_key_gen = sp2v_sig_chk[3]; - assign ctr_ready = sp2v_sig_chk[4]; + assign ghash_in_ready = sp2v_sig_chk[4]; + assign ghash_out_valid = sp2v_sig_chk[5]; + assign ctr_ready = sp2v_sig_chk[6]; for (genvar i = 0; i < NumSlicesCtr; i++) begin : gen_ctr_we - assign ctr_we[i] = sp2v_sig_chk[5+i]; + assign ctr_we[i] = sp2v_sig_chk[7+i]; end // Collect encoding errors. diff --git a/hw/ip/aes/rtl/aes_control_fsm.sv b/hw/ip/aes/rtl/aes_control_fsm.sv index 0d60b390058b0..27056e92960fb 100644 --- a/hw/ip/aes/rtl/aes_control_fsm.sv +++ b/hw/ip/aes/rtl/aes_control_fsm.sv @@ -13,7 +13,8 @@ module aes_control_fsm import aes_pkg::*; import aes_reg_pkg::*; #( - parameter bit SecMasking = 0 + parameter bit AESGCMEnable = 0, + parameter bit SecMasking = 0 ) ( input logic clk_i, input logic rst_ni, @@ -30,6 +31,9 @@ module aes_control_fsm input prs_rate_e prng_reseed_rate_i, input logic manual_operation_i, input logic key_touch_forces_reseed_i, + input logic ctrl_gcm_qe_i, + output logic ctrl_gcm_we_o, + input gcm_phase_e gcm_phase_i, input logic start_i, input logic key_iv_data_in_clear_i, input logic data_out_clear_i, @@ -47,11 +51,12 @@ module aes_control_fsm input logic [NumRegsData-1:0] data_in_qe_i, input logic [NumRegsData-1:0] data_out_re_i, output logic data_in_we_o, - output logic data_out_we_o, // Sparsify + output data_out_sel_e data_out_sel_o, + output logic data_out_we_o, // Sparsify // Previous input data register output dip_sel_e data_in_prev_sel_o, - output logic data_in_prev_we_o, // Sparsify + output logic data_in_prev_we_o, // Sparsify // Cipher I/O muxes output si_sel_e state_in_sel_o, @@ -59,19 +64,20 @@ module aes_control_fsm output add_so_sel_e add_state_out_sel_o, // Counter - output logic ctr_incr_o, // Sparsify - input logic ctr_ready_i, // Sparsify - input logic [NumSlicesCtr-1:0] ctr_we_i, // Sparsify + output logic ctr_inc32_o, // Sparsify + output logic ctr_incr_o, // Sparsify + input logic ctr_ready_i, // Sparsify + input logic [NumSlicesCtr-1:0] ctr_we_i, // Sparsify // Cipher core control and sync - output logic cipher_in_valid_o, // Sparsify - input logic cipher_in_ready_i, // Sparsify - input logic cipher_out_valid_i, // Sparsify - output logic cipher_out_ready_o, // Sparsify - output logic cipher_crypt_o, // Sparsify - input logic cipher_crypt_i, // Sparsify - output logic cipher_dec_key_gen_o, // Sparsify - input logic cipher_dec_key_gen_i, // Sparsify + output logic cipher_in_valid_o, // Sparsify + input logic cipher_in_ready_i, // Sparsify + input logic cipher_out_valid_i, // Sparsify + output logic cipher_out_ready_o, // Sparsify + output logic cipher_crypt_o, // Sparsify + input logic cipher_crypt_i, // Sparsify + output logic cipher_dec_key_gen_o, // Sparsify + input logic cipher_dec_key_gen_i, // Sparsify output logic cipher_prng_reseed_o, input logic cipher_prng_reseed_i, output logic cipher_key_clear_o, @@ -79,17 +85,23 @@ module aes_control_fsm output logic cipher_data_out_clear_o, input logic cipher_data_out_clear_i, + // GHASH control and sync + output logic ghash_in_valid_o, // Sparsify + input logic ghash_in_ready_i, // Sparsify + input logic ghash_out_valid_i, // Sparsify + output logic ghash_out_ready_o, // Sparsify + output logic ghash_load_hash_subkey_o, // Sparsify + // Initial key registers output key_init_sel_e key_init_sel_o, - output logic [NumSharesKey-1:0][NumRegsKey-1:0] key_init_we_o, // Sparsify + output logic [NumSharesKey-1:0][NumRegsKey-1:0] key_init_we_o, // Sparsify // IV registers output iv_sel_e iv_sel_o, - output logic [NumSlicesCtr-1:0] iv_we_o, // Sparsify + output logic [NumSlicesCtr-1:0] iv_we_o, // Sparsify // Pseudo-random number generator interface - output logic prng_data_req_o, - input logic prng_data_ack_i, + output logic prng_update_o, output logic prng_reseed_req_o, input logic prng_reseed_ack_i, @@ -173,6 +185,21 @@ module aes_control_fsm logic input_ready; logic input_ready_we; + logic gcm_init, gcm_restore, gcm_aad, gcm_txt, gcm_save, gcm_tag; + logic start_common_gcm, start_gcm; + logic start_gcm_init, start_gcm_hash_subkey, start_gcm_s; + logic start_gcm_restore, start_gcm_aad, start_gcm_txt, start_gcm_save; + logic start_gcm_tag; + logic doing_gcm_hsk, doing_gcm_s, doing_gcm_txt; + logic hash_subkey_ready_d, hash_subkey_ready_q; + logic s_ready_d, s_ready_q; + logic doing_gcm_restore_d, doing_gcm_restore_q; + logic doing_gcm_aad_d, doing_gcm_aad_q; + logic doing_gcm_tag_d, doing_gcm_tag_q; + logic doing_gcm_save_d, doing_gcm_save_q; + logic ghash_out_done; + logic ghash_idle; + logic block_ctr_expr; logic block_ctr_decr; @@ -203,6 +230,41 @@ module aes_control_fsm assign start_ofb = (mode_i == AES_OFB) & iv_ready; assign start_ctr = (mode_i == AES_CTR) & iv_ready & ctr_ready_i; + // For the initial GCM phase, we need key and IV but then encrypt two blocks. The input data + // is not required. + assign gcm_init = (mode_i == AES_GCM) & (gcm_phase_i == GCM_INIT); + assign start_common_gcm = key_init_ready & (sideload_i ? key_sideload_valid_i : 1'b1); + assign start_gcm_hash_subkey = gcm_init & ~hash_subkey_ready_q & iv_ready & ctr_ready_i; + assign start_gcm_s = gcm_init & ~s_ready_q & iv_ready & ctr_ready_i; + assign start_gcm_init = (start_gcm_hash_subkey | start_gcm_s) & start_common_gcm; + + // For the restore phase of GCM, we need key, IV and input data. + assign gcm_restore = (mode_i == AES_GCM) & (gcm_phase_i == GCM_RESTORE); + assign start_gcm_restore = gcm_restore & iv_ready & ctr_ready_i & data_in_new & start_common_gcm; + + // For the AAD and ciphertext/plaintext phases of GCM, we need key, IV and input data. But for + // the AAD phase, only the input data is really used and marked as used. + assign gcm_aad = (mode_i == AES_GCM) & (gcm_phase_i == GCM_AAD); + assign gcm_txt = (mode_i == AES_GCM) & (gcm_phase_i == GCM_TEXT); + assign start_gcm_aad = gcm_aad & iv_ready & ctr_ready_i & data_in_new; + assign start_gcm_txt = gcm_txt & iv_ready & ctr_ready_i & data_in_new; + assign start_gcm = start_gcm_aad | start_gcm_txt; + + // For the save phase of GCM, we need no inputs. + assign gcm_save = (mode_i == AES_GCM) & (gcm_phase_i == GCM_SAVE); + assign start_gcm_save = gcm_save & hash_subkey_ready_q & s_ready_q; + + // For the tag phase of GCM, we just need the input data. + assign gcm_tag = (mode_i == AES_GCM) & (gcm_phase_i == GCM_TAG); + assign start_gcm_tag = gcm_tag & data_in_new; + + // The GHASH block is idle whenever it's ready to receive inputs and where not about to start + // a GCM related operation. + assign ghash_idle = ghash_in_ready_i & ~(start_gcm_init | start_gcm | start_gcm_tag); + + // In GCM, the counter performs inc32() instead of inc128(), i.e., the counter wraps at 32 bits. + assign ctr_inc32_o = (mode_i == AES_GCM); + // If set to start manually, we just wait for the trigger. Otherwise, check common as well as // mode-specific start conditions. assign start = cfg_valid & no_alert & @@ -213,7 +275,12 @@ module aes_control_fsm start_cbc | start_cfb | start_ofb | - start_ctr) & start_common)); + start_ctr | + start_gcm) & start_common) | + start_gcm_init | + start_gcm_restore | + start_gcm_save | + start_gcm_tag); // If not set to overwrite data, we wait for any previous output data to be read. data_out_read // synchronously clears output_valid_q, unless new output data is written in the exact same @@ -233,6 +300,9 @@ module aes_control_fsm assign doing_cfb_dec = (mode_i == AES_CFB && op_i == AES_DEC) & crypt; assign doing_ofb = (mode_i == AES_OFB) & crypt; assign doing_ctr = (mode_i == AES_CTR) & crypt; + assign doing_gcm_hsk = gcm_init & ~hash_subkey_ready_q & crypt; + assign doing_gcm_s = gcm_init & hash_subkey_ready_q & crypt; + assign doing_gcm_txt = gcm_txt & crypt; // FSM always_comb begin : aes_ctrl_fsm @@ -259,6 +329,12 @@ module aes_control_fsm cipher_key_clear_o = 1'b0; cipher_data_out_clear_o = 1'b0; + // GHASH control + ghash_in_valid_o = 1'b0; + ghash_out_ready_o = 1'b0; + ghash_out_done = 1'b0; + ghash_load_hash_subkey_o = ~hash_subkey_ready_q; + // Initial key registers key_init_sel_o = sideload_i ? KEY_INIT_KEYMGR : KEY_INIT_INPUT; key_init_we_o = {NumSharesKey * NumRegsKey{1'b0}}; @@ -267,14 +343,15 @@ module aes_control_fsm iv_sel_o = IV_INPUT; iv_we_o = {NumSlicesCtr{1'b0}}; - // Control register - ctrl_we_o = 1'b0; + // Control registers + ctrl_we_o = 1'b0; + ctrl_gcm_we_o = 1'b0; // Alert alert_o = 1'b0; // Pseudo-random number generator control - prng_data_req_o = 1'b0; + prng_update_o = 1'b0; prng_reseed_req_o = 1'b0; // Trigger register control @@ -290,9 +367,10 @@ module aes_control_fsm stall_we = 1'b0; // Key, data I/O register control - data_in_load = 1'b0; - data_in_we_o = 1'b0; - data_out_we_o = 1'b0; + data_in_load = 1'b0; + data_in_we_o = 1'b0; + data_out_sel_o = DATA_OUT_CIPHER; + data_out_we_o = 1'b0; // Register status tracker control key_init_clear = 1'b0; @@ -306,9 +384,15 @@ module aes_control_fsm block_ctr_decr = 1'b0; // FSM - aes_ctrl_ns = aes_ctrl_cs; - start_core = 1'b0; - prng_reseed_done_d = prng_reseed_done_q | prng_reseed_ack_i; + aes_ctrl_ns = aes_ctrl_cs; + start_core = 1'b0; + prng_reseed_done_d = prng_reseed_done_q | prng_reseed_ack_i; + hash_subkey_ready_d = hash_subkey_ready_q; + s_ready_d = s_ready_q; + doing_gcm_restore_d = doing_gcm_restore_q; + doing_gcm_aad_d = doing_gcm_aad_q; + doing_gcm_tag_d = doing_gcm_tag_q; + doing_gcm_save_d = doing_gcm_save_q; unique case (aes_ctrl_cs) @@ -319,8 +403,9 @@ module aes_control_fsm // Update status register. A write to the main control register (if sideload is enabled) // or writing the last key register can initiate a PRNG reseed operation via trigger // register. To avoid that subsequent writes to the main control, key or IV registers - // collide with the start of the reseed operation, de-assert the idle bit. - idle = ~(start_core | (prng_reseed_o & prng_reseed_we_o)); + // collide with the start of the reseed operation, de-assert the idle bit. The GHASH block + // may still be busy while the cipher core is actually idle. + idle = ~(start_core | (prng_reseed_o & prng_reseed_we_o)) & ghash_idle; idle_we = 1'b1; // Clear the start trigger when seeing invalid configurations or performing automatic @@ -333,9 +418,11 @@ module aes_control_fsm key_init_we_o = sideload_i ? {NumSharesKey * NumRegsKey{key_sideload}} : key_init_qe_i; iv_we_o = iv_qe; - // Updates to the control register are only allowed if the core is not about to start and - // there isn't a storage error. A storage error is unrecoverable and requires a reset. - ctrl_we_o = !ctrl_err_storage_i ? ctrl_qe_i : 1'b0; + // Updates to the main and GCM control registers are only allowed if the core is not + // about to start and there isn't a storage error. A storage error is unrecoverable and + // requires a reset. + ctrl_we_o = !ctrl_err_storage_i ? ctrl_qe_i : 1'b0; + ctrl_gcm_we_o = !ctrl_err_storage_i ? ctrl_gcm_qe_i : 1'b0; // Control register updates clear all register status trackers. key_init_clear = ctrl_we_o; @@ -361,8 +448,56 @@ module aes_control_fsm end end else if (key_iv_data_in_clear_i || data_out_clear_i) begin - // To clear registers, we must first request fresh pseudo-random data. - aes_ctrl_ns = CTRL_PRNG_UPDATE; + // To clear registers, we update the PRNG and then wait for the GHASH block. + prng_update_o = 1'b1; + + // 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_iv_data_in_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 = CTRL_GHASH_READY; + end + + end else if (start_gcm_restore) begin + // We don't have work for the AES cipher core but for the GHASH block only. + // Mask the input data and load it into the GHASH block. + state_in_sel_o = SI_DATA; + add_state_in_sel_o = ADD_SI_ZERO; + + // Perform handshake and advance to the loading state where the input data is marked as + // used. + ghash_in_valid_o = 1'b1; + if (ghash_in_ready_i) begin + doing_gcm_restore_d = 1'b1; + start_we = 1'b1; + aes_ctrl_ns = CTRL_LOAD; + end + + end else if (start_gcm_aad || start_gcm_tag) begin + // We don't have work for the AES cipher core but for the GHASH block only. Load the + // input data into the previous input data register such that it can be loaded into + // the GHASH block in unmasked form. + data_in_prev_sel_o = DIP_DATA_IN; + data_in_prev_we_o = 1'b1; + + // Advance to the loading state where the input data is marked as used. + doing_gcm_aad_d = start_gcm_aad; + doing_gcm_tag_d = start_gcm_tag; + start_we = 1'b1; + aes_ctrl_ns = CTRL_LOAD; + + end else if (start_gcm_save) begin + // We don't have work for the AES cipher core but for the GHASH block only. Update the + // PRNG (to clear the internal state after saving it) and advance. + prng_update_o = 1'b1; + doing_gcm_save_d = 1'b1; + start_we = 1'b1; + aes_ctrl_ns = CTRL_GHASH_READY; end else if (start) begin // Signal that we want to start encryption/decryption. @@ -380,25 +515,32 @@ module aes_control_fsm doing_cfb_enc ? DIP_DATA_IN : doing_cfb_dec ? DIP_DATA_IN : doing_ofb ? DIP_DATA_IN : - doing_ctr ? DIP_DATA_IN : DIP_CLEAR; + doing_ctr ? DIP_DATA_IN : + doing_gcm_txt ? DIP_DATA_IN : DIP_CLEAR; data_in_prev_we_o = doing_cbc_dec | doing_cfb_enc | doing_cfb_dec | doing_ofb | - doing_ctr; + doing_ctr | + doing_gcm_txt; // State input mux control state_in_sel_o = doing_cfb_enc ? SI_ZERO : doing_cfb_dec ? SI_ZERO : doing_ofb ? SI_ZERO : - doing_ctr ? SI_ZERO : SI_DATA; + doing_ctr ? SI_ZERO : + doing_gcm_hsk ? SI_ZERO : + doing_gcm_s ? SI_ZERO : + doing_gcm_txt ? SI_ZERO : SI_DATA; - // State input additon mux control + // State input addition mux control add_state_in_sel_o = doing_cbc_enc ? ADD_SI_IV : doing_cfb_enc ? ADD_SI_IV : doing_cfb_dec ? ADD_SI_IV : doing_ofb ? ADD_SI_IV : - doing_ctr ? ADD_SI_IV : ADD_SI_ZERO; + doing_ctr ? ADD_SI_IV : + doing_gcm_s ? ADD_SI_IV : + doing_gcm_txt ? ADD_SI_IV : ADD_SI_ZERO; // We have work for the cipher core, perform handshake. cipher_in_valid_o = 1'b1; @@ -420,53 +562,95 @@ module aes_control_fsm doing_cfb_enc | doing_cfb_dec | doing_ofb | - doing_ctr); + doing_ctr | + doing_gcm_hsk | + doing_gcm_s | + doing_gcm_txt); data_in_load = ~cipher_dec_key_gen_i; // Trigger counter increment. - ctr_incr_o = doing_ctr; + ctr_incr_o = doing_ctr | doing_gcm_hsk | doing_gcm_s | doing_gcm_txt; // Unless we are just generating the start key for decryption, we must update the PRNG. - aes_ctrl_ns = !cipher_dec_key_gen_i ? CTRL_PRNG_UPDATE : CTRL_FINISH; - end - - CTRL_PRNG_UPDATE: begin // Fresh pseudo-random data is used to: // - clear the state in the final cipher round, // - clear any other registers in the CLEAR_I/CO states. + prng_update_o = !cipher_dec_key_gen_i; + // Unless we are just generating the start key for decryption, we may need to interface + // the GHASH block as well + aes_ctrl_ns = !cipher_dec_key_gen_i ? CTRL_GHASH_READY : CTRL_FINISH; + end + + CTRL_GHASH_READY: begin // 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 : {NumSlicesCtr{1'b0}}; + iv_sel_o = doing_ctr || + doing_gcm_hsk || + doing_gcm_s || + doing_gcm_txt ? IV_CTR : IV_INPUT; + iv_we_o = doing_ctr || + doing_gcm_hsk || + doing_gcm_s || + doing_gcm_txt ? ctr_we_i : {NumSlicesCtr{1'b0}}; + + // Ongoing encryption/decryption operations have the highest priority. The clear triggers + // might for example have become asserted after the handshake with the cipher core. + if (cipher_crypt_i) begin + if (doing_gcm_hsk || doing_gcm_s || doing_gcm_txt) begin + // We actually have some work for the GHASH block. Make sure it's ready before we move. + // We send the valid in a following clock cycle. Doing this check here, allows to + // decouple the valid from the ready. + if (ghash_in_ready_i) begin + aes_ctrl_ns = CTRL_FINISH; + end + end else begin + // We're not actually using the GHASH block and don't need to check it's status. + aes_ctrl_ns = CTRL_FINISH; + end - // Request fresh pseudo-random data, perform handshake. - prng_data_req_o = 1'b1; - if (prng_data_ack_i) begin + end else if (doing_gcm_restore_q) begin + // We're actually already done: The input data has already been forwarded to the GHASH + // block. We ended up here because we had to go through the loading state. + doing_gcm_restore_d = 1'b0; + aes_ctrl_ns = CTRL_IDLE; + + end else if (doing_gcm_aad_q) begin + // Pass the AAD to the GHASH block. We're done after the input handshake. + ghash_in_valid_o = 1'b1; + if (ghash_in_ready_i) begin + doing_gcm_aad_d = 1'b0; + aes_ctrl_ns = CTRL_IDLE; + end - // 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 + end else if (doing_gcm_save_q) begin + // Perform the handshake with the GHASH block and then wait for the GHASH block to output + // the state. + ghash_in_valid_o = 1'b1; + if (ghash_in_ready_i) begin aes_ctrl_ns = CTRL_FINISH; + end - end else if (key_iv_data_in_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_iv_data_in_clear_i; - cipher_data_out_clear_o = data_out_clear_i; + end else if (doing_gcm_tag_q) begin + // Pass the AAD and text length to the GHASH block and wait for the final authentication + // tag afterwards. + ghash_in_valid_o = 1'b1; + if (ghash_in_ready_i) begin + aes_ctrl_ns = CTRL_FINISH; + end - // We have work for the cipher core, perform handshake. - cipher_in_valid_o = 1'b1; - if (cipher_in_ready_i) begin - aes_ctrl_ns = CTRL_CLEAR_I; - end - end else begin - // Another write to the trigger register must have overwritten the trigger bits that - // actually caused us to enter this state. Just return. - aes_ctrl_ns = CTRL_IDLE; - end // cipher_crypt_i - end // prng_data_ack_i + end else if (key_iv_data_in_clear_i || data_out_clear_i) begin + // We actually have some work for the GHASH block. Make sure it's ready before we move. + // We send the valid in a following clock cycle. Doing this check here, allows to + // decouple the valid from the ready. + if (ghash_in_ready_i) begin + aes_ctrl_ns = CTRL_CLEAR_I; + end + end else begin + // Another write to the trigger register must have overwritten the trigger bits that + // actually caused us to enter this state. Just return. + aes_ctrl_ns = CTRL_IDLE; + end end CTRL_PRNG_RESEED: begin @@ -504,6 +688,32 @@ module aes_control_fsm block_ctr_decr = 1'b1; aes_ctrl_ns = CTRL_IDLE; end + end else if (doing_gcm_save_q || doing_gcm_tag_q) begin + // Handshake signals: We are ready once the output data registers can be written. Don't + // let data propagate in case of mux selector or sparsely encoded signals taking on + // invalid values. + ghash_out_ready_o = finish; + ghash_out_done = finish & ghash_out_valid_i & + ~mux_sel_err_i & ~sp_enc_err_i & ~cipher_op_err; + + // Signal if the GHASH block is stalled (because previous output has not yet been read). + stall = ~finish & ghash_out_valid_i; + stall_we = 1'b1; + + // Forward the GHASH output instead of the cipher core output. + data_out_sel_o = DATA_OUT_GHASH; + + // Proceed upon successful handshake. Mark hash subkey and s as not ready, the GHASH + // block clears those registers after the handshake. + if (ghash_out_done) begin + doing_gcm_save_d = 1'b0; + doing_gcm_tag_d = 1'b0; + hash_subkey_ready_d = 1'b0; + s_ready_d = 1'b0; + data_out_we_o = 1'b1; + aes_ctrl_ns = CTRL_IDLE; + end + end else begin // Handshake signals: We are ready once the output data registers can be written. Don't // let data propagate in case of mux selector or sparsely encoded signals taking on @@ -521,23 +731,31 @@ module aes_control_fsm doing_cfb_enc ? ADD_SO_DIP : doing_cfb_dec ? ADD_SO_DIP : doing_ofb ? ADD_SO_DIP : - doing_ctr ? ADD_SO_DIP : ADD_SO_ZERO; + doing_ctr ? ADD_SO_DIP : + doing_gcm_txt ? ADD_SO_DIP : ADD_SO_ZERO; // IV control // - CBC/CFB/OFB: IV registers are only updated when cipher finishes. - // - CTR: IV registers are updated by counter during cipher operation. + // - CTR/GCM: IV registers are updated by counter during cipher operation. + // The same holds when we're computing the hash subkey for GCM. iv_sel_o = doing_cbc_enc ? IV_DATA_OUT : doing_cbc_dec ? IV_DATA_IN_PREV : doing_cfb_enc ? IV_DATA_OUT : doing_cfb_dec ? IV_DATA_IN_PREV : doing_ofb ? IV_DATA_OUT_RAW : - doing_ctr ? IV_CTR : IV_INPUT; + doing_ctr ? IV_CTR : + doing_gcm_hsk ? IV_CTR : + doing_gcm_s ? IV_CTR : + doing_gcm_txt ? IV_CTR : IV_INPUT; iv_we_o = doing_cbc_enc || doing_cbc_dec || doing_cfb_enc || doing_cfb_dec || doing_ofb ? {NumSlicesCtr{cipher_out_done}} : - doing_ctr ? ctr_we_i : {NumSlicesCtr{1'b0}}; + doing_ctr ? ctr_we_i : + doing_gcm_hsk ? ctr_we_i : + doing_gcm_s ? ctr_we_i : + doing_gcm_txt ? ctr_we_i : {NumSlicesCtr{1'b0}}; // Arm the IV status tracker: After finishing, the IV registers can be written again // by software. We need to make sure software does not partially update the IV. @@ -546,13 +764,24 @@ module aes_control_fsm doing_cfb_enc | doing_cfb_dec | doing_ofb | - doing_ctr) & cipher_out_done; - - // Proceed upon successful handshake. + doing_ctr | + doing_gcm_hsk | + doing_gcm_s | + doing_gcm_txt) & cipher_out_done; + + // Proceed upon successful handshake. When initializing GHASH for GCM, don't write to the + // cipher output to the output data registers but forward it to the GHASH block and + // mark the hash subkey or S as ready. if (cipher_out_done) begin - block_ctr_decr = 1'b1; - data_out_we_o = 1'b1; - aes_ctrl_ns = CTRL_IDLE; + block_ctr_decr = 1'b1; + data_out_we_o = doing_gcm_hsk | + doing_gcm_s ? 1'b0 : 1'b1; + ghash_in_valid_o = doing_gcm_hsk | + doing_gcm_s | + doing_gcm_txt ? 1'b1 : 1'b0; + hash_subkey_ready_d = doing_gcm_hsk ? 1'b1 : hash_subkey_ready_q; + s_ready_d = doing_gcm_s ? 1'b1 : s_ready_q; + aes_ctrl_ns = CTRL_IDLE; end end end @@ -591,6 +820,9 @@ module aes_control_fsm if (cipher_key_clear_i) begin // Clear the trigger bit. key_iv_data_in_clear_we = 1'b1; + + // The GHASH block can now clear it's internal registers. + ghash_in_valid_o = 1'b1; end // To clear the output data registers, we re-use the muxing resources of the cipher core. @@ -639,6 +871,43 @@ module aes_control_fsm end end + if (AESGCMEnable) begin : gen_reg_fsm_gcm + always_ff @(posedge clk_i or negedge rst_ni) begin : reg_fsm_gcm + if (!rst_ni) begin + hash_subkey_ready_q <= 1'b0; + s_ready_q <= 1'b0; + doing_gcm_restore_q <= 1'b0; + doing_gcm_aad_q <= 1'b0; + doing_gcm_save_q <= 1'b0; + doing_gcm_tag_q <= 1'b0; + end else begin + hash_subkey_ready_q <= hash_subkey_ready_d; + s_ready_q <= s_ready_d; + doing_gcm_restore_q <= doing_gcm_restore_d; + doing_gcm_aad_q <= doing_gcm_aad_d; + doing_gcm_save_q <= doing_gcm_save_d; + doing_gcm_tag_q <= doing_gcm_tag_d; + end + end + end else begin : gen_no_reg_fsm_gcm + // GCM is simply not supported. + assign hash_subkey_ready_q = 1'b0; + assign s_ready_q = 1'b0; + assign doing_gcm_restore_q = 1'b0; + assign doing_gcm_aad_q = 1'b0; + assign doing_gcm_save_q = 1'b0; + assign doing_gcm_tag_q = 1'b0; + + // Tie-off unused signals. + logic unused_gcm_d; + assign unused_gcm_d = ^{hash_subkey_ready_d, + s_ready_d, + doing_gcm_restore_d, + doing_gcm_aad_d, + doing_gcm_save_d, + doing_gcm_tag_d}; + end + ///////////////////// // Status Tracking // ///////////////////// @@ -850,6 +1119,7 @@ module aes_control_fsm AES_CFB, AES_OFB, AES_CTR, + AES_GCM, AES_NONE }) `ASSERT(AesOpValid, !ctrl_err_storage_i |-> op_i inside { @@ -863,7 +1133,7 @@ module aes_control_fsm `ASSERT(AesControlStateValid, !alert_o |-> aes_ctrl_cs inside { CTRL_IDLE, CTRL_LOAD, - CTRL_PRNG_UPDATE, + CTRL_GHASH_READY, CTRL_PRNG_RESEED, CTRL_FINISH, CTRL_CLEAR_I, diff --git a/hw/ip/aes/rtl/aes_control_fsm_n.sv b/hw/ip/aes/rtl/aes_control_fsm_n.sv index 9f0afbeb18b4f..464582cad050b 100644 --- a/hw/ip/aes/rtl/aes_control_fsm_n.sv +++ b/hw/ip/aes/rtl/aes_control_fsm_n.sv @@ -18,7 +18,8 @@ module aes_control_fsm_n import aes_pkg::*; import aes_reg_pkg::*; #( - parameter bit SecMasking = 0 + parameter bit AESGCMEnable = 0, + parameter bit SecMasking = 0 ) ( input logic clk_i, input logic rst_ni, @@ -35,6 +36,9 @@ module aes_control_fsm_n input prs_rate_e prng_reseed_rate_i, input logic manual_operation_i, input logic key_touch_forces_reseed_i, + input logic ctrl_gcm_qe_i, + output logic ctrl_gcm_we_o, + input gcm_phase_e gcm_phase_i, input logic start_i, input logic key_iv_data_in_clear_i, input logic data_out_clear_i, @@ -52,11 +56,12 @@ module aes_control_fsm_n input logic [NumRegsData-1:0] data_in_qe_i, input logic [NumRegsData-1:0] data_out_re_i, output logic data_in_we_o, - output logic data_out_we_no, // Sparsify + output data_out_sel_e data_out_sel_o, + output logic data_out_we_no, // Sparsify // Previous input data register output dip_sel_e data_in_prev_sel_o, - output logic data_in_prev_we_no, // Sparsify + output logic data_in_prev_we_no, // Sparsify // Cipher I/O muxes output si_sel_e state_in_sel_o, @@ -64,19 +69,20 @@ module aes_control_fsm_n output add_so_sel_e add_state_out_sel_o, // Counter - output logic ctr_incr_no, // Sparsify - input logic ctr_ready_ni, // Sparsify - input logic [NumSlicesCtr-1:0] ctr_we_ni, // Sparsify + output logic ctr_inc32_no, // Sparsify + output logic ctr_incr_no, // Sparsify + input logic ctr_ready_ni, // Sparsify + input logic [NumSlicesCtr-1:0] ctr_we_ni, // Sparsify // Cipher core control and sync - output logic cipher_in_valid_no, // Sparsify - input logic cipher_in_ready_ni, // Sparsify - input logic cipher_out_valid_ni, // Sparsify - output logic cipher_out_ready_no, // Sparsify - output logic cipher_crypt_no, // Sparsify - input logic cipher_crypt_ni, // Sparsify - output logic cipher_dec_key_gen_no, // Sparsify - input logic cipher_dec_key_gen_ni, // Sparsify + output logic cipher_in_valid_no, // Sparsify + input logic cipher_in_ready_ni, // Sparsify + input logic cipher_out_valid_ni, // Sparsify + output logic cipher_out_ready_no, // Sparsify + output logic cipher_crypt_no, // Sparsify + input logic cipher_crypt_ni, // Sparsify + output logic cipher_dec_key_gen_no, // Sparsify + input logic cipher_dec_key_gen_ni, // Sparsify output logic cipher_prng_reseed_o, input logic cipher_prng_reseed_i, output logic cipher_key_clear_o, @@ -84,17 +90,23 @@ module aes_control_fsm_n output logic cipher_data_out_clear_o, input logic cipher_data_out_clear_i, + // GHASH control and sync + output logic ghash_in_valid_no, // Sparsify + input logic ghash_in_ready_ni, // Sparsify + input logic ghash_out_valid_ni, // Sparsify + output logic ghash_out_ready_no, // Sparsify + output logic ghash_load_hash_subkey_no, // Sparsify + // Initial key registers output key_init_sel_e key_init_sel_o, - output logic [NumSharesKey-1:0][NumRegsKey-1:0] key_init_we_no, // Sparsify + output logic [NumSharesKey-1:0][NumRegsKey-1:0] key_init_we_no, // Sparsify // IV registers output iv_sel_e iv_sel_o, - output logic [NumSlicesCtr-1:0] iv_we_no, // Sparsify + output logic [NumSlicesCtr-1:0] iv_we_no, // Sparsify // Pseudo-random number generator interface - output logic prng_data_req_o, - input logic prng_data_ack_i, + output logic prng_update_o, output logic prng_reseed_req_o, input logic prng_reseed_ack_i, @@ -134,6 +146,8 @@ module aes_control_fsm_n prng_reseed_rate_i, manual_operation_i, key_touch_forces_reseed_i, + ctrl_gcm_qe_i, + gcm_phase_i, start_i, key_iv_data_in_clear_i, data_out_clear_i, @@ -156,7 +170,8 @@ module aes_control_fsm_n cipher_prng_reseed_i, cipher_key_clear_i, cipher_data_out_clear_i, - prng_data_ack_i, + ghash_in_ready_ni, + ghash_out_valid_ni, prng_reseed_ack_i, output_lost_i }); @@ -174,6 +189,8 @@ module aes_control_fsm_n prng_reseed_rate_i, manual_operation_i, key_touch_forces_reseed_i, + ctrl_gcm_qe_i, + gcm_phase_i, start_i, key_iv_data_in_clear_i, data_out_clear_i, @@ -196,7 +213,8 @@ module aes_control_fsm_n cipher_prng_reseed_i, cipher_key_clear_i, cipher_data_out_clear_i, - prng_data_ack_i, + ghash_in_ready_ni, + ghash_out_valid_ni, prng_reseed_ack_i, output_lost_i }; @@ -221,6 +239,9 @@ module aes_control_fsm_n prs_rate_e prng_reseed_rate; logic manual_operation; logic key_touch_forces_reseed; + logic ctrl_gcm_qe; + gcm_phase_e gcm_phase; + logic [$bits(gcm_phase)-1:0] gcm_phase_raw; logic start; logic key_iv_data_in_clear; logic data_out_clear; @@ -243,7 +264,8 @@ module aes_control_fsm_n logic cipher_prng_reseed_in_buf; logic cipher_key_clear_in_buf; logic cipher_data_out_clear_in_buf; - logic prng_data_ack; + logic ghash_in_ready_n; + logic ghash_out_valid_n; logic prng_reseed_ack; logic output_lost_in_buf; @@ -257,6 +279,8 @@ module aes_control_fsm_n prng_reseed_rate, manual_operation, key_touch_forces_reseed, + ctrl_gcm_qe, + gcm_phase_raw, start, key_iv_data_in_clear, data_out_clear, @@ -279,22 +303,27 @@ module aes_control_fsm_n cipher_prng_reseed_in_buf, cipher_key_clear_in_buf, cipher_data_out_clear_in_buf, - prng_data_ack, + ghash_in_ready_n, + ghash_out_valid_n, prng_reseed_ack, output_lost_in_buf} = in_buf; assign cipher_op = ciph_op_e'(cipher_op_raw); + assign gcm_phase = gcm_phase_e'(gcm_phase_raw); // Intermediate output signals logic ctrl_we; + logic ctrl_gcm_we; logic alert; logic data_in_we; + data_out_sel_e data_out_sel; logic data_out_we; dip_sel_e data_in_prev_sel; logic data_in_prev_we; si_sel_e state_in_sel; add_si_sel_e add_state_in_sel; add_so_sel_e add_state_out_sel; + logic ctr_inc32; logic ctr_incr; logic cipher_in_valid; logic cipher_out_ready; @@ -303,11 +332,14 @@ module aes_control_fsm_n logic cipher_prng_reseed_out_buf; logic cipher_key_clear_out_buf; logic cipher_data_out_clear_out_buf; + logic ghash_in_valid; + logic ghash_out_ready; + logic ghash_load_hash_subkey; key_init_sel_e key_init_sel; logic [NumSharesKey-1:0][NumRegsKey-1:0] key_init_we; iv_sel_e iv_sel; logic [NumSlicesCtr-1:0] iv_we; - logic prng_data_req; + logic prng_update; logic prng_reseed_req; logic start_we; logic key_iv_data_in_clear_we; @@ -334,7 +366,8 @@ module aes_control_fsm_n // negated outputs, important output signals are inverted further below. Thanks to the prim_buf // synthesis optimization barriers, tools will push the inverters into the regular FSM. aes_control_fsm #( - .SecMasking ( SecMasking ) + .AESGCMEnable ( AESGCMEnable ), + .SecMasking ( SecMasking ) ) u_aes_control_fsm ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -350,6 +383,9 @@ module aes_control_fsm_n .prng_reseed_rate_i ( prng_reseed_rate ), .manual_operation_i ( manual_operation ), .key_touch_forces_reseed_i ( key_touch_forces_reseed ), + .ctrl_gcm_qe_i ( ctrl_gcm_qe ), + .ctrl_gcm_we_o ( ctrl_gcm_we ), + .gcm_phase_i ( gcm_phase ), .start_i ( start ), .key_iv_data_in_clear_i ( key_iv_data_in_clear ), .data_out_clear_i ( data_out_clear ), @@ -366,6 +402,7 @@ module aes_control_fsm_n .data_in_qe_i ( data_in_qe ), .data_out_re_i ( data_out_re ), .data_in_we_o ( data_in_we ), + .data_out_sel_o ( data_out_sel ), .data_out_we_o ( data_out_we ), // Invert below for _n output. .data_in_prev_sel_o ( data_in_prev_sel ), @@ -375,6 +412,7 @@ module aes_control_fsm_n .add_state_in_sel_o ( add_state_in_sel ), .add_state_out_sel_o ( add_state_out_sel ), + .ctr_inc32_o ( ctr_inc32 ), // Invert below for _n output. .ctr_incr_o ( ctr_incr ), // Invert below for _n output. .ctr_ready_i ( ~ctr_ready_n ), // Invert for regular FSM. .ctr_we_i ( ~ctr_we_n ), // Invert for regular FSM. @@ -394,14 +432,19 @@ module aes_control_fsm_n .cipher_data_out_clear_o ( cipher_data_out_clear_out_buf ), .cipher_data_out_clear_i ( cipher_data_out_clear_in_buf ), + .ghash_in_valid_o ( ghash_in_valid ), // Invert below for _n output. + .ghash_in_ready_i ( ~ghash_in_ready_n ), // Invert for regular FSM. + .ghash_out_valid_i ( ~ghash_out_valid_n ), // Invert for regular FSM. + .ghash_out_ready_o ( ghash_out_ready ), // Invert below for _n output. + .ghash_load_hash_subkey_o ( ghash_load_hash_subkey ), // Invert below for _n output. + .key_init_sel_o ( key_init_sel ), .key_init_we_o ( key_init_we ), // Invert below for _n output. .iv_sel_o ( iv_sel ), .iv_we_o ( iv_we ), // Invert below for _n output. - .prng_data_req_o ( prng_data_req ), - .prng_data_ack_i ( prng_data_ack ), + .prng_update_o ( prng_update ), .prng_reseed_req_o ( prng_reseed_req ), .prng_reseed_ack_i ( prng_reseed_ack ), @@ -430,14 +473,17 @@ module aes_control_fsm_n localparam int NumOutBufBits = $bits({ ctrl_we_o, + ctrl_gcm_we_o, alert_o, data_in_we_o, + data_out_sel_o, data_out_we_no, data_in_prev_sel_o, data_in_prev_we_no, state_in_sel_o, add_state_in_sel_o, add_state_out_sel_o, + ctr_inc32_no, ctr_incr_no, cipher_in_valid_no, cipher_out_ready_no, @@ -446,11 +492,14 @@ module aes_control_fsm_n cipher_prng_reseed_o, cipher_key_clear_o, cipher_data_out_clear_o, + ghash_in_valid_no, + ghash_out_ready_no, + ghash_load_hash_subkey_no, key_init_sel_o, key_init_we_no, iv_sel_o, iv_we_no, - prng_data_req_o, + prng_update_o, prng_reseed_req_o, start_we_o, key_iv_data_in_clear_we_o, @@ -475,14 +524,17 @@ module aes_control_fsm_n // inverters back into the regular FSM. assign out = { ctrl_we, + ctrl_gcm_we, alert, data_in_we, + data_out_sel, ~data_out_we, data_in_prev_sel, ~data_in_prev_we, state_in_sel, add_state_in_sel, add_state_out_sel, + ~ctr_inc32, ~ctr_incr, ~cipher_in_valid, ~cipher_out_ready, @@ -491,11 +543,14 @@ module aes_control_fsm_n cipher_prng_reseed_out_buf, cipher_key_clear_out_buf, cipher_data_out_clear_out_buf, + ~ghash_in_valid, + ~ghash_out_ready, + ~ghash_load_hash_subkey, key_init_sel, ~key_init_we, iv_sel, ~iv_we, - prng_data_req, + prng_update, prng_reseed_req, start_we, key_iv_data_in_clear_we, @@ -524,14 +579,17 @@ module aes_control_fsm_n ); assign {ctrl_we_o, + ctrl_gcm_we_o, alert_o, data_in_we_o, + data_out_sel_o, data_out_we_no, data_in_prev_sel_o, data_in_prev_we_no, state_in_sel_o, add_state_in_sel_o, add_state_out_sel_o, + ctr_inc32_no, ctr_incr_no, cipher_in_valid_no, cipher_out_ready_no, @@ -540,11 +598,14 @@ module aes_control_fsm_n cipher_prng_reseed_o, cipher_key_clear_o, cipher_data_out_clear_o, + ghash_in_valid_no, + ghash_out_ready_no, + ghash_load_hash_subkey_no, key_init_sel_o, key_init_we_no, iv_sel_o, iv_we_no, - prng_data_req_o, + prng_update_o, prng_reseed_req_o, start_we_o, key_iv_data_in_clear_we_o, diff --git a/hw/ip/aes/rtl/aes_control_fsm_p.sv b/hw/ip/aes/rtl/aes_control_fsm_p.sv index 053fdb20256b3..f306fd8fbede2 100644 --- a/hw/ip/aes/rtl/aes_control_fsm_p.sv +++ b/hw/ip/aes/rtl/aes_control_fsm_p.sv @@ -14,7 +14,8 @@ module aes_control_fsm_p import aes_pkg::*; import aes_reg_pkg::*; #( - parameter bit SecMasking = 0 + parameter bit AESGCMEnable = 0, + parameter bit SecMasking = 0 ) ( input logic clk_i, input logic rst_ni, @@ -31,6 +32,9 @@ module aes_control_fsm_p input prs_rate_e prng_reseed_rate_i, input logic manual_operation_i, input logic key_touch_forces_reseed_i, + input logic ctrl_gcm_qe_i, + output logic ctrl_gcm_we_o, + input gcm_phase_e gcm_phase_i, input logic start_i, input logic key_iv_data_in_clear_i, input logic data_out_clear_i, @@ -48,11 +52,12 @@ module aes_control_fsm_p input logic [NumRegsData-1:0] data_in_qe_i, input logic [NumRegsData-1:0] data_out_re_i, output logic data_in_we_o, - output logic data_out_we_o, // Sparsify + output data_out_sel_e data_out_sel_o, + output logic data_out_we_o, // Sparsify // Previous input data register output dip_sel_e data_in_prev_sel_o, - output logic data_in_prev_we_o, // Sparsify + output logic data_in_prev_we_o, // Sparsify // Cipher I/O muxes output si_sel_e state_in_sel_o, @@ -60,19 +65,20 @@ module aes_control_fsm_p output add_so_sel_e add_state_out_sel_o, // Counter - output logic ctr_incr_o, // Sparsify - input logic ctr_ready_i, // Sparsify - input logic [NumSlicesCtr-1:0] ctr_we_i, // Sparsify + output logic ctr_inc32_o, // Sparsify + output logic ctr_incr_o, // Sparsify + input logic ctr_ready_i, // Sparsify + input logic [NumSlicesCtr-1:0] ctr_we_i, // Sparsify // Cipher core control and sync - output logic cipher_in_valid_o, // Sparsify - input logic cipher_in_ready_i, // Sparsify - input logic cipher_out_valid_i, // Sparsify - output logic cipher_out_ready_o, // Sparsify - output logic cipher_crypt_o, // Sparsify - input logic cipher_crypt_i, // Sparsify - output logic cipher_dec_key_gen_o, // Sparsify - input logic cipher_dec_key_gen_i, // Sparsify + output logic cipher_in_valid_o, // Sparsify + input logic cipher_in_ready_i, // Sparsify + input logic cipher_out_valid_i, // Sparsify + output logic cipher_out_ready_o, // Sparsify + output logic cipher_crypt_o, // Sparsify + input logic cipher_crypt_i, // Sparsify + output logic cipher_dec_key_gen_o, // Sparsify + input logic cipher_dec_key_gen_i, // Sparsify output logic cipher_prng_reseed_o, input logic cipher_prng_reseed_i, output logic cipher_key_clear_o, @@ -80,17 +86,23 @@ module aes_control_fsm_p output logic cipher_data_out_clear_o, input logic cipher_data_out_clear_i, + // GHASH control and sync + output logic ghash_in_valid_o, // Sparsify + input logic ghash_in_ready_i, // Sparsify + input logic ghash_out_valid_i, // Sparsify + output logic ghash_out_ready_o, // Sparsify + output logic ghash_load_hash_subkey_o, // Sparsify + // Initial key registers output key_init_sel_e key_init_sel_o, - output logic [NumSharesKey-1:0][NumRegsKey-1:0] key_init_we_o, // Sparsify + output logic [NumSharesKey-1:0][NumRegsKey-1:0] key_init_we_o, // Sparsify // IV registers output iv_sel_e iv_sel_o, - output logic [NumSlicesCtr-1:0] iv_we_o, // Sparsify + output logic [NumSlicesCtr-1:0] iv_we_o, // Sparsify // Pseudo-random number generator interface - output logic prng_data_req_o, - input logic prng_data_ack_i, + output logic prng_update_o, output logic prng_reseed_req_o, input logic prng_reseed_ack_i, @@ -130,6 +142,8 @@ module aes_control_fsm_p prng_reseed_rate_i, manual_operation_i, key_touch_forces_reseed_i, + ctrl_gcm_qe_i, + gcm_phase_i, start_i, key_iv_data_in_clear_i, data_out_clear_i, @@ -152,7 +166,8 @@ module aes_control_fsm_p cipher_prng_reseed_i, cipher_key_clear_i, cipher_data_out_clear_i, - prng_data_ack_i, + ghash_in_ready_i, + ghash_out_valid_i, prng_reseed_ack_i, output_lost_i }); @@ -170,6 +185,8 @@ module aes_control_fsm_p prng_reseed_rate_i, manual_operation_i, key_touch_forces_reseed_i, + ctrl_gcm_qe_i, + gcm_phase_i, start_i, key_iv_data_in_clear_i, data_out_clear_i, @@ -192,7 +209,8 @@ module aes_control_fsm_p cipher_prng_reseed_i, cipher_key_clear_i, cipher_data_out_clear_i, - prng_data_ack_i, + ghash_in_ready_i, + ghash_out_valid_i, prng_reseed_ack_i, output_lost_i }; @@ -217,6 +235,9 @@ module aes_control_fsm_p prs_rate_e prng_reseed_rate; logic manual_operation; logic key_touch_forces_reseed; + logic ctrl_gcm_qe; + gcm_phase_e gcm_phase; + logic [$bits(gcm_phase)-1:0] gcm_phase_raw; logic start; logic key_iv_data_in_clear; logic data_out_clear; @@ -239,7 +260,8 @@ module aes_control_fsm_p logic cipher_prng_reseed_in_buf; logic cipher_key_clear_in_buf; logic cipher_data_out_clear_in_buf; - logic prng_data_ack; + logic ghash_in_ready; + logic ghash_out_valid; logic prng_reseed_ack; logic output_lost_in_buf; @@ -253,6 +275,8 @@ module aes_control_fsm_p prng_reseed_rate, manual_operation, key_touch_forces_reseed, + ctrl_gcm_qe, + gcm_phase_raw, start, key_iv_data_in_clear, data_out_clear, @@ -275,22 +299,27 @@ module aes_control_fsm_p cipher_prng_reseed_in_buf, cipher_key_clear_in_buf, cipher_data_out_clear_in_buf, - prng_data_ack, + ghash_in_ready, + ghash_out_valid, prng_reseed_ack, output_lost_in_buf} = in_buf; assign cipher_op = ciph_op_e'(cipher_op_raw); + assign gcm_phase = gcm_phase_e'(gcm_phase_raw); // Intermediate output signals logic ctrl_we; + logic ctrl_gcm_we; logic alert; logic data_in_we; + data_out_sel_e data_out_sel; logic data_out_we; dip_sel_e data_in_prev_sel; logic data_in_prev_we; si_sel_e state_in_sel; add_si_sel_e add_state_in_sel; add_so_sel_e add_state_out_sel; + logic ctr_inc32; logic ctr_incr; logic cipher_in_valid; logic cipher_out_ready; @@ -299,11 +328,14 @@ module aes_control_fsm_p logic cipher_prng_reseed_out_buf; logic cipher_key_clear_out_buf; logic cipher_data_out_clear_out_buf; + logic ghash_in_valid; + logic ghash_out_ready; + logic ghash_load_hash_subkey; key_init_sel_e key_init_sel; logic [NumSharesKey-1:0][NumRegsKey-1:0] key_init_we; iv_sel_e iv_sel; logic [NumSlicesCtr-1:0] iv_we; - logic prng_data_req; + logic prng_update; logic prng_reseed_req; logic start_we; logic key_iv_data_in_clear_we; @@ -326,7 +358,8 @@ module aes_control_fsm_p ///////////////// aes_control_fsm #( - .SecMasking ( SecMasking ) + .AESGCMEnable ( AESGCMEnable ), + .SecMasking ( SecMasking ) ) u_aes_control_fsm ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -342,6 +375,9 @@ module aes_control_fsm_p .prng_reseed_rate_i ( prng_reseed_rate ), .manual_operation_i ( manual_operation ), .key_touch_forces_reseed_i ( key_touch_forces_reseed ), + .ctrl_gcm_qe_i ( ctrl_gcm_qe ), + .ctrl_gcm_we_o ( ctrl_gcm_we ), + .gcm_phase_i ( gcm_phase ), .start_i ( start ), .key_iv_data_in_clear_i ( key_iv_data_in_clear ), .data_out_clear_i ( data_out_clear ), @@ -358,6 +394,7 @@ module aes_control_fsm_p .data_in_qe_i ( data_in_qe ), .data_out_re_i ( data_out_re ), .data_in_we_o ( data_in_we ), + .data_out_sel_o ( data_out_sel ), .data_out_we_o ( data_out_we ), .data_in_prev_sel_o ( data_in_prev_sel ), @@ -367,6 +404,7 @@ module aes_control_fsm_p .add_state_in_sel_o ( add_state_in_sel ), .add_state_out_sel_o ( add_state_out_sel ), + .ctr_inc32_o ( ctr_inc32 ), .ctr_incr_o ( ctr_incr ), .ctr_ready_i ( ctr_ready ), .ctr_we_i ( ctr_we ), @@ -386,14 +424,19 @@ module aes_control_fsm_p .cipher_data_out_clear_o ( cipher_data_out_clear_out_buf ), .cipher_data_out_clear_i ( cipher_data_out_clear_in_buf ), + .ghash_in_valid_o ( ghash_in_valid ), + .ghash_in_ready_i ( ghash_in_ready ), + .ghash_out_valid_i ( ghash_out_valid ), + .ghash_out_ready_o ( ghash_out_ready ), + .ghash_load_hash_subkey_o ( ghash_load_hash_subkey ), + .key_init_sel_o ( key_init_sel ), .key_init_we_o ( key_init_we ), .iv_sel_o ( iv_sel ), .iv_we_o ( iv_we ), - .prng_data_req_o ( prng_data_req ), - .prng_data_ack_i ( prng_data_ack ), + .prng_update_o ( prng_update ), .prng_reseed_req_o ( prng_reseed_req ), .prng_reseed_ack_i ( prng_reseed_ack ), @@ -422,14 +465,17 @@ module aes_control_fsm_p localparam int NumOutBufBits = $bits({ ctrl_we_o, + ctrl_gcm_we_o, alert_o, data_in_we_o, + data_out_sel_o, data_out_we_o, data_in_prev_sel_o, data_in_prev_we_o, state_in_sel_o, add_state_in_sel_o, add_state_out_sel_o, + ctr_inc32_o, ctr_incr_o, cipher_in_valid_o, cipher_out_ready_o, @@ -438,11 +484,14 @@ module aes_control_fsm_p cipher_prng_reseed_o, cipher_key_clear_o, cipher_data_out_clear_o, + ghash_in_valid_o, + ghash_out_ready_o, + ghash_load_hash_subkey_o, key_init_sel_o, key_init_we_o, iv_sel_o, iv_we_o, - prng_data_req_o, + prng_update_o, prng_reseed_req_o, start_we_o, key_iv_data_in_clear_we_o, @@ -465,14 +514,17 @@ module aes_control_fsm_p assign out = { ctrl_we, + ctrl_gcm_we, alert, data_in_we, + data_out_sel, data_out_we, data_in_prev_sel, data_in_prev_we, state_in_sel, add_state_in_sel, add_state_out_sel, + ctr_inc32, ctr_incr, cipher_in_valid, cipher_out_ready, @@ -481,11 +533,14 @@ module aes_control_fsm_p cipher_prng_reseed_out_buf, cipher_key_clear_out_buf, cipher_data_out_clear_out_buf, + ghash_in_valid, + ghash_out_ready, + ghash_load_hash_subkey, key_init_sel, key_init_we, iv_sel, iv_we, - prng_data_req, + prng_update, prng_reseed_req, start_we, key_iv_data_in_clear_we, @@ -514,14 +569,17 @@ module aes_control_fsm_p ); assign {ctrl_we_o, + ctrl_gcm_we_o, alert_o, data_in_we_o, + data_out_sel_o, data_out_we_o, data_in_prev_sel_o, data_in_prev_we_o, state_in_sel_o, add_state_in_sel_o, add_state_out_sel_o, + ctr_inc32_o, ctr_incr_o, cipher_in_valid_o, cipher_out_ready_o, @@ -530,11 +588,14 @@ module aes_control_fsm_p cipher_prng_reseed_o, cipher_key_clear_o, cipher_data_out_clear_o, + ghash_in_valid_o, + ghash_out_ready_o, + ghash_load_hash_subkey_o, key_init_sel_o, key_init_we_o, iv_sel_o, iv_we_o, - prng_data_req_o, + prng_update_o, prng_reseed_req_o, start_we_o, key_iv_data_in_clear_we_o, diff --git a/hw/ip/aes/rtl/aes_core.sv b/hw/ip/aes/rtl/aes_core.sv index 8b9db779928e3..56f8f25908dae 100644 --- a/hw/ip/aes/rtl/aes_core.sv +++ b/hw/ip/aes/rtl/aes_core.sv @@ -11,6 +11,7 @@ module aes_core import aes_reg_pkg::*; #( parameter bit AES192Enable = 1, + parameter bit AESGCMEnable = 1, parameter bit SecMasking = 1, parameter sbox_impl_e SecSBoxImpl = SBoxImplDom, parameter int unsigned SecStartTriggerDelay = 0, @@ -70,6 +71,12 @@ module aes_core logic manual_operation_q; logic ctrl_reg_err_update; logic ctrl_reg_err_storage; + logic ctrl_gcm_qe; + logic ctrl_gcm_we; + gcm_phase_e gcm_phase_q; + logic [4:0] num_valid_bytes_q; + logic ctrl_gcm_reg_err_update; + logic ctrl_gcm_reg_err_storage; logic ctrl_err_update; logic ctrl_err_storage; logic ctrl_err_storage_d; @@ -125,6 +132,7 @@ module aes_core logic [NumSlicesCtr-1:0][SliceSizeCtr-1:0] ctr; sp2v_e [NumSlicesCtr-1:0] ctr_we; + sp2v_e ctr_inc32; sp2v_e ctr_incr; sp2v_e ctr_ready; logic ctr_alert; @@ -149,12 +157,17 @@ module aes_core add_so_sel_e add_state_out_sel; logic add_state_out_sel_err; + logic [NumRegsData-1:0][31:0] data_out; logic [NumRegsData-1:0][31:0] data_out_d; logic [NumRegsData-1:0][31:0] data_out_q; sp2v_e data_out_we_ctrl; sp2v_e data_out_we; logic [NumRegsData-1:0] data_out_re; logic [NumRegsData-1:0] data_out_re_buf; + logic [DataOutSelWidth-1:0] data_out_sel_raw; + data_out_sel_e data_out_sel_ctrl; + data_out_sel_e data_out_sel; + logic data_out_sel_err; sp2v_e cipher_in_valid; sp2v_e cipher_in_ready; @@ -172,10 +185,16 @@ module aes_core logic cipher_data_out_clear_busy; logic cipher_alert; + sp2v_e ghash_in_valid; + sp2v_e ghash_in_ready; + sp2v_e ghash_out_valid; + sp2v_e ghash_out_ready; + sp2v_e ghash_load_hash_subkey; + logic ghash_alert; + // Pseudo-random data for clearing purposes logic [WidthPRDClearing-1:0] prd_clearing [NumSharesKey]; - logic prd_clearing_upd_req; - logic prd_clearing_upd_ack; + logic prd_clearing_update; logic prd_clearing_rsd_req; logic prd_clearing_rsd_ack; logic [127:0] prd_clearing_128 [NumShares]; @@ -200,8 +219,7 @@ module aes_core .clk_i ( clk_i ), .rst_ni ( rst_ni ), - .data_req_i ( prd_clearing_upd_req ), - .data_ack_o ( prd_clearing_upd_ack ), + .data_update_i ( prd_clearing_update ), .data_o ( prd_clearing ), .reseed_req_i ( prd_clearing_rsd_req ), .reseed_ack_o ( prd_clearing_rsd_ack ), @@ -388,6 +406,7 @@ module aes_core .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .inc32_i ( ctr_inc32 ), .incr_i ( ctr_incr ), .ready_o ( ctr_ready ), .alert_o ( ctr_alert ), @@ -408,7 +427,8 @@ module aes_core (aes_mode_q == AES_CBC && aes_op_q == AES_DEC) ? CIPH_INV : (aes_mode_q == AES_CFB) ? CIPH_FWD : (aes_mode_q == AES_OFB) ? CIPH_FWD : - (aes_mode_q == AES_CTR) ? CIPH_FWD : CIPH_FWD; + (aes_mode_q == AES_CTR) ? CIPH_FWD : + (aes_mode_q == AES_GCM) ? CIPH_FWD : CIPH_FWD; // This primitive is used to place a size-only constraint on the // buffers to act as a synthesis optimization barrier. @@ -519,11 +539,13 @@ module aes_core // Only unmask the final cipher core output. Unmasking intermediate output data causes // additional SCA leakage and thus has to be avoided. Forward PRD instead of a determinsitic - // value to avoid leaking the cipher core output when it becomes valid. + // value to avoid leaking the cipher core output when it becomes valid. Don't unmask the hash + // subkey in case of GCM. logic [3:0][3:0][7:0] state_done_muxed [NumShares]; for (genvar s = 0; s < NumShares; s++) begin : gen_state_done_muxed - assign state_done_muxed[s] = - (cipher_out_valid == SP2V_HIGH) ? state_done[s] : prd_clearing_state[s]; + assign state_done_muxed[s] = ((cipher_out_valid == SP2V_HIGH) && + !(aes_mode_q == AES_GCM && + gcm_phase_q == GCM_INIT)) ? state_done[s] : prd_clearing_state[s]; end // Avoid aggressive synthesis optimizations. @@ -550,15 +572,84 @@ module aes_core end // Convert output state to output data format (every column corresponds to one output word). - assign data_out_d = aes_transpose(state_out ^ add_state_out); + assign data_out = aes_transpose(state_out ^ add_state_out); + + /////////// + // GHASH // + /////////// + + if (AESGCMEnable) begin : gen_ghash + logic [3:0][3:0][7:0] ghash_state_out; + + logic ghash_clear; + assign ghash_clear = cipher_key_clear | cipher_key_clear_busy; + + // The actual GHASH module. + aes_ghash #( + .SecMasking ( SecMasking ), + .SecSBoxImpl ( SecSBoxImpl ) + ) u_aes_ghash ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + + .in_valid_i ( ghash_in_valid ), + .in_ready_o ( ghash_in_ready ), + + .out_valid_o ( ghash_out_valid ), + .out_ready_i ( ghash_out_ready ), + + .op_i ( aes_op_q ), + .gcm_phase_i ( gcm_phase_q ), + .num_valid_bytes_i ( num_valid_bytes_q ), + .load_hash_subkey_i ( ghash_load_hash_subkey ), + .clear_i ( ghash_clear ), + .alert_fatal_i ( alert_fatal_o ), + .alert_o ( ghash_alert ), + + .cipher_state_init_i ( state_init ), + .data_in_prev_i ( data_in_prev_q ), + .data_out_i ( data_out_d ), + .cipher_state_done_i ( state_done ), + .ghash_state_done_o ( ghash_state_out ) + ); - ////////////////////// - // Control Register // - ////////////////////// + // Mux for output data registers + always_comb begin : data_out_mux + unique case (data_out_sel) + DATA_OUT_CIPHER: data_out_d = data_out; + DATA_OUT_GHASH: data_out_d = ghash_state_out; + default: data_out_d = ghash_state_out; + endcase + end + + end else begin : gen_no_ghash + // GHASH isn't there and thus generates no back pressure / alerts / output to be muxed. + assign ghash_in_ready = SP2V_HIGH; + assign ghash_out_valid = SP2V_HIGH; + assign ghash_alert = 1'b0; + assign data_out_d = data_out; + + // Tie-off unused signals. + sp2v_e unused_ghash_in_valid; + sp2v_e unused_ghash_out_ready; + sp2v_e unused_ghash_load_hash_subkey; + logic [4:0] unused_num_valid_bytes; + data_out_sel_e unused_data_out_sel; + assign unused_ghash_in_valid = ghash_in_valid; + assign unused_ghash_out_ready = ghash_out_ready; + assign unused_ghash_load_hash_subkey = ghash_load_hash_subkey; + assign unused_num_valid_bytes = num_valid_bytes_q; + assign unused_data_out_sel = data_out_sel; + end + + /////////////////////// + // Control Registers // + /////////////////////// // Shadowed register primitve aes_ctrl_reg_shadowed #( - .AES192Enable ( AES192Enable ) + .AES192Enable ( AES192Enable ), + .AESGCMEnable ( AESGCMEnable ) ) u_ctrl_reg_shadowed ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), @@ -582,12 +673,30 @@ module aes_core assign key_touch_forces_reseed = reg2hw.ctrl_aux_shadowed.key_touch_forces_reseed.q; assign force_masks = reg2hw.ctrl_aux_shadowed.force_masks.q; + // GCM control register + aes_ctrl_gcm_reg_shadowed #( + .AESGCMEnable ( AESGCMEnable ) + ) u_ctrl_gcm_reg_shadowed ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .rst_shadowed_ni ( rst_shadowed_ni ), + .qe_o ( ctrl_gcm_qe ), + .we_i ( ctrl_gcm_we ), + .gcm_phase_o ( gcm_phase_q ), + .num_valid_bytes_o ( num_valid_bytes_q ), + .err_update_o ( ctrl_gcm_reg_err_update ), + .err_storage_o ( ctrl_gcm_reg_err_storage ), + .reg2hw_ctrl_gcm_i ( reg2hw.ctrl_gcm_shadowed ), + .hw2reg_ctrl_gcm_o ( hw2reg.ctrl_gcm_shadowed ) + ); + ///////////// // Control // ///////////// // Control aes_control #( + .AESGCMEnable ( AESGCMEnable ), .SecMasking ( SecMasking ), .SecStartTriggerDelay ( SecStartTriggerDelay ) ) u_aes_control ( @@ -605,6 +714,9 @@ module aes_core .prng_reseed_rate_i ( prng_reseed_rate_q ), .manual_operation_i ( manual_operation_q ), .key_touch_forces_reseed_i ( key_touch_forces_reseed ), + .ctrl_gcm_qe_i ( ctrl_gcm_qe ), + .ctrl_gcm_we_o ( ctrl_gcm_we ), + .gcm_phase_i ( gcm_phase_q ), .start_i ( reg2hw.trigger.start.q ), .key_iv_data_in_clear_i ( reg2hw.trigger.key_iv_data_in_clear.q ), .data_out_clear_i ( reg2hw.trigger.data_out_clear.q ), @@ -621,6 +733,7 @@ module aes_core .data_in_qe_i ( data_in_qe_buf ), .data_out_re_i ( data_out_re_buf ), .data_in_we_o ( data_in_we ), + .data_out_sel_o ( data_out_sel_ctrl ), .data_out_we_o ( data_out_we_ctrl ), .data_in_prev_sel_o ( data_in_prev_sel_ctrl ), @@ -630,6 +743,7 @@ module aes_core .add_state_in_sel_o ( add_state_in_sel_ctrl ), .add_state_out_sel_o ( add_state_out_sel_ctrl ), + .ctr_inc32_o ( ctr_inc32 ), .ctr_incr_o ( ctr_incr ), .ctr_ready_i ( ctr_ready ), .ctr_we_i ( ctr_we ), @@ -649,13 +763,18 @@ module aes_core .cipher_data_out_clear_o ( cipher_data_out_clear ), .cipher_data_out_clear_i ( cipher_data_out_clear_busy ), + .ghash_in_valid_o ( ghash_in_valid ), + .ghash_in_ready_i ( ghash_in_ready ), + .ghash_out_valid_i ( ghash_out_valid ), + .ghash_out_ready_o ( ghash_out_ready ), + .ghash_load_hash_subkey_o ( ghash_load_hash_subkey ), + .key_init_sel_o ( key_init_sel_ctrl ), .key_init_we_o ( key_init_we_ctrl ), .iv_sel_o ( iv_sel_ctrl ), .iv_we_o ( iv_we_ctrl ), - .prng_data_req_o ( prd_clearing_upd_req ), - .prng_data_ack_i ( prd_clearing_upd_ack ), + .prng_update_o ( prd_clearing_update ), .prng_reseed_req_o ( prd_clearing_rsd_req ), .prng_reseed_ack_i ( prd_clearing_rsd_ack ), @@ -784,9 +903,22 @@ module aes_core ); assign iv_sel = iv_sel_e'(iv_sel_raw); + aes_sel_buf_chk #( + .Num ( DataOutSelNum ), + .Width ( DataOutSelWidth ), + .EnSecBuf ( 1'b1 ) + ) u_aes_data_out_sel_buf_chk ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .sel_i ( data_out_sel_ctrl ), + .sel_o ( data_out_sel_raw ), + .err_o ( data_out_sel_err ) + ); + assign data_out_sel = data_out_sel_e'(data_out_sel_raw); + // Signal invalid mux selector signals to control FSM which will lock up and trigger an alert. assign mux_sel_err = data_in_prev_sel_err | state_in_sel_err | add_state_in_sel_err | - add_state_out_sel_err | key_init_sel_err | iv_sel_err; + add_state_out_sel_err | key_init_sel_err | iv_sel_err | data_out_sel_err; ////////////////////////////// // Sparsely Encoded Signals // @@ -907,7 +1039,7 @@ module aes_core assign clear_on_fatal = ClearStatusOnFatalAlert ? alert_fatal_o : 1'b0; // Recoverable alert conditions are signaled as a single alert event. - assign ctrl_err_update = ctrl_reg_err_update | shadowed_update_err_i; + assign ctrl_err_update = ctrl_reg_err_update | shadowed_update_err_i | ctrl_gcm_reg_err_update; assign alert_recov_o = ctrl_err_update; // The recoverable alert is observable via status register until the AES operation is restarted @@ -916,7 +1048,8 @@ module aes_core assign hw2reg.status.alert_recov_ctrl_update_err.de = ctrl_err_update | ctrl_we | clear_on_fatal; // Fatal alert conditions need to remain asserted until reset. - assign ctrl_err_storage_d = ctrl_reg_err_storage | shadowed_storage_err_i; + assign ctrl_err_storage_d = + ctrl_reg_err_storage | shadowed_storage_err_i | ctrl_gcm_reg_err_storage; always_ff @(posedge clk_i or negedge rst_ni) begin : ctrl_err_storage_reg if (!rst_ni) begin ctrl_err_storage_q <= 1'b0; @@ -930,6 +1063,7 @@ module aes_core assign alert_fatal_o = ctrl_err_storage | ctr_alert | cipher_alert | + ghash_alert | ctrl_alert | intg_err_alert_i; @@ -959,6 +1093,7 @@ module aes_core AES_CFB, AES_OFB, AES_CTR, + AES_GCM, AES_NONE }) `ASSERT(AesOpValid, !ctrl_err_storage |-> aes_op_q inside { diff --git a/hw/ip/aes/rtl/aes_ctr.sv b/hw/ip/aes/rtl/aes_ctr.sv index 11ec79163314c..f07b55a332bf3 100644 --- a/hw/ip/aes/rtl/aes_ctr.sv +++ b/hw/ip/aes/rtl/aes_ctr.sv @@ -12,6 +12,7 @@ module aes_ctr import aes_pkg::*; input logic clk_i, input logic rst_ni, + input sp2v_e inc32_i, input sp2v_e incr_i, output sp2v_e ready_o, output logic alert_o, @@ -50,12 +51,16 @@ module aes_ctr import aes_pkg::*; logic [SliceSizeCtr-1:0] ctr_i_slice; logic [SliceSizeCtr-1:0] ctr_o_slice; + sp2v_e inc32; + logic inc32_err; sp2v_e incr; logic incr_err; + logic sp_enc_err; logic mr_err; // Sparsified FSM signals. These are needed for connecting the individual bits of the Sp2V // signals to the single-rail FSMs. + logic [Sp2VWidth-1:0] sp_inc32; logic [Sp2VWidth-1:0] sp_incr; logic [Sp2VWidth-1:0] sp_ready; logic [Sp2VWidth-1:0] sp_ctr_we; @@ -73,13 +78,27 @@ module aes_ctr import aes_pkg::*; assign ctr_i_rev = aes_rev_order_byte(ctr_i); // SEC_CM: CTRL.SPARSE - // Check sparsely encoded incr signal. + // Check sparsely encoded inc32 and incr signals. + logic [Sp2VWidth-1:0] inc32_raw; + aes_sel_buf_chk #( + .Num ( Sp2VNum ), + .Width ( Sp2VWidth ), + .EnSecBuf ( 1'b0 ) + ) u_aes_inc32_buf_chk ( + .clk_i ( clk_i ), + .rst_ni ( rst_ni ), + .sel_i ( inc32_i ), + .sel_o ( inc32_raw ), + .err_o ( inc32_err ) + ); + assign inc32 = sp2v_e'(inc32_raw); + logic [Sp2VWidth-1:0] incr_raw; aes_sel_buf_chk #( .Num ( Sp2VNum ), .Width ( Sp2VWidth ), .EnSecBuf ( 1'b0 ) - ) u_aes_sb_en_buf_chk ( + ) u_aes_incr_buf_chk ( .clk_i ( clk_i ), .rst_ni ( rst_ni ), .sel_i ( incr_i ), @@ -88,6 +107,9 @@ module aes_ctr import aes_pkg::*; ); assign incr = sp2v_e'(incr_raw); + // Collect encoding errors. + assign sp_enc_err = inc32_err | incr_err; + ///////////// // Counter // ///////////// @@ -100,7 +122,8 @@ module aes_ctr import aes_pkg::*; ///////// // Convert sp2v_e signals to sparsified inputs. - assign sp_incr = {incr}; + assign sp_inc32 = {inc32}; + assign sp_incr = {incr}; // SEC_CM: CTR.FSM.REDUN // For every bit in the Sp2V signals, one separate rail is instantiated. The inputs and outputs @@ -111,9 +134,10 @@ module aes_ctr import aes_pkg::*; .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .inc32_i ( sp_inc32[i] ), // Sparsified .incr_i ( sp_incr[i] ), // Sparsified .ready_o ( sp_ready[i] ), // Sparsified - .incr_err_i ( incr_err ), + .sp_enc_err_i ( sp_enc_err ), .mr_err_i ( mr_err ), .alert_o ( mr_alert[i] ), // OR-combine @@ -127,9 +151,10 @@ module aes_ctr import aes_pkg::*; .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .inc32_ni ( sp_inc32[i] ), // Sparsified .incr_ni ( sp_incr[i] ), // Sparsified .ready_no ( sp_ready[i] ), // Sparsified - .incr_err_i ( incr_err ), + .sp_enc_err_i ( sp_enc_err ), .mr_err_i ( mr_err ), .alert_o ( mr_alert[i] ), // OR-combine diff --git a/hw/ip/aes/rtl/aes_ctr_fsm.sv b/hw/ip/aes/rtl/aes_ctr_fsm.sv index 13d8cdf7d29b0..26caa30d1d519 100644 --- a/hw/ip/aes/rtl/aes_ctr_fsm.sv +++ b/hw/ip/aes/rtl/aes_ctr_fsm.sv @@ -11,9 +11,10 @@ module aes_ctr_fsm import aes_pkg::*; input logic clk_i, input logic rst_ni, + input logic inc32_i, // Sparsify using multi-rail. input logic incr_i, // Sparsify using multi-rail. output logic ready_o, // Sparsify using multi-rail. - input logic incr_err_i, + input logic sp_enc_err_i, input logic mr_err_i, output logic alert_o, @@ -26,6 +27,7 @@ module aes_ctr_fsm import aes_pkg::*; // Signals aes_ctr_e aes_ctr_ns, aes_ctr_cs; logic [SliceIdxWidth-1:0] ctr_slice_idx_d, ctr_slice_idx_q; + logic [SliceIdxWidth-1:0] ctr_slice_idx_max; logic ctr_carry_d, ctr_carry_q; logic [SliceSizeCtr:0] ctr_value; @@ -38,6 +40,9 @@ module aes_ctr_fsm import aes_pkg::*; assign ctr_value = ctr_slice_i + {{(SliceSizeCtr-1){1'b0}}, ctr_carry_q}; assign ctr_slice_o = ctr_value[SliceSizeCtr-1:0]; + // Perform either inc128() or inc32() for GCM. + assign ctr_slice_idx_max = inc32_i ? SliceIdxWidth'(SliceIdxMaxInc32) : {SliceIdxWidth{1'b1}}; + ///////////// // Control // ///////////// @@ -69,7 +74,7 @@ module aes_ctr_fsm import aes_pkg::*; CTR_INCR: begin // Increment slice index. ctr_slice_idx_d = ctr_slice_idx_q + SliceIdxWidth'(1); - ctr_carry_d = ctr_value[SliceSizeCtr]; + ctr_carry_d = ctr_slice_idx_q >= ctr_slice_idx_max ? 1'b0 : ctr_value[SliceSizeCtr]; ctr_we_o = 1'b1; if (ctr_slice_idx_q == {SliceIdxWidth{1'b1}}) begin @@ -92,7 +97,7 @@ module aes_ctr_fsm import aes_pkg::*; endcase // Unconditionally jump into the terminal error state in case an error is detected. - if (incr_err_i || mr_err_i) begin + if (sp_enc_err_i || mr_err_i) begin aes_ctr_ns = CTR_ERROR; end end diff --git a/hw/ip/aes/rtl/aes_ctr_fsm_n.sv b/hw/ip/aes/rtl/aes_ctr_fsm_n.sv index e4308cf78c894..66547eb5bd79f 100644 --- a/hw/ip/aes/rtl/aes_ctr_fsm_n.sv +++ b/hw/ip/aes/rtl/aes_ctr_fsm_n.sv @@ -16,9 +16,10 @@ module aes_ctr_fsm_n import aes_pkg::*; input logic clk_i, input logic rst_ni, + input logic inc32_ni, // Sparsify using multi-rail. input logic incr_ni, // Sparsify using multi-rail. output logic ready_no, // Sparsify using multi-rail. - input logic incr_err_i, + input logic sp_enc_err_i, input logic mr_err_i, output logic alert_o, @@ -33,8 +34,9 @@ module aes_ctr_fsm_n import aes_pkg::*; ///////////////////// localparam int NumInBufBits = $bits({ + inc32_ni, incr_ni, - incr_err_i, + sp_enc_err_i, mr_err_i, ctr_slice_i }); @@ -42,8 +44,9 @@ module aes_ctr_fsm_n import aes_pkg::*; logic [NumInBufBits-1:0] in, in_buf; assign in = { + inc32_ni, incr_ni, - incr_err_i, + sp_enc_err_i, mr_err_i, ctr_slice_i }; @@ -57,13 +60,15 @@ module aes_ctr_fsm_n import aes_pkg::*; .out_o(in_buf) ); + logic inc32_n; logic incr_n; - logic incr_err; + logic sp_enc_err; logic mr_err; logic [SliceSizeCtr-1:0] ctr_i_slice; - assign {incr_n, - incr_err, + assign {inc32_n, + incr_n, + sp_enc_err, mr_err, ctr_i_slice} = in_buf; @@ -86,9 +91,10 @@ module aes_ctr_fsm_n import aes_pkg::*; .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .inc32_i ( ~inc32_n ), // Invert for regular FSM. .incr_i ( ~incr_n ), // Invert for regular FSM. .ready_o ( ready ), // Invert below for negated output. - .incr_err_i ( incr_err ), + .sp_enc_err_i ( sp_enc_err ), .mr_err_i ( mr_err ), .alert_o ( alert ), diff --git a/hw/ip/aes/rtl/aes_ctr_fsm_p.sv b/hw/ip/aes/rtl/aes_ctr_fsm_p.sv index 20ab23480866c..3d83a99d53089 100644 --- a/hw/ip/aes/rtl/aes_ctr_fsm_p.sv +++ b/hw/ip/aes/rtl/aes_ctr_fsm_p.sv @@ -12,9 +12,10 @@ module aes_ctr_fsm_p import aes_pkg::*; input logic clk_i, input logic rst_ni, + input logic inc32_i, // Sparsify input logic incr_i, // Sparsify output logic ready_o, // Sparsify - input logic incr_err_i, + input logic sp_enc_err_i, input logic mr_err_i, output logic alert_o, @@ -29,8 +30,9 @@ module aes_ctr_fsm_p import aes_pkg::*; ///////////////////// localparam int NumInBufBits = $bits({ + inc32_i, incr_i, - incr_err_i, + sp_enc_err_i, mr_err_i, ctr_slice_i }); @@ -38,8 +40,9 @@ module aes_ctr_fsm_p import aes_pkg::*; logic [NumInBufBits-1:0] in, in_buf; assign in = { + inc32_i, incr_i, - incr_err_i, + sp_enc_err_i, mr_err_i, ctr_slice_i }; @@ -53,13 +56,15 @@ module aes_ctr_fsm_p import aes_pkg::*; .out_o(in_buf) ); + logic inc32; logic incr; - logic incr_err; + logic sp_enc_err; logic mr_err; logic [SliceSizeCtr-1:0] ctr_i_slice; - assign {incr, - incr_err, + assign {inc32, + incr, + sp_enc_err, mr_err, ctr_i_slice} = in_buf; @@ -78,9 +83,10 @@ module aes_ctr_fsm_p import aes_pkg::*; .clk_i ( clk_i ), .rst_ni ( rst_ni ), + .inc32_i ( inc32 ), .incr_i ( incr ), .ready_o ( ready ), - .incr_err_i ( incr_err ), + .sp_enc_err_i ( sp_enc_err ), .mr_err_i ( mr_err ), .alert_o ( alert ), diff --git a/hw/ip/aes/rtl/aes_ctrl_gcm_reg_shadowed.sv b/hw/ip/aes/rtl/aes_ctrl_gcm_reg_shadowed.sv new file mode 100644 index 0000000000000..0ba295b7d5a40 --- /dev/null +++ b/hw/ip/aes/rtl/aes_ctrl_gcm_reg_shadowed.sv @@ -0,0 +1,180 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// AES Galois/Counter Mode (GCM) shadowed control register +// +// This module implements the shadowed AES GCM control register. The main differences compared +// to implementing the register as part of the auto-generated aes_reg_top.sv are: +// +// 1. The hardware can block updates to the GCM control register from software. +// Whenever the module is busy, GCM control register writes are ignored. +// 2. Invalid values written by software are resolved to valid configurations. + +`include "prim_assert.sv" + +module aes_ctrl_gcm_reg_shadowed + import aes_pkg::*; + import aes_reg_pkg::*; +#( + parameter bit AESGCMEnable = 1 +) ( + input logic clk_i, + input logic rst_ni, + input logic rst_shadowed_ni, + // Main control + output logic qe_o, // software wants to write + input logic we_i, // hardware grants software write + output gcm_phase_e gcm_phase_o, + output logic [4:0] num_valid_bytes_o, + + // Alerts + output logic err_update_o, + output logic err_storage_o, + + // Bus interface + input aes_reg2hw_ctrl_gcm_shadowed_reg_t reg2hw_ctrl_gcm_i, + output aes_hw2reg_ctrl_gcm_shadowed_reg_t hw2reg_ctrl_gcm_o +); + + // Signals + logic err_update_gcm_phase; + logic err_update_num_valid_bytes; + logic err_storage_gcm_phase; + logic err_storage_num_valid_bytes; + + // Get and forward write enable. Writes are only allowed if the module is idle. + assign qe_o = reg2hw_ctrl_gcm_i.phase.qe & reg2hw_ctrl_gcm_i.num_valid_bytes.qe; + + if (AESGCMEnable) begin : gen_ctrl_gcm_reg_shadowed + ctrl_gcm_reg_t ctrl_gcm_wd; + gcm_phase_e gcm_phase_reg_if, gcm_phase_d, gcm_phase_q; + logic [4:0] num_valid_bytes; + + // Get and resolve values from register interface. + assign gcm_phase_reg_if = gcm_phase_e'(reg2hw_ctrl_gcm_i.phase.q); + always_comb begin : gcm_phase_get + // Resolve unsupported input values. + unique case (gcm_phase_reg_if) + GCM_INIT: gcm_phase_d = GCM_INIT; + GCM_RESTORE: gcm_phase_d = GCM_RESTORE; + GCM_AAD: gcm_phase_d = GCM_AAD; + GCM_TEXT: gcm_phase_d = GCM_TEXT; + GCM_SAVE: gcm_phase_d = GCM_SAVE; + GCM_TAG: gcm_phase_d = GCM_TAG; + default: gcm_phase_d = GCM_INIT; // Unsupported values are mapped to GCM_INIT. + endcase + + // Only a subset of next phase transitions are allowed. + unique case (gcm_phase_q) + GCM_INIT: gcm_phase_d = gcm_phase_d == GCM_RESTORE || + gcm_phase_d == GCM_AAD || + gcm_phase_d == GCM_TEXT || + gcm_phase_d == GCM_TAG ? gcm_phase_d : gcm_phase_q; + GCM_RESTORE: gcm_phase_d = gcm_phase_d == GCM_INIT || + gcm_phase_d == GCM_AAD || + gcm_phase_d == GCM_TEXT ? gcm_phase_d : gcm_phase_q; + GCM_AAD: gcm_phase_d = gcm_phase_d == GCM_INIT || + gcm_phase_d == GCM_TEXT || + gcm_phase_d == GCM_SAVE || + gcm_phase_d == GCM_TAG ? gcm_phase_d : gcm_phase_q; + GCM_TEXT: gcm_phase_d = gcm_phase_d == GCM_INIT || + gcm_phase_d == GCM_SAVE || + gcm_phase_d == GCM_TAG ? gcm_phase_d : gcm_phase_q; + GCM_SAVE: gcm_phase_d = gcm_phase_d == GCM_INIT ? gcm_phase_d : gcm_phase_q; + GCM_TAG: gcm_phase_d = gcm_phase_d == GCM_INIT ? gcm_phase_d : gcm_phase_q; + default: gcm_phase_d = gcm_phase_q; // If we end up in an unspported value (which + // should never happen), keep it. + endcase + end + assign ctrl_gcm_wd.phase = gcm_phase_d; + + assign num_valid_bytes = reg2hw_ctrl_gcm_i.num_valid_bytes.q; + // Unsupported values are mapped to 16. + assign ctrl_gcm_wd.num_valid_bytes = num_valid_bytes != 5'd0 ? num_valid_bytes : 5'd16; + + // SEC_CM: GCM.CONFIG.SHADOW + // Instantiate one shadowed register primitive per field. An update error in a field should + // only prevent the update of the affected field. + prim_subreg_shadow #( + .DW ($bits(gcm_phase_e)), + .SwAccess(prim_subreg_pkg::SwAccessWO), + .RESVAL (AES_CTRL_GCM_SHADOWED_PHASE_RESVAL) + ) u_ctrl_gcm_reg_shadowed_phase ( + .clk_i, + .rst_ni, + .rst_shadowed_ni, + .re (reg2hw_ctrl_gcm_i.phase.re), + .we (we_i), + .wd ({ctrl_gcm_wd.phase}), + .de (1'b0), + .d ('0), + .qe (), + .q (gcm_phase_q), + .qs (), + .ds (), + .phase (), + .err_update (err_update_gcm_phase), + .err_storage(err_storage_gcm_phase) + ); + assign hw2reg_ctrl_gcm_o.phase.d = {gcm_phase_q}; + + prim_subreg_shadow #( + .DW (5), + .SwAccess(prim_subreg_pkg::SwAccessWO), + .RESVAL (AES_CTRL_GCM_SHADOWED_NUM_VALID_BYTES_RESVAL) + ) u_ctrl_gcm_reg_shadowed_num_valid_bytes ( + .clk_i, + .rst_ni, + .rst_shadowed_ni, + .re (reg2hw_ctrl_gcm_i.num_valid_bytes.re), + .we (we_i), + .wd ({ctrl_gcm_wd.num_valid_bytes}), + .de (1'b0), + .d ('0), + .qe (), + .q (hw2reg_ctrl_gcm_o.num_valid_bytes.d), + .qs (), + .ds (), + .phase (), + .err_update (err_update_num_valid_bytes), + .err_storage(err_storage_num_valid_bytes) + ); + end else begin : gen_no_ctrl_gcm_reg_shadowed + // Tie off unused inputs. + logic unused_ctrl_gcm; + assign unused_ctrl_gcm = ^{reg2hw_ctrl_gcm_i.phase.re, + reg2hw_ctrl_gcm_i.phase.q, + reg2hw_ctrl_gcm_i.num_valid_bytes.re, + reg2hw_ctrl_gcm_i.num_valid_bytes.q}; + logic unused_we; + assign unused_we = we_i; + + logic unused_clk; + logic unused_rst; + logic unused_rst_shadowed; + assign unused_clk = clk_i; + assign unused_rst = rst_ni; + assign unused_rst_shadowed = rst_shadowed_ni; + + // Tie off control signals. + assign hw2reg_ctrl_gcm_o.phase.d = {GCM_INIT}; + assign hw2reg_ctrl_gcm_o.num_valid_bytes.d = 5'd16; + + // Tie off error signals. + assign err_update_gcm_phase = 1'b0; + assign err_update_num_valid_bytes = 1'b0; + assign err_storage_gcm_phase = 1'b0; + assign err_storage_num_valid_bytes = 1'b0; + end + + // Collect alerts. + assign err_update_o = err_update_gcm_phase | err_update_num_valid_bytes; + assign err_storage_o = err_storage_gcm_phase | err_storage_num_valid_bytes; + + // Generate shorter references. + // Doing that here as opposed to in aes_core avoids several Verilator lint errors. + assign gcm_phase_o = gcm_phase_e'(hw2reg_ctrl_gcm_o.phase.d); + assign num_valid_bytes_o = hw2reg_ctrl_gcm_o.num_valid_bytes.d; + +endmodule diff --git a/hw/ip/aes/rtl/aes_ctrl_reg_shadowed.sv b/hw/ip/aes/rtl/aes_ctrl_reg_shadowed.sv index 46d824008b068..f92707bf33488 100644 --- a/hw/ip/aes/rtl/aes_ctrl_reg_shadowed.sv +++ b/hw/ip/aes/rtl/aes_ctrl_reg_shadowed.sv @@ -17,7 +17,8 @@ module aes_ctrl_reg_shadowed import aes_pkg::*; import aes_reg_pkg::*; #( - parameter bit AES192Enable = 1 + parameter bit AES192Enable = 1, + parameter bit AESGCMEnable = 1 ) ( input logic clk_i, input logic rst_ni, @@ -90,6 +91,7 @@ module aes_ctrl_reg_shadowed AES_CFB: ctrl_wd.mode = AES_CFB; AES_OFB: ctrl_wd.mode = AES_OFB; AES_CTR: ctrl_wd.mode = AES_CTR; + AES_GCM: ctrl_wd.mode = AESGCMEnable ? AES_GCM : AES_NONE; default: ctrl_wd.mode = AES_NONE; // unsupported values are mapped to AES_NONE endcase end diff --git a/hw/ip/aes/rtl/aes_ghash.sv b/hw/ip/aes/rtl/aes_ghash.sv new file mode 100644 index 0000000000000..7e716fb5cc5c8 --- /dev/null +++ b/hw/ip/aes/rtl/aes_ghash.sv @@ -0,0 +1,431 @@ +// Copyright lowRISC contributors (OpenTitan project). +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +// +// AES GHASH implementation for AES-GCM +// +// This module implements the GHASH core including hash state and hash key register required for +// AES-GCM. +// +// Details on the data formats +// --------------------------- +// +// The aes_core as well as the aes_cipher_core modules use 4-dimensional SystemVerilog arrays to +// represent AES states: +// +// logic [3:0][3:0][7:0] state_q [NumShares]; +// +// The fourth dimension (unpacked) corresponds to the different shares. The first element holds the +// (masked) data share whereas the other elements hold the masks (masked implementation only). +// The three packed dimensions correspond to the 128-bit state matrix per share. This +// implementation uses the same encoding as the Advanced Encryption Standard (AES) FIPS Publication +// 197 available at https://www.nist.gov/publications/advanced-encryption-standard-aes (see Section +// 3.4). An input sequence of 16 bytes (128-bit, left most byte is the first one) +// +// B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 +// +// is mapped to the state matrix as +// +// [ B0 B4 B8 B12 ] +// [ B1 B5 B9 B13 ] +// [ B2 B6 B10 B14 ] +// [ B3 B7 B11 B15 ] . +// +// In contrast, this implementation of the GHASH module uses 2-dimensional SystemVerilog arrays +// to represent bit strings: +// +// logic [127:0] hash_subkey_q [NumShares]; +// +// The second dimension (unpacked) corresponds to the different shares. The first element holds +// the (masked) data share whereas the other elements hold the masks (masked implementation only). +// The unpacked dimension corresponds to the 128-bit bit string per share. This implementation +// uses the same encoding as Recommendation for Block Cipher Modes of Operation: Galois/Counter +// Mode (GCM) and GMAC NIST Special Publication 800-38D available at +// https://csrc.nist.gov/pubs/sp/800/38/d/final (See Section 6.1) and as Advanced Encryption +// Standard (AES) FIPS Publication 197 available at +// https://www.nist.gov/publications/advanced-encryption-standard-aes (see Section 3.3). An input +// sequence of 128 bits (left most bit is the first one) +// +// b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 ... b125 b126 b127 +// +// is mapped to Bytes as follows +// +// B0 = {b0 b1 b2 b3 b4 b5 b6 b7 } +// B1 = {b8 b9 b10 b11 b12 b13 b14 b15 } +// . +// B15 = {b120 b121 b122 b123 b124 b125 b126 b127} . +// +// Internally, this is mapped to the 128-bit packed dimension of the SystemVerilog array as follows +// +// /-------- Byte 0 --------\ ... /-------- Byte 15 -------\ +// 128'b{ b0, b1, b2, ... b5, b6, b7, b8, b9, ..., b119, b120, ... b126, b127 } +// +// meaning the hexadecimal representations of these values can directly be compared with test vector +// data found in The Galois/Counter Mode of Operation (GCM) available at +// https://csrc.nist.rip/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf (See +// Appendix B). +// +// However, when interfacing the GF(2^128) multiplier, the bit order has to reversed to obtain +// packed 128-bit SystemVerilog arrays with the MSB left and the LSB right, i.e., +// +// 128'b{ b127, b126, ... b1, b0 } . +// +// The final authentication tag is put out via Data Out registers and uses again the above format +// +// MSB LSB +// - DATA_OUT_0 32'h{ B3 B2 B1 B0 } +// - DATA_OUT_1 32'h{ B7 B6 B5 B4 } +// - DATA_OUT_2 32'h{ B11 B10 B9 B8 } +// - DATA_OUT_3 32'h{ B15 B14 B13 B12 } +// +// Or in terms of bits +// MSB LSB +// - DATA_OUT_0 32'h = 32'h{ b24 b25 b26 b27 b28 b29 b30 b31 ... b0 b1 b2 b3 b4 b5 b6 b7 } +// - ... + +`include "prim_assert.sv" + +module aes_ghash + import aes_pkg::*; + import aes_reg_pkg::*; +#( + parameter bit SecMasking = 0, + parameter sbox_impl_e SecSBoxImpl = SBoxImplLut, + + localparam int NumShares = SecMasking ? 2 : 1 // derived parameter +) ( + input logic clk_i, + input logic rst_ni, + + // Input handshake signals + input sp2v_e in_valid_i, + output sp2v_e in_ready_o, + + // Output handshake signals + output sp2v_e out_valid_o, + input sp2v_e out_ready_i, + + // Control signals + input aes_op_e op_i, + input gcm_phase_e gcm_phase_i, + input logic [4:0] num_valid_bytes_i, + input sp2v_e load_hash_subkey_i, + input logic clear_i, + input logic alert_fatal_i, + output logic alert_o, + + // I/O data signals + input logic [3:0][3:0][7:0] cipher_state_init_i [NumShares], // Masked cipher core input + // for GCM_RESTORE + input logic [GCMDegree-1:0] data_in_prev_i, // Ciphertext for decryption + // or AAD + input logic [NumRegsData-1:0][31:0] data_out_i, // Ciphertext for encryption + input logic [3:0][3:0][7:0] cipher_state_done_i [NumShares], // Masked cipher core output + output logic [NumRegsData-1:0][31:0] ghash_state_done_o +); + + // For now, this implementation is always unmasked. + localparam int NumSharesLocal = 1; + + // Parameters + // The number of cycles must be a power of two and ideally matches the minimum latency of the + // cipher core which is 56 clock cycles (masked) or 12 clock cycles (unmasked) for AES-128. + localparam int unsigned GFMultCycles = (SecSBoxImpl == SBoxImplDom) ? 32 : 8; + + // Signals + logic [GCMDegree-1:0] s_d [NumSharesLocal]; + logic [GCMDegree-1:0] s_q [NumSharesLocal]; + sp2v_e s_we; + logic [15:0][7:0] ghash_in; + logic [15:0][7:0] ghash_in_valid; + ghash_in_sel_e ghash_in_sel; + logic [GCMDegree-1:0] ghash_state_d [NumSharesLocal]; + logic [GCMDegree-1:0] ghash_state_q [NumSharesLocal]; + logic [GCMDegree-1:0] ghash_state_add [NumSharesLocal]; + sp2v_e ghash_state_we; + ghash_state_sel_e ghash_state_sel; + logic [GCMDegree-1:0] ghash_state_mult [NumSharesLocal]; + logic [GCMDegree-1:0] hash_subkey_d [NumSharesLocal]; + logic [GCMDegree-1:0] hash_subkey_q [NumSharesLocal]; + sp2v_e hash_subkey_we; + logic gf_mult_req; + logic gf_mult_ack; + aes_ghash_e aes_ghash_ns, aes_ghash_cs; + + ////////////////////////////////// + // Input Data Format Conversion // + ////////////////////////////////// + // Covert the input data to the internal data format. + logic [GCMDegree-1:0] cipher_state_init [NumSharesLocal]; + logic [GCMDegree-1:0] cipher_state_done [NumSharesLocal]; + logic [GCMDegree-1:0] data_in_prev; + logic [GCMDegree-1:0] data_out; + always_comb begin : data_in_conversion + cipher_state_done = '{default: '0}; + cipher_state_init = '{default: '0}; + for (int s = 0; s < NumShares; s++) begin + cipher_state_done[0] ^= aes_state_to_ghash_vec(cipher_state_done_i[s]); + cipher_state_init[0] ^= aes_state_to_ghash_vec(cipher_state_init_i[s]); + end + data_in_prev = aes_state_to_ghash_vec(aes_transpose(data_in_prev_i)); + data_out = aes_state_to_ghash_vec(aes_transpose(data_out_i)); + end + + + //////////////////// + // S = AES_K(J_0) // + //////////////////// + // The initial counter block J_0 encrypted using the encryption key K. For the unmasked + // implementation this is only used at the very end. For the masked implementaion, it is used + // multiple times and in various forms throughout the computation of the authentication tag. + // + // This register can be cleared with pseudo-random data by loading the output of the cipher + // core after having cleared the internal state of the cipher core. + assign s_d = cipher_state_done; + always_ff @(posedge clk_i or negedge rst_ni) begin : s_reg + if (!rst_ni) begin + s_q <= '{default: '0}; + end else if (s_we == SP2V_HIGH) begin + s_q <= s_d; + end + end + + ///////////////// + // GHASH Input // + ///////////////// + // Select the ciphertext for encryption / decryption or S for the final authentication tag. + always_comb begin : ghash_in_mux + unique case (ghash_in_sel) + GHASH_IN_DATA_IN_PREV: ghash_in = data_in_prev; + GHASH_IN_DATA_OUT: ghash_in = data_out; + GHASH_IN_S: ghash_in = s_q[0]; + default: ghash_in = data_out; + endcase + end + + // Mask invalid bytes. The least significant byte is mapped to Position 15 internally. See + // the section "Details on the data formats" in the header for details. + always_comb begin + for (int unsigned i = 0; i < 16; i++) begin + ghash_in_valid[15-i] = num_valid_bytes_i > i[4:0] ? ghash_in[15-i] : 8'b0; + end + end + + ///////////////// + // GHASH State // + ///////////////// + // Add the GHASH input to the current state. + assign ghash_state_add[0] = ghash_state_q[0] ^ ghash_in_valid; + if (SecMasking || NumSharesLocal != 1) begin : gen_ghash_state_shares + for (genvar s = 1; s < NumSharesLocal; s++) begin : gen_ghash_state_shares_s + assign ghash_state_add[s] = ghash_state_q[s]; + assign ghash_state_mult[s] = ghash_state_q[s]; + end + end + + always_comb begin : ghash_state_mux + unique case (ghash_state_sel) + GHASH_STATE_RESTORE: ghash_state_d = cipher_state_init; + GHASH_STATE_INIT: ghash_state_d = '{default: '0}; + GHASH_STATE_ADD: ghash_state_d = ghash_state_add; + GHASH_STATE_MULT: ghash_state_d = ghash_state_mult; + default: ghash_state_d = ghash_state_add; + endcase + end + + // This register can be cleared with pseudo-random data by adding the output of the cipher core + // to the current state after having cleared the internal state of the cipher core. + always_ff @(posedge clk_i or negedge rst_ni) begin : ghash_state_reg + if (!rst_ni) begin + ghash_state_q <= '{default: '0}; + end else if (ghash_state_we == SP2V_HIGH) begin + ghash_state_q <= ghash_state_d; + end + end + + ///////////////// + // Hash Subkey // + ///////////////// + // This register can be cleared with pseudo-random data by loading the output of the cipher + // core after having cleared the internal state of the cipher core. + assign hash_subkey_d = cipher_state_done; + always_ff @(posedge clk_i or negedge rst_ni) begin : hash_subkey_reg + if (!rst_ni) begin + hash_subkey_q <= '{default: '0}; + end else if (hash_subkey_we == SP2V_HIGH) begin + hash_subkey_q <= hash_subkey_d; + end + end + + ////////////////////////// + // GF(2^128) Multiplier // + ////////////////////////// + + logic [GCMDegree-1:0] gf_mult_prod; + + prim_gf_mult #( + .Width (GCMDegree), + .StagesPerCycle(GCMDegree / GFMultCycles), + .IPoly (GCMIPoly) + ) u_gf_mult ( + .clk_i (clk_i), + .rst_ni(rst_ni), + + .req_i(gf_mult_req), + .ack_o(gf_mult_ack), + + .operand_a_i(aes_ghash_reverse_bit_order(ghash_state_q[0])), // The A input is scanned. + .operand_b_i(aes_ghash_reverse_bit_order(hash_subkey_q[0])), // The B input is not scanned. + + .prod_o(gf_mult_prod) + ); + assign ghash_state_mult[0] = aes_ghash_reverse_bit_order(gf_mult_prod); + + ///////////////// + // Control FSM // + ///////////////// + + always_comb begin : aes_ghash_fsm + + // Handshake signals + in_ready_o = SP2V_LOW; + out_valid_o = SP2V_LOW; + + // Data path + s_we = SP2V_LOW; + + ghash_in_sel = GHASH_IN_DATA_OUT; + + ghash_state_sel = GHASH_STATE_ADD; + ghash_state_we = SP2V_LOW; + + hash_subkey_we = SP2V_LOW; + + gf_mult_req = 1'b0; + + // FSM + aes_ghash_ns = aes_ghash_cs; + + // Alert + alert_o = 1'b0; + + unique case (aes_ghash_cs) + GHASH_IDLE: begin + in_ready_o = SP2V_HIGH; + if (in_valid_i == SP2V_HIGH) begin + if (clear_i) begin + // Clearing has highest priority. + s_we = SP2V_HIGH; + ghash_state_we = SP2V_HIGH; + hash_subkey_we = SP2V_HIGH; + + end else if (gcm_phase_i == GCM_INIT) begin + if (load_hash_subkey_i == SP2V_HIGH) begin + + // Load the hash subkey. + hash_subkey_we = SP2V_HIGH; + end else begin + + // Load S and initialize the state. + s_we = SP2V_HIGH; + ghash_state_sel = GHASH_STATE_INIT; + ghash_state_we = SP2V_HIGH; + end + + end else if (gcm_phase_i == GCM_RESTORE) begin + // Restore a previously loaded GHASH state. + ghash_state_sel = GHASH_STATE_RESTORE; + ghash_state_we = SP2V_HIGH; + + end else if (gcm_phase_i == GCM_AAD || + gcm_phase_i == GCM_TEXT || + gcm_phase_i == GCM_TAG) begin + // Select the proper input for the addition. + ghash_in_sel = + (gcm_phase_i == GCM_AAD) ? GHASH_IN_DATA_IN_PREV : + (gcm_phase_i == GCM_TEXT && op_i == AES_DEC) ? GHASH_IN_DATA_IN_PREV : + (gcm_phase_i == GCM_TEXT && op_i == AES_ENC) ? GHASH_IN_DATA_OUT : + (gcm_phase_i == GCM_TAG) ? GHASH_IN_DATA_IN_PREV : + GHASH_IN_DATA_OUT; + + // Add the current input to the GHASH state to start the multiplication in the next + // clock cycle. + ghash_state_sel = GHASH_STATE_ADD; + ghash_state_we = SP2V_HIGH; + + aes_ghash_ns = GHASH_MULT; + + end else if (gcm_phase_i == GCM_SAVE) begin + // Get ready to output the current GHASH state. + aes_ghash_ns = GHASH_OUT; + + end else begin + // Handshake without a valid command. We should never get here. If we do (e.g. via a + // malicious glitch), error out immediately. + aes_ghash_ns = GHASH_ERROR; + end + end + end + + GHASH_MULT: begin + // Perform the multiplication and update the state. + gf_mult_req = 1'b1; + if (gf_mult_ack) begin + ghash_state_sel = GHASH_STATE_MULT; + ghash_state_we = SP2V_HIGH; + aes_ghash_ns = (gcm_phase_i == GCM_TAG) ? GHASH_TAG : GHASH_IDLE; + end + end + + GHASH_TAG: begin + // Add S to the GHASH state and then get ready to output the final tag. + ghash_in_sel = GHASH_IN_S; + ghash_state_sel = GHASH_STATE_ADD; + ghash_state_we = SP2V_HIGH; + + aes_ghash_ns = GHASH_OUT; + end + + GHASH_OUT: begin + // Perform output handshake and clear all internal state with pseudo-random data. + out_valid_o = SP2V_HIGH; + if (out_ready_i == SP2V_HIGH) begin + s_we = SP2V_HIGH; + ghash_state_we = SP2V_HIGH; + hash_subkey_we = SP2V_HIGH; + aes_ghash_ns = GHASH_IDLE; + end + end + + GHASH_ERROR: begin + // Terminal error state + alert_o = 1'b1; + end + + // We should never get here. If we do (e.g. via a malicious glitch), error out immediately. + default: begin + aes_ghash_ns = GHASH_ERROR; + alert_o = 1'b1; + end + endcase + + // Unconditionally jump into the terminal error state if a fatal alert has been triggered. + if (alert_fatal_i) begin + aes_ghash_ns = GHASH_ERROR; + end + end + + // SEC_CM: GHASH.FSM.SPARSE + `PRIM_FLOP_SPARSE_FSM(u_state_regs, aes_ghash_ns, + aes_ghash_cs, aes_ghash_e, GHASH_IDLE) + + ///////////// + // Outputs // + ///////////// + + // Covert the output data from the internal data format to the output format. + always_comb begin : data_out_conversion + ghash_state_done_o = aes_transpose(aes_state_to_ghash_vec(ghash_state_q[0])); + end + +endmodule diff --git a/hw/ip/aes/rtl/aes_pkg.sv b/hw/ip/aes/rtl/aes_pkg.sv index 0643bb88cf605..acbf4fadf0104 100644 --- a/hw/ip/aes/rtl/aes_pkg.sv +++ b/hw/ip/aes/rtl/aes_pkg.sv @@ -19,6 +19,9 @@ parameter int unsigned SliceSizeCtr = 16; parameter int unsigned NumSlicesCtr = aes_reg_pkg::NumRegsIv * 32 / SliceSizeCtr; parameter int unsigned SliceIdxWidth = prim_util_pkg::vbits(NumSlicesCtr); +// In GCM, the counter performs inc32() instead of inc128(), i.e., the counter wraps at 32 bits. +parameter int unsigned SliceIdxMaxInc32 = 32 / SliceSizeCtr - 1; + // Widths of signals carrying pseudo-random data for clearing parameter int unsigned WidthPRDClearing = 64; parameter int unsigned NumChunksPRDClearing128 = 128/WidthPRDClearing; @@ -83,12 +86,26 @@ typedef enum integer { // see aes_sbox_canright_dom.sv } sbox_impl_e; +// GF(2^128) irreducible, field-generating polynomial for AES-GCM +// See Section "6.3 Multiplication Operation on Blocks" of +// https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf on Page 11: +// "Let R be the bit string 11100001 || 0^120." +// And further on Page 12: +// "The reduction modulus is the polynomial of degree 128 that corresponds to R || 1" +// Or in other words: x^128 + x^7 + x^2 + x + 1 +// The MSB gets clipped off below. +parameter int unsigned GCMDegree = 128; +parameter bit [GCMDegree-1:0] GCMIPoly = GCMDegree'(1'b1) << 7 | + GCMDegree'(1'b1) << 2 | + GCMDegree'(1'b1) << 1 | + GCMDegree'(1'b1) << 0; // Parameters used for controlgroups in the coverage parameter int AES_OP_WIDTH = 2; parameter int AES_MODE_WIDTH = 6; parameter int AES_KEYLEN_WIDTH = 3; parameter int AES_PRNGRESEEDRATE_WIDTH = 3; +parameter int AES_GCMPHASE_WIDTH = 6; // SEC_CM: MAIN.CONFIG.SPARSE typedef enum logic [AES_OP_WIDTH-1:0] { @@ -103,9 +120,11 @@ typedef enum logic [AES_MODE_WIDTH-1:0] { AES_CFB = 6'b00_0100, AES_OFB = 6'b00_1000, AES_CTR = 6'b01_0000, - AES_NONE = 6'b10_0000 + AES_GCM = 6'b10_0000, + AES_NONE = 6'b11_1111 } aes_mode_e; +// SEC_CM: MAIN.CONFIG.SPARSE typedef enum logic [AES_OP_WIDTH-1:0] { CIPH_FWD = 2'b01, CIPH_INV = 2'b10 @@ -126,6 +145,16 @@ typedef enum logic [AES_PRNGRESEEDRATE_WIDTH-1:0] { } prs_rate_e; parameter int unsigned BlockCtrWidth = 13; +// SEC_CM: GCM.CONFIG.SPARSE +typedef enum logic [AES_GCMPHASE_WIDTH-1:0] { + GCM_INIT = 6'b00_0001, + GCM_RESTORE = 6'b00_0010, + GCM_AAD = 6'b00_0100, + GCM_TEXT = 6'b00_1000, + GCM_SAVE = 6'b01_0000, + GCM_TAG = 6'b10_0000 +} gcm_phase_e; + typedef struct packed { logic [31:7] unused; logic alert_fatal_fault; @@ -220,7 +249,7 @@ typedef struct packed { typedef enum logic [CtrlStateWidth-1:0] { CTRL_IDLE = 6'b001001, CTRL_LOAD = 6'b100011, - CTRL_PRNG_UPDATE = 6'b111101, + CTRL_GHASH_READY = 6'b111101, CTRL_PRNG_RESEED = 6'b010000, CTRL_FINISH = 6'b100100, CTRL_CLEAR_I = 6'b111010, @@ -228,6 +257,34 @@ typedef struct packed { CTRL_ERROR = 6'b010111 } aes_ctrl_e; +// Encoding generated with: +// $ ./util/design/sparse-fsm-encode.py -d 3 -m 5 -n 6 \ +// -s 31468618 --language=sv +// +// Hamming distance histogram: +// +// 0: -- +// 1: -- +// 2: -- +// 3: |||||||||||||||||||| (50.00%) +// 4: |||||||||||||||| (40.00%) +// 5: |||| (10.00%) +// 6: -- +// +// Minimum Hamming distance: 3 +// Maximum Hamming distance: 5 +// Minimum Hamming weight: 1 +// Maximum Hamming weight: 5 +// +localparam int GhashStateWidth = 6; +typedef enum logic [GhashStateWidth-1:0] { + GHASH_IDLE = 6'b110000, + GHASH_MULT = 6'b001000, + GHASH_TAG = 6'b000011, + GHASH_OUT = 6'b011101, + GHASH_ERROR = 6'b111110 +} aes_ghash_e; + // Generic, sparse mux selector encodings // Encoding generated with: @@ -299,6 +356,35 @@ typedef enum logic [Mux4SelWidth-1:0] { MUX4_SEL_3 = 5'b10111 } mux4_sel_e; +// Encoding generated with: +// $ ./util/design/sparse-fsm-encode.py -d 3 -m 5 -n 6 \ +// -s 31468618 --language=sv +// +// Hamming distance histogram: +// +// 0: -- +// 1: -- +// 2: -- +// 3: |||||||||||||||||||| (50.00%) +// 4: |||||||||||||||| (40.00%) +// 5: |||| (10.00%) +// 6: -- +// +// Minimum Hamming distance: 3 +// Maximum Hamming distance: 5 +// Minimum Hamming weight: 1 +// Maximum Hamming weight: 5 +// +localparam int Mux5SelWidth = 6; +typedef enum logic [Mux5SelWidth-1:0] { + MUX5_SEL_0 = 6'b110000, + MUX5_SEL_1 = 6'b001000, + MUX5_SEL_2 = 6'b000011, + MUX5_SEL_3 = 6'b011101, + MUX5_SEL_4 = 6'b111110 +} mux5_sel_e; + + // $ ./sparse-fsm-encode.py -d 3 -m 6 -n 6 \ // -s 31468618 --language=sv // @@ -423,6 +509,30 @@ typedef enum logic [AddSOSelWidth-1:0] { ADD_SO_DIP = MUX3_SEL_2 } add_so_sel_e; +parameter int GHashInSelNum = 3; +parameter int GHashInSelWidth = Mux3SelWidth; +typedef enum logic [GHashInSelWidth-1:0] { + GHASH_IN_DATA_IN_PREV = MUX3_SEL_0, + GHASH_IN_DATA_OUT = MUX3_SEL_1, + GHASH_IN_S = MUX3_SEL_2 +} ghash_in_sel_e; + +parameter int GHashStateSelNum = 4; +parameter int GHashStateSelWidth = Mux4SelWidth; +typedef enum logic [GHashStateSelWidth-1:0] { + GHASH_STATE_RESTORE = MUX4_SEL_0, + GHASH_STATE_INIT = MUX4_SEL_1, + GHASH_STATE_ADD = MUX4_SEL_2, + GHASH_STATE_MULT = MUX4_SEL_3 +} ghash_state_sel_e; + +parameter int DataOutSelNum = 2; +parameter int DataOutSelWidth = Mux2SelWidth; +typedef enum logic [DataOutSelWidth-1:0] { + DATA_OUT_CIPHER = MUX2_SEL_0, + DATA_OUT_GHASH = MUX2_SEL_1 +} data_out_sel_e; + // Sparse two-value signal type sp2v_e parameter int Sp2VNum = 2; parameter int Sp2VWidth = Mux2SelWidth; @@ -453,6 +563,12 @@ parameter ctrl_reg_t CTRL_RESET = '{ operation: aes_op_e'(aes_reg_pkg::AES_CTRL_SHADOWED_OPERATION_RESVAL) }; +// GCM control register type +typedef struct packed { + logic [4:0] num_valid_bytes; + gcm_phase_e phase; +} ctrl_gcm_reg_t; + // Multiplication by {02} (i.e. x) on GF(2^8) // with field generating polynomial {01}{1b} (9'h11b) // Sometimes also denoted by xtime(). @@ -513,6 +629,28 @@ function automatic logic [3:0][3:0][7:0] aes_transpose(logic [3:0][3:0][7:0] in) return transpose; endfunction +// Convert AES byte state matrix to internal GHASH bit vector representation. +function automatic logic [127:0] aes_state_to_ghash_vec(logic [3:0][3:0][7:0] in); + logic [127:0] out; + logic [15:0][7:0] byte_vec; + for (int i = 0; i < 4; i++) begin + for (int j = 0; j < 4; j++) begin + byte_vec[15 - 4*i - j] = in[j][i]; + end + end + out = byte_vec; + return out; +endfunction + +// Convert internal GHASH bit vector representation to simple bit vector. +function automatic logic [127:0] aes_ghash_reverse_bit_order(logic [127:0] in); + logic [127:0] out; + for (int i = 0; i < 128; i++) begin + out[i] = in[127-i]; + end + return out; +endfunction + // Extract single column from state matrix function automatic logic [3:0][7:0] aes_col_get(logic [3:0][3:0][7:0] in, logic [1:0] idx); logic [3:0][7:0] out; diff --git a/hw/ip/aes/rtl/aes_prng_clearing.sv b/hw/ip/aes/rtl/aes_prng_clearing.sv index 0301349fd8306..5e20f4da5edab 100644 --- a/hw/ip/aes/rtl/aes_prng_clearing.sv +++ b/hw/ip/aes/rtl/aes_prng_clearing.sv @@ -27,8 +27,7 @@ module aes_prng_clearing import aes_pkg::*; input logic rst_ni, // Connections to AES internals, PRNG consumers - input logic data_req_i, - output logic data_ack_o, + input logic data_update_i, output logic [Width-1:0] data_o [NumSharesKey], input logic reseed_req_i, output logic reseed_ack_o, @@ -45,6 +44,12 @@ module aes_prng_clearing import aes_pkg::*; logic lfsr_en; logic [Width-1:0] lfsr_state; + // The data requests are fed from an LFSR. Reseed requests take precedence internally to the + // LFSR. If there is an outstanding reseed request, the PRNG can keep updating and providing + // pseudo-random data (using the old seed). If the reseeding is taking place, the LFSR will + // provide fresh pseudo-random data (the new seed) in the next cycle anyway. This means the PRNG + // is always ready to provide new pseudo-random data. + // In the current SCA setup, we don't have sufficient resources to implement the infrastructure // required for PRNG reseeding (CSRNG, EDN, etc.). Therefore, we skip any reseeding requests if // the SecSkipPRNGReseeding parameter is set. Performing the reseeding without proper entropy @@ -55,12 +60,9 @@ module aes_prng_clearing import aes_pkg::*; `ASSERT_STATIC_LINT_ERROR(AesSecSkipPRNGReseedingNonDefault, SecSkipPRNGReseeding == 0) // LFSR control - assign lfsr_en = data_req_i & data_ack_o; + assign lfsr_en = data_update_i; assign seed_en = SecSkipPRNGReseeding ? 1'b0 : seed_valid; - // 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; - // Width adaption for reseeding interface. We get EntropyWidth bits at a time. if (Width/2 == EntropyWidth) begin : gen_buffer // We buffer the first EntropyWidth bits. diff --git a/hw/ip/aes/rtl/aes_reg_pkg.sv b/hw/ip/aes/rtl/aes_reg_pkg.sv index 9edec48bd6c64..f791e3038486a 100644 --- a/hw/ip/aes/rtl/aes_reg_pkg.sv +++ b/hw/ip/aes/rtl/aes_reg_pkg.sv @@ -121,6 +121,19 @@ package aes_reg_pkg; } idle; } aes_reg2hw_status_reg_t; + typedef struct packed { + struct packed { + logic [4:0] q; + logic qe; + logic re; + } num_valid_bytes; + struct packed { + logic [5:0] q; + logic qe; + logic re; + } phase; + } aes_reg2hw_ctrl_gcm_shadowed_reg_t; + typedef struct packed { logic [31:0] d; } aes_hw2reg_key_share0_mreg_t; @@ -213,30 +226,41 @@ package aes_reg_pkg; } alert_fatal_fault; } aes_hw2reg_status_reg_t; + typedef struct packed { + struct packed { + logic [5:0] d; + } phase; + struct packed { + logic [4:0] d; + } num_valid_bytes; + } aes_hw2reg_ctrl_gcm_shadowed_reg_t; + // Register -> HW type typedef struct packed { - aes_reg2hw_alert_test_reg_t alert_test; // [957:954] - aes_reg2hw_key_share0_mreg_t [7:0] key_share0; // [953:690] - aes_reg2hw_key_share1_mreg_t [7:0] key_share1; // [689:426] - aes_reg2hw_iv_mreg_t [3:0] iv; // [425:294] - aes_reg2hw_data_in_mreg_t [3:0] data_in; // [293:162] - aes_reg2hw_data_out_mreg_t [3:0] data_out; // [161:30] - aes_reg2hw_ctrl_shadowed_reg_t ctrl_shadowed; // [29:8] - aes_reg2hw_ctrl_aux_shadowed_reg_t ctrl_aux_shadowed; // [7:6] - aes_reg2hw_trigger_reg_t trigger; // [5:2] - aes_reg2hw_status_reg_t status; // [1:0] + aes_reg2hw_alert_test_reg_t alert_test; // [970:967] + aes_reg2hw_key_share0_mreg_t [7:0] key_share0; // [966:703] + aes_reg2hw_key_share1_mreg_t [7:0] key_share1; // [702:439] + aes_reg2hw_iv_mreg_t [3:0] iv; // [438:307] + aes_reg2hw_data_in_mreg_t [3:0] data_in; // [306:175] + aes_reg2hw_data_out_mreg_t [3:0] data_out; // [174:43] + aes_reg2hw_ctrl_shadowed_reg_t ctrl_shadowed; // [42:21] + aes_reg2hw_ctrl_aux_shadowed_reg_t ctrl_aux_shadowed; // [20:19] + aes_reg2hw_trigger_reg_t trigger; // [18:15] + aes_reg2hw_status_reg_t status; // [14:13] + aes_reg2hw_ctrl_gcm_shadowed_reg_t ctrl_gcm_shadowed; // [12:0] } aes_reg2hw_t; // HW -> register type typedef struct packed { - aes_hw2reg_key_share0_mreg_t [7:0] key_share0; // [937:682] - aes_hw2reg_key_share1_mreg_t [7:0] key_share1; // [681:426] - aes_hw2reg_iv_mreg_t [3:0] iv; // [425:298] - aes_hw2reg_data_in_mreg_t [3:0] data_in; // [297:166] - aes_hw2reg_data_out_mreg_t [3:0] data_out; // [165:38] - aes_hw2reg_ctrl_shadowed_reg_t ctrl_shadowed; // [37:22] - aes_hw2reg_trigger_reg_t trigger; // [21:14] - aes_hw2reg_status_reg_t status; // [13:0] + aes_hw2reg_key_share0_mreg_t [7:0] key_share0; // [948:693] + aes_hw2reg_key_share1_mreg_t [7:0] key_share1; // [692:437] + aes_hw2reg_iv_mreg_t [3:0] iv; // [436:309] + aes_hw2reg_data_in_mreg_t [3:0] data_in; // [308:177] + aes_hw2reg_data_out_mreg_t [3:0] data_out; // [176:49] + aes_hw2reg_ctrl_shadowed_reg_t ctrl_shadowed; // [48:33] + aes_hw2reg_trigger_reg_t trigger; // [32:25] + aes_hw2reg_status_reg_t status; // [24:11] + aes_hw2reg_ctrl_gcm_shadowed_reg_t ctrl_gcm_shadowed; // [10:0] } aes_hw2reg_t; // Register offsets @@ -274,6 +298,7 @@ package aes_reg_pkg; parameter logic [BlockAw-1:0] AES_CTRL_AUX_REGWEN_OFFSET = 8'h 7c; parameter logic [BlockAw-1:0] AES_TRIGGER_OFFSET = 8'h 80; parameter logic [BlockAw-1:0] AES_STATUS_OFFSET = 8'h 84; + parameter logic [BlockAw-1:0] AES_CTRL_GCM_SHADOWED_OFFSET = 8'h 88; // Reset values for hwext registers and their fields parameter logic [1:0] AES_ALERT_TEST_RESVAL = 2'h 0; @@ -327,13 +352,16 @@ package aes_reg_pkg; parameter logic [31:0] AES_DATA_OUT_2_DATA_OUT_2_RESVAL = 32'h 0; parameter logic [31:0] AES_DATA_OUT_3_RESVAL = 32'h 0; parameter logic [31:0] AES_DATA_OUT_3_DATA_OUT_3_RESVAL = 32'h 0; - parameter logic [15:0] AES_CTRL_SHADOWED_RESVAL = 16'h 1181; + parameter logic [15:0] AES_CTRL_SHADOWED_RESVAL = 16'h 11fd; parameter logic [1:0] AES_CTRL_SHADOWED_OPERATION_RESVAL = 2'h 1; - parameter logic [5:0] AES_CTRL_SHADOWED_MODE_RESVAL = 6'h 20; + parameter logic [5:0] AES_CTRL_SHADOWED_MODE_RESVAL = 6'h 3f; parameter logic [2:0] AES_CTRL_SHADOWED_KEY_LEN_RESVAL = 3'h 1; parameter logic [0:0] AES_CTRL_SHADOWED_SIDELOAD_RESVAL = 1'h 0; parameter logic [2:0] AES_CTRL_SHADOWED_PRNG_RESEED_RATE_RESVAL = 3'h 1; parameter logic [0:0] AES_CTRL_SHADOWED_MANUAL_OPERATION_RESVAL = 1'h 0; + parameter logic [10:0] AES_CTRL_GCM_SHADOWED_RESVAL = 11'h 401; + parameter logic [5:0] AES_CTRL_GCM_SHADOWED_PHASE_RESVAL = 6'h 1; + parameter logic [4:0] AES_CTRL_GCM_SHADOWED_NUM_VALID_BYTES_RESVAL = 5'h 10; // Register index typedef enum int { @@ -370,11 +398,12 @@ package aes_reg_pkg; AES_CTRL_AUX_SHADOWED, AES_CTRL_AUX_REGWEN, AES_TRIGGER, - AES_STATUS + AES_STATUS, + AES_CTRL_GCM_SHADOWED } aes_id_e; // Register width information to check illegal writes - parameter logic [3:0] AES_PERMIT [34] = '{ + parameter logic [3:0] AES_PERMIT [35] = '{ 4'b 0001, // index[ 0] AES_ALERT_TEST 4'b 1111, // index[ 1] AES_KEY_SHARE0_0 4'b 1111, // index[ 2] AES_KEY_SHARE0_1 @@ -408,7 +437,8 @@ package aes_reg_pkg; 4'b 0001, // index[30] AES_CTRL_AUX_SHADOWED 4'b 0001, // index[31] AES_CTRL_AUX_REGWEN 4'b 0001, // index[32] AES_TRIGGER - 4'b 0001 // index[33] AES_STATUS + 4'b 0001, // index[33] AES_STATUS + 4'b 0011 // index[34] AES_CTRL_GCM_SHADOWED }; endpackage diff --git a/hw/ip/aes/rtl/aes_reg_top.sv b/hw/ip/aes/rtl/aes_reg_top.sv index 6731f93256c9b..69efe94df91a9 100644 --- a/hw/ip/aes/rtl/aes_reg_top.sv +++ b/hw/ip/aes/rtl/aes_reg_top.sv @@ -56,9 +56,9 @@ module aes_reg_top ( // also check for spurious write enables logic reg_we_err; - logic [33:0] reg_we_check; + logic [34:0] reg_we_check; prim_reg_we_check #( - .OneHotWidth(34) + .OneHotWidth(35) ) u_prim_reg_we_check ( .clk_i(clk_i), .rst_ni(rst_ni), @@ -231,6 +231,12 @@ module aes_reg_top ( logic status_input_ready_qs; logic status_alert_recov_ctrl_update_err_qs; logic status_alert_fatal_fault_qs; + logic ctrl_gcm_shadowed_re; + logic ctrl_gcm_shadowed_we; + logic [5:0] ctrl_gcm_shadowed_phase_qs; + logic [5:0] ctrl_gcm_shadowed_phase_wd; + logic [4:0] ctrl_gcm_shadowed_num_valid_bytes_qs; + logic [4:0] ctrl_gcm_shadowed_num_valid_bytes_wd; // Register instances // R[alert_test]: V(True) @@ -1429,8 +1435,45 @@ module aes_reg_top ( ); + // R[ctrl_gcm_shadowed]: V(True) + logic ctrl_gcm_shadowed_qe; + logic [1:0] ctrl_gcm_shadowed_flds_we; + assign ctrl_gcm_shadowed_qe = &ctrl_gcm_shadowed_flds_we; + // F[phase]: 5:0 + prim_subreg_ext #( + .DW (6) + ) u_ctrl_gcm_shadowed_phase ( + .re (ctrl_gcm_shadowed_re), + .we (ctrl_gcm_shadowed_we), + .wd (ctrl_gcm_shadowed_phase_wd), + .d (hw2reg.ctrl_gcm_shadowed.phase.d), + .qre (reg2hw.ctrl_gcm_shadowed.phase.re), + .qe (ctrl_gcm_shadowed_flds_we[0]), + .q (reg2hw.ctrl_gcm_shadowed.phase.q), + .ds (), + .qs (ctrl_gcm_shadowed_phase_qs) + ); + assign reg2hw.ctrl_gcm_shadowed.phase.qe = ctrl_gcm_shadowed_qe; + + // F[num_valid_bytes]: 10:6 + prim_subreg_ext #( + .DW (5) + ) u_ctrl_gcm_shadowed_num_valid_bytes ( + .re (ctrl_gcm_shadowed_re), + .we (ctrl_gcm_shadowed_we), + .wd (ctrl_gcm_shadowed_num_valid_bytes_wd), + .d (hw2reg.ctrl_gcm_shadowed.num_valid_bytes.d), + .qre (reg2hw.ctrl_gcm_shadowed.num_valid_bytes.re), + .qe (ctrl_gcm_shadowed_flds_we[1]), + .q (reg2hw.ctrl_gcm_shadowed.num_valid_bytes.q), + .ds (), + .qs (ctrl_gcm_shadowed_num_valid_bytes_qs) + ); + assign reg2hw.ctrl_gcm_shadowed.num_valid_bytes.qe = ctrl_gcm_shadowed_qe; + - logic [33:0] addr_hit; + + logic [34:0] addr_hit; always_comb begin addr_hit = '0; addr_hit[ 0] = (reg_addr == AES_ALERT_TEST_OFFSET); @@ -1467,6 +1510,7 @@ module aes_reg_top ( addr_hit[31] = (reg_addr == AES_CTRL_AUX_REGWEN_OFFSET); addr_hit[32] = (reg_addr == AES_TRIGGER_OFFSET); addr_hit[33] = (reg_addr == AES_STATUS_OFFSET); + addr_hit[34] = (reg_addr == AES_CTRL_GCM_SHADOWED_OFFSET); end assign addrmiss = (reg_re || reg_we) ? ~|addr_hit : 1'b0 ; @@ -1507,7 +1551,8 @@ module aes_reg_top ( (addr_hit[30] & (|(AES_PERMIT[30] & ~reg_be))) | (addr_hit[31] & (|(AES_PERMIT[31] & ~reg_be))) | (addr_hit[32] & (|(AES_PERMIT[32] & ~reg_be))) | - (addr_hit[33] & (|(AES_PERMIT[33] & ~reg_be))))); + (addr_hit[33] & (|(AES_PERMIT[33] & ~reg_be))) | + (addr_hit[34] & (|(AES_PERMIT[34] & ~reg_be))))); end // Generate write-enables @@ -1628,6 +1673,12 @@ module aes_reg_top ( assign trigger_data_out_clear_wd = reg_wdata[2]; assign trigger_prng_reseed_wd = reg_wdata[3]; + assign ctrl_gcm_shadowed_re = addr_hit[34] & reg_re & !reg_error; + assign ctrl_gcm_shadowed_we = addr_hit[34] & reg_we & !reg_error; + + assign ctrl_gcm_shadowed_phase_wd = reg_wdata[5:0]; + + assign ctrl_gcm_shadowed_num_valid_bytes_wd = reg_wdata[10:6]; // Assign write-enables to checker logic vector. always_comb begin @@ -1666,6 +1717,7 @@ module aes_reg_top ( reg_we_check[31] = ctrl_aux_regwen_we; reg_we_check[32] = trigger_we; reg_we_check[33] = 1'b0; + reg_we_check[34] = ctrl_gcm_shadowed_we; end // Read data return @@ -1824,6 +1876,11 @@ module aes_reg_top ( reg_rdata_next[6] = status_alert_fatal_fault_qs; end + addr_hit[34]: begin + reg_rdata_next[5:0] = ctrl_gcm_shadowed_phase_qs; + reg_rdata_next[10:6] = ctrl_gcm_shadowed_num_valid_bytes_qs; + end + default: begin reg_rdata_next = '1; end