From 4d9879e4884c7b3c1dd9c6490a19dbbdd6fe1e40 Mon Sep 17 00:00:00 2001 From: Pascal Nasahl Date: Fri, 29 Aug 2025 16:14:34 +0200 Subject: [PATCH 1/3] [sca,fi] Update the CW310 bitstreams & binaries Bitstreams were generated with: ./bazelisk.sh build //hw/bitstream/vivado:fpga_cw310_test_rom ot-sca_cw310 binaries & bitstreams & opentitantool: commit: lowRISC/opentitan@867c06a ot-sca_cw310_aes binaries & bitstreams: commit: lowRISC/opentitan@51a8f50 ot-sca_cw310_otbn binaries & bitstreams: commit: lowRISC/opentitan@2898576 ot-sca_cw310_kmac binaries & bitstreams: commit: lowRISC/opentitan@a288f62 Signed-off-by: Pascal Nasahl --- objs/fi_ibex_ujson_fpga_cw310.bin | 4 ++-- objs/fi_otbn_ujson_fpga_cw310.bin | 4 ++-- objs/fi_ujson_fpga_cw310.bin | 4 ++-- objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit | 2 +- objs/lowrisc_systems_chip_earlgrey_cw310_0.1_aes.bit | 2 +- objs/lowrisc_systems_chip_earlgrey_cw310_0.1_kmac.bit | 2 +- objs/lowrisc_systems_chip_earlgrey_cw310_0.1_otbn.bit | 2 +- objs/opentitantool | 4 ++-- objs/sca_aes_ujson_fpga_cw310.bin | 4 ++-- objs/sca_kmac_ujson_fpga_cw310.bin | 4 ++-- objs/sca_otbn_ujson_fpga_cw310.bin | 4 ++-- objs/sca_ujson_fpga_cw310.bin | 4 ++-- 12 files changed, 20 insertions(+), 20 deletions(-) diff --git a/objs/fi_ibex_ujson_fpga_cw310.bin b/objs/fi_ibex_ujson_fpga_cw310.bin index 67461835..4f8fe0b8 100644 --- a/objs/fi_ibex_ujson_fpga_cw310.bin +++ b/objs/fi_ibex_ujson_fpga_cw310.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c932432e4a79a28b606cfe9338988749215901a1b3d32360b8898d1d7021b674 -size 285596 +oid sha256:fc6a8b5a8f06f417a39a3a7306fae82d21ad417f7b0364d33f13bd5ee0cd679e +size 309708 diff --git a/objs/fi_otbn_ujson_fpga_cw310.bin b/objs/fi_otbn_ujson_fpga_cw310.bin index 2a92ba93..39b783cc 100644 --- a/objs/fi_otbn_ujson_fpga_cw310.bin +++ b/objs/fi_otbn_ujson_fpga_cw310.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e1447a5895b3a72b8d602b950a51565721a97c13f69a2079c4763ba9b648c6c7 -size 112292 +oid sha256:34f5286d225c4f753b12f50c40094074b4d09566d665d0061b510793d01674cc +size 118496 diff --git a/objs/fi_ujson_fpga_cw310.bin b/objs/fi_ujson_fpga_cw310.bin index bc9303fe..d79851f8 100644 --- a/objs/fi_ujson_fpga_cw310.bin +++ b/objs/fi_ujson_fpga_cw310.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9bcb682aacf5ecb92e34db02729c0e33ebbfdb18bf813adb593ae3e40dde3ef7 -size 136928 +oid sha256:de0cee1cb79640cf9f7b3367475ded142dcd9b88f1f07385b18f83293591dd8b +size 166320 diff --git a/objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit b/objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit index 0acab19d..718bd6e0 100644 --- a/objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit +++ b/objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c397f847700937be717e13998ed962524f71d8d6823fcf73af61c4bec6e9a7d +oid sha256:d0084bd1ab3932c5daee74d19dde0c4b129d43478d5074864ac6872d6021baa4 size 15878032 diff --git a/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_aes.bit b/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_aes.bit index 6352d0dc..1af56af6 100644 --- a/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_aes.bit +++ b/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_aes.bit @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b665cfc1e5a88d4fdb6364ed67b33704ffff2580f075d61a3e978d02d977f584 +oid sha256:4301903ac3c48d177140ef62c4db4f0a9f70a5a96e4cadba54d16ee35c7abfb9 size 15878032 diff --git a/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_kmac.bit b/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_kmac.bit index 7e9e9bf4..c4c6528d 100644 --- a/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_kmac.bit +++ b/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_kmac.bit @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8e7e00516e6d9c4373a8df7688d2ca9cc43e520c6c4b31f9d40435df5c4ffef +oid sha256:59b6a6fcd5eefcaaf6eaddbe787763950d8f2c95a327aacb1be37d9c3b319c7e size 15878032 diff --git a/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_otbn.bit b/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_otbn.bit index 22b6a800..7527d612 100644 --- a/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_otbn.bit +++ b/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_otbn.bit @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e84b5269e25c1032d988044760c9a752d75230120f9b937187a0165762259f8e +oid sha256:fdc4bb345209e7b67f830941cbbd2f5bfa99d4ff922dec86975ad5bd2f7d216b size 15878032 diff --git a/objs/opentitantool b/objs/opentitantool index 767eda83..5160bd54 100755 --- a/objs/opentitantool +++ b/objs/opentitantool @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97551411cf3d996d97f27ec7bda9e6016281ad3c944a021126c0da1542bada2a -size 39676456 +oid sha256:2b68388062f5dcb666136a864d65340db375d54b33968615c1546c18d3c0396d +size 37469800 diff --git a/objs/sca_aes_ujson_fpga_cw310.bin b/objs/sca_aes_ujson_fpga_cw310.bin index fdc52aa0..356dd7fc 100644 --- a/objs/sca_aes_ujson_fpga_cw310.bin +++ b/objs/sca_aes_ujson_fpga_cw310.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6093bfb968bf7d89bf0c7849de9147350210a9912081b3ff9425319bb6ab9721 -size 156016 +oid sha256:31b2c90e679528dc076e3314b496598c56075dec38f0c38aa07f1b856834f187 +size 165864 diff --git a/objs/sca_kmac_ujson_fpga_cw310.bin b/objs/sca_kmac_ujson_fpga_cw310.bin index fdc52aa0..356dd7fc 100644 --- a/objs/sca_kmac_ujson_fpga_cw310.bin +++ b/objs/sca_kmac_ujson_fpga_cw310.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6093bfb968bf7d89bf0c7849de9147350210a9912081b3ff9425319bb6ab9721 -size 156016 +oid sha256:31b2c90e679528dc076e3314b496598c56075dec38f0c38aa07f1b856834f187 +size 165864 diff --git a/objs/sca_otbn_ujson_fpga_cw310.bin b/objs/sca_otbn_ujson_fpga_cw310.bin index fdc52aa0..356dd7fc 100644 --- a/objs/sca_otbn_ujson_fpga_cw310.bin +++ b/objs/sca_otbn_ujson_fpga_cw310.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6093bfb968bf7d89bf0c7849de9147350210a9912081b3ff9425319bb6ab9721 -size 156016 +oid sha256:31b2c90e679528dc076e3314b496598c56075dec38f0c38aa07f1b856834f187 +size 165864 diff --git a/objs/sca_ujson_fpga_cw310.bin b/objs/sca_ujson_fpga_cw310.bin index e55d3aa3..a90dd685 100644 --- a/objs/sca_ujson_fpga_cw310.bin +++ b/objs/sca_ujson_fpga_cw310.bin @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d791944d98c0a13c03a940bd460a2101ef15d29a4d5b37abec4fba9036e339d1 -size 156016 +oid sha256:dc62185fd84e405aadec00e1e59d04c67bd194ce89b9f7ea20490a1d5ac63722 +size 166020 From 81443019a775a1d5144e3b2d238785339acc02ae Mon Sep 17 00:00:00 2001 From: Siemen Dhooghe Date: Sat, 30 Aug 2025 11:21:44 +0200 Subject: [PATCH 2/3] [update] Update yaml files Update the yaml files to version v1.0.3 of OpenTitan's pentest framework. Signed-off-by: Siemen Dhooghe --- capture/configs/aes_sca_chip.yaml | 54 +++-- capture/configs/aes_sca_cw305.yaml | 67 ------ capture/configs/aes_sca_cw310.yaml | 52 +++-- capture/configs/capture_ecdsa256_cw310.yaml | 6 +- capture/configs/capture_ecdsa384_cw310.yaml | 2 + capture/configs/hmac_sca_chip.yaml | 63 +++-- capture/configs/hmac_sca_cw310.yaml | 59 +++-- capture/configs/ibex_sca_chip.yaml | 61 +++-- capture/configs/ibex_sca_cw310.yaml | 54 +++-- capture/configs/kmac_sca_chip.yaml | 55 +++-- capture/configs/kmac_sca_cw310.yaml | 49 ++-- .../otbn_vertical_keygen_sca_cw310.yaml | 16 +- .../otbn_vertical_modinv_sca_cw310.yaml | 16 +- ...chip_masks_off.yaml => sha3_sca_chip.yaml} | 50 ++-- capture/configs/sha3_sca_cw310.yaml | 49 ++-- capture/configs/sha3_sca_cw310_masks_off.yaml | 49 ++-- ci/cfg/ci_aes_sca_fvsr_cw305.yaml | 56 ----- ci/cfg/ci_aes_sca_fvsr_cw310_ujson.yaml | 51 ++-- ci/cfg/ci_aes_sca_random_cw305.yaml | 56 ----- ci/cfg/ci_aes_sca_random_cw310_ujson.yaml | 52 +++-- ci/cfg/ci_capture_ecdsa256_cw310.yaml | 5 +- ci/cfg/ci_capture_ecdsa384_cw310.yaml | 5 +- ci/cfg/ci_capture_otbn_vertical_keygen.yaml | 5 +- ci/cfg/ci_capture_otbn_vertical_modinv.yaml | 6 +- ci/cfg/ci_crypto_aes_vcc_dummy_cw310.yaml | 185 +++++++++++++-- ci/cfg/ci_hmac_sca_fvsr_cw310_ujson.yaml | 51 ++-- ci/cfg/ci_ibex_fi_vcc_dummy_cw310.yaml | 178 +++++++++++++- ci/cfg/ci_ibex_sca_cw310_ujson.yaml | 46 +++- ci/cfg/ci_kmac_sca_fvsr_cw310_ujson.yaml | 48 ++-- ci/cfg/ci_kmac_sca_random_cw310_ujson.yaml | 48 ++-- ci/cfg/ci_otbn_fi_vcc_dummy_cw310.yaml | 178 +++++++++++++- ci/cfg/ci_sha3_sca_fvsr_cw310_ujson.yaml | 50 ++-- ci/cfg/ci_sha3_sca_random_cw310_ujson.yaml | 46 ++-- .../pen.global_fi.crypto.aes.cw310.yaml | 55 ----- .../configs/pen.global_fi.crypto.aes.yaml | 218 +++++++++++++++++ .../configs/pen.global_fi.crypto.hmac.yaml | 212 +++++++++++++++++ .../pen.global_fi.crypto.kmac.cw310.yaml | 55 ----- .../configs/pen.global_fi.crypto.kmac.yaml | 216 +++++++++++++++++ .../pen.global_fi.crypto.sha256.cw310.yaml | 55 ----- ...bal_fi.crypto.shadow_reg_access.cw310.yaml | 52 ----- ...en.global_fi.crypto.shadow_reg_access.yaml | 213 +++++++++++++++++ ...bal_fi.ibex.address_translation.cw310.yaml | 52 ----- ...en.global_fi.ibex.address_translation.yaml | 211 +++++++++++++++++ ...ibex.address_translation_config.cw310.yaml | 52 ----- ...al_fi.ibex.address_translation_config.yaml | 214 +++++++++++++++++ ...fi.ibex.char.conditional_branch.cw310.yaml | 62 ----- ...lobal_fi.ibex.char.conditional_branch.yaml | 221 ++++++++++++++++++ ...en.global_fi.ibex.char.csr_read.cw310.yaml | 52 ----- .../pen.global_fi.ibex.char.csr_read.yaml | 214 +++++++++++++++++ ...n.global_fi.ibex.char.csr_write.cw310.yaml | 52 ----- .../pen.global_fi.ibex.char.csr_write.yaml | 209 +++++++++++++++++ ....global_fi.ibex.char.flash_read.cw310.yaml | 52 ----- .../pen.global_fi.ibex.char.flash_read.yaml | 214 +++++++++++++++++ ...global_fi.ibex.char.flash_write.cw310.yaml | 52 ----- .../pen.global_fi.ibex.char.flash_write.yaml | 209 +++++++++++++++++ ...x.char.hardened_check_eq_unimps.cw310.yaml | 58 ----- ...fi.ibex.char.hardened_check_eq_unimps.yaml | 215 +++++++++++++++++ ...global_fi.ibex.char.mem_op_loop.cw310.yaml | 52 ----- .../pen.global_fi.ibex.char.mem_op_loop.yaml | 209 +++++++++++++++++ ...global_fi.ibex.char.reg_op_loop.cw310.yaml | 52 ----- .../pen.global_fi.ibex.char.reg_op_loop.yaml | 209 +++++++++++++++++ ...obal_fi.ibex.char.register_file.cw310.yaml | 52 ----- ...pen.global_fi.ibex.char.register_file.yaml | 209 +++++++++++++++++ ...fi.ibex.char.register_file_read.cw310.yaml | 52 ----- ...lobal_fi.ibex.char.register_file_read.yaml | 209 +++++++++++++++++ ...n.global_fi.ibex.char.sram_read.cw310.yaml | 52 ----- .../pen.global_fi.ibex.char.sram_read.yaml | 209 +++++++++++++++++ ...global_fi.ibex.char.sram_static.cw310.yaml | 52 ----- .../pen.global_fi.ibex.char.sram_static.yaml | 209 +++++++++++++++++ ....global_fi.ibex.char.sram_write.cw310.yaml | 52 ----- .../pen.global_fi.ibex.char.sram_write.yaml | 209 +++++++++++++++++ ...al_fi.ibex.char.sram_write_read.cw310.yaml | 52 ----- ...n.global_fi.ibex.char.sram_write_read.yaml | 209 +++++++++++++++++ ...char.sram_write_static_unrolled.cw310.yaml | 52 ----- ....ibex.char.sram_write_static_unrolled.yaml | 209 +++++++++++++++++ ....ibex.char.unconditional_branch.cw310.yaml | 52 ----- ...bal_fi.ibex.char.unconditional_branch.yaml | 209 +++++++++++++++++ ...x.char.unconditional_branch_nop.cw310.yaml | 52 ----- ...fi.ibex.char.unconditional_branch_nop.yaml | 209 +++++++++++++++++ ....ibex.char.unrolled_mem_op_loop.cw310.yaml | 52 ----- ...bal_fi.ibex.char.unrolled_mem_op_loop.yaml | 209 +++++++++++++++++ ....ibex.char.unrolled_reg_op_loop.cw310.yaml | 52 ----- ...bal_fi.ibex.char.unrolled_reg_op_loop.yaml | 209 +++++++++++++++++ ...char.unrolled_reg_op_loop_chain.cw310.yaml | 52 ----- ....ibex.char.unrolled_reg_op_loop_chain.yaml | 209 +++++++++++++++++ .../pen.global_fi.otbn.char.beq.cw310.yaml | 51 ---- .../configs/pen.global_fi.otbn.char.beq.yaml | 214 +++++++++++++++++ ...pen.global_fi.otbn.char.bn.rshi.cw310.yaml | 52 ----- .../pen.global_fi.otbn.char.bn.rshi.yaml | 210 +++++++++++++++++ .../pen.global_fi.otbn.char.bn.sel.cw310.yaml | 52 ----- .../pen.global_fi.otbn.char.bn.sel.yaml | 210 +++++++++++++++++ ...pen.global_fi.otbn.char.bn.wsrr.cw310.yaml | 51 ---- .../pen.global_fi.otbn.char.bn.wsrr.yaml | 209 +++++++++++++++++ ...global_fi.otbn.char.dmem.access.cw310.yaml | 51 ---- .../pen.global_fi.otbn.char.dmem.access.yaml | 209 +++++++++++++++++ ....global_fi.otbn.char.dmem.write.cw310.yaml | 51 ---- .../pen.global_fi.otbn.char.dmem.write.yaml | 209 +++++++++++++++++ ...otbn.char.hardware_dmem_op_loop.cw310.yaml | 51 ---- ...al_fi.otbn.char.hardware_dmem_op_loop.yaml | 209 +++++++++++++++++ ....otbn.char.hardware_reg_op_loop.cw310.yaml | 51 ---- ...bal_fi.otbn.char.hardware_reg_op_loop.yaml | 209 +++++++++++++++++ .../pen.global_fi.otbn.char.jal.cw310.yaml | 51 ---- .../configs/pen.global_fi.otbn.char.jal.yaml | 209 +++++++++++++++++ .../pen.global_fi.otbn.char.lw.cw310.yaml | 51 ---- .../configs/pen.global_fi.otbn.char.lw.yaml | 209 +++++++++++++++++ .../pen.global_fi.otbn.char.mem.cw310.yaml | 52 ----- .../configs/pen.global_fi.otbn.char.mem.yaml | 210 +++++++++++++++++ .../pen.global_fi.otbn.char.rf.cw310.yaml | 51 ---- .../configs/pen.global_fi.otbn.char.rf.yaml | 209 +++++++++++++++++ ...otbn.char.unrolled_dmem_op_loop.cw310.yaml | 51 ---- ...al_fi.otbn.char.unrolled_dmem_op_loop.yaml | 209 +++++++++++++++++ ....otbn.char.unrolled_reg_op_loop.cw310.yaml | 51 ---- ...bal_fi.otbn.char.unrolled_reg_op_loop.yaml | 209 +++++++++++++++++ ...pen.global_fi.otbn.key_sideload.cw310.yaml | 51 ---- .../pen.global_fi.otbn.key_sideload.yaml | 209 +++++++++++++++++ ...n.global_fi.otbn.load_integrity.cw310.yaml | 51 ---- .../pen.global_fi.otbn.load_integrity.yaml | 209 +++++++++++++++++ .../configs/pen.global_fi.otbn.pc.cw310.yaml | 52 ----- .../configs/pen.global_fi.otbn.pc.yaml | 210 +++++++++++++++++ ...en.global_fi.otp_ctrl.data_read.cw310.yaml | 50 ---- .../pen.global_fi.otp_ctrl.data_read.yaml | 216 +++++++++++++++++ .../pen.global_fi.rng.csrng.cw310.yaml | 52 ----- .../configs/pen.global_fi.rng.csrng.yaml | 216 +++++++++++++++++ .../configs/pen.global_fi.rng.edn.cw310.yaml | 52 ----- .../configs/pen.global_fi.rng.edn.yaml | 214 +++++++++++++++++ 125 files changed, 10852 insertions(+), 3018 deletions(-) delete mode 100644 capture/configs/aes_sca_cw305.yaml rename capture/configs/{sha3_sca_chip_masks_off.yaml => sha3_sca_chip.yaml} (67%) delete mode 100644 ci/cfg/ci_aes_sca_fvsr_cw305.yaml delete mode 100644 ci/cfg/ci_aes_sca_random_cw305.yaml delete mode 100644 fault_injection/configs/pen.global_fi.crypto.aes.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.crypto.aes.yaml create mode 100644 fault_injection/configs/pen.global_fi.crypto.hmac.yaml delete mode 100644 fault_injection/configs/pen.global_fi.crypto.kmac.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.crypto.kmac.yaml delete mode 100644 fault_injection/configs/pen.global_fi.crypto.sha256.cw310.yaml delete mode 100644 fault_injection/configs/pen.global_fi.crypto.shadow_reg_access.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.crypto.shadow_reg_access.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.address_translation.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.address_translation.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.address_translation_config.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.address_translation_config.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.conditional_branch.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.conditional_branch.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.csr_read.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.csr_read.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.csr_write.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.csr_write.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.flash_read.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.flash_read.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.flash_write.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.flash_write.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.hardened_check_eq_unimps.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.hardened_check_eq_unimps.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.mem_op_loop.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.mem_op_loop.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.reg_op_loop.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.reg_op_loop.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.register_file.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.register_file.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.register_file_read.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.register_file_read.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.sram_read.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.sram_read.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.sram_static.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.sram_static.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.sram_write.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.sram_write.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.sram_write_read.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.sram_write_read.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.sram_write_static_unrolled.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.sram_write_static_unrolled.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch_nop.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch_nop.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.unrolled_mem_op_loop.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.unrolled_mem_op_loop.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop.yaml delete mode 100644 fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop_chain.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop_chain.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.beq.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.beq.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.bn.rshi.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.bn.rshi.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.bn.sel.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.bn.sel.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.bn.wsrr.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.bn.wsrr.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.dmem.access.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.dmem.access.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.dmem.write.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.dmem.write.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.hardware_dmem_op_loop.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.hardware_dmem_op_loop.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.hardware_reg_op_loop.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.hardware_reg_op_loop.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.jal.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.jal.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.lw.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.lw.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.mem.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.mem.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.rf.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.rf.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.unrolled_dmem_op_loop.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.unrolled_dmem_op_loop.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.char.unrolled_reg_op_loop.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.char.unrolled_reg_op_loop.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.key_sideload.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.key_sideload.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.load_integrity.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.load_integrity.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otbn.pc.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otbn.pc.yaml delete mode 100644 fault_injection/configs/pen.global_fi.otp_ctrl.data_read.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.otp_ctrl.data_read.yaml delete mode 100644 fault_injection/configs/pen.global_fi.rng.csrng.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.rng.csrng.yaml delete mode 100644 fault_injection/configs/pen.global_fi.rng.edn.cw310.yaml create mode 100644 fault_injection/configs/pen.global_fi.rng.edn.yaml diff --git a/capture/configs/aes_sca_chip.yaml b/capture/configs/aes_sca_chip.yaml index b6c2b717..889cd488 100644 --- a/capture/configs/aes_sca_chip.yaml +++ b/capture/configs/aes_sca_chip.yaml @@ -1,19 +1,17 @@ target: target_type: chip fw_bin: "../objs/sca_ujson_chip_signed.img" + opentitantool: "../objs/opentitantool" target_clk_mult: 1 target_freq: 100000000 baudrate: 115200 - output_len_bytes: 16 - protocol: "ujson" - port: "/dev/ttyUSB1" + # You can specify the port or leave it empty to find it automatically. # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "sw" waverunner: waverunner_ip: 192.168.33.128 - num_segments: 20 # num_samples: 6000 # offset_samples: 0 # cycles will only be used if not given in samples @@ -24,22 +22,22 @@ waverunner: channel: C1 sparsing: 0 capture: - scope_select: waverunner + # scope_select: husky, waverunner, none + scope_select: none num_traces: 1000 - show_plot: True + num_segments: 20 + show_plot: False plot_traces: 100 + # trace_db: cw trace_db: ot_trace_library trace_threshold: 10000 - # trace_db: cw test: - which_test: aes_random_batch + which_test: daisy_chain + # which_test: single + # which_test: daisy_chain # which_test: aes_random # which_test: aes_fvsr_key - # which_test: aes_fvsr_key_batch # which_test: aes_fvsr_data - # which_test: aes_fvsr_data_batch - key_len_bytes: 16 - text_len_bytes: 16 # These initial values are used only for random capture but not fixed-vs-random. key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] @@ -49,11 +47,27 @@ test: # 32-bit seed for masking on device. To switch off the masking, use 0 as LFSR seed. # lfsr_seed: 0x00000000 lfsr_seed: 0xdeadbeef - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/capture/configs/aes_sca_cw305.yaml b/capture/configs/aes_sca_cw305.yaml deleted file mode 100644 index f659b184..00000000 --- a/capture/configs/aes_sca_cw305.yaml +++ /dev/null @@ -1,67 +0,0 @@ -target: - target_type: cw305 - fpga_bitstream: "../objs/lowrisc_systems_chip_englishbreakfast_cw305_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/aes_serial_fpga_cw305.bin" - # target_clk_mult is a hardcoded value in the bitstream. Do not change. - target_clk_mult: 0.1 - target_freq: 10000000 - baudrate: 115200 - output_len_bytes: 16 - protocol: "simpleserial" - # Trigger source. - # hw: Precise, hardware-generated trigger - FPGA only. - # sw: Fully software-controlled trigger. - trigger: "hw" -husky: - sampling_rate: 200000000 - num_segments: 80 - # Number of target clock cycles per trace - AES w/ DOM is doing - # ~56/72 cycles per encryption (AES-128/256). - num_cycles: 60 - # Offset in target clock cycles - The AES idle signal becomes visible - # 1 target clock cycle later and there are 2 synchronization stages at - # 100 MHz at the top level. - offset_cycles: -2 - scope_gain: 20 -waverunner: - waverunner_ip: 100.107.71.10 - num_segments: 20 - num_samples: 6000 - sample_offset: 0 -capture: - scope_select: husky - #scope_select: waverunner - num_traces: 10000 - show_plot: True - plot_traces: 100 - #trace_db: ot_trace_library - trace_db: cw - trace_threshold: 10000 -test: - #which_test: aes_random - #which_test: aes_random_batch - #which_test: aes_fvsr_key - which_test: aes_fvsr_key_batch - # which_test: aes_fvsr_data - # which_test: aes_fvsr_data_batch - key_len_bytes: 16 - text_len_bytes: 16 - key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] - text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] - key_for_gen: [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xE0, 0xF0] - # Seed for PRNG generating sequence of plaintexts and keys for batch captures - # on the host and on the device. - batch_prng_seed: 0 - # 32-bit seed for SW key masking. Key masks are generated using an LFSR. - # To switch off the masking, 0 must be used as LFSR seed. - #lfsr_seed: 0x00000000 - lfsr_seed: 0xdeadbeef - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/capture/configs/aes_sca_cw310.yaml b/capture/configs/aes_sca_cw310.yaml index fa172412..6604767a 100644 --- a/capture/configs/aes_sca_cw310.yaml +++ b/capture/configs/aes_sca_cw310.yaml @@ -3,26 +3,23 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1_aes.bit" force_program_bitstream: True fw_bin: "../objs/sca_aes_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.10 target_freq: 10000000 baudrate: 115200 - output_len_bytes: 16 - protocol: "ujson" - port: "/dev/opentitan/cw310_1_tty_03" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "hw" husky: sampling_rate: 200000000 - num_segments: 20 num_cycles: 60 offset_cycles: -2 scope_gain: 38 waverunner: waverunner_ip: 100.107.71.10 - num_segments: 20 # num_samples: 6000 # offset_samples: 0 # cycles will only be used if not given in samples @@ -33,23 +30,22 @@ waverunner: channel: C1 sparsing: 0 capture: + # scope_select: husky, waverunner, none scope_select: husky - # scope_select: waverunner + num_segments: 20 num_traces: 1000 show_plot: True plot_traces: 100 + # trace_db: cw trace_db: ot_trace_library trace_threshold: 10000 - # trace_db: cw test: - #which_test: aes_random_batch + which_test: single + # which_test: single + # which_test: daisy_chain # which_test: aes_random # which_test: aes_fvsr_key - # which_test: aes_fvsr_key_batch # which_test: aes_fvsr_data - which_test: aes_fvsr_data_batch - key_len_bytes: 16 - text_len_bytes: 16 # These initial values are used only for random capture but not fixed-vs-random. key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] @@ -59,11 +55,27 @@ test: # 32-bit seed for masking on device. To switch off the masking, use 0 as LFSR seed. # lfsr_seed: 0x00000000 lfsr_seed: 0xdeadbeef - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/capture/configs/capture_ecdsa256_cw310.yaml b/capture/configs/capture_ecdsa256_cw310.yaml index b946fc1b..ec940df7 100644 --- a/capture/configs/capture_ecdsa256_cw310.yaml +++ b/capture/configs/capture_ecdsa256_cw310.yaml @@ -2,6 +2,8 @@ device: fpga_bitstream: objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit force_program_bitstream: True fw_bin: objs/ecc256_serial_fpga_cw310.bin + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. # The clock frequency of the target block is equal to # pll_frequency * target_clk_mult. pll_frequency is controllable via # ChipWhisperer API, whereas target_clk_mult is baked into the FPGA @@ -15,10 +17,6 @@ device: target_clk_mult: 0.1 baudrate: 115200 capture: - # Only ECDSA-256 (32) and ECDSA-384 (48) are supported at this moment. - key_len_bytes: 32 - plain_text_len_bytes: 32 - output_len_bytes: 32 # With pll_frequency = 20 MHz and target_clk_mult = 0.1, 2000 # target clock cycles correspond to 200000 scope samples on Husky # (100x oversampling). diff --git a/capture/configs/capture_ecdsa384_cw310.yaml b/capture/configs/capture_ecdsa384_cw310.yaml index 59a5f35d..bec48c32 100644 --- a/capture/configs/capture_ecdsa384_cw310.yaml +++ b/capture/configs/capture_ecdsa384_cw310.yaml @@ -2,6 +2,8 @@ device: fpga_bitstream: objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit force_program_bitstream: False fw_bin: objs/ecc384_serial_fpga_cw310.bin + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. # The clock frequency of the target block is equal to # pll_frequency * target_clk_mult. pll_frequency is controllable via # ChipWhisperer API, whereas target_clk_mult is baked into the FPGA diff --git a/capture/configs/hmac_sca_chip.yaml b/capture/configs/hmac_sca_chip.yaml index 18aaa0ed..ff843e42 100644 --- a/capture/configs/hmac_sca_chip.yaml +++ b/capture/configs/hmac_sca_chip.yaml @@ -1,15 +1,13 @@ target: target_type: chip fw_bin: "../objs/sca_ujson_chip_signed.img" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. target_clk_mult: 1 target_freq: 100000000 baudrate: 115200 - output_len_bytes: 16 - protocol: "ujson" - port: "/dev/ttyUSB1" waverunner: waverunner_ip: 192.168.33.128 - num_segments: 20 # cycles will only be used if not given in samples num_cycles: 160 offset_cycles: 115 @@ -18,37 +16,52 @@ waverunner: channel: C1 sparsing: 0 capture: - scope_select: waverunner - num_traces: 60 + # scope_select: husky, waverunner, none + scope_select: none + num_segments: 20 + num_traces: 500 show_plot: True plot_traces: 10 + # trace_db: cw trace_db: ot_trace_library trace_threshold: 10000 - # trace_db: cw test: - # which_test: hmac_batch_random - # which_test: hmac_batch_fvsr - # which_test: hmac_random - which_test: hmac_fvsr - key_len_bytes: 32 + # which_test: single + # which_test: random + # which_test: data_fvsr + # which_test: daisy_chain + which_test: single key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9, 0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] - msg_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # seed for PRNG to generate sequence of messages, and keys; Python random # class on host, Mersenne twister implementation on OT SW. batch_prng_seed: 0 # Trigger configuration. - start_trigger: False - msg_trigger: False - process_trigger: True - finish_trigger: False - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + # 0 = start_trigger, 1 = msg_trigger, 2 = process_trigger, 3 = finish_trigger + trigger: 0 + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/capture/configs/hmac_sca_cw310.yaml b/capture/configs/hmac_sca_cw310.yaml index 1bbedf82..2044f067 100644 --- a/capture/configs/hmac_sca_cw310.yaml +++ b/capture/configs/hmac_sca_cw310.yaml @@ -3,50 +3,63 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: True fw_bin: "../objs/sca_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. target_clk_mult: 0.24 target_freq: 24000000 baudrate: 115200 - output_len_bytes: 16 - protocol: "ujson" - port: "/dev/opentitan/cw310_1_tty_03" husky: sampling_rate: 200000000 - num_segments: 20 num_cycles: 60 offset_cycles: -2 scope_gain: 38 capture: + # scope_select: husky, waverunner, none scope_select: husky + num_segments: 20 num_traces: 100 show_plot: True plot_traces: 10 + # trace_db: cw trace_db: ot_trace_library trace_threshold: 10000 - # trace_db: cw test: - # which_test: hmac_batch_random - # which_test: hmac_batch_fvsr - # which_test: hmac_random - which_test: hmac_fvsr - key_len_bytes: 32 + # which_test: single + # which_test: random + # which_test: data_fvsr + # which_test: daisy_chain + which_test: single key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9, 0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] - msg_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # seed for PRNG to generate sequence of messages, and keys; Python random # class on host, Mersenne twister implementation on OT SW. batch_prng_seed: 0 # Trigger configuration. - start_trigger: False - msg_trigger: False - process_trigger: True - finish_trigger: False - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + # 0 = start_trigger, 1 = msg_trigger, 2 = process_trigger, 3 = finish_trigger + trigger: 0 + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/capture/configs/ibex_sca_chip.yaml b/capture/configs/ibex_sca_chip.yaml index 83cb9cd9..a9cf9ecb 100644 --- a/capture/configs/ibex_sca_chip.yaml +++ b/capture/configs/ibex_sca_chip.yaml @@ -1,15 +1,13 @@ target: target_type: chip fw_bin: "../objs/sca_ujson_chip_signed.img" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. target_clk_mult: 1 target_freq: 100000000 baudrate: 115200 - output_len_bytes: 16 - protocol: "ujson" - port: "/dev/ttyUSB1" waverunner: waverunner_ip: 192.168.33.128 - num_segments: 1 # cycles will only be used if not given in samples num_cycles: 100 # Do not capture 100 nops that are inserted to give the trigger time to rise. @@ -19,41 +17,62 @@ waverunner: channel: C1 sparsing: 0 capture: - scope_select: waverunner + # scope_select: husky, waverunner, none + scope_select: none + num_segments: 10 num_traces: 101 show_plot: True plot_traces: 20 trace_db: ot_trace_library trace_threshold: 50 test: + # which_test: ibex_sca_combi_operations_batch_fvsr + # which_test: ibex_sca_combi_operations_batch # which_test: ibex_sca_tl_write_batch_fvsr # which_test: ibex_sca_tl_write_batch_fvsr_fix_address # which_test: ibex_sca_tl_write_batch_random # which_test: ibex_sca_tl_write_batch_random_fix_address - # which_test: ibex_sca_tl_write_fvsr - # which_test: ibex_sca_tl_write_random + # which_test: ibex_sca_tl_write # which_test: ibex_sca_tl_read_batch_fvsr # which_test: ibex_sca_tl_read_batch_fvsr_fix_address # which_test: ibex_sca_tl_read_batch_random # which_test: ibex_sca_tl_read_batch_random_fix_address - # which_test: ibex_sca_tl_read_fvsr - # which_test: ibex_sca_tl_read_random + # which_test: ibex_sca_tl_read # which_test: ibex_sca_register_file_write_batch_fvsr # which_test: ibex_sca_register_file_write_batch_random - # which_test: ibex_sca_register_file_write_fvsr - # which_test: ibex_sca_register_file_write_random + # which_test: ibex_sca_register_file_write # which_test: ibex_sca_register_file_read_batch_fvsr # which_test: ibex_sca_register_file_read_batch_random - # which_test: ibex_sca_register_file_read_fvsr - which_test: ibex_sca_register_file_read_random + # which_test: ibex_sca_register_file_read + which_test: ibex_sca_register_file_read + # Combi test uses the first two values of the fixed input. + input_fixed: [0xABBABABE, 0xABADCAFE, 0xBAAAAAAD, 0xBAD22222, 0xBBADBEEF, 0xBEBEBEBE, 0xBEEFCACE, 0xC00010FF] + # Trigger for the combi test, 12-bit value, each bit sets the trigger for one of the 12 trigger windows. + trigger: 0 # seed for PRNG to generate sequence of plaintexts and keys; Python random # class on host, Mersenne twister implementation on OT SW. batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/capture/configs/ibex_sca_cw310.yaml b/capture/configs/ibex_sca_cw310.yaml index 7e96e380..7352608e 100644 --- a/capture/configs/ibex_sca_cw310.yaml +++ b/capture/configs/ibex_sca_cw310.yaml @@ -3,54 +3,70 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: False fw_bin: ../objs/sca_ujson_fpga_cw310.bin + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. target_clk_mult: 0.24 target_freq: 24000000 baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" husky: samling_rate: 200000000 - num_segments: 20 num_cycles: 100 # Do not capture 100 nops that are inserted to give the trigger time to rise. offset_cycles: 100 scope_gain: 27 capture: + # scope_select: husky, waverunner, none scope_select: husky + num_segments: 20 num_traces: 5000 show_plot: True plot_traces: 100 trace_db: ot_trace_library trace_threshold: 10000 test: + # which_test: ibex_sca_combi_operations_batch_fvsr + # which_test: ibex_sca_combi_operations_batch # which_test: ibex_sca_tl_write_batch_fvsr # which_test: ibex_sca_tl_write_batch_fvsr_fix_address # which_test: ibex_sca_tl_write_batch_random # which_test: ibex_sca_tl_write_batch_random_fix_address - # which_test: ibex_sca_tl_write_fvsr - # which_test: ibex_sca_tl_write_random + # which_test: ibex_sca_tl_write # which_test: ibex_sca_tl_read_batch_fvsr # which_test: ibex_sca_tl_read_batch_fvsr_fix_address # which_test: ibex_sca_tl_read_batch_random # which_test: ibex_sca_tl_read_batch_random_fix_address - # which_test: ibex_sca_tl_read_fvsr - # which_test: ibex_sca_tl_read_random + # which_test: ibex_sca_tl_read # which_test: ibex_sca_register_file_write_batch_fvsr # which_test: ibex_sca_register_file_write_batch_random - # which_test: ibex_sca_register_file_write_fvsr - # which_test: ibex_sca_register_file_write_random + # which_test: ibex_sca_register_file_write # which_test: ibex_sca_register_file_read_batch_fvsr # which_test: ibex_sca_register_file_read_batch_random - # which_test: ibex_sca_register_file_read_fvsr - which_test: ibex_sca_register_file_read_random + # which_test: ibex_sca_register_file_read + which_test: ibex_sca_register_file_read # seed for PRNG to generate sequence of plaintexts and keys; Python random # class on host, Mersenne twister implementation on OT SW. batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/capture/configs/kmac_sca_chip.yaml b/capture/configs/kmac_sca_chip.yaml index 026097ac..f035d6d3 100644 --- a/capture/configs/kmac_sca_chip.yaml +++ b/capture/configs/kmac_sca_chip.yaml @@ -1,19 +1,17 @@ target: target_type: chip fw_bin: "../objs/sca_ujson_chip_signed.img" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. target_clk_mult: 1 target_freq: 100000000 baudrate: 115200 - output_len_bytes: 16 - protocol: "ujson" - port: "/dev/ttyUSB1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "sw" waverunner: waverunner_ip: 192.168.33.128 - num_segments: 1 # cycles will only be used if not given in samples num_cycles: 160 offset_cycles: 115 @@ -22,20 +20,21 @@ waverunner: channel: C1 sparsing: 0 capture: - scope_select: waverunner - num_traces: 20000 + # scope_select: husky, waverunner, none + scope_select: none + num_segments: 20 + num_traces: 500 show_plot: True plot_traces: 10 + # trace_db: cw trace_db: ot_trace_library trace_threshold: 10000 - # trace_db: cw test: - # which_test: kmac_random - # which_test: kmac_fvsr_key_batch - which_test: kmac_fvsr_key - key_len_bytes: 16 + # which_test: single + # which_test: fvsr_key + # which_test: daisy_chain + which_test: single key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] - text_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # 32-bit seed for SW key masking. Key masks are generated using an LFSR. # For unprotected implemetation, lfsr_seed should be set to 0. This will @@ -47,11 +46,27 @@ test: lfsr_seed: 0xdeadbeef # seed for PRNG to generate sequence of plaintexts and keys; Python random class on host, Mersenne twister implementation on OT SW batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/capture/configs/kmac_sca_cw310.yaml b/capture/configs/kmac_sca_cw310.yaml index c55eb6c5..5ec3166c 100644 --- a/capture/configs/kmac_sca_cw310.yaml +++ b/capture/configs/kmac_sca_cw310.yaml @@ -3,20 +3,18 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1_kmac.bit" force_program_bitstream: True fw_bin: "../objs/sca_kmac_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.10 target_freq: 10000000 baudrate: 115200 - output_len_bytes: 16 - protocol: "ujson" - port: "/dev/opentitan/cw310_1_tty_03" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "hw" husky: sampling_rate: 200000000 - num_segments: 20 # Number of target clock cycles per trace - KMAC is doing 24 or 96 cycles # for the key absorb w/o or w/ DOM, respectively, as well as 23 cycles for # XORing the key into the state. @@ -34,7 +32,9 @@ husky: offset_cycles: 115 scope_gain: 26 capture: + # scope_select: husky, waverunner, none scope_select: husky + num_segments: 20 num_traces: 1000 show_plot: True plot_traces: 100 @@ -42,12 +42,11 @@ capture: trace_db: ot_trace_library trace_threshold: 10000 test: - # which_test: kmac_random - # which_test: kmac_fvsr_key - which_test: kmac_fvsr_key_batch - key_len_bytes: 16 + # which_test: single + # which_test: fvsr_key + # which_test: daisy_chain + which_test: single key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] - text_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # 32-bit seed for SW key masking. Key masks are generated using an LFSR. # For unprotected implemetation, lfsr_seed should be set to 0. This will @@ -59,11 +58,27 @@ test: lfsr_seed: 0xdeadbeef # seed for PRNG to generate sequence of plaintexts and keys; Python random class on host, Mersenne twister implementation on OT SW batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/capture/configs/otbn_vertical_keygen_sca_cw310.yaml b/capture/configs/otbn_vertical_keygen_sca_cw310.yaml index b3adc37f..3618ca7a 100644 --- a/capture/configs/otbn_vertical_keygen_sca_cw310.yaml +++ b/capture/configs/otbn_vertical_keygen_sca_cw310.yaml @@ -3,20 +3,18 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: True fw_bin: "../objs/sca_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.24 target_freq: 24000000 baudrate: 115200 - output_len_bytes: 40 - protocol: "ujson" - port: "/dev/opentitan/cw310_1_tty_03" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "hw" husky: sampling_rate: 200000000 - num_segments: 20 num_cycles: 200 offset_cycles: 0 scope_gain: 24 @@ -24,21 +22,19 @@ husky: decimate: 1 waverunner: waverunner_ip: 100.107.71.10 - num_segments: 20 num_samples: 6000 sample_offset: 0 capture: - scope_select: husky + # scope_select: husky, waverunner, none + scope_select: none show_plot: True plot_traces: 100 + num_segments: 20 num_traces: 1000 trace_threshold: 10000 trace_db: ot_trace_library test: batch_prng_seed: 6 - key_len_bytes: 40 - text_len_bytes: 40 - plain_text_len_bytes: 40 masks_off: False # Currently, 'p256' is the only supported curve. curve: p256 @@ -47,4 +43,4 @@ test: # For app = keygen: There are two fixed-vs-random test types, KEY and SEED # Currently batch-mode capture only works with SEED test_type: SEED - batch_mode: False \ No newline at end of file + batch_mode: False diff --git a/capture/configs/otbn_vertical_modinv_sca_cw310.yaml b/capture/configs/otbn_vertical_modinv_sca_cw310.yaml index ca8cad82..827c3f30 100644 --- a/capture/configs/otbn_vertical_modinv_sca_cw310.yaml +++ b/capture/configs/otbn_vertical_modinv_sca_cw310.yaml @@ -3,20 +3,18 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: True fw_bin: "../objs/sca_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.24 target_freq: 24000000 baudrate: 115200 - output_len_bytes: 40 - protocol: "ujson" - port: "/dev/opentitan/cw310_1_tty_03" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "hw" husky: sampling_rate: 200000000 - num_segments: 20 num_cycles: 1000 offset_cycles: 0 scope_gain: 24 @@ -24,21 +22,19 @@ husky: decimate: 1 waverunner: waverunner_ip: 100.107.71.10 - num_segments: 20 num_samples: 6000 sample_offset: 0 capture: - scope_select: husky + # scope_select: husky, waverunner, none + scope_select: none show_plot: True plot_traces: 100 + num_segments: 20 num_traces: 1000 trace_threshold: 10000 trace_db: ot_trace_library test: batch_prng_seed: 6 - key_len_bytes: 40 - text_len_bytes: 40 - plain_text_len_bytes: 40 masks_off: False # Currently, 'p256' is the only supported curve. curve: p256 @@ -47,4 +43,4 @@ test: # For app = keygen: There are two fixed-vs-random test types, KEY and SEED # Currently batch-mode capture only works with SEED test_type: SEED - batch_mode: False \ No newline at end of file + batch_mode: False diff --git a/capture/configs/sha3_sca_chip_masks_off.yaml b/capture/configs/sha3_sca_chip.yaml similarity index 67% rename from capture/configs/sha3_sca_chip_masks_off.yaml rename to capture/configs/sha3_sca_chip.yaml index 2fc0595b..3ac67b15 100644 --- a/capture/configs/sha3_sca_chip_masks_off.yaml +++ b/capture/configs/sha3_sca_chip.yaml @@ -1,19 +1,17 @@ target: target_type: chip fw_bin: "../objs/sca_ujson_chip_signed.img" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. target_clk_mult: 1 target_freq: 100000000 baudrate: 115200 - output_len_bytes: 16 - protocol: "ujson" - port: "/dev/ttyUSB1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "sw" waverunner: waverunner_ip: 192.168.33.128 - num_segments: 1 # num_samples: 6000 # offset_samples: 0 # cycles will only be used if not given in samples @@ -24,22 +22,22 @@ waverunner: channel: C1 sparsing: 0 capture: - scope_select: waverunner - #key_len_bytes: 16 - plain_text_len_bytes: 16 + # scope_select: husky, waverunner, none + scope_select: none + num_segments: 20 num_traces: 100 show_plot: True plot_traces: 100 trace_db: ot_trace_library trace_threshold: 10000 test: - which_test: sha3_random - #which_test: sha3_fvsr_data + #which_test: single_absorb + #which_test: batch_absorb + which_test: single_absorb # Switch the masking on or off. When off, messages aren't masked upon loading # into the SHA3 core and the PRNG isn't advanced during SHA3 processing. # Works for SHA3 only. Doesn't work when processing key material. masks_off: true - text_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # 32-bit seed for SW key masking. Key masks are generated using an LFSR. # For unprotected implemetation, lfsr_seed should be set to 0. This will @@ -52,11 +50,27 @@ test: lfsr_seed: 0xdeadbeef # seed for PRNG to generate sequence of plaintexts and keys; Python random class on host, Mersenne twister implementation on OT SW batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/capture/configs/sha3_sca_cw310.yaml b/capture/configs/sha3_sca_cw310.yaml index 3e1be569..637e0d93 100644 --- a/capture/configs/sha3_sca_cw310.yaml +++ b/capture/configs/sha3_sca_cw310.yaml @@ -3,19 +3,17 @@ target: fpga_bitstream: ../objs/lowrisc_systems_chip_earlgrey_cw310_0.1_kmac.bit force_program_bitstream: True fw_bin: ../objs/sca_kmac_ujson_fpga_cw310.bin + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. target_clk_mult: 0.24 target_freq: 24000000 baudrate: 115200 - output_len_bytes: 32 - protocol: "ujson" - port: "/dev/opentitan/cw310_1_tty_03" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "hw" husky: samling_rate: 200000000 - num_segments: 20 # Number of target clock cycles per trace - SHA3 with DOM is doing 120 # cycles (24 for loading and padding, 96 for processing) with 320 delay # cycles between loading the plaintext and adding the padding. The plaintext @@ -24,23 +22,22 @@ husky: offset_cycles: 320 scope_gain: 27 capture: + # scope_select: husky, waverunner, none scope_select: husky - #key_len_bytes: 16 - plain_text_len_bytes: 16 + num_segments: 20 num_traces: 5000 show_plot: True plot_traces: 100 trace_db: ot_trace_library trace_threshold: 10000 test: - #which_test: sha3_random - #which_test: sha3_fvsr_data - which_test: sha3_fvsr_data_batch + #which_test: single_absorb + #which_test: batch_absorb + which_test: single_absorb # Switch the masking on or off. When off, messages aren't masked upon loading # into the SHA3 core and the PRNG isn't advanced during SHA3 processing. # Works for SHA3 only. Doesn't work when processing key material. masks_off: false - text_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # 32-bit seed for SW key masking. Key masks are generated using an LFSR. # For unprotected implemetation, lfsr_seed should be set to 0. This will @@ -53,11 +50,27 @@ test: lfsr_seed: 0xdeadbeef # seed for PRNG to generate sequence of plaintexts and keys; Python random class on host, Mersenne twister implementation on OT SW batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/capture/configs/sha3_sca_cw310_masks_off.yaml b/capture/configs/sha3_sca_cw310_masks_off.yaml index c3f5ca79..a5725b0e 100644 --- a/capture/configs/sha3_sca_cw310_masks_off.yaml +++ b/capture/configs/sha3_sca_cw310_masks_off.yaml @@ -3,19 +3,17 @@ target: fpga_bitstream: ../objs/lowrisc_systems_chip_earlgrey_cw310_0.1_kmac.bit force_program_bitstream: True fw_bin: ../objs/sca_kmac_ujson_fpga_cw310.bin + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. target_clk_mult: 0.24 target_freq: 24000000 baudrate: 115200 - output_len_bytes: 32 - protocol: "ujson" - port: "/dev/opentitan/cw310_1_tty_03" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "hw" husky: samling_rate: 200000000 - num_segments: 20 # Number of target clock cycles per trace - SHA3 with DOM is doing 120 # cycles (24 for loading and padding, 96 for processing) with 320 delay # cycles between loading the plaintext and adding the padding. The plaintext @@ -24,23 +22,22 @@ husky: offset_cycles: 320 scope_gain: 27 capture: + # scope_select: husky, waverunner, none scope_select: husky - #key_len_bytes: 16 - plain_text_len_bytes: 16 + num_segments: 20 num_traces: 5000 show_plot: True plot_traces: 100 trace_db: ot_trace_library trace_threshold: 10000 test: - #which_test: sha3_random - #which_test: sha3_fvsr_data - which_test: sha3_fvsr_data_batch + #which_test: single_absorb + #which_test: batch_absorb + which_test: single_absorb # Switch the masking on or off. When off, messages aren't masked upon loading # into the SHA3 core and the PRNG isn't advanced during SHA3 processing. # Works for SHA3 only. Doesn't work when processing key material. masks_off: true - text_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # 32-bit seed for SW key masking. Key masks are generated using an LFSR. # For unprotected implemetation, lfsr_seed should be set to 0. This will @@ -53,11 +50,27 @@ test: lfsr_seed: 0xdeadbeef # seed for PRNG to generate sequence of plaintexts and keys; Python random class on host, Mersenne twister implementation on OT SW batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/ci/cfg/ci_aes_sca_fvsr_cw305.yaml b/ci/cfg/ci_aes_sca_fvsr_cw305.yaml deleted file mode 100644 index 4a116b7f..00000000 --- a/ci/cfg/ci_aes_sca_fvsr_cw305.yaml +++ /dev/null @@ -1,56 +0,0 @@ -target: - target_type: cw305 - fpga_bitstream: "../objs/lowrisc_systems_chip_englishbreakfast_cw305_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/aes_serial_fpga_cw305.bin" - # target_clk_mult is a hardcoded value in the bitstream. Do not change. - target_clk_mult: 0.1 - target_freq: 10000000 - baudrate: 115200 - output_len_bytes: 16 - protocol: "simpleserial" - # Trigger source. - # hw: Precise, hardware-generated trigger - FPGA only. - # sw: Fully software-controlled trigger. - trigger: "hw" -husky: - sampling_rate: 200000000 - num_segments: 80 - num_cycles: 60 - offset_cycles: -2 - scope_gain: 20 -waverunner: - waverunner_ip: 100.107.71.10 - num_segments: 1 - num_samples: 6000 - sample_offset: 0 -capture: - scope_select: husky - # scope_select: waverunner - num_traces: 4000 - show_plot: True - plot_traces: 100 - trace_db: ot_trace_library - # trace_db: cw - trace_threshold: 10000 -test: - which_test: aes_fvsr_key_batch - key_len_bytes: 16 - text_len_bytes: 16 - key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] - text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] - key_for_gen: [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xE0, 0xF0] - # Seed for PRNG generating sequence of plaintexts and keys for batch captures - # on the host and on the device. - batch_prng_seed: 0 - # 32-bit seed for SW key masking. Key masks are generated using an LFSR. - # To switch off the masking, 0 must be used as LFSR seed. - lfsr_seed: 0xdeadbeef - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/ci/cfg/ci_aes_sca_fvsr_cw310_ujson.yaml b/ci/cfg/ci_aes_sca_fvsr_cw310_ujson.yaml index 52cdd82c..ee22d2a7 100644 --- a/ci/cfg/ci_aes_sca_fvsr_cw310_ujson.yaml +++ b/ci/cfg/ci_aes_sca_fvsr_cw310_ujson.yaml @@ -3,31 +3,28 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1_aes.bit" force_program_bitstream: True fw_bin: "../objs/sca_aes_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + port: "/dev/ttyACM_CW310_1" # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.10 target_freq: 10000000 - baudrate: 115200 - output_len_bytes: 16 - protocol: "ujson" - port: "/dev/ttyACM_CW310_1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "hw" husky: sampling_rate: 200000000 - num_segments: 20 num_cycles: 60 offset_cycles: -2 scope_gain: 38 waverunner: waverunner_ip: 100.107.71.10 - num_segments: 20 num_samples: 6000 sample_offset: 0 capture: scope_select: husky # scope_select: waverunner + num_segments: 20 num_traces: 1000 show_plot: True plot_traces: 100 @@ -35,12 +32,12 @@ capture: # trace_db: cw trace_threshold: 10000 test: - # which_test: aes_random_batch + # which_test: daisy_chain + # which_test: single + # which_test: daisy_chain # which_test: aes_random - which_test: aes_fvsr_key_batch - # which_test: aes_fvsr_key - key_len_bytes: 16 - text_len_bytes: 16 + which_test: aes_fvsr_key + # which_test: aes_fvsr_data # These initial values are used only for random capture but not fixed-vs-random. key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] @@ -50,11 +47,27 @@ test: # 32-bit seed for masking on device. To switch off the masking, use 0 as LFSR seed. lfsr_seed: 0x00000000 # lfsr_seed: 0xdeadbeef - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/ci/cfg/ci_aes_sca_random_cw305.yaml b/ci/cfg/ci_aes_sca_random_cw305.yaml deleted file mode 100644 index 34fcb5c3..00000000 --- a/ci/cfg/ci_aes_sca_random_cw305.yaml +++ /dev/null @@ -1,56 +0,0 @@ -target: - target_type: cw305 - fpga_bitstream: "../objs/lowrisc_systems_chip_englishbreakfast_cw305_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/aes_serial_fpga_cw305.bin" - # target_clk_mult is a hardcoded value in the bitstream. Do not change. - target_clk_mult: 0.1 - target_freq: 10000000 - baudrate: 115200 - output_len_bytes: 16 - protocol: "simpleserial" - # Trigger source. - # hw: Precise, hardware-generated trigger - FPGA only. - # sw: Fully software-controlled trigger. - trigger: "hw" -husky: - sampling_rate: 200000000 - num_segments: 80 - num_cycles: 60 - offset_cycles: -2 - scope_gain: 20 -waverunner: - waverunner_ip: 100.107.71.10 - num_segments: 1 - num_samples: 6000 - sample_offset: 0 -capture: - scope_select: husky - # scope_select: waverunner - num_traces: 4000 - show_plot: True - plot_traces: 100 - # trace_db: ot_trace_library - trace_db: cw - trace_threshold: 10000 -test: - which_test: aes_random_batch - key_len_bytes: 16 - text_len_bytes: 16 - key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] - text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] - key_for_gen: [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xE0, 0xF0] - # Seed for PRNG generating sequence of plaintexts and keys for batch captures - # on the host and on the device. - batch_prng_seed: 0 - # 32-bit seed for SW key masking. Key masks are generated using an LFSR. - # To switch off the masking, 0 must be used as LFSR seed. - lfsr_seed: 0xdeadbeef - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/ci/cfg/ci_aes_sca_random_cw310_ujson.yaml b/ci/cfg/ci_aes_sca_random_cw310_ujson.yaml index c31b4f2d..2599c107 100644 --- a/ci/cfg/ci_aes_sca_random_cw310_ujson.yaml +++ b/ci/cfg/ci_aes_sca_random_cw310_ujson.yaml @@ -3,31 +3,28 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1_aes.bit" force_program_bitstream: True fw_bin: "../objs/sca_aes_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + port: "/dev/ttyACM_CW310_1" # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.10 target_freq: 10000000 - baudrate: 115200 - output_len_bytes: 16 - protocol: "ujson" - port: "/dev/ttyACM_CW310_1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "hw" husky: sampling_rate: 200000000 - num_segments: 20 num_cycles: 60 offset_cycles: -2 scope_gain: 38 waverunner: waverunner_ip: 100.107.71.10 - num_segments: 20 num_samples: 6000 sample_offset: 0 capture: scope_select: husky # scope_select: waverunner + num_segments: 20 num_traces: 1000 show_plot: True plot_traces: 100 @@ -35,11 +32,12 @@ capture: # trace_db: cw trace_threshold: 10000 test: - which_test: aes_random_batch - # which_test: aes_random - # which_test: aes_fvsr_key_batch - key_len_bytes: 16 - text_len_bytes: 16 + # which_test: daisy_chain + # which_test: single + # which_test: daisy_chain + which_test: aes_random + # which_test: aes_fvsr_key + # which_test: aes_fvsr_data key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] key_for_gen: [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xE0, 0xF0] @@ -48,11 +46,27 @@ test: # 32-bit seed for masking on device. To switch off the masking, use 0 as LFSR seed. lfsr_seed: 0x00000000 # lfsr_seed: 0xdeadbeef - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/ci/cfg/ci_capture_ecdsa256_cw310.yaml b/ci/cfg/ci_capture_ecdsa256_cw310.yaml index a8c9e878..70f2e4b9 100644 --- a/ci/cfg/ci_capture_ecdsa256_cw310.yaml +++ b/ci/cfg/ci_capture_ecdsa256_cw310.yaml @@ -2,6 +2,7 @@ device: fpga_bitstream: ../cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit force_program_bitstream: True fw_bin: ../cw/objs/ecc256_serial_fpga_cw310.bin + opentitantool: "../objs/opentitantool" # The clock frequency of the target block is equal to # pll_frequency * target_clk_mult. pll_frequency is controllable via # ChipWhisperer API, whereas target_clk_mult is baked into the FPGA @@ -10,10 +11,6 @@ device: target_clk_mult: 0.1 baudrate: 115200 capture: - # Only ECDSA-256 (32) and ECDSA-384 (48) are supported at this moment. - key_len_bytes: 32 - plain_text_len_bytes: 32 - output_len_bytes: 32 # With pll_frequency = 20 MHz and target_clk_mult = 0.1, 2000 # target clock cycles correspond to 200000 scope samples on Husky # (100x oversampling). diff --git a/ci/cfg/ci_capture_ecdsa384_cw310.yaml b/ci/cfg/ci_capture_ecdsa384_cw310.yaml index 665b2fc0..2c5c9e24 100644 --- a/ci/cfg/ci_capture_ecdsa384_cw310.yaml +++ b/ci/cfg/ci_capture_ecdsa384_cw310.yaml @@ -2,6 +2,7 @@ device: fpga_bitstream: ../cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit force_program_bitstream: True fw_bin: ../cw/objs/ecc384_serial_fpga_cw310.bin + opentitantool: "../objs/opentitantool" # The clock frequency of the target block is equal to # pll_frequency * target_clk_mult. pll_frequency is controllable via # ChipWhisperer API, whereas target_clk_mult is baked into the FPGA @@ -10,10 +11,6 @@ device: target_clk_mult: 0.1 baudrate: 115200 capture: - # Only ECDSA-256 (32) and ECDSA-384 (48) are supported at this moment. - key_len_bytes: 48 - plain_text_len_bytes: 48 - output_len_bytes: 48 # With pll_frequency = 20 MHz and target_clk_mult = 0.1, 2000 # target clock cycles correspond to 200000 scope samples on Husky # (100x oversampling). diff --git a/ci/cfg/ci_capture_otbn_vertical_keygen.yaml b/ci/cfg/ci_capture_otbn_vertical_keygen.yaml index a3e6442e..9988ef40 100644 --- a/ci/cfg/ci_capture_otbn_vertical_keygen.yaml +++ b/ci/cfg/ci_capture_otbn_vertical_keygen.yaml @@ -2,6 +2,7 @@ device: fpga_bitstream: ../cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit force_program_bitstream: True fw_bin: ../cw/objs/otbn_vertical_serial_fpga_cw310.bin + opentitantool: "../objs/opentitantool" # The clock frequency of the target block is equal to # pll_frequency * target_clk_mult. pll_frequency is controllable via # ChipWhisperer API, whereas target_clk_mult is baked into the FPGA @@ -22,11 +23,7 @@ capture: # There are two fixed-vs-random test types, KEY and SEED # Currently batch-mode capture only works with SEED test_type: KEY - key_len_bytes: 40 - plain_text_len_bytes: 40 masks_off: false - # Output length (most likely unused). - output_len_bytes: 40 # Fifo Size is 131070 = max num samples to avoid multiple runs per trace num_cycles: 200 offset_cycles: 0 diff --git a/ci/cfg/ci_capture_otbn_vertical_modinv.yaml b/ci/cfg/ci_capture_otbn_vertical_modinv.yaml index 93c6880c..69d3b58e 100644 --- a/ci/cfg/ci_capture_otbn_vertical_modinv.yaml +++ b/ci/cfg/ci_capture_otbn_vertical_modinv.yaml @@ -2,6 +2,7 @@ device: fpga_bitstream: ../cw/objs/lowrisc_systems_chip_earlgrey_cw310_0.1_ecdsa.bit force_program_bitstream: True fw_bin: ../cw/objs/otbn_vertical_serial_fpga_cw310.bin + opentitantool: "../objs/opentitantool" # The clock frequency of the target block is equal to # pll_frequency * target_clk_mult. pll_frequency is controllable via # ChipWhisperer API, whereas target_clk_mult is baked into the FPGA @@ -19,12 +20,7 @@ capture: # Since this is not encryption, they don't correspond to key/plaintext, but # rather seed/mask. use_fixed_key_iter: False # See https://github.com/lowRISC/ot-sca/issues/116 - # Here key/text length = length of key shares (40-byte shares, 32-byte key) - key_len_bytes: 40 - plain_text_len_bytes: 40 masks_off: false - # Output length (most likely unused). - output_len_bytes: 32 # Fifo Size is 131070 = max num samples to avoid multiple runs per trace num_cycles: 5000 offset_cycles: 0 diff --git a/ci/cfg/ci_crypto_aes_vcc_dummy_cw310.yaml b/ci/cfg/ci_crypto_aes_vcc_dummy_cw310.yaml index f9fec67e..0dbec452 100644 --- a/ci/cfg/ci_crypto_aes_vcc_dummy_cw310.yaml +++ b/ci/cfg/ci_crypto_aes_vcc_dummy_cw310.yaml @@ -3,11 +3,9 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: True fw_bin: "../objs/fi_ujson_fpga_cw310.bin" - output_len_bytes: 16 + opentitantool: "../objs/opentitantool" target_clk_mult: 0.24 target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" port: "/dev/ttyACM_CW310_1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. @@ -47,19 +45,180 @@ fiproject: plot_y_axis: "glitch_width" plot_y_axis_legend: "[ns]" test: + # which_test: "crypto_aes_key" + # which_test: "crypto_aes_plaintext" which_test: "crypto_aes_encrypt" - expected_result: '{"ciphertext":[141,145,88,155,234,129,16,92,221,12,69,21,69,208,99,12],"err_status":0,"ast_alerts":[0,0]}' + # which_test: "crypto_fi_aes_ciphertext" + plaintext: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + key: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] # Set to true if the test should ignore alerts returned by the test. As the # alert handler on the device could sometime fire alerts that are not # related to the FI, ignoring is by default set to true. A manual analysis # still can be performed as the alerts are stored in the database. ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False - + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/ci/cfg/ci_hmac_sca_fvsr_cw310_ujson.yaml b/ci/cfg/ci_hmac_sca_fvsr_cw310_ujson.yaml index eafae4c9..82d4c434 100644 --- a/ci/cfg/ci_hmac_sca_fvsr_cw310_ujson.yaml +++ b/ci/cfg/ci_hmac_sca_fvsr_cw310_ujson.yaml @@ -3,21 +3,19 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: True fw_bin: "../objs/sca_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.24 target_freq: 24000000 - baudrate: 115200 - output_len_bytes: 32 - protocol: "ujson" port: "/dev/ttyACM_CW310_1" husky: sampling_rate: 200000000 - num_segments: 20 num_cycles: 60 offset_cycles: -2 scope_gain: 38 capture: scope_select: husky + num_segments: 20 num_traces: 100 show_plot: True plot_traces: 10 @@ -25,26 +23,41 @@ capture: trace_threshold: 10000 # trace_db: cw test: - which_test: hmac_fvsr - key_len_bytes: 32 + # which_test: single + # which_test: random + which_test: data_fvsr + # which_test: daisy_chain key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9, 0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] - msg_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # seed for PRNG to generate sequence of messages, and keys; Python random # class on host, Mersenne twister implementation on OT SW. batch_prng_seed: 0 # Trigger configuration. - start_trigger: False - msg_trigger: False - process_trigger: True - finish_trigger: False - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + # 0 = start_trigger, 1 = msg_trigger, 2 = process_trigger, 3 = finish_trigger + trigger: 0 + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/ci/cfg/ci_ibex_fi_vcc_dummy_cw310.yaml b/ci/cfg/ci_ibex_fi_vcc_dummy_cw310.yaml index fc7279a3..1e116981 100644 --- a/ci/cfg/ci_ibex_fi_vcc_dummy_cw310.yaml +++ b/ci/cfg/ci_ibex_fi_vcc_dummy_cw310.yaml @@ -3,11 +3,9 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: True fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 + opentitantool: "../objs/opentitantool" target_clk_mult: 0.24 target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" port: "/dev/ttyACM_CW310_1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. @@ -54,11 +52,169 @@ test: # related to the FI, ignoring is by default set to true. A manual analysis # still can be performed as the alerts are stored in the database. ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/ci/cfg/ci_ibex_sca_cw310_ujson.yaml b/ci/cfg/ci_ibex_sca_cw310_ujson.yaml index 020cf491..79e204d3 100644 --- a/ci/cfg/ci_ibex_sca_cw310_ujson.yaml +++ b/ci/cfg/ci_ibex_sca_cw310_ujson.yaml @@ -3,31 +3,53 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: True fw_bin: ../objs/sca_ujson_fpga_cw310.bin + opentitantool: "../objs/opentitantool" target_clk_mult: 0.24 target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" port: "/dev/ttyACM_CW310_1" husky: samling_rate: 200000000 - num_segments: 1 num_cycles: 50 offset_cycles: 100 scope_gain: 27 capture: scope_select: husky + num_segments: 1 num_traces: 40 show_plot: True plot_traces: 20 trace_db: ot_trace_library trace_threshold: 10000 test: - which_test: ibex_sca_register_file_read_random - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + which_test: ibex_sca_register_file_read_batch_random + # Combi test uses the first two values of the fixed input. + input_fixed: [0xABBABABE, 0xABADCAFE, 0xBAAAAAAD, 0xBAD22222, 0xBBADBEEF, 0xBEBEBEBE, 0xBEEFCACE, 0xC00010FF] + # Seed for PRNG generating sequence of plaintexts and keys for batch captures + # on the host and on the device. + batch_prng_seed: 0 + # Trigger for the combi test, 12-bit value, each bit sets the trigger for one of the 12 trigger windows. + trigger: 0 + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/ci/cfg/ci_kmac_sca_fvsr_cw310_ujson.yaml b/ci/cfg/ci_kmac_sca_fvsr_cw310_ujson.yaml index 5452415e..9936336c 100644 --- a/ci/cfg/ci_kmac_sca_fvsr_cw310_ujson.yaml +++ b/ci/cfg/ci_kmac_sca_fvsr_cw310_ujson.yaml @@ -4,13 +4,10 @@ target: force_program_bitstream: True # fw_bin: ../objs/kmac_serial_fpga_cw310.bin fw_bin: "../objs/sca_kmac_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.10 target_freq: 10000000 - baudrate: 115200 - output_len_bytes: 32 - # protocol: "simpleserial" - protocol: "ujson" port: "/dev/ttyACM_CW310_1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. @@ -18,7 +15,6 @@ target: trigger: "hw" husky: sampling_rate: 200000000 - num_segments: 20 # Number of target clock cycles per trace - KMAC is doing 24 or 96 cycles # for the key absorb w/o or w/ DOM, respectively, as well as 23 cycles for # XORing the key into the state. @@ -37,6 +33,7 @@ husky: scope_gain: 26 capture: scope_select: husky + num_segments: 20 num_traces: 1000 show_plot: True plot_traces: 100 @@ -44,12 +41,11 @@ capture: trace_db: ot_trace_library trace_threshold: 10000 test: - # which_test: kmac_random - # which_test: kmac_fvsr_key - which_test: kmac_fvsr_key_batch - key_len_bytes: 16 + # which_test: single + which_test: fvsr_key + # which_test: daisy_chain + # which_test: single key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] - text_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # 32-bit seed for SW key masking. Key masks are generated using an LFSR. # For unprotected implemetation, lfsr_seed should be set to 0. This will @@ -61,11 +57,27 @@ test: lfsr_seed: 0xdeadbeef # seed for PRNG to generate sequence of plaintexts and keys; Python random class on host, Mersenne twister implementation on OT SW batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/ci/cfg/ci_kmac_sca_random_cw310_ujson.yaml b/ci/cfg/ci_kmac_sca_random_cw310_ujson.yaml index 824df344..dd159aae 100644 --- a/ci/cfg/ci_kmac_sca_random_cw310_ujson.yaml +++ b/ci/cfg/ci_kmac_sca_random_cw310_ujson.yaml @@ -4,13 +4,10 @@ target: force_program_bitstream: True # fw_bin: ../objs/kmac_serial_fpga_cw310.bin fw_bin: "../objs/sca_kmac_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" # target_clk_mult is a hardcoded value in the bitstream. Do not change. target_clk_mult: 0.10 target_freq: 10000000 - baudrate: 115200 - output_len_bytes: 32 - # protocol: "simpleserial" - protocol: "ujson" port: "/dev/ttyACM_CW310_1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. @@ -18,7 +15,6 @@ target: trigger: "hw" husky: sampling_rate: 200000000 - num_segments: 1 # Number of target clock cycles per trace - KMAC is doing 24 or 96 cycles # for the key absorb w/o or w/ DOM, respectively, as well as 23 cycles for # XORing the key into the state. @@ -37,6 +33,7 @@ husky: scope_gain: 26 capture: scope_select: husky + num_segments: 1 num_traces: 100 show_plot: True plot_traces: 100 @@ -44,12 +41,11 @@ capture: trace_db: ot_trace_library trace_threshold: 10000 test: - which_test: kmac_random - # which_test: kmac_fvsr_key - # which_test: kmac_fvsr_key_batch - key_len_bytes: 16 + # which_test: single + # which_test: fvsr_key + which_test: daisy_chain + # which_test: single key_fixed: [0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9] - text_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # 32-bit seed for SW key masking. Key masks are generated using an LFSR. # For unprotected implemetation, lfsr_seed should be set to 0. This will @@ -61,11 +57,27 @@ test: lfsr_seed: 0xdeadbeef # seed for PRNG to generate sequence of plaintexts and keys; Python random class on host, Mersenne twister implementation on OT SW batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/ci/cfg/ci_otbn_fi_vcc_dummy_cw310.yaml b/ci/cfg/ci_otbn_fi_vcc_dummy_cw310.yaml index 4c372054..3e5b450a 100644 --- a/ci/cfg/ci_otbn_fi_vcc_dummy_cw310.yaml +++ b/ci/cfg/ci_otbn_fi_vcc_dummy_cw310.yaml @@ -3,11 +3,9 @@ target: fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" force_program_bitstream: True fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 + opentitantool: "../objs/opentitantool" target_clk_mult: 0.24 target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" port: "/dev/ttyACM_CW310_1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. @@ -54,11 +52,169 @@ test: # related to the FI, ignoring is by default set to true. A manual analysis # still can be performed as the alerts are stored in the database. ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/ci/cfg/ci_sha3_sca_fvsr_cw310_ujson.yaml b/ci/cfg/ci_sha3_sca_fvsr_cw310_ujson.yaml index 29193807..b64cb3ce 100644 --- a/ci/cfg/ci_sha3_sca_fvsr_cw310_ujson.yaml +++ b/ci/cfg/ci_sha3_sca_fvsr_cw310_ujson.yaml @@ -4,20 +4,16 @@ target: force_program_bitstream: True # fw_bin: ../objs/sha3_serial_fpga_cw310.bin fw_bin: ../objs/sca_kmac_ujson_fpga_cw310.bin + opentitantool: "../objs/opentitantool" target_clk_mult: 0.24 target_freq: 24000000 - baudrate: 115200 - output_len_bytes: 32 - # protocol: "simpleserial" - protocol: "ujson" port: "/dev/ttyACM_CW310_1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. # sw: Fully software-controlled trigger. trigger: "hw" husky: - samling_rate: 200000000 - num_segments: 20 + samling_rate: 200000000 # Number of target clock cycles per trace - SHA3 with DOM is doing 120 # cycles (24 for loading and padding, 96 for processing) with 320 delay # cycles between loading the plaintext and adding the padding. The plaintext @@ -27,22 +23,20 @@ husky: scope_gain: 27 capture: scope_select: husky - #key_len_bytes: 16 - plain_text_len_bytes: 16 + num_segments: 20 num_traces: 100 show_plot: True plot_traces: 100 trace_db: ot_trace_library trace_threshold: 10000 test: - # which_test: sha3_random - # which_test: sha3_fvsr_data - which_test: sha3_fvsr_data_batch + #which_test: single_absorb + which_test: batch_absorb + # which_test: single_absorb # Switch the masking on or off. When off, messages aren't masked upon loading # into the SHA3 core and the PRNG isn't advanced during SHA3 processing. # Works for SHA3 only. Doesn't work when processing key material. masks_off: true - text_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # 32-bit seed for SW key masking. Key masks are generated using an LFSR. # For unprotected implemetation, lfsr_seed should be set to 0. This will @@ -55,11 +49,27 @@ test: lfsr_seed: 0xdeadbeef # seed for PRNG to generate sequence of plaintexts and keys; Python random class on host, Mersenne twister implementation on OT SW batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/ci/cfg/ci_sha3_sca_random_cw310_ujson.yaml b/ci/cfg/ci_sha3_sca_random_cw310_ujson.yaml index f223522e..5bdf1ec6 100644 --- a/ci/cfg/ci_sha3_sca_random_cw310_ujson.yaml +++ b/ci/cfg/ci_sha3_sca_random_cw310_ujson.yaml @@ -4,12 +4,9 @@ target: force_program_bitstream: True # fw_bin: ../objs/sha3_serial_fpga_cw310.bin fw_bin: ../objs/sca_kmac_ujson_fpga_cw310.bin + opentitantool: "../objs/opentitantool" target_clk_mult: 0.24 target_freq: 24000000 - baudrate: 115200 - output_len_bytes: 32 - # protocol: "simpleserial" - protocol: "ujson" port: "/dev/ttyACM_CW310_1" # Trigger source. # hw: Precise, hardware-generated trigger - FPGA only. @@ -17,7 +14,6 @@ target: trigger: "hw" husky: samling_rate: 200000000 - num_segments: 1 # Number of target clock cycles per trace - SHA3 with DOM is doing 120 # cycles (24 for loading and padding, 96 for processing) with 320 delay # cycles between loading the plaintext and adding the padding. The plaintext @@ -29,20 +25,20 @@ capture: scope_select: husky #key_len_bytes: 16 plain_text_len_bytes: 16 + num_segments: 1 num_traces: 100 show_plot: True plot_traces: 100 trace_db: ot_trace_library trace_threshold: 10000 test: - which_test: sha3_random - # which_test: sha3_fvsr_data - # which_test: sha3_fvsr_data_batch + #which_test: single_absorb + #which_test: batch_absorb + which_test: single_absorb # Switch the masking on or off. When off, messages aren't masked upon loading # into the SHA3 core and the PRNG isn't advanced during SHA3 processing. # Works for SHA3 only. Doesn't work when processing key material. masks_off: true - text_len_bytes: 16 text_fixed: [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA] # 32-bit seed for SW key masking. Key masks are generated using an LFSR. # For unprotected implemetation, lfsr_seed should be set to 0. This will @@ -55,11 +51,27 @@ test: lfsr_seed: 0xdeadbeef # seed for PRNG to generate sequence of plaintexts and keys; Python random class on host, Mersenne twister implementation on OT SW batch_prng_seed: 0 - # When True, the instruction cache is enabled. - enable_icache: True - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } diff --git a/fault_injection/configs/pen.global_fi.crypto.aes.cw310.yaml b/fault_injection/configs/pen.global_fi.crypto.aes.cw310.yaml deleted file mode 100644 index a5816671..00000000 --- a/fault_injection/configs/pen.global_fi.crypto.aes.cw310.yaml +++ /dev/null @@ -1,55 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - # which_test: "crypto_aes_key" - # which_test: "crypto_aes_plaintext" - which_test: "crypto_aes_encrypt" - # which_test: "crypto_fi_aes_ciphertext" - expected_result: '{"ciphertext":[141,145,88,155,234,129,16,92,221,12,69,21,69,208,99,12],"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.crypto.aes.yaml b/fault_injection/configs/pen.global_fi.crypto.aes.yaml new file mode 100644 index 00000000..0c16fa32 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.crypto.aes.yaml @@ -0,0 +1,218 @@ +target: + target_type: chip + # fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "dummy" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_voltage_min: 150 + glitch_voltage_max: 150 + glitch_voltage_step: 10 + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + # which_test: "crypto_aes_key" + # which_test: "crypto_aes_plaintext" + which_test: "crypto_aes_encrypt" + # which_test: "crypto_fi_aes_ciphertext" + plaintext: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + key: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.crypto.hmac.yaml b/fault_injection/configs/pen.global_fi.crypto.hmac.yaml new file mode 100644 index 00000000..73c15eff --- /dev/null +++ b/fault_injection/configs/pen.global_fi.crypto.hmac.yaml @@ -0,0 +1,212 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "crypto_sha256_start" + # which_test: "crypto_sha256_msg" + # which_test: "crypto_sha256_process" + # which_test: "crypto_sha256_finish" + expected_result: '{"tag":[686569403,627255979,3962665531,1869430007,3580678696,2543765621,4151418325,927402239],"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.crypto.kmac.cw310.yaml b/fault_injection/configs/pen.global_fi.crypto.kmac.cw310.yaml deleted file mode 100644 index 79f0b993..00000000 --- a/fault_injection/configs/pen.global_fi.crypto.kmac.cw310.yaml +++ /dev/null @@ -1,55 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - # which_test: "crypto_kmac_key" - which_test: "crypto_kmac_absorb" - # which_test: "crypto_kmac_squeeze" - # which_test: "crypto_kmac_static" - expected_result: '{"digest":[184,34,91,108,231,47,251,27],"digest_2nd":[142,188,186,201,216,47,203,192],"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.crypto.kmac.yaml b/fault_injection/configs/pen.global_fi.crypto.kmac.yaml new file mode 100644 index 00000000..92f816a0 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.crypto.kmac.yaml @@ -0,0 +1,216 @@ +target: + target_type: chip + # fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "dummy" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_voltage_min: 150 + glitch_voltage_max: 150 + glitch_voltage_step: 10 + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + # which_test: "crypto_kmac_key" + which_test: "crypto_kmac_absorb" + # which_test: "crypto_kmac_squeeze" + # which_test: "crypto_kmac_static" + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.crypto.sha256.cw310.yaml b/fault_injection/configs/pen.global_fi.crypto.sha256.cw310.yaml deleted file mode 100644 index c5ce6f7a..00000000 --- a/fault_injection/configs/pen.global_fi.crypto.sha256.cw310.yaml +++ /dev/null @@ -1,55 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "crypto_sha256_start" - # which_test: "crypto_sha256_msg" - # which_test: "crypto_sha256_process" - # which_test: "crypto_sha256_finish" - expected_result: '{"tag":[686569403,627255979,3962665531,1869430007,3580678696,2543765621,4151418325,927402239],"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.crypto.shadow_reg_access.cw310.yaml b/fault_injection/configs/pen.global_fi.crypto.shadow_reg_access.cw310.yaml deleted file mode 100644 index b65ce3df..00000000 --- a/fault_injection/configs/pen.global_fi.crypto.shadow_reg_access.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "crypto_shadow_reg_access" - expected_result: '{"result":[68162304,0,0],"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.crypto.shadow_reg_access.yaml b/fault_injection/configs/pen.global_fi.crypto.shadow_reg_access.yaml new file mode 100644 index 00000000..7d7ac3c5 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.crypto.shadow_reg_access.yaml @@ -0,0 +1,213 @@ +target: + target_type: chip + # fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "dummy" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_voltage_min: 150 + glitch_voltage_max: 150 + glitch_voltage_step: 10 + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "crypto_shadow_reg_access" + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.address_translation.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.address_translation.cw310.yaml deleted file mode 100644 index f4313d53..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.address_translation.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_address_translation" - expected_result: '{"result":0,"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.address_translation.yaml b/fault_injection/configs/pen.global_fi.ibex.address_translation.yaml new file mode 100644 index 00000000..2238919c --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.address_translation.yaml @@ -0,0 +1,211 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "husky" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_address_translation" + expected_result: '{"result":0,"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.address_translation_config.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.address_translation_config.cw310.yaml deleted file mode 100644 index 3684250b..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.address_translation_config.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_address_translation_config" - expected_result: '{"result":0,"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.address_translation_config.yaml b/fault_injection/configs/pen.global_fi.ibex.address_translation_config.yaml new file mode 100644 index 00000000..b2fbc23e --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.address_translation_config.yaml @@ -0,0 +1,214 @@ +target: + target_type: chip + #fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "dummy" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_voltage_min: 150 + glitch_voltage_max: 150 + glitch_voltage_step: 10 + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_address_translation_config" + expected_result: '{"result":0,"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.conditional_branch.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.conditional_branch.cw310.yaml deleted file mode 100644 index 6e3f6d83..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.conditional_branch.cw310.yaml +++ /dev/null @@ -1,62 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_conditional_branch_beq" - expected_result: '{"result1":175,"result2":239,"err_status":0,"ast_alerts":[0,0]}' - # which_test: "ibex_char_conditional_branch_bne" - # expected_result: '{"result1":175,"result2":175,"err_status":0,"ast_alerts":[0,0]}' - # which_test: "ibex_char_conditional_branch_bge" - # expected_result: '{"result1":175,"result2":239,"err_status":0,"ast_alerts":[0,0]}' - # which_test: "ibex_char_conditional_branch_bgeu" - # expected_result: '{"result1":175,"result2":239,"err_status":0,"ast_alerts":[0,0]}' - # which_test: "ibex_char_conditional_branch_blt" - # expected_result: '{"result1":239,"result2":175,"err_status":0,"ast_alerts":[0,0]}' - # which_test: "ibex_char_conditional_branch_bltu" - # expected_result: '{"result1":239,"result2":175,"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.conditional_branch.yaml b/fault_injection/configs/pen.global_fi.ibex.char.conditional_branch.yaml new file mode 100644 index 00000000..5444a5d8 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.conditional_branch.yaml @@ -0,0 +1,221 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "husky" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_conditional_branch_beq" + expected_result: '{"result1":175,"result2":239,"err_status":0,"ast_alerts":[0,0]}' + # which_test: "ibex_char_conditional_branch_bne" + # expected_result: '{"result1":175,"result2":175,"err_status":0,"ast_alerts":[0,0]}' + # which_test: "ibex_char_conditional_branch_bge" + # expected_result: '{"result1":175,"result2":239,"err_status":0,"ast_alerts":[0,0]}' + # which_test: "ibex_char_conditional_branch_bgeu" + # expected_result: '{"result1":175,"result2":239,"err_status":0,"ast_alerts":[0,0]}' + # which_test: "ibex_char_conditional_branch_blt" + # expected_result: '{"result1":239,"result2":175,"err_status":0,"ast_alerts":[0,0]}' + # which_test: "ibex_char_conditional_branch_bltu" + # expected_result: '{"result1":239,"result2":175,"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.csr_read.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.csr_read.cw310.yaml deleted file mode 100644 index 70a6555a..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.csr_read.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_csr_read" - expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.csr_read.yaml b/fault_injection/configs/pen.global_fi.ibex.char.csr_read.yaml new file mode 100644 index 00000000..00f08e3d --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.csr_read.yaml @@ -0,0 +1,214 @@ +target: + target_type: chip + #fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "dummy" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_voltage_min: 150 + glitch_voltage_max: 150 + glitch_voltage_step: 10 + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_csr_read" + expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.csr_write.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.csr_write.cw310.yaml deleted file mode 100644 index af8b69fd..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.csr_write.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_csr_write" - expected_result: '{"result":0,"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.csr_write.yaml b/fault_injection/configs/pen.global_fi.ibex.char.csr_write.yaml new file mode 100644 index 00000000..1d8cf68d --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.csr_write.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_csr_write" + expected_result: '{"result":0,"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.flash_read.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.flash_read.cw310.yaml deleted file mode 100644 index adcfb460..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.flash_read.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_flash_read" - expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.flash_read.yaml b/fault_injection/configs/pen.global_fi.ibex.char.flash_read.yaml new file mode 100644 index 00000000..6966f460 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.flash_read.yaml @@ -0,0 +1,214 @@ +target: + target_type: chip + # fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "dummy" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_voltage_min: 150 + glitch_voltage_max: 150 + glitch_voltage_step: 10 + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_flash_read" + expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.flash_write.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.flash_write.cw310.yaml deleted file mode 100644 index 1a16563b..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.flash_write.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_flash_write" - expected_result: '{"result":0,"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.flash_write.yaml b/fault_injection/configs/pen.global_fi.ibex.char.flash_write.yaml new file mode 100644 index 00000000..7922145d --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.flash_write.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_flash_write" + expected_result: '{"result":0,"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.hardened_check_eq_unimps.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.hardened_check_eq_unimps.cw310.yaml deleted file mode 100644 index 43a7931f..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.hardened_check_eq_unimps.cw310.yaml +++ /dev/null @@ -1,58 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_hardened_check_eq_unimp" - # which_test: "ibex_char_hardened_check_eq_2_unimps" - # which_test: "ibex_char_hardened_check_eq_3_unimps" - # which_test: "ibex_char_hardened_check_eq_4_unimps" - # which_test: "ibex_char_hardened_check_eq_5_unimps" - # which_test: "ibex_char_hardened_check_eq_complement_branch" - # For this test, the expected result is actually a crash of the system. On - # a successful FI attack, this could be one result: - expected_result: '{"result1":0,"result2":1,"err_status":0,"alerts":0}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.hardened_check_eq_unimps.yaml b/fault_injection/configs/pen.global_fi.ibex.char.hardened_check_eq_unimps.yaml new file mode 100644 index 00000000..60fd6328 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.hardened_check_eq_unimps.yaml @@ -0,0 +1,215 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_hardened_check_eq_unimp" + # which_test: "ibex_char_hardened_check_eq_2_unimps" + # which_test: "ibex_char_hardened_check_eq_3_unimps" + # which_test: "ibex_char_hardened_check_eq_4_unimps" + # which_test: "ibex_char_hardened_check_eq_5_unimps" + # which_test: "ibex_char_hardened_check_eq_complement_branch" + # For this test, the expected result is actually a crash of the system. On + # a successful FI attack, this could be one result: + expected_result: '{"result1":0,"result2":1,"err_status":0,"alerts":0}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.mem_op_loop.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.mem_op_loop.cw310.yaml deleted file mode 100644 index 65fc7761..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.mem_op_loop.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_mem_op_loop" - expected_result: '{"result":[10000,0,0,0,0,0,0,0,0,0,0,0],"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.mem_op_loop.yaml b/fault_injection/configs/pen.global_fi.ibex.char.mem_op_loop.yaml new file mode 100644 index 00000000..4cf04b93 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.mem_op_loop.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_mem_op_loop" + expected_result: '{"result":[10000,0,0,0,0,0,0,0,0,0,0,0],"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.reg_op_loop.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.reg_op_loop.cw310.yaml deleted file mode 100644 index c705959c..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.reg_op_loop.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_reg_op_loop" - expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.reg_op_loop.yaml b/fault_injection/configs/pen.global_fi.ibex.char.reg_op_loop.yaml new file mode 100644 index 00000000..ceaea843 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.reg_op_loop.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_reg_op_loop" + expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.register_file.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.register_file.cw310.yaml deleted file mode 100644 index b9b25a2b..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.register_file.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_register_file" - expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.register_file.yaml b/fault_injection/configs/pen.global_fi.ibex.char.register_file.yaml new file mode 100644 index 00000000..218df563 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.register_file.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_register_file" + expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.register_file_read.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.register_file_read.cw310.yaml deleted file mode 100644 index 60f5c384..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.register_file_read.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_register_file_read" - expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.register_file_read.yaml b/fault_injection/configs/pen.global_fi.ibex.char.register_file_read.yaml new file mode 100644 index 00000000..e25b253b --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.register_file_read.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_register_file_read" + expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.sram_read.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.sram_read.cw310.yaml deleted file mode 100644 index 362758b8..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.sram_read.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_sram_read" - expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.sram_read.yaml b/fault_injection/configs/pen.global_fi.ibex.char.sram_read.yaml new file mode 100644 index 00000000..db8c7cc6 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.sram_read.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_sram_read" + expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.sram_static.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.sram_static.cw310.yaml deleted file mode 100644 index 21d5bc1d..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.sram_static.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_sram_static" - expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.sram_static.yaml b/fault_injection/configs/pen.global_fi.ibex.char.sram_static.yaml new file mode 100644 index 00000000..f1023f2c --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.sram_static.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_sram_static" + expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.sram_write.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.sram_write.cw310.yaml deleted file mode 100644 index dcf93c80..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.sram_write.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_sram_write" - expected_result: '{"memory":[464367618,2343432205,2779096485,2880154539,2881141438,2880293630,3131746989,3134333474,3148725999,3200171710,3203386062,3221229823,3405697037,3405709037,3435973836,3452816845,219540062,3735883980,3735928559,3735931646,3735929054,3735943697,3735941133,3741239533,3735936685,3490524077,3958107115,4208909997,4261281277,4276215469,4277009102,4277075694,464367618,2343432205,2779096485,2880154539,2881141438,2880293630,3131746989,3134333474,3148725999,3200171710,3203386062,3221229823,3405697037,3405709037,3435973836,3452816845,219540062,3735883980,3735928559,3735931646,3735929054,3735943697,3735941133,3741239533,3735936685,3490524077,3958107115,4208909997,4261281277,4276215469,4277009102,4277075694],"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.sram_write.yaml b/fault_injection/configs/pen.global_fi.ibex.char.sram_write.yaml new file mode 100644 index 00000000..01df248c --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.sram_write.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_sram_write" + expected_result: '{"memory":[464367618,2343432205,2779096485,2880154539,2881141438,2880293630,3131746989,3134333474,3148725999,3200171710,3203386062,3221229823,3405697037,3405709037,3435973836,3452816845,219540062,3735883980,3735928559,3735931646,3735929054,3735943697,3735941133,3741239533,3735936685,3490524077,3958107115,4208909997,4261281277,4276215469,4277009102,4277075694,464367618,2343432205,2779096485,2880154539,2881141438,2880293630,3131746989,3134333474,3148725999,3200171710,3203386062,3221229823,3405697037,3405709037,3435973836,3452816845,219540062,3735883980,3735928559,3735931646,3735929054,3735943697,3735941133,3741239533,3735936685,3490524077,3958107115,4208909997,4261281277,4276215469,4277009102,4277075694],"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.sram_write_read.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.sram_write_read.cw310.yaml deleted file mode 100644 index cb8a5c20..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.sram_write_read.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_sram_write_read" - expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.sram_write_read.yaml b/fault_injection/configs/pen.global_fi.ibex.char.sram_write_read.yaml new file mode 100644 index 00000000..bc86e29e --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.sram_write_read.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_sram_write_read" + expected_result: '{"err_status":0,"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false],"data":[0,0,0,0,0,0,0,0,0,0,0,0,0],"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.sram_write_static_unrolled.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.sram_write_static_unrolled.cw310.yaml deleted file mode 100644 index c5520fb4..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.sram_write_static_unrolled.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_sram_write_static_unrolled" - expected_result: '{"memory":[464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618],"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.sram_write_static_unrolled.yaml b/fault_injection/configs/pen.global_fi.ibex.char.sram_write_static_unrolled.yaml new file mode 100644 index 00000000..2151be5e --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.sram_write_static_unrolled.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_sram_write_static_unrolled" + expected_result: '{"memory":[464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618,464367618],"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch.cw310.yaml deleted file mode 100644 index 41ef5cb0..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_unconditional_branch" - expected_result: '{"result":30,"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch.yaml b/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch.yaml new file mode 100644 index 00000000..d9526f35 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_unconditional_branch" + expected_result: '{"result":30,"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch_nop.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch_nop.cw310.yaml deleted file mode 100644 index c1e3574c..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch_nop.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_unconditional_branch_nop" - expected_result: '{"result":0,"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch_nop.yaml b/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch_nop.yaml new file mode 100644 index 00000000..a9ded05b --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.unconditional_branch_nop.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_unconditional_branch_nop" + expected_result: '{"result":0,"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.unrolled_mem_op_loop.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.unrolled_mem_op_loop.cw310.yaml deleted file mode 100644 index 95565b8a..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.unrolled_mem_op_loop.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_unrolled_mem_op_loop" - expected_result: '{"result":10000,"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.unrolled_mem_op_loop.yaml b/fault_injection/configs/pen.global_fi.ibex.char.unrolled_mem_op_loop.yaml new file mode 100644 index 00000000..52ed7d6b --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.unrolled_mem_op_loop.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_unrolled_mem_op_loop" + expected_result: '{"result":10000,"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop.cw310.yaml deleted file mode 100644 index 2a7e5990..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_unrolled_reg_op_loop" - expected_result: '{"result":10000,"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop.yaml b/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop.yaml new file mode 100644 index 00000000..d68a7b33 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_unrolled_reg_op_loop" + expected_result: '{"result":10000,"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop_chain.cw310.yaml b/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop_chain.cw310.yaml deleted file mode 100644 index 1880e04f..00000000 --- a/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop_chain.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: True - fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "ibex_char_unrolled_reg_op_loop_chain" - expected_result: '{"result":[60,55,56,57,58,59,0,0,0,0,0,0],"err_status":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop_chain.yaml b/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop_chain.yaml new file mode 100644 index 00000000..f2cd5466 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.ibex.char.unrolled_reg_op_loop_chain.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: True + fw_bin: "../objs/fi_ibex_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "ibex_char_unrolled_reg_op_loop_chain" + expected_result: '{"result":[60,55,56,57,58,59,0,0,0,0,0,0],"err_status":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.beq.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.beq.cw310.yaml deleted file mode 100644 index 9c9fb7cb..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.beq.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_beq" - expected_result: '{"result":0,"insn_cnt":509,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.beq.yaml b/fault_injection/configs/pen.global_fi.otbn.char.beq.yaml new file mode 100644 index 00000000..88f0e4d9 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.beq.yaml @@ -0,0 +1,214 @@ +target: + target_type: chip + # fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "dummy" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_voltage_min: 150 + glitch_voltage_max: 150 + glitch_voltage_step: 10 + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_beq" + expected_result: '{"result":0,"insn_cnt":509,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.bn.rshi.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.bn.rshi.cw310.yaml deleted file mode 100644 index b642ec78..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.bn.rshi.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_bn_rshi" - expected_result: '{"big_num":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"insn_cnt":109,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - input: {"big_num": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]} - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.bn.rshi.yaml b/fault_injection/configs/pen.global_fi.otbn.char.bn.rshi.yaml new file mode 100644 index 00000000..ca5f59d4 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.bn.rshi.yaml @@ -0,0 +1,210 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_bn_rshi" + expected_result: '{"big_num":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"insn_cnt":109,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + input: {"big_num": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]} + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.bn.sel.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.bn.sel.cw310.yaml deleted file mode 100644 index 9ca168e5..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.bn.sel.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_bn_sel" - expected_result: '{"big_num":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"insn_cnt":1014,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - input: {"big_num": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]} - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.bn.sel.yaml b/fault_injection/configs/pen.global_fi.otbn.char.bn.sel.yaml new file mode 100644 index 00000000..a3f20ddc --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.bn.sel.yaml @@ -0,0 +1,210 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_bn_sel" + expected_result: '{"big_num":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"insn_cnt":1014,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + input: {"big_num": [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]} + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.bn.wsrr.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.bn.wsrr.cw310.yaml deleted file mode 100644 index 5178cada..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.bn.wsrr.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_bn_wsrr" - expected_result: '{"res":0,"insn_cnt":1089,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.bn.wsrr.yaml b/fault_injection/configs/pen.global_fi.otbn.char.bn.wsrr.yaml new file mode 100644 index 00000000..c538db80 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.bn.wsrr.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_bn_wsrr" + expected_result: '{"res":0,"insn_cnt":1089,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.dmem.access.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.dmem.access.cw310.yaml deleted file mode 100644 index b8596f31..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.dmem.access.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_dmem_access" - expected_result: '{"res":0,"insn_cnt":271,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.dmem.access.yaml b/fault_injection/configs/pen.global_fi.otbn.char.dmem.access.yaml new file mode 100644 index 00000000..177077af --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.dmem.access.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_dmem_access" + expected_result: '{"res":0,"insn_cnt":271,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.dmem.write.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.dmem.write.cw310.yaml deleted file mode 100644 index 637e0038..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.dmem.write.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_dmem_write" - expected_result: '{"result":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"insn_cnt":1,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.dmem.write.yaml b/fault_injection/configs/pen.global_fi.otbn.char.dmem.write.yaml new file mode 100644 index 00000000..1e42d7c5 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.dmem.write.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_dmem_write" + expected_result: '{"result":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"insn_cnt":1,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.hardware_dmem_op_loop.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.hardware_dmem_op_loop.cw310.yaml deleted file mode 100644 index 5815faed..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.hardware_dmem_op_loop.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_hardware_dmem_op_loop" - expected_result: '{"loop_counter":10000,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.hardware_dmem_op_loop.yaml b/fault_injection/configs/pen.global_fi.otbn.char.hardware_dmem_op_loop.yaml new file mode 100644 index 00000000..a66f6d31 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.hardware_dmem_op_loop.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_hardware_dmem_op_loop" + expected_result: '{"loop_counter":10000,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.hardware_reg_op_loop.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.hardware_reg_op_loop.cw310.yaml deleted file mode 100644 index d3a6b2da..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.hardware_reg_op_loop.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_hardware_reg_op_loop" - expected_result: '{"loop_counter":10000,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.hardware_reg_op_loop.yaml b/fault_injection/configs/pen.global_fi.otbn.char.hardware_reg_op_loop.yaml new file mode 100644 index 00000000..1707eceb --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.hardware_reg_op_loop.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_hardware_reg_op_loop" + expected_result: '{"loop_counter":10000,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.jal.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.jal.cw310.yaml deleted file mode 100644 index 1c025148..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.jal.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_jal" - expected_result: '{"result":0,"insn_cnt":505,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.jal.yaml b/fault_injection/configs/pen.global_fi.otbn.char.jal.yaml new file mode 100644 index 00000000..55c48ebc --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.jal.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_jal" + expected_result: '{"result":0,"insn_cnt":505,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.lw.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.lw.cw310.yaml deleted file mode 100644 index 31c1cc81..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.lw.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_lw" - expected_result: '{"result":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"insn_cnt":1084,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.lw.yaml b/fault_injection/configs/pen.global_fi.otbn.char.lw.yaml new file mode 100644 index 00000000..ef35529a --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.lw.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_lw" + expected_result: '{"result":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"insn_cnt":1084,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.mem.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.mem.cw310.yaml deleted file mode 100644 index db7f8085..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.mem.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_mem" - expected_result: '{"res":0,"imem_data":[0,0,0,0,0,0,0,0],"imem_addr":[0,0,0,0,0,0,0,0],"dmem_data":[0,0,0,0,0,0,0,0],"dmem_addr":[0,0,0,0,0,0,0,0],"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - config: {"byte_offset": 0, "num_words": 4, "imem": False, "dmem": True} - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.mem.yaml b/fault_injection/configs/pen.global_fi.otbn.char.mem.yaml new file mode 100644 index 00000000..3bb8c189 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.mem.yaml @@ -0,0 +1,210 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_mem" + expected_result: '{"res":0,"imem_data":[0,0,0,0,0,0,0,0],"imem_addr":[0,0,0,0,0,0,0,0],"dmem_data":[0,0,0,0,0,0,0,0],"dmem_addr":[0,0,0,0,0,0,0,0],"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + config: {"byte_offset": 0, "num_words": 4, "imem": False, "dmem": True} + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.rf.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.rf.cw310.yaml deleted file mode 100644 index 1d0e75ce..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.rf.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_rf" - expected_result: '{"res":0,"faulty_gpr":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"faulty_wdr":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.rf.yaml b/fault_injection/configs/pen.global_fi.otbn.char.rf.yaml new file mode 100644 index 00000000..52574e8e --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.rf.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_rf" + expected_result: '{"res":0,"faulty_gpr":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"faulty_wdr":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.unrolled_dmem_op_loop.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.unrolled_dmem_op_loop.cw310.yaml deleted file mode 100644 index be1b916b..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.unrolled_dmem_op_loop.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_unrolled_dmem_op_loop" - expected_result: '{"loop_counter":100,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.unrolled_dmem_op_loop.yaml b/fault_injection/configs/pen.global_fi.otbn.char.unrolled_dmem_op_loop.yaml new file mode 100644 index 00000000..fb0aa41a --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.unrolled_dmem_op_loop.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_unrolled_dmem_op_loop" + expected_result: '{"loop_counter":100,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.char.unrolled_reg_op_loop.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.char.unrolled_reg_op_loop.cw310.yaml deleted file mode 100644 index b3df1f4a..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.char.unrolled_reg_op_loop.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_char_unrolled_reg_op_loop" - expected_result: '{"loop_counter":100,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.char.unrolled_reg_op_loop.yaml b/fault_injection/configs/pen.global_fi.otbn.char.unrolled_reg_op_loop.yaml new file mode 100644 index 00000000..28173b95 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.char.unrolled_reg_op_loop.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_char_unrolled_reg_op_loop" + expected_result: '{"loop_counter":100,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.key_sideload.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.key_sideload.cw310.yaml deleted file mode 100644 index 30d52d03..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.key_sideload.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_key_sideload" - expected_result: '{"result":0,"err_status":0,"alerts":0}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.key_sideload.yaml b/fault_injection/configs/pen.global_fi.otbn.key_sideload.yaml new file mode 100644 index 00000000..08040862 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.key_sideload.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_key_sideload" + expected_result: '{"result":0,"err_status":0,"alerts":0}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.load_integrity.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.load_integrity.cw310.yaml deleted file mode 100644 index 47258274..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.load_integrity.cw310.yaml +++ /dev/null @@ -1,51 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_load_integrity" - expected_result: '{"result":0,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.load_integrity.yaml b/fault_injection/configs/pen.global_fi.otbn.load_integrity.yaml new file mode 100644 index 00000000..41f18861 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.load_integrity.yaml @@ -0,0 +1,209 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_load_integrity" + expected_result: '{"result":0,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otbn.pc.cw310.yaml b/fault_injection/configs/pen.global_fi.otbn.pc.cw310.yaml deleted file mode 100644 index f007d90f..00000000 --- a/fault_injection/configs/pen.global_fi.otbn.pc.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM1" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 10000 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 100 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "otbn_pc" - expected_result: '{"pc_dmem":2224,"pc_otbn":2224,"insn_cnt":472,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' - input: {"pc": 0x8b0} - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.otbn.pc.yaml b/fault_injection/configs/pen.global_fi.otbn.pc.yaml new file mode 100644 index 00000000..2de6cb3c --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otbn.pc.yaml @@ -0,0 +1,210 @@ +target: + target_type: cw310 + fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_otbn_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + fi_gear: "husky" + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 10000 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 100 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "otbn_pc" + expected_result: '{"pc_dmem":2224,"pc_otbn":2224,"insn_cnt":472,"err_otbn":0,"err_ibx":0,"ast_alerts":[0,0]}' + input: {"pc": 0x8b0} + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.otp_ctrl.data_read.cw310.yaml b/fault_injection/configs/pen.global_fi.otp_ctrl.data_read.cw310.yaml deleted file mode 100644 index 31157403..00000000 --- a/fault_injection/configs/pen.global_fi.otp_ctrl.data_read.cw310.yaml +++ /dev/null @@ -1,50 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/sca_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM2" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 1 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - # Possible tests: "otp_fi_vendor_test", "otp_fi_owner_sw_cfg", "otp_fi_hw_cfg", "otp_fi_life_cycle" - # These tests determine the OTP partition which is checked for a successful fault injection - which_test: "otp_fi_vendor_test" - # expected_result isn't actually required for this test, because FI success is determined - # by compairing otp memory content before and after FI - # otp_status_code = 32768 (= 1 << 15) means otp controller is idle and no error occured - # expected_result: '{"otp_status_codes":32768,"otp_error_causes":[0,0,0,0,0,0,0,0,0,0],"ibex_err_status":0,"alerts":0}' - expected_result: '{"ibex_err_status":0,"alerts":0}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True diff --git a/fault_injection/configs/pen.global_fi.otp_ctrl.data_read.yaml b/fault_injection/configs/pen.global_fi.otp_ctrl.data_read.yaml new file mode 100644 index 00000000..72a83ca6 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.otp_ctrl.data_read.yaml @@ -0,0 +1,216 @@ +target: + target_type: chip + #fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/sca_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "dummy" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + # Voltage glitch width in cycles. + glitch_voltage_min: 150 + glitch_voltage_max: 150 + glitch_voltage_step: 10 + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + # Possible tests: "otp_fi_vendor_test", "otp_fi_owner_sw_cfg", "otp_fi_hw_cfg", "otp_fi_life_cycle" + # These tests determine the OTP partition which is checked for a successful fault injection + which_test: "otp_fi_vendor_test" + expected_result: '{"data_faulty":[false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false],"otp_error_causes":[0,0,0,0,0,0,0,0,0,0],"otp_status_codes":0,"alerts":[0,0,0],"ast_alerts":[0,0]}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.rng.csrng.cw310.yaml b/fault_injection/configs/pen.global_fi.rng.csrng.cw310.yaml deleted file mode 100644 index 564ad0c6..00000000 --- a/fault_injection/configs/pen.global_fi.rng.csrng.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "rng_csrng_bias" - expected_result: '{"res":0,"rand":[932170270,3480632584,387346064,186012424,899661374,2795183089,336687633,3222931513,1490543709,3319795384,3464147855,1850271046,1239323641,2292604615,3314177342,1567494162],"alerts":[0,0,0],"err_status":0}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.rng.csrng.yaml b/fault_injection/configs/pen.global_fi.rng.csrng.yaml new file mode 100644 index 00000000..a0b7982e --- /dev/null +++ b/fault_injection/configs/pen.global_fi.rng.csrng.yaml @@ -0,0 +1,216 @@ +target: + target_type: chip + #fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "dummy" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + glitch_voltage_min: 150 + glitch_voltage_max: 150 + glitch_voltage_step: 10 + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "rng_csrng_bias" + # 0 = start_trigger, 1 = valid_trigger, 2 = read_trigger, 3 = all_trigger + trigger: 0 + expected_result: '{"res":0,"rand":[932170270,3480632584,387346064,186012424,899661374,2795183089,336687633,3222931513,1490543709,3319795384,3464147855,1850271046,1239323641,2292604615,3314177342,1567494162],"alerts":[0,0,0],"err_status":0}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } diff --git a/fault_injection/configs/pen.global_fi.rng.edn.cw310.yaml b/fault_injection/configs/pen.global_fi.rng.edn.cw310.yaml deleted file mode 100644 index 28fd3444..00000000 --- a/fault_injection/configs/pen.global_fi.rng.edn.cw310.yaml +++ /dev/null @@ -1,52 +0,0 @@ -target: - target_type: cw310 - fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" - force_program_bitstream: False - fw_bin: "../objs/fi_ujson_fpga_cw310.bin" - output_len_bytes: 16 - target_clk_mult: 0.24 - target_freq: 24000000 - baudrate: 115200 - protocol: "ujson" - port: "/dev/ttyACM4" -fisetup: - fi_gear: "husky" - fi_type: "voltage_glitch" - parameter_generation: "random" - # Voltage glitch width in cycles. - glitch_width_min: 5 - glitch_width_max: 150 - glitch_width_step: 3 - # Range for trigger delay in cycles. - trigger_delay_min: 0 - trigger_delay_max: 500 - trigger_step: 10 - # Number of iterations for the parameter sweep. - num_iterations: 100 -fiproject: - # Project database type and memory threshold. - project_db: "ot_fi_project" - project_mem_threshold: 10000 - # Store FI plot. - show_plot: True - num_plots: 10 - plot_x_axis: "trigger_delay" - plot_x_axis_legend: "[cycles]" - plot_y_axis: "glitch_width" - plot_y_axis_legend: "[cycles]" -test: - which_test: "rng_edn_resp_ack" - expected_result: '{"collisions":0,"rand":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"alerts":[0,0,0],"err_status":0}' - # Set to true if the test should ignore alerts returned by the test. As the - # alert handler on the device could sometime fire alerts that are not - # related to the FI, ignoring is by default set to true. A manual analysis - # still can be performed as the alerts are stored in the database. - ignore_alerts: True - # When True, the instruction cache is enabled. - enable_icache: False - # When True, the dummy instructions are enabled. - enable_dummy_instr: False - # When True, enable the jittery clock. - enable_jittery_clock: False - # When True, enable the SRAM readback feature. - sram_readback_enable: False diff --git a/fault_injection/configs/pen.global_fi.rng.edn.yaml b/fault_injection/configs/pen.global_fi.rng.edn.yaml new file mode 100644 index 00000000..5c0bf412 --- /dev/null +++ b/fault_injection/configs/pen.global_fi.rng.edn.yaml @@ -0,0 +1,214 @@ +target: + target_type: chip + #fpga_bitstream: "../objs/lowrisc_systems_chip_earlgrey_cw310_0.1.bit" + force_program_bitstream: False + fw_bin: "../objs/fi_ujson_fpga_cw310.bin" + opentitantool: "../objs/opentitantool" + # You can specify the port or leave it empty to find it automatically. + target_clk_mult: 0.24 + target_freq: 24000000 + baudrate: 115200 +fisetup: + # dummy, husky, chipshouter + fi_gear: "dummy" + # voltage_glitch, clock_glitch, lfi, emfi + fi_type: "voltage_glitch" + parameter_generation: "random" + glitch_voltage_min: 150 + glitch_voltage_max: 150 + glitch_voltage_step: 10 + # Voltage glitch width in cycles. + glitch_width_min: 5 + glitch_width_max: 150 + glitch_width_step: 3 + # Range for trigger delay in cycles. + trigger_delay_min: 0 + trigger_delay_max: 500 + trigger_step: 10 + # Number of iterations for the parameter sweep. + num_iterations: 100 +fiproject: + # Project database type and memory threshold. + project_db: "ot_fi_project" + project_mem_threshold: 10000 + # Store FI plot. + show_plot: True + num_plots: 10 + plot_x_axis: "trigger_delay" + plot_x_axis_legend: "[cycles]" + plot_y_axis: "glitch_width" + plot_y_axis_legend: "[cycles]" +test: + which_test: "rng_edn_resp_ack" + expected_result: '{"collisions":0,"rand":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"alerts":[0,0,0],"err_status":0}' + # Set to true if the test should ignore alerts returned by the test. As the + # alert handler on the device could sometime fire alerts that are not + # related to the FI, ignoring is by default set to true. A manual analysis + # still can be performed as the alerts are stored in the database. + ignore_alerts: True + core_config: { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, + } + sensor_config: { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], + } + alert_config: { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + # On FPGA, changing the flash alerts causes an alert itself + False, # "flash_ctrl_recov_err", + False, # "flash_ctrl_fatal_std_err", + False, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + False, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, + } From a5e1b3d5d888e82de008d6cb3c5e78e996a013de Mon Sep 17 00:00:00 2001 From: Siemen Dhooghe Date: Sat, 30 Aug 2025 11:22:16 +0200 Subject: [PATCH 3/3] [update] Update ot-sca to opentitan v1.0.3 Integrate the capture and fault injection scripts to the latest pentest framework v1.0.3. This also deprecates the CW305 board and removes the output_len and input_len values in the cfg. Signed-off-by: Siemen Dhooghe Co-authored-by: Pascal Nasahl --- .github/workflows/fpga.yml | 49 - analysis/ceca.py | 73 +- analysis/tvla.py | 942 ++++--- capture/README.md | 5 +- capture/capture_aes.py | 563 +++-- capture/capture_hmac.py | 551 +++-- capture/capture_ibex.py | 528 ++-- capture/capture_kmac.py | 578 ++--- capture/capture_otbn.py | 579 +++-- capture/capture_sha3.py | 547 ++-- .../ot_trace_library/trace_library.py | 109 +- capture/project_library/project.py | 68 +- capture/scopes/chipwhisperer/cw_segmented.py | 13 +- capture/scopes/chipwhisperer/husky.py | 59 +- capture/scopes/scope.py | 88 +- capture/scopes/waverunner/test_waverunner.py | 2 +- capture/scopes/waverunner/waverunner.py | 86 +- ci/ci_trace_check/ci_compare_aes_traces.py | 44 +- cw/capture.py | 2189 ++++++++++++----- cw/mix_columns_cpa_attack.py | 29 +- cw/save_waverunner_config_to_file.py | 2 +- cw/test_capture.sh | 6 +- doc/ci.md | 10 +- doc/getting_started.md | 81 +- fault_injection/fi_crypto.py | 269 +- .../fi_gear/chipshouter/chipshouter.py | 170 +- fault_injection/fi_gear/dummy/dummy_clk.py | 44 +- fault_injection/fi_gear/dummy/dummy_emfi.py | 100 +- fault_injection/fi_gear/dummy/dummy_lfi.py | 100 +- fault_injection/fi_gear/dummy/dummy_vcc.py | 59 +- fault_injection/fi_gear/fi_gear.py | 185 +- fault_injection/fi_gear/husky/husky_vcc.py | 62 +- fault_injection/fi_gear/utility.py | 3 +- fault_injection/fi_ibex.py | 152 +- fault_injection/fi_otbn.py | 152 +- fault_injection/fi_otp.py | 160 +- fault_injection/fi_rng.py | 159 +- fault_injection/project_library/project.py | 67 +- python-requirements.txt | 7 +- target/chip.py | 120 +- target/communication/common_library.py | 311 +++ target/communication/fi_alert_commands.py | 89 + target/communication/fi_crypto_commands.py | 341 +-- target/communication/fi_ibex_commands.py | 331 ++- target/communication/fi_otbn_commands.py | 171 +- target/communication/fi_otp_commands.py | 74 +- target/communication/fi_rng_commands.py | 157 +- target/communication/fi_rom_commands.py | 74 + target/communication/sca_aes_commands.py | 364 +-- target/communication/sca_hmac_commands.py | 277 ++- target/communication/sca_ibex_commands.py | 242 +- target/communication/sca_kmac_commands.py | 244 +- target/communication/sca_otbn_commands.py | 334 +-- target/communication/sca_prng_commands.py | 30 +- target/communication/sca_sha3_commands.py | 275 +-- target/communication/sca_trigger_commands.py | 32 +- target/cw_fpga.py | 93 +- target/targets.py | 238 +- test/cmd.py | 20 +- test/repo.py | 2 +- test/tvla_test.py | 159 +- util/check_version.py | 16 +- util/cw_to_trs.py | 82 +- util/db_to_zarr_converter.py | 85 +- util/helpers.py | 72 +- util/histograms.py | 45 +- util/leakage_models.py | 37 +- util/plot.py | 73 +- util/spiflash.py | 120 +- util/trace_util.py | 23 +- util/ttest.py | 15 +- util/update_husky_fw.py | 18 +- 72 files changed, 7990 insertions(+), 5464 deletions(-) create mode 100644 target/communication/common_library.py create mode 100644 target/communication/fi_alert_commands.py create mode 100644 target/communication/fi_rom_commands.py diff --git a/.github/workflows/fpga.yml b/.github/workflows/fpga.yml index b5120f7d..8c7dc11f 100644 --- a/.github/workflows/fpga.yml +++ b/.github/workflows/fpga.yml @@ -99,55 +99,6 @@ jobs: name: traces_sha3_random_cw310_ujson path: ./ci/projects/sha3_sca_random_cw310_ujson.html - sca_capture_cw305: - name: Capture AES SCA traces (CW305) - runs-on: [ubuntu-22.04-fpga, cw305] - timeout-minutes: 30 - - steps: - - uses: actions/checkout@v4 - with: - lfs: true - - - name: Install python dependencies - run: | - python3 -m pip install --user -r python-requirements.txt - mkdir -p ci/projects - - - name: Capture AES FVSR traces - working-directory: ci - run: | - ../capture/capture_aes.py -c cfg/ci_aes_sca_fvsr_cw305.yaml -p projects/aes_sca_fvsr_cw305 - - - name: Upload AES FVSR traces - uses: actions/upload-artifact@v4 - with: - name: traces_aes_fvsr_key_cw305 - path: ./ci/projects/aes_sca_fvsr_cw305.html - - - name: Capture AES Random traces - working-directory: ci - run: | - ../capture/capture_aes.py -c cfg/ci_aes_sca_random_cw305.yaml -p projects/aes_sca_random_cw305 - - - name: Upload AES Random traces - uses: actions/upload-artifact@v4 - with: - name: traces_aes_random_cw305 - path: ./ci/projects/aes_sca_random_cw305.html - - - name: Perform specific TVLA on AES Random traces - working-directory: ci - run: | - ../analysis/tvla.py --cfg-file cfg/ci_tvla_cfg_aes_specific_byte_0_15_rnd_0_1.yaml run-tvla - continue-on-error: true - - - name: Upload figures of specific TVLA for AES. - uses: actions/upload-artifact@v4 - with: - name: tvla_figures_aes_specific - path: ./ci/tmp/figures - kmac_sca_capture_cw310: name: Capture KMAC SCA traces (CW310) runs-on: [ubuntu-22.04-fpga, cw310] diff --git a/analysis/ceca.py b/analysis/ceca.py index bbd22918..02b2a84d 100755 --- a/analysis/ceca.py +++ b/analysis/ceca.py @@ -21,7 +21,7 @@ # Append ot-sca root directory to path such that ceca.py can find the # project_library module located in the capture/ directory. ABS_PATH = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(ABS_PATH + '/..') +sys.path.append(ABS_PATH + "/..") from capture.project_library.project import ProjectConfig # noqa : E402 from capture.project_library.project import SCAProject # noqa : E402 @@ -91,28 +91,29 @@ def __init__(self, project_file, trace_slice, attack_window, attack_direction): # ChipWhisperer or ot_trace_library project? project_type = "cw" if ".db" in project_file: - project_type = 'ot_trace_library' + project_type = "ot_trace_library" # Open the project. - project_cfg = ProjectConfig(type = project_type, - path = project_file, - wave_dtype = np.uint16, - overwrite = False - ) + project_cfg = ProjectConfig( + type=project_type, path=project_file, wave_dtype=np.uint16, overwrite=False + ) self.project = SCAProject(project_cfg) self.project.open_project() # TODO: Consider more efficient formats. self.num_samples = attack_window.stop - attack_window.start if attack_direction == AttackDirection.INPUT: - self.texts = np.vstack(self.project.get_plaintexts( - trace_slice.start, trace_slice.stop)) + self.texts = np.vstack( + self.project.get_plaintexts(trace_slice.start, trace_slice.stop) + ) else: - self.texts = np.vstack(self.project.get_ciphertexts( - trace_slice.start, trace_slice.stop)) + self.texts = np.vstack( + self.project.get_ciphertexts(trace_slice.start, trace_slice.stop) + ) - self.traces = np.asarray(self.project.get_waves( - trace_slice.start, trace_slice.stop))[:, attack_window] + self.traces = np.asarray( + self.project.get_waves(trace_slice.start, trace_slice.stop) + )[:, attack_window] self.project.close(save=False) @@ -176,7 +177,7 @@ def count_and_sum_text_traces(self): val_changes = np.where(np.roll(sorted_bytes, 1) != sorted_bytes)[0] # Append the number of rows to be able to use ``pairwise``. val_indices = list(val_changes) + [sorted_bytes.shape[0]] - for (start, end) in more_itertools.pairwise(val_indices): + for start, end in more_itertools.pairwise(val_indices): byte_val = sorted_bytes[start] cnts[byte_pos, byte_val] = end - start act_indices = sorted_indices[start:end] @@ -396,7 +397,7 @@ def find_best_diffs(pairwise_diffs_scores): # other bytes. diffs = np.zeros(16, dtype=np.uint8) for byte in range(1, 16): - for (a, b) in more_itertools.pairwise(paths[byte]): + for a, b in more_itertools.pairwise(paths[byte]): diffs[byte] ^= int(pairwise_diffs_scores[a, b, 0]) return diffs @@ -502,14 +503,12 @@ def perform_attack( # ChipWhisperer or ot_trace_library project? project_type = "cw" if ".db" in project_file: - project_type = 'ot_trace_library' + project_type = "ot_trace_library" # Open the project. - project_cfg = ProjectConfig(type = project_type, - path = project_file, - wave_dtype = np.uint16, - overwrite = False - ) + project_cfg = ProjectConfig( + type=project_type, path=project_file, wave_dtype=np.uint16, overwrite=False + ) project = SCAProject(project_cfg) project.open_project() @@ -559,7 +558,7 @@ def worker_trace_slices(): num_traces = filter_noisy_traces(workers, mean, std_dev, max_std) logging.info( f"Will use {num_traces} traces " - f"({100*num_traces/orig_num_traces:.1f}% of all traces)" + f"({100 * num_traces / orig_num_traces:.1f}% of all traces)" ) # Mean traces for all values of all text bytes. mean_text_traces = compute_mean_text_traces(workers) @@ -568,18 +567,21 @@ def worker_trace_slices(): diffs = find_best_diffs(pairwise_diffs_scores) logging.info(f"Difference values (delta_0_i): {diffs}") # Recover the key. - key = recover_key(diffs, attack_direction, project.get_plaintexts(0), - project.get_ciphertexts(0)) + key = recover_key( + diffs, attack_direction, project.get_plaintexts(0), project.get_ciphertexts(0) + ) if key is not None: logging.info(f"Recovered AES key: {bytes(key).hex()}") else: logging.error("Failed to recover the AES key") # Compare differences - both matrices are symmetric and have an all-zero main diagonal. - correct_diffs = compare_diffs(pairwise_diffs_scores, attack_direction, - project.get_keys(0)) + correct_diffs = compare_diffs( + pairwise_diffs_scores, attack_direction, project.get_keys(0) + ) logging.info( - f"Recovered {((np.sum(correct_diffs)-16)/2).astype(int)}/120 " - "differences between key bytes") + f"Recovered {((np.sum(correct_diffs) - 16) / 2).astype(int)}/120 " + "differences between key bytes" + ) project.close(save=False) return key @@ -592,8 +594,10 @@ def parse_args(): Mischke, and T. Eisenbarth (https://eprint.iacr.org/2010/297.pdf).""" ) parser.add_argument( - "-f", "--project-file", required=True, - help="chipwhisperer or ot_trace_library project file" + "-f", + "--project-file", + required=True, + help="chipwhisperer or ot_trace_library project file", ) parser.add_argument( "-n", @@ -658,9 +662,12 @@ def main(): attack.""" args = parse_args() config_logger() - ray.init(runtime_env={"working_dir": "../", - "excludes": ["*.db", "*.cwp", "*.npy", "*.bit", - "*/lfs/*", "*.pack"]}) + ray.init( + runtime_env={ + "working_dir": "../", + "excludes": ["*.db", "*.cwp", "*.npy", "*.bit", "*/lfs/*", "*.pack"], + } + ) key = perform_attack(**vars(args)) sys.exit(0 if key is not None else 1) diff --git a/analysis/tvla.py b/analysis/tvla.py index 147fd7a8..6d7c8364 100755 --- a/analysis/tvla.py +++ b/analysis/tvla.py @@ -19,18 +19,18 @@ from joblib import Parallel, delayed ABS_PATH = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(ABS_PATH + '/..') -import util.plot as plot # noqa : E402 -from capture.project_library.project import ProjectConfig # noqa : E402 -from capture.project_library.project import SCAProject # noqa : E402 -from util.histograms import compute_histograms_aes_bit # noqa : E402 -from util.histograms import compute_histograms_aes_byte # noqa : E402 -from util.histograms import compute_histograms_general # noqa : E402 -from util.leakage_models import compute_leakage_aes_bit # noqa : E402 -from util.leakage_models import compute_leakage_aes_byte # noqa : E402 -from util.leakage_models import compute_leakage_general # noqa : E402 -from util.leakage_models import find_fixed_entry # noqa : E402 -from util.ttest import ttest_hist_xy # noqa : E402 +sys.path.append(ABS_PATH + "/..") +import util.plot as plot # noqa: E402 +from capture.project_library.project import ProjectConfig # noqa: E402 +from capture.project_library.project import SCAProject # noqa: E402 +from util.histograms import compute_histograms_aes_bit # noqa: E402 +from util.histograms import compute_histograms_aes_byte # noqa: E402 +from util.histograms import compute_histograms_general # noqa: E402 +from util.leakage_models import compute_leakage_aes_bit # noqa: E402 +from util.leakage_models import compute_leakage_aes_byte # noqa: E402 +from util.leakage_models import compute_leakage_general # noqa: E402 +from util.leakage_models import find_fixed_entry # noqa: E402 +from util.ttest import ttest_hist_xy # noqa: E402 app = typer.Typer(add_completion=False) @@ -74,20 +74,32 @@ def plot_fvsr_stats(traces, leakage): diff_var = np.zeros((1, num_samples)) np.subtract(var_fixed, var_random, diff_var) - plot.save_plot_to_file(np.stack((avg_fixed, avg_random), axis=0), np.array((1, 0)), 2, - "tmp/avg_fixed_random_traces.html") - plot.save_plot_to_file(diff_avg, None, 1, - "tmp/diff_avg_trace.html") - plot.save_plot_to_file(np.stack((var_fixed, var_random), axis=0), np.array((1, 0)), 2, - "tmp/var_fixed_random_traces.html") - plot.save_plot_to_file(diff_var, None, 1, - "tmp/diff_var_trace.html") - - -def compute_statistics(test_type, num_orders, histograms, x_axis, - rnd_list = None, byte_list = None, bit_list = None): - """ Computing t-test statistics for a set of time samples. - """ + plot.save_plot_to_file( + np.stack((avg_fixed, avg_random), axis=0), + np.array((1, 0)), + 2, + "tmp/avg_fixed_random_traces.html", + ) + plot.save_plot_to_file(diff_avg, None, 1, "tmp/diff_avg_trace.html") + plot.save_plot_to_file( + np.stack((var_fixed, var_random), axis=0), + np.array((1, 0)), + 2, + "tmp/var_fixed_random_traces.html", + ) + plot.save_plot_to_file(diff_var, None, 1, "tmp/diff_var_trace.html") + + +def compute_statistics( + test_type, + num_orders, + histograms, + x_axis, + rnd_list=None, + byte_list=None, + bit_list=None, +): + """Computing t-test statistics for a set of time samples.""" if test_type in {"GENERAL_KEY", "GENERAL_DATA"}: num_rnds = 1 num_data = 1 @@ -133,11 +145,19 @@ def compute_statistics(test_type, num_orders, histograms, x_axis, return ttest_trace -def tvla_plotting_fnc(axs, num_orders, i_rnd, i_byte, ttest_trace, - single_trace, threshold, num_samples, sample_start, - metadata): - """Plotting trace in different colors, depending on where the trigger is high - """ +def tvla_plotting_fnc( + axs, + num_orders, + i_rnd, + i_byte, + ttest_trace, + single_trace, + threshold, + num_samples, + sample_start, + metadata, +): + """Plotting trace in different colors, depending on where the trigger is high""" c = np.ones(num_samples) xaxs = range(sample_start, sample_start + num_samples) # Catch case where offset data isn't saved to project file (e.g. older measurement) @@ -160,38 +180,46 @@ def tvla_plotting_fnc(axs, num_orders, i_rnd, i_byte, ttest_trace, trigger_low = num_samples axs[0].set_ylabel("trace") if trigger_high > 0: - axs[0].plot(xaxs[:trigger_high], - single_trace[:trigger_high], - "grey", - label='trigger low') + axs[0].plot( + xaxs[:trigger_high], + single_trace[:trigger_high], + "grey", + label="trigger low", + ) if trigger_low > trigger_high: - axs[0].plot(xaxs[trigger_high:trigger_low], - single_trace[trigger_high:trigger_low], - "k", - label='trigger high') + axs[0].plot( + xaxs[trigger_high:trigger_low], + single_trace[trigger_high:trigger_low], + "k", + label="trigger high", + ) if trigger_low < num_samples: - axs[0].plot(xaxs[trigger_low:], - single_trace[trigger_low:], - "grey", - label='trigger low') - axs[0].legend(loc='upper right', prop={'size': 7}) + axs[0].plot( + xaxs[trigger_low:], single_trace[trigger_low:], "grey", label="trigger low" + ) + axs[0].legend(loc="upper right", prop={"size": 7}) for i_order in range(num_orders): - axs[1 + i_order].set_ylabel('t-test ' + str(i_order + 1)) + axs[1 + i_order].set_ylabel("t-test " + str(i_order + 1)) axs[1 + i_order].plot(xaxs, c * threshold, "r") axs[1 + i_order].plot(xaxs, -threshold * c, "r") if trigger_high > 0: axs[1 + i_order].plot( xaxs[:trigger_high], - ttest_trace[i_order, i_rnd, i_byte][:trigger_high], "grey") + ttest_trace[i_order, i_rnd, i_byte][:trigger_high], + "grey", + ) if trigger_low > trigger_high: axs[1 + i_order].plot( xaxs[trigger_high:trigger_low], - ttest_trace[i_order, i_rnd, - i_byte][trigger_high:trigger_low], "k") + ttest_trace[i_order, i_rnd, i_byte][trigger_high:trigger_low], + "k", + ) if trigger_low < num_samples: axs[1 + i_order].plot( - xaxs[trigger_low:], ttest_trace[i_order, i_rnd, - i_byte][trigger_low:], "grey") + xaxs[trigger_low:], + ttest_trace[i_order, i_rnd, i_byte][trigger_low:], + "grey", + ) return axs @@ -209,28 +237,34 @@ def run_tvla(ctx: typer.Context): Path("tmp").mkdir(exist_ok=True) log_format = "%(asctime)s %(levelname)s: %(message)s" - log.basicConfig(format=log_format, - datefmt="%Y-%m-%d %I:%M:%S", - handlers=[ - log.FileHandler("tmp/log.txt"), - log.StreamHandler() - ], - level=log.INFO, - force=True,) - - if (cfg["mode"] != "kmac" and cfg["mode"] != "aes" and cfg["mode"] != "sha3" and - cfg["mode"] != "otbn"): - log.info("Unsupported mode:" + cfg["mode"] + ", falling back to \"aes\"") + log.basicConfig( + format=log_format, + datefmt="%Y-%m-%d %I:%M:%S", + handlers=[log.FileHandler("tmp/log.txt"), log.StreamHandler()], + level=log.INFO, + force=True, + ) + + if ( + cfg["mode"] != "kmac" and cfg["mode"] != "aes" and + cfg["mode"] != "sha3" and cfg["mode"] != "otbn" + ): + log.info("Unsupported mode:" + cfg["mode"] + ', falling back to "aes"') # Currently, specific TVLA exists only for AES. # Other modes can be tested only using general TVLA. if cfg["mode"] in {"kmac", "otbn", "sha3"}: - assert cfg["test_type"] != "SPECIFIC_BYTE", "Specific test not supported for this mode." - assert cfg["test_type"] != "SPECIFIC_BIT", "Specific test not supported for this mode." + assert ( + cfg["test_type"] != "SPECIFIC_BYTE" + ), "Specific test not supported for this mode." + assert ( + cfg["test_type"] != "SPECIFIC_BIT" + ), "Specific test not supported for this mode." if cfg["mode"] == "sha3": - assert cfg["test_type"] == "GENERAL_DATA", \ - "SHA3 can only be tested using GENERAL_DATA test type" + assert ( + cfg["test_type"] == "GENERAL_DATA" + ), "SHA3 can only be tested using GENERAL_DATA test type" if cfg["test_type"] == "GENERAL_DATA": general_test_key = False @@ -304,7 +338,7 @@ def run_tvla(ctx: typer.Context): if cfg["mode"] == "otbn": if "key_len_bytes" not in cfg: - raise RuntimeError('key_len_bytes must be set for otbn mode!') + raise RuntimeError("key_len_bytes must be set for otbn mode!") else: key_len_bytes = cfg["key_len_bytes"] @@ -328,15 +362,15 @@ def run_tvla(ctx: typer.Context): if cfg["input_histogram_file"] is not None: # Load previously generated histograms. histograms_file = np.load(cfg["input_histogram_file"]) - histograms_in = histograms_file['histograms'] - single_trace = histograms_file['single_trace'] + histograms_in = histograms_file["histograms"] + single_trace = histograms_file["single_trace"] num_samples = histograms_in.shape[3] trace_resolution = histograms_in.shape[4] # If previously generated histograms are loaded, the rounds and bytes of interest must # match. Otherwise, indices would get mixed up. - assert np.all(rnd_list == histograms_file['rnd_list']) + assert np.all(rnd_list == histograms_file["rnd_list"]) if specific_test_byte: - assert np.all(byte_list == histograms_file['byte_list']) + assert np.all(byte_list == histograms_file["byte_list"]) # Computing the t-test statistics vs. time. log.info("Computing T-test Statistics") @@ -351,14 +385,22 @@ def run_tvla(ctx: typer.Context): # Compute statistics. # ttest_trace has dimensions [num_orders, num_rnds, num_data, num_samples]. ttest_trace = Parallel(n_jobs=num_jobs)( - delayed(compute_statistics)(cfg["test_type"], num_orders, - histograms_in[:, :, :, i:i + sample_step_ttest, :], - x_axis, rnd_list, byte_list, bit_list) - for i in range(0, num_samples, sample_step_ttest)) + delayed(compute_statistics)( + cfg["test_type"], + num_orders, + histograms_in[:, :, :, i: i + sample_step_ttest, :], + x_axis, + rnd_list, + byte_list, + bit_list, + ) + for i in range(0, num_samples, sample_step_ttest) + ) ttest_trace = np.concatenate((ttest_trace[:]), axis=3) - if (cfg["input_histogram_file"] is None or cfg["output_histogram_file"] is not None) \ - and cfg["ttest_step_file"] is None: + if ( + cfg["input_histogram_file"] is None or cfg["output_histogram_file"] is not None + ) and cfg["ttest_step_file"] is None: # Either don't have previously generated histograms or we need to append previously # generated histograms. # Make sure the project file is compatible with the previously generated histograms. @@ -366,12 +408,13 @@ def run_tvla(ctx: typer.Context): if not project_type: project_type = "cw" - project_cfg = ProjectConfig(type = project_type, - path = cfg["project_file"], - wave_dtype = np.uint16, - overwrite = False, - trace_threshold = cfg.get("trace_threshold") - ) + project_cfg = ProjectConfig( + type=project_type, + path=cfg["project_file"], + wave_dtype=np.uint16, + overwrite=False, + trace_threshold=cfg.get("trace_threshold"), + ) project = SCAProject(project_cfg) project.open_project() metadata = project.get_metadata() @@ -390,24 +433,28 @@ def run_tvla(ctx: typer.Context): # Slice of wave file # these options are only tested for otbn - if ("sample_start" in cfg and cfg["sample_start"] is not None): + if "sample_start" in cfg and cfg["sample_start"] is not None: sample_start = cfg["sample_start"] else: sample_start = 0 assert sample_start < len(project.get_waves(0)) - if ("num_samples" in cfg and cfg["num_samples"] is not None): + if "num_samples" in cfg and cfg["num_samples"] is not None: num_samples = cfg["num_samples"] else: num_samples = len(project.get_waves(0)) - sample_start - if (num_samples + sample_start > len(project.get_waves(0))): - log.warning(f"Selected sample window {sample_start} to " + - f"{sample_start+num_samples} is out of range!") + if num_samples + sample_start > len(project.get_waves(0)): + log.warning( + f"Selected sample window {sample_start} to " + + f"{sample_start + num_samples} is out of range!" + ) num_samples = len(project.get_waves(0)) - sample_start - log.warning(f"Will use samples from {sample_start} " + - f"to {sample_start+num_samples} instead!") + log.warning( + f"Will use samples from {sample_start} " + + f"to {sample_start + num_samples} instead!" + ) # Overall number of traces, trace start and end indices. num_traces_max = metadata.get("num_traces") @@ -439,10 +486,14 @@ def run_tvla(ctx: typer.Context): trace_start_vec.append(trace_start_tot + i_step * num_traces_step) if i_step < num_steps - 1 or num_traces_rem == 0: num_traces_vec.append(num_traces_step) - trace_end_vec.append(trace_start_vec[i_step] + num_traces_vec[i_step] - 1) + trace_end_vec.append( + trace_start_vec[i_step] + num_traces_vec[i_step] - 1 + ) else: num_traces_vec.append(num_traces_step + num_traces_rem) - trace_end_vec.append(trace_start_vec[i_step] + num_traces_vec[i_step] - 1) + trace_end_vec.append( + trace_start_vec[i_step] + num_traces_vec[i_step] - 1 + ) # The number of parallel jobs to use for the processing-heavy tasks. num_jobs = multiprocessing.cpu_count() @@ -465,8 +516,13 @@ def run_tvla(ctx: typer.Context): trace_start = trace_start_vec[i_step] trace_end = trace_end_vec[i_step] - log.info("Processing Step %i/%i: Trace %i - %i", - i_step + 1, num_steps, trace_start, trace_end) + log.info( + "Processing Step %i/%i: Trace %i - %i", + i_step + 1, + num_steps, + trace_start, + trace_end, + ) if cfg["trace_file"] is None: # Make sure to re-open the CW project file as we close it during @@ -479,18 +535,20 @@ def run_tvla(ctx: typer.Context): # Converting traces from floating point to integer and creating a dense copy. log.info("Converting Traces") - if proj_waves[0].dtype == 'uint16': + if proj_waves[0].dtype == "uint16": traces = np.empty((num_traces, num_samples), dtype=np.uint16) - log.info(f"Will use samples from {sample_start} to {sample_start+num_samples}") + log.info( + f"Will use samples from {sample_start} to {sample_start + num_samples}" + ) for i_trace in range(num_traces): - traces[i_trace] = proj_waves[i_trace][sample_start: - sample_start + - num_samples] + traces[i_trace] = proj_waves[i_trace][ + sample_start: sample_start + num_samples + ] else: traces = np.empty((num_traces, num_samples), dtype=np.double) for i_trace in range(num_traces): traces[i_trace] = (proj_waves[i_trace] + 0.5) * trace_resolution - traces = traces.astype('uint16') + traces = traces.astype("uint16") # Define upper and lower limits. max_trace = trace_resolution @@ -507,9 +565,10 @@ def run_tvla(ctx: typer.Context): # Filtering of converted traces (len = num_samples). traces_to_use itself can be # used to index the entire project file (len >= num_samples). traces_to_use = np.zeros(num_traces_max, dtype=bool) - traces_to_use[trace_start:trace_end + 1] = np.all((traces >= min_trace) & - (traces <= max_trace), axis=1) - traces = traces[traces_to_use[trace_start:trace_end + 1]] + traces_to_use[trace_start: trace_end + 1] = np.all( + (traces >= min_trace) & (traces <= max_trace), axis=1 + ) + traces = traces[traces_to_use[trace_start: trace_end + 1]] if i_step == 0: # Keep a single trace to create the figures. @@ -517,26 +576,33 @@ def run_tvla(ctx: typer.Context): if save_to_disk_trace: log.info("Saving Traces") - np.savez('tmp/traces.npy', traces=traces, traces_to_use=traces_to_use, - trace_start=trace_start, trace_end=trace_end) - - if ((save_to_disk_trace is True or save_to_disk_ttest is True) and - general_test and i_step == 0): - np.save('tmp/single_trace.npy', single_trace) + np.savez( + "tmp/traces.npy", + traces=traces, + traces_to_use=traces_to_use, + trace_start=trace_start, + trace_end=trace_end, + ) + + if ( + (save_to_disk_trace is True or save_to_disk_ttest is True) and + general_test and i_step == 0 + ): + np.save("tmp/single_trace.npy", single_trace) else: trace_file = np.load(cfg["trace_file"]) - traces = trace_file['traces'] - traces_to_use = trace_file['traces_to_use'] + traces = trace_file["traces"] + traces_to_use = trace_file["traces_to_use"] assert num_samples == traces.shape[1] # If a trace range is specified, it must match the range in the trace file. # Otherwise, we might end up using a leakage model that doesn't match the actual # traces. if cfg["trace_start"] is None: - trace_start = trace_file['trace_start'] - assert trace_start == trace_file['trace_start'] + trace_start = trace_file["trace_start"] + assert trace_start == trace_file["trace_start"] if cfg["trace_end"] is None: - trace_end = trace_file['trace_end'] - assert trace_end == trace_file['trace_end'] + trace_end = trace_file["trace_end"] + assert trace_end == trace_file["trace_end"] num_traces = trace_end - trace_start + 1 # The project file must match the trace file. assert num_traces_max == len(traces_to_use) @@ -546,7 +612,7 @@ def run_tvla(ctx: typer.Context): num_traces = np.sum(traces_to_use) log.info( f"Will use {num_traces} traces " - f"({100*num_traces/num_traces_orig:.1f}%)" + f"({100 * num_traces / num_traces_orig:.1f}%)" ) num_traces_used_total += num_traces @@ -581,34 +647,48 @@ def run_tvla(ctx: typer.Context): for i in range(num_traces_max): if general_test_data: plaintexts_nparrays.append( - np.frombuffer(project.project.textins[i], dtype=np.uint8)) + np.frombuffer( + project.project.textins[i], dtype=np.uint8 + ) + ) else: - keys_nparrays.append(np.frombuffer(project.project.keys[i], - dtype=np.uint8)) + keys_nparrays.append( + np.frombuffer( + project.project.keys[i], dtype=np.uint8 + ) + ) # Select the correct slice of keys for each step. if OTTraceLib: if general_test_data: - plaintexts[:] = project.get_plaintexts(trace_start, trace_end + 1) + plaintexts[:] = project.get_plaintexts( + trace_start, trace_end + 1 + ) else: keys[:] = project.get_keys(trace_start, trace_end + 1) else: if general_test_data: - plaintexts[:] = plaintexts_nparrays[trace_start:trace_end + 1] + plaintexts[:] = plaintexts_nparrays[ + trace_start: trace_end + 1 + ] else: - keys[:] = keys_nparrays[trace_start:trace_end + 1] + keys[:] = keys_nparrays[trace_start: trace_end + 1] # Only select traces to use. if general_test_key: - keys = keys[traces_to_use[trace_start:trace_end + 1]] + keys = keys[traces_to_use[trace_start: trace_end + 1]] if general_test_data: - plaintexts = plaintexts[traces_to_use[trace_start:trace_end + 1]] + plaintexts = plaintexts[traces_to_use[trace_start: trace_end + 1]] if specific_test: - keys = keys[traces_to_use[trace_start:trace_end + 1]] + keys = keys[traces_to_use[trace_start: trace_end + 1]] if OTTraceLib: plaintexts = project.get_plaintexts(trace_start, trace_end + 1) else: - plaintexts[:] = project.project.textins[trace_start:trace_end + 1] - plaintexts = plaintexts[traces_to_use[trace_start:trace_end + 1]] + plaintexts[:] = project.project.textins[ + trace_start: trace_end + 1 + ] + plaintexts = plaintexts[ + traces_to_use[trace_start: trace_end + 1] + ] # We don't need the project file anymore after this point. Close it # together with all trace files opened in the background. @@ -622,18 +702,24 @@ def run_tvla(ctx: typer.Context): log.info("Computing Leakage") if specific_test_byte: leakage = Parallel(n_jobs=num_jobs)( - delayed(compute_leakage_aes_byte)(keys[i:i + trace_step_leakage], - plaintexts[i:i + trace_step_leakage]) - for i in range(0, num_traces, trace_step_leakage)) + delayed(compute_leakage_aes_byte)( + keys[i: i + trace_step_leakage], + plaintexts[i: i + trace_step_leakage], + ) + for i in range(0, num_traces, trace_step_leakage) + ) else: leakage = Parallel(n_jobs=num_jobs)( - delayed(compute_leakage_aes_bit)(keys[i:i + trace_step_leakage], - plaintexts[i:i + trace_step_leakage]) - for i in range(0, num_traces, trace_step_leakage)) + delayed(compute_leakage_aes_bit)( + keys[i: i + trace_step_leakage], + plaintexts[i: i + trace_step_leakage], + ) + for i in range(0, num_traces, trace_step_leakage) + ) leakage = np.concatenate((leakage[:]), axis=2) if save_to_disk_leakage: log.info("Saving Leakage") - np.save('tmp/leakage.npy', leakage) + np.save("tmp/leakage.npy", leakage) else: leakage = np.load(cfg["leakage_file"]) assert num_traces == leakage.shape[2] @@ -645,7 +731,9 @@ def run_tvla(ctx: typer.Context): assert general_test_data log.info("Computing Leakage") # We identify the fixed data by looking at the first 20 plaintexts in the project. - leakage = compute_leakage_general(plaintexts, find_fixed_entry(plaintexts[0:20])) + leakage = compute_leakage_general( + plaintexts, find_fixed_entry(plaintexts[0:20]) + ) # Uncomment the function call below for debugging e.g. when the t-test results aren't # centered around 0. @@ -665,15 +753,27 @@ def run_tvla(ctx: typer.Context): # > 0 (random set, x = 1). # The computation is parallelized over the samples. histograms = Parallel(n_jobs=num_jobs)( - delayed(compute_histograms_aes_byte)(trace_resolution, rnd_list, byte_list, - traces[:, i:i + sample_step_hist], leakage) - for i in range(0, num_samples, sample_step_hist)) + delayed(compute_histograms_aes_byte)( + trace_resolution, + rnd_list, + byte_list, + traces[:, i: i + sample_step_hist], + leakage, + ) + for i in range(0, num_samples, sample_step_hist) + ) histograms = np.concatenate((histograms[:]), axis=3) elif specific_test_bit: histograms = Parallel(n_jobs=num_jobs)( - delayed(compute_histograms_aes_bit)(trace_resolution, rnd_list, bit_list, - traces[:, i:i + sample_step_hist], leakage) - for i in range(0, num_samples, sample_step_hist)) + delayed(compute_histograms_aes_bit)( + trace_resolution, + rnd_list, + bit_list, + traces[:, i: i + sample_step_hist], + leakage, + ) + for i in range(0, num_samples, sample_step_hist) + ) histograms = np.concatenate((histograms[:]), axis=3) else: # For every time sample we make 2 histograms, one for the fixed set and one for the @@ -684,10 +784,11 @@ def run_tvla(ctx: typer.Context): # v and w indices are not used but we keep them for code compatiblitly with # non-general AES TVLA. histograms = Parallel(n_jobs=num_jobs)( - delayed(compute_histograms_general)(trace_resolution, - traces[:, i:i + sample_step_hist], - leakage) - for i in range(0, num_samples, sample_step_hist)) + delayed(compute_histograms_general)( + trace_resolution, traces[:, i: i + sample_step_hist], leakage + ) + for i in range(0, num_samples, sample_step_hist) + ) histograms = np.concatenate((histograms[:]), axis=3) # Free traces from memory as they are not needed anymore. @@ -704,8 +805,14 @@ def run_tvla(ctx: typer.Context): # Histograms can be saved for later use if output file name is passed. if cfg["output_histogram_file"] is not None: log.info("Saving Histograms") - np.savez(cfg["output_histogram_file"], histograms=histograms, rnd_list=rnd_list, - byte_list=byte_list, bit_list=bit_list, single_trace = trace_to_plot) + np.savez( + cfg["output_histogram_file"], + histograms=histograms, + rnd_list=rnd_list, + byte_list=byte_list, + bit_list=bit_list, + single_trace=trace_to_plot, + ) # Computing the t-test statistics vs. time. log.info("Computing T-test Statistics") @@ -718,10 +825,17 @@ def run_tvla(ctx: typer.Context): # Compute statistics. # ttest_trace has dimensions [num_orders, num_rnds, num_bytes, num_samples]. ttest_trace = Parallel(n_jobs=num_jobs)( - delayed(compute_statistics)(cfg["test_type"], num_orders, - histograms[:, :, :, i:i + sample_step_ttest, :], - x_axis, rnd_list, byte_list, bit_list) - for i in range(0, num_samples, sample_step_ttest)) + delayed(compute_statistics)( + cfg["test_type"], + num_orders, + histograms[:, :, :, i: i + sample_step_ttest, :], + x_axis, + rnd_list, + byte_list, + bit_list, + ) + for i in range(0, num_samples, sample_step_ttest) + ) ttest_trace = np.concatenate((ttest_trace[:]), axis=3) # Building the t-test statistics vs. number of traces used. ttest_step has dimensions @@ -729,8 +843,9 @@ def run_tvla(ctx: typer.Context): # every round, every byte, every sample and every step, we track the t-test value. log.info("Updating T-test Statistics vs. Number of Traces") if i_step == 0: - ttest_step = np.empty((num_orders, num_rnds, num_data, num_samples, - num_steps)) + ttest_step = np.empty( + (num_orders, num_rnds, num_data, num_samples, num_steps) + ) ttest_step[:, :, :, :, i_step] = ttest_trace rnd_ext = list(range(num_rnds)) @@ -740,27 +855,31 @@ def run_tvla(ctx: typer.Context): elif cfg["ttest_step_file"] is not None: # Load previously generated t-test results. ttest_step_file = np.load(cfg["ttest_step_file"], allow_pickle=True) - metadata = ttest_step_file['metadata'].item() - sample_start = ttest_step_file['sample_start'] - single_trace = ttest_step_file['single_trace'] - trace_start_vec = ttest_step_file['trace_start_vec'] - num_traces_used_total = ttest_step_file['num_traces'] - ttest_step = ttest_step_file['ttest_step'] + metadata = ttest_step_file["metadata"].item() + sample_start = ttest_step_file["sample_start"] + single_trace = ttest_step_file["single_trace"] + trace_start_vec = ttest_step_file["trace_start_vec"] + num_traces_used_total = ttest_step_file["num_traces"] + ttest_step = ttest_step_file["ttest_step"] num_orders = ttest_step.shape[0] num_samples = ttest_step.shape[3] num_steps = ttest_step.shape[4] - trace_end_vec = ttest_step_file['trace_end_vec'] + trace_end_vec = ttest_step_file["trace_end_vec"] # The rounds and bytes of interest must be available in the previously generated t-test # results. In addition, we may need to translate indices to extract the right portion of # of the loaded results. rnd_ext = np.zeros((num_rnds), dtype=np.uint8) byte_ext = np.zeros((num_bytes), dtype=np.uint8) for i_rnd in range(num_rnds): - assert rnd_list[i_rnd] in ttest_step_file['rnd_list'] - rnd_ext[i_rnd] = np.where(ttest_step_file['rnd_list'] == rnd_list[i_rnd])[0][0] + assert rnd_list[i_rnd] in ttest_step_file["rnd_list"] + rnd_ext[i_rnd] = np.where(ttest_step_file["rnd_list"] == rnd_list[i_rnd])[ + 0 + ][0] for i_byte in range(num_bytes): - assert byte_list[i_byte] in ttest_step_file['byte_list'] - byte_ext[i_byte] = np.where(ttest_step_file['byte_list'] == byte_list[i_byte])[0][0] + assert byte_list[i_byte] in ttest_step_file["byte_list"] + byte_ext[i_byte] = np.where( + ttest_step_file["byte_list"] == byte_list[i_byte] + )[0][0] # Plot the t-test vs. time figures for the maximum number of traces. ttest_trace = ttest_step[:, :, :, :, num_steps - 1] @@ -775,20 +894,22 @@ def run_tvla(ctx: typer.Context): if save_to_disk_ttest: if num_steps > 1: log.info("Saving T-test Step") - np.savez_compressed('tmp/ttest-step.npy', - ttest_step=ttest_step, - num_traces=num_traces_used_total, - metadata=metadata, - sample_start=sample_start, - trace_start_vec=trace_start_vec, - trace_end_vec=trace_end_vec, - rnd_list=rnd_list, - byte_list=byte_list, - bit_list=bit_list, - single_trace=trace_to_plot) + np.savez_compressed( + "tmp/ttest-step.npy", + ttest_step=ttest_step, + num_traces=num_traces_used_total, + metadata=metadata, + sample_start=sample_start, + trace_start_vec=trace_start_vec, + trace_end_vec=trace_end_vec, + rnd_list=rnd_list, + byte_list=byte_list, + bit_list=bit_list, + single_trace=trace_to_plot, + ) else: log.info("Saving T-test") - np.save('tmp/ttest.npy', ttest_trace) + np.save("tmp/ttest.npy", ttest_trace) # Check ttest results. threshold = 4.5 @@ -800,11 +921,15 @@ def run_tvla(ctx: typer.Context): if np.any(failure) or np.any(nan): if specific_test_byte: if np.any(failure): - log.info("Leakage above threshold identified in the following order(s), round(s) " - "and byte(s) marked with X:") + log.info( + "Leakage above threshold identified in the following order(s), round(s) " + "and byte(s) marked with X:" + ) if np.any(nan): - log.info("Couldn't compute statistics for order(s), round(s) and byte(s) marked " - "with O:") + log.info( + "Couldn't compute statistics for order(s), round(s) and byte(s) marked " + "with O:" + ) with UnformattedLog(): byte_str = "Byte |" dash_str = "----------" @@ -829,11 +954,15 @@ def run_tvla(ctx: typer.Context): log.info("") elif specific_test_bit: if np.any(failure): - log.info("Leakage above threshold identified in the following order(s), round(s) " - "and bit(s) marked with X:") + log.info( + "Leakage above threshold identified in the following order(s), round(s) " + "and bit(s) marked with X:" + ) if np.any(nan): - log.info("Couldn't compute statistics for order(s), round(s) and bit(s) marked " - "with O:") + log.info( + "Couldn't compute statistics for order(s), round(s) and bit(s) marked " + "with O:" + ) with UnformattedLog(): bit_str = "Bit |" dash_str = "----------" @@ -857,7 +986,9 @@ def run_tvla(ctx: typer.Context): log.info(f"{result_str}") log.info("") else: - log.info("Leakage above threshold identified in the following order(s) marked with X") + log.info( + "Leakage above threshold identified in the following order(s) marked with X" + ) if np.any(nan): log.info("Couldn't compute statistics for order(s) marked with O:") with UnformattedLog(): @@ -880,28 +1011,29 @@ def run_tvla(ctx: typer.Context): textbox = "" # Catch case where certain metadata isn't saved to project file (e.g. older measurement) try: - sampling_rate = float(metadata['sampling_rate']) / 1e6 - textbox = textbox + "Sample rate:\n" + str( - math.floor(sampling_rate)) + " MS/s\n\n" + sampling_rate = float(metadata["sampling_rate"]) / 1e6 + textbox = ( + textbox + + "Sample rate:\n" + + str(math.floor(sampling_rate)) + + " MS/s\n\n" + ) except KeyError: textbox = textbox try: - textbox = textbox + "Masks off:\n" + metadata['masks_off'] + "\n\n" + textbox = textbox + "Masks off:\n" + metadata["masks_off"] + "\n\n" except KeyError: textbox = textbox try: - textbox = textbox + "Samples:\n" + str( - metadata['num_samples']) + "\n\n" + textbox = textbox + "Samples:\n" + str(metadata["num_samples"]) + "\n\n" except KeyError: textbox = textbox try: - textbox = textbox + "Offset:\n" + str( - metadata['offset_samples']) + "\n\n" + textbox = textbox + "Offset:\n" + str(metadata["offset_samples"]) + "\n\n" except KeyError: textbox = textbox try: - textbox = textbox + "Scope gain:\n" + str( - metadata['scope_gain']) + "\n\n" + textbox = textbox + "Scope gain:\n" + str(metadata["scope_gain"]) + "\n\n" except KeyError: textbox = textbox try: @@ -921,40 +1053,57 @@ def run_tvla(ctx: typer.Context): for i_data in range(num_data): fig, axs = plt.subplots(num_orders + 1, 1, sharex=True) - axs = tvla_plotting_fnc(axs, num_orders, i_rnd, i_data, - ttest_trace, single_trace, - threshold, num_samples, - sample_start, metadata) + axs = tvla_plotting_fnc( + axs, + num_orders, + i_rnd, + i_data, + ttest_trace, + single_trace, + threshold, + num_samples, + sample_start, + metadata, + ) if specific_test_byte: - title = "TVLA of " + "aes_t_test_round_" + str( - rnd_list[i_rnd]) + "_byte_" + str(byte_list[i_data]) + title = ( + "TVLA of " + + "aes_t_test_round_" + + str(rnd_list[i_rnd]) + + "_byte_" + + str(byte_list[i_data]) + ) elif specific_test_bit: - title = "TVLA of " + "aes_t_test_round_" + str( - rnd_list[i_rnd]) + "_bit_" + str(bit_list[i_data]) + title = ( + "TVLA of " + + "aes_t_test_round_" + + str(rnd_list[i_rnd]) + + "_bit_" + + str(bit_list[i_data]) + ) # Catch case where datetime data isn't saved # to project file (e.g. older measurement) try: - title = title + "\n" + "Captured: " + metadata[ - 'datetime'] + title = title + "\n" + "Captured: " + metadata["datetime"] except KeyError: title = title axs[0].set_title(title) # Add metadata to plot if textbox != "": - left, width = .67, .5 - bottom, height = .25, .5 + left, width = 0.67, 0.5 + bottom, height = 0.25, 0.5 right = left + width top = bottom + height - plt.gcf().text(0.5 * (left + right), - 0.5 * (bottom + top), - textbox, - fontsize=9, - horizontalalignment='center', - verticalalignment='center', - bbox=dict(boxstyle='round', - facecolor='w', - linewidth=0.6)) + plt.gcf().text( + 0.5 * (left + right), + 0.5 * (bottom + top), + textbox, + fontsize=9, + horizontalalignment="center", + verticalalignment="center", + bbox=dict(boxstyle="round", facecolor="w", linewidth=0.6), + ) plt.subplots_adjust(right=0.84) plt.xlabel("time [samples]") @@ -971,37 +1120,46 @@ def run_tvla(ctx: typer.Context): else: fig, axs = plt.subplots(num_orders + 1, 1, sharex=True) - axs = tvla_plotting_fnc(axs, num_orders, 0, 0, ttest_trace, - single_trace, threshold, num_samples, - sample_start, metadata) + axs = tvla_plotting_fnc( + axs, + num_orders, + 0, + 0, + ttest_trace, + single_trace, + threshold, + num_samples, + sample_start, + metadata, + ) - title = "TVLA of " + (cfg["project_file"]).rsplit('/', 1)[-1] + title = "TVLA of " + (cfg["project_file"]).rsplit("/", 1)[-1] # Catch case where datetime data isn't saved to project file (e.g. older measurement) try: - title = title + "\n" + "Captured: " + metadata['datetime'] + title = title + "\n" + "Captured: " + metadata["datetime"] except KeyError: title = title axs[0].set_title(title) # Add metadata to plot if textbox != "": - left, width = .67, .5 - bottom, height = .25, .5 + left, width = 0.67, 0.5 + bottom, height = 0.25, 0.5 right = left + width top = bottom + height - plt.gcf().text(0.5 * (left + right), - 0.5 * (bottom + top), - textbox, - fontsize=9, - horizontalalignment='center', - verticalalignment='center', - bbox=dict(boxstyle='round', - facecolor='w', - linewidth=0.6)) + plt.gcf().text( + 0.5 * (left + right), + 0.5 * (bottom + top), + textbox, + fontsize=9, + horizontalalignment="center", + verticalalignment="center", + bbox=dict(boxstyle="round", facecolor="w", linewidth=0.6), + ) plt.subplots_adjust(right=0.84) plt.xlabel("time [samples]") - plt.savefig('tmp/figures/' + cfg["mode"] + '_fixed_vs_random.png') + plt.savefig("tmp/figures/" + cfg["mode"] + "_fixed_vs_random.png") plt.show() # Plotting figures for t-test statistics vs. number of traces used. @@ -1009,15 +1167,17 @@ def run_tvla(ctx: typer.Context): # result of one time sample for one byte and one round. if num_steps > 1: - log.info("Plotting T-test Statistics vs. Number of Traces, this may take a while.") + log.info( + "Plotting T-test Statistics vs. Number of Traces, this may take a while." + ) # Determine resolution. xres_vec = [10e6, 1e6, 100e3, 10e3, 1e3, 100, 10, 1] for xres in xres_vec: if int(np.around((trace_end_vec[0] - trace_start_vec[0]) / xres)) > 0: if xres >= 1e6: - xres_label = str(int(xres / 1e6)) + 'M' + xres_label = str(int(xres / 1e6)) + "M" elif xres >= 1e3: - xres_label = str(int(xres / 1e3)) + 'k' + xres_label = str(int(xres / 1e3)) + "k" else: xres_label = str(int(xres)) break @@ -1028,7 +1188,9 @@ def run_tvla(ctx: typer.Context): # Empty every second label if we got more than 10 steps. if num_steps > 10: for i_step in range(num_steps): - xticklabels[i_step] = "" if (i_step % 2 == 0) else xticklabels[i_step] + xticklabels[i_step] = ( + "" if (i_step % 2 == 0) else xticklabels[i_step] + ) for i_rnd in range(num_rnds): @@ -1050,24 +1212,49 @@ def run_tvla(ctx: typer.Context): # The widnow width is 100 samples + 40 samples extended on each side. half_window = samples_per_rnd // 2 + 40 - samples = {"aes": range(max(rnd_offset + (rnd_list[i_rnd] * samples_per_rnd) - - half_window, 0), - min(rnd_offset + (rnd_list[i_rnd] * samples_per_rnd) + - half_window, num_samples))} + samples = { + "aes": range( + max( + rnd_offset + + (rnd_list[i_rnd] * samples_per_rnd) - + half_window, + 0, + ), + min( + rnd_offset + + (rnd_list[i_rnd] * samples_per_rnd) + + half_window, + num_samples, + ), + ) + } else: # Even if cfg["sample_start"] is specified and cfg["num_samples"] is not, # num_samples is set to a valid value and the code below has valid inputs. - range_specified = True if \ - (("sample_start" in cfg and cfg["sample_start"] is not None) or - ("num_samples" in cfg and cfg["num_samples"] is not None)) else False + range_specified = ( + True + if ( + ("sample_start" in cfg and cfg["sample_start"] is not None) or + ("num_samples" in cfg and cfg["num_samples"] is not None) + ) + else False + ) samples = { # Simply plot all samples within the selected range. "aes": range(0, num_samples), # Plot samples within key absorption phase, unless a range is specified. - "kmac": range(0, num_samples) if range_specified else range(520, 2460), + "kmac": ( + range(0, num_samples) + if range_specified + else range(520, 2460) + ), # Plot samples within actual SHA3 phase, unless a range is specified. - "sha3": range(0, num_samples) if range_specified else range(1150, 3150), + "sha3": ( + range(0, num_samples) + if range_specified + else range(1150, 3150) + ), # Simply plot all samples within the selected range. "otbn": range(0, num_samples), } @@ -1075,22 +1262,31 @@ def run_tvla(ctx: typer.Context): for i_order in range(num_orders): for i_byte in range(num_bytes): for i_sample in samples[cfg["mode"]]: - axs[i_order].plot(ttest_step[i_order, - rnd_ext[i_rnd], - byte_ext[i_byte], - i_sample], - 'k') - axs[i_order].plot(c * threshold, 'r') - axs[i_order].plot(-threshold * c, 'r') - axs[i_order].set_xlabel(str('number of traces [' + xres_label + ']')) + axs[i_order].plot( + ttest_step[ + i_order, rnd_ext[i_rnd], byte_ext[i_byte], i_sample + ], + "k", + ) + axs[i_order].plot(c * threshold, "r") + axs[i_order].plot(-threshold * c, "r") + axs[i_order].set_xlabel( + str("number of traces [" + xres_label + "]") + ) axs[i_order].set_xticks(range(num_steps)) axs[i_order].set_xticklabels(xticklabels) axs[i_order].set_ylabel( - 't-test ' + str(i_order + 1) + - "\nfor samples " + str(samples[cfg["mode"]][0]) + - ' to ' + str(samples[cfg["mode"]][-1])) - - filename = cfg["mode"] + "_t_test_steps_round_" + str(rnd_list[i_rnd]) + ".png" + "t-test " + + str(i_order + 1) + + "\nfor samples " + + str(samples[cfg["mode"]][0]) + + " to " + + str(samples[cfg["mode"]][-1]) + ) + + filename = ( + cfg["mode"] + "_t_test_steps_round_" + str(rnd_list[i_rnd]) + ".png" + ) plt.savefig("tmp/figures/" + filename) if num_rnds == 1: plt.show() @@ -1121,94 +1317,167 @@ def run_tvla(ctx: typer.Context): # Help messages of the options -help_cfg_file = inspect.cleandoc("""Configuration file. Default: """ + str(default_cfg_file)) -help_project_file = inspect.cleandoc("""Name of the ChipWhisperer project file to use. Default: - """ + str(default_project_file)) -help_trace_file = inspect.cleandoc("""Name of the trace file containing the numpy array with all +help_cfg_file = inspect.cleandoc( + """Configuration file. Default: """ + str(default_cfg_file) +) +help_project_file = inspect.cleandoc( + """Name of the ChipWhisperer project file to use. Default: + """ + + str(default_project_file) +) +help_trace_file = inspect.cleandoc( + """Name of the trace file containing the numpy array with all traces in 16-bit integer format. If not provided, the data from the ChipWhisperer project file - is used. Ignored for number-of-steps > 1. Default: """ + str(default_trace_file)) -help_trace_start = inspect.cleandoc("""Index of the first trace to use. If not provided, starts at - the first trace. Default: """ + str(default_trace_start)) -help_trace_end = inspect.cleandoc("""Index of the last trace to use. If not provided, ends at the - last trace. Default: """ + str(default_trace_end)) -help_leakage_file = inspect.cleandoc("""Name of the leakage file containing the numpy array with the + is used. Ignored for number-of-steps > 1. Default: """ + + str(default_trace_file) +) +help_trace_start = inspect.cleandoc( + """Index of the first trace to use. If not provided, starts at + the first trace. Default: """ + + str(default_trace_start) +) +help_trace_end = inspect.cleandoc( + """Index of the last trace to use. If not provided, ends at the + last trace. Default: """ + + str(default_trace_end) +) +help_leakage_file = inspect.cleandoc( + """Name of the leakage file containing the numpy array with the leakage model for all rounds, all bytes, and all traces. If not provided, the leakage is computed from the data in the ChipWhisperer project file. Ignored for number-of-steps > 1. - Default: """ + str(default_leakage_file)) -help_save_to_disk = inspect.cleandoc("""Save trace and leakage files to disk. Ignored when - number-of-steps > 1. Default: """ + str(default_save_to_disk)) -help_save_to_disk_ttest = inspect.cleandoc("""Save t-test files to disk. Ignored when - ttset-step-file is not None. Default: """ + str(default_save_to_disk_ttest)) -help_round_select = inspect.cleandoc("""Index of the AES round for which the histograms are to be + Default: """ + + str(default_leakage_file) +) +help_save_to_disk = inspect.cleandoc( + """Save trace and leakage files to disk. Ignored when + number-of-steps > 1. Default: """ + + str(default_save_to_disk) +) +help_save_to_disk_ttest = inspect.cleandoc( + """Save t-test files to disk. Ignored when + ttset-step-file is not None. Default: """ + + str(default_save_to_disk_ttest) +) +help_round_select = inspect.cleandoc( + """Index of the AES round for which the histograms are to be computed: 0-10. If not provided, the histograms for all AES rounds are computed. To select multiple but not all rounds, specify the argument once per selected round, e.g., - "--round-select 0 --round-select 1". Default: """ + str(default_round_select)) -help_byte_select = inspect.cleandoc("""Index of the AES state byte for which the histograms are to + "--round-select 0 --round-select 1". Default: """ + + str(default_round_select) +) +help_byte_select = inspect.cleandoc( + """Index of the AES state byte for which the histograms are to be computed: 0-15. If not provided, the histograms for all AES state bytes are computed. To select multiple but not all bytes, specify the argument once per selected byte, e.g., - "--byte-select 0 --byte-select 1". Default: """ + str(default_byte_select)) -help_input_histogram_file = inspect.cleandoc("""Name of the input file containing the histograms. + "--byte-select 0 --byte-select 1". Default: """ + + str(default_byte_select) +) +help_input_histogram_file = inspect.cleandoc( + """Name of the input file containing the histograms. Not required. If both -input_histogram_file and -output_histogram_file are provided, the input file is appended with more data to produce the output file. - Default: """ + str(default_input_histogram_file)) -help_output_histogram_file = inspect.cleandoc("""Name of the output file to store generated + Default: """ + + str(default_input_histogram_file) +) +help_output_histogram_file = inspect.cleandoc( + """Name of the output file to store generated histograms. Not required. If both -input_histogram_file and -output_histogram_file are provided, the input file is appended with more data to produce the output file. - Default: """ + str(default_output_histogram_file)) -help_number_of_steps = inspect.cleandoc("""Number of steps to breakdown the analysis into. For + Default: """ + + str(default_output_histogram_file) +) +help_number_of_steps = inspect.cleandoc( + """Number of steps to breakdown the analysis into. For every step, traces are separately filtered and the leakage is computed. The histograms are appended to the ones of the previous step. This is useful when operating on very large trace sets and/or when analyzing how results change with the number of traces used. Default: - """ + str(default_number_of_steps)) -help_ttest_step_file = inspect.cleandoc("""Name of the t-test step file containing one t-test + """ + + str(default_number_of_steps) +) +help_ttest_step_file = inspect.cleandoc( + """Name of the t-test step file containing one t-test analysis per step. If not provided, the data is recomputed. Default: - """ + str(default_ttest_step_file)) -help_plot_figures = inspect.cleandoc("""Plot figures and save them to disk. Default: - """ + str(default_plot_figures)) -help_test_type = inspect.cleandoc("""Select test type: can be either "SPECIFIC_BYTE", "GENERA_KEY", + """ + + str(default_ttest_step_file) +) +help_plot_figures = inspect.cleandoc( + """Plot figures and save them to disk. Default: + """ + + str(default_plot_figures) +) +help_test_type = inspect.cleandoc( + """Select test type: can be either "SPECIFIC_BYTE", "GENERA_KEY", or "GENERAL_DATA". - Default: """ + str(default_test_type)) -help_mode = inspect.cleandoc("""Select mode: can be either "aes", "kmac", "sha3" or "otbn". - Default: """ + str(default_mode)) -help_filter_traces = inspect.cleandoc("""Excludes the outlier traces from the analysis. A trace is + Default: """ + + str(default_test_type) +) +help_mode = inspect.cleandoc( + """Select mode: can be either "aes", "kmac", "sha3" or "otbn". + Default: """ + + str(default_mode) +) +help_filter_traces = inspect.cleandoc( + """Excludes the outlier traces from the analysis. A trace is an outlier if any of the points is more than 3.5 sigma away from the mean. - Default: """ + str(default_filter_traces)) -help_update_cfg_file = inspect.cleandoc("""Update existing configuration file or create if there - isn't any configuration file. Default: """ + str(default_update_cfg_file)) + Default: """ + + str(default_filter_traces) +) +help_update_cfg_file = inspect.cleandoc( + """Update existing configuration file or create if there + isn't any configuration file. Default: """ + + str(default_update_cfg_file) +) @app.callback() -def main(ctx: typer.Context, - cfg_file: str = typer.Option(None, help=help_cfg_file), - project_file: str = typer.Option(None, help=help_project_file), - trace_file: str = typer.Option(None, help=help_trace_file), - trace_start: int = typer.Option(None, help=help_trace_start), - trace_end: int = typer.Option(None, help=help_trace_end), - leakage_file: str = typer.Option(None, help=help_leakage_file), - save_to_disk: bool = typer.Option(None, help=help_save_to_disk), - save_to_disk_ttest: bool = typer.Option(None, help=help_save_to_disk_ttest), - round_select: list[int] = typer.Option(None, help=help_round_select), - byte_select: list[int] = typer.Option(None, help=help_byte_select), - input_histogram_file: str = typer.Option(None, help=help_input_histogram_file), - output_histogram_file: str = typer.Option(None, help=help_output_histogram_file), - number_of_steps: int = typer.Option(None, help=help_number_of_steps), - ttest_step_file: str = typer.Option(None, help=help_ttest_step_file), - plot_figures: bool = typer.Option(None, help=help_plot_figures), - test_type: str = typer.Option(None, help=help_test_type), - mode: str = typer.Option(None, help=help_mode), - filter_traces: bool = typer.Option(None, help=help_filter_traces), - update_cfg_file: bool = typer.Option(None, help=help_update_cfg_file)): +def main( + ctx: typer.Context, + cfg_file: str = typer.Option(None, help=help_cfg_file), + project_file: str = typer.Option(None, help=help_project_file), + trace_file: str = typer.Option(None, help=help_trace_file), + trace_start: int = typer.Option(None, help=help_trace_start), + trace_end: int = typer.Option(None, help=help_trace_end), + leakage_file: str = typer.Option(None, help=help_leakage_file), + save_to_disk: bool = typer.Option(None, help=help_save_to_disk), + save_to_disk_ttest: bool = typer.Option(None, help=help_save_to_disk_ttest), + round_select: list[int] = typer.Option(None, help=help_round_select), + byte_select: list[int] = typer.Option(None, help=help_byte_select), + input_histogram_file: str = typer.Option(None, help=help_input_histogram_file), + output_histogram_file: str = typer.Option(None, help=help_output_histogram_file), + number_of_steps: int = typer.Option(None, help=help_number_of_steps), + ttest_step_file: str = typer.Option(None, help=help_ttest_step_file), + plot_figures: bool = typer.Option(None, help=help_plot_figures), + test_type: str = typer.Option(None, help=help_test_type), + mode: str = typer.Option(None, help=help_mode), + filter_traces: bool = typer.Option(None, help=help_filter_traces), + update_cfg_file: bool = typer.Option(None, help=help_update_cfg_file), +): """A histogram-based TVLA described in "Fast Leakage Assessment" by O. Reparaz, B. Gierlichs and I. Verbauwhede (https://eprint.iacr.org/2017/624.pdf).""" cfg = {} # Assign default values to the options. - for v in ['project_file', 'trace_file', 'trace_start', 'trace_end', 'leakage_file', - 'save_to_disk', 'save_to_disk_ttest', 'round_select', 'byte_select', - 'input_histogram_file', 'output_histogram_file', 'number_of_steps', - 'ttest_step_file', 'plot_figures', 'test_type', 'mode', 'filter_traces']: - run_cmd = f'''cfg[v] = default_{v}''' + for v in [ + "project_file", + "trace_file", + "trace_start", + "trace_end", + "leakage_file", + "save_to_disk", + "save_to_disk_ttest", + "round_select", + "byte_select", + "input_histogram_file", + "output_histogram_file", + "number_of_steps", + "ttest_step_file", + "plot_figures", + "test_type", + "mode", + "filter_traces", + ]: + run_cmd = f"""cfg[v] = default_{v}""" exec(run_cmd) # Load options from configuration file, if provided. @@ -1218,27 +1487,40 @@ def main(ctx: typer.Context, f.close() # Overwrite options from CLI, if provided. - for v in ['project_file', 'trace_file', 'trace_start', 'trace_end', 'leakage_file', - 'save_to_disk', 'save_to_disk_ttest', - 'input_histogram_file', 'output_histogram_file', 'number_of_steps', - 'ttest_step_file', 'plot_figures', 'test_type', 'mode', 'filter_traces']: - run_cmd = f'''if {v} is not None: cfg[v] = {v}''' + for v in [ + "project_file", + "trace_file", + "trace_start", + "trace_end", + "leakage_file", + "save_to_disk", + "save_to_disk_ttest", + "input_histogram_file", + "output_histogram_file", + "number_of_steps", + "ttest_step_file", + "plot_figures", + "test_type", + "mode", + "filter_traces", + ]: + run_cmd = f"""if {v} is not None: cfg[v] = {v}""" exec(run_cmd) # The list arguments need to be handled a bit differently. - for v in ['round_select', 'byte_select']: - run_cmd = f'''if {v}: cfg[v] = {v}''' + for v in ["round_select", "byte_select"]: + run_cmd = f"""if {v}: cfg[v] = {v}""" exec(run_cmd) if not os.path.exists(str(script_dir) + "/tmp"): os.makedirs(str(script_dir) + "/tmp") - with open(str(script_dir) + "/tmp/tvla_cfg.yaml", 'w') as f: + with open(str(script_dir) + "/tmp/tvla_cfg.yaml", "w") as f: yaml.dump(cfg, f) f.close() if update_cfg_file: if cfg_file is None: cfg_file = str(script_dir) + "/tvla_cfg.yaml" - with open(cfg_file, 'w') as f: + with open(cfg_file, "w") as f: yaml.dump(cfg, f, sort_keys=False) f.close() diff --git a/capture/README.md b/capture/README.md index 5b16d1c6..63fdaa81 100644 --- a/capture/README.md +++ b/capture/README.md @@ -36,7 +36,7 @@ The capture configs stored in `configs/` follow the following structure: - capture - test -The target entry specifies the target. Currently, only the `cw310` or `cw305` +The target entry specifies the target. Currently, only the `cw310` FGPA boards are supported. The scope entry defines (indirectly) the sampling rate as well as the scope gain and cycle offset. With the capture entry, the user can select the corresponding scope, configure the trace plot, and select @@ -51,6 +51,3 @@ a template. The template follows the following structure: - Configure the cipher and establish the communication interface - Capture traces - Print traces - -The communication interface (e.g., the individual simpleserial commands) for -each cipher needs to be added to `lib/ot_communication.py`. diff --git a/capture/capture_aes.py b/capture/capture_aes.py index de441950..336ca437 100755 --- a/capture/capture_aes.py +++ b/capture/capture_aes.py @@ -3,7 +3,7 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 -import binascii +import json import logging import random import signal @@ -27,9 +27,11 @@ from target.communication.sca_prng_commands import OTPRNG from target.communication.sca_trigger_commands import OTTRIGGER from target.targets import Target, TargetConfig -from util import check_version -from util import data_generator as dg -from util import plot +from util import check_version, plot + +# Both the number of bytes in the plaintext and key are fixed. +plaintext_len = 16 +key_len = 16 """AES SCA capture script. @@ -47,7 +49,7 @@ def abort_handler_during_loop(this_project, sig, frame): - """ Abort capture and store traces. + """Abort capture and store traces. Args: this_project: Project instance. @@ -60,23 +62,18 @@ def abort_handler_during_loop(this_project, sig, frame): @dataclass class CaptureConfig: - """ Configuration class for the current capture. - """ + """Configuration class for the current capture.""" + capture_mode: str - batch_mode: bool num_traces: int num_segments: int - output_len: int text_fixed: bytearray key_fixed: bytearray - key_len_bytes: int - text_len_bytes: int - protocol: str port: Optional[str] = "None" def setup(cfg: dict, project: Path): - """ Setup target, scope, and project. + """Setup target, scope, and project. Args: cfg: The configuration for the current experiment. @@ -88,76 +85,89 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + ) # Create target config & setup target. logger.info(f"Initializing target {cfg['target']['target_type']} ...") target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial"), - interface = cfg["target"].get("interface"), - husky_serial = cfg["husky"].get("usb_serial") + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], + pll_frequency=cfg["target"]["pll_frequency"], + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + interface=cfg["target"].get("interface"), + husky_serial = cfg["husky"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) target = Target(target_cfg) # Init scope. scope_type = cfg["capture"]["scope_select"] - # Will determine sampling rate (for Husky only), if not given in cfg. - cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) - # Will convert number of cycles into number of samples if they are not given in cfg. - cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) - # Will convert offset in cycles into offset in samples, if they are not given in cfg. - cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) - - logger.info(f"Initializing scope {scope_type} with a sampling rate of {cfg[scope_type]['sampling_rate']}...") # noqa: E501 - - # Determine if we are in batch mode or not. - batch = False - if "batch" in cfg["test"]["which_test"]: + # Check the ChipWhisperer version. + if scope_type == "husky": + check_version.check_cw("5.7.0") + + if scope_type != "none": + # Will determine sampling rate (for Husky only), if not given in cfg. + cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) + # Will convert number of cycles into number of samples if they are not given in cfg. + cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) + # Will convert offset in cycles into offset in samples, if they are not given in cfg. + cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) + + logger.info( + f"Initializing scope {scope_type} with a sampling rate of \ + {cfg[scope_type]['sampling_rate']}..." + ) # noqa: E501 + + # Determine if we are in batch mode or not. batch = True - - # Create scope config & setup scope. - scope_cfg = ScopeConfig( - scope_type = scope_type, - batch_mode = batch, - bit = cfg[scope_type].get("bit"), - acqu_channel = cfg[scope_type].get("channel"), - ip = cfg[scope_type].get("waverunner_ip"), - num_samples = cfg[scope_type]["num_samples"], - offset_samples = cfg[scope_type]["offset_samples"], - sampling_rate = cfg[scope_type].get("sampling_rate"), - num_segments = cfg[scope_type].get("num_segments"), - sparsing = cfg[scope_type].get("sparsing"), - scope_gain = cfg[scope_type].get("scope_gain"), - pll_frequency = cfg["target"]["pll_frequency"], - scope_sn = cfg[scope_type].get("usb_serial"), - ) - scope = Scope(scope_cfg) - - # Init project. - project_cfg = ProjectConfig(type = cfg["capture"]["trace_db"], - path = project, - wave_dtype = np.uint16, - overwrite = True, - trace_threshold = cfg["capture"].get("trace_threshold") - ) - project = SCAProject(project_cfg) - project.create_project() + if "single" in cfg["test"]["which_test"]: + batch = False + + # Create scope config & setup scope. + scope_cfg = ScopeConfig( + scope_type=scope_type, + batch_mode=batch, + bit=cfg[scope_type].get("bit"), + acqu_channel=cfg[scope_type].get("channel"), + ip=cfg[scope_type].get("waverunner_ip"), + num_samples=cfg[scope_type]["num_samples"], + offset_samples=cfg[scope_type]["offset_samples"], + sampling_rate=cfg[scope_type].get("sampling_rate"), + num_segments=cfg["capture"].get("num_segments"), + sparsing=cfg[scope_type].get("sparsing"), + scope_gain=cfg[scope_type].get("scope_gain"), + pll_frequency=cfg["target"]["pll_frequency"], + scope_sn=cfg[scope_type].get("usb_serial"), + ) + scope = Scope(scope_cfg) + + # Init project. + project_cfg = ProjectConfig( + type=cfg["capture"]["trace_db"], + path=project, + wave_dtype=np.uint16, + overwrite=True, + trace_threshold=cfg["capture"].get("trace_threshold"), + ) + project = SCAProject(project_cfg) + project.create_project() + else: + scope = None + project = None return target, scope, project -def establish_communication(target, capture_cfg: CaptureConfig): - """ Establish communication with the target device. +def establish_communication(target): + """Establish communication with the target device. Args: target: The OT target. @@ -169,29 +179,32 @@ def establish_communication(target, capture_cfg: CaptureConfig): ot_trig: The communication interface to the SCA trigger. """ # Create communication interface to OT AES. - ot_aes = OTAES(target=target, protocol=capture_cfg.protocol) + ot_aes = OTAES(target=target) # Create communication interface to OT PRNG. - ot_prng = OTPRNG(target=target, protocol=capture_cfg.protocol) + ot_prng = OTPRNG(target=target) # Create communication interface to SCA trigger. - ot_trig = OTTRIGGER(target=target, protocol=capture_cfg.protocol) + ot_trig = OTTRIGGER(target=target) return ot_aes, ot_prng, ot_trig -def configure_cipher(cfg, capture_cfg, ot_aes, ot_prng): - """ Configure the AES cipher. +def configure_cipher(cfg, ot_aes, ot_prng): + """Configure the AES cipher. Establish communication with the AES cipher and configure the seed. Args: cfg: The project config. - capture_cfg: The capture config. ot_aes: The communication interface to the AES SCA application. ot_prng: The communication interface to the PRNG SCA application. Returns: device_id: The ID of the target device. + owner_page: The owner info page + boot_log: The boot log + boot_measurments: The boot measurements + version: The testOS version """ # Check if we want to run AES SCA for FPGA or discrete. On the FPGA, we # can use functionality helping us to capture cleaner traces. @@ -199,94 +212,115 @@ def configure_cipher(cfg, capture_cfg, ot_aes, ot_prng): if "cw" in cfg["target"]["target_type"]: fpga_mode_bit = 1 # Initialize AES on the target. - device_id = ot_aes.init(fpga_mode_bit, - cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) - + device_id, owner_page, boot_log, boot_measurements, version = ot_aes.init( + fpga_mode_bit, cfg["test"]["core_config"], cfg["test"]["sensor_config"] + ) # Configure PRNGs. # Seed the software LFSR used for initial key masking and additionally # turning off the masking when '0'. ot_aes.seed_lfsr(cfg["test"]["lfsr_seed"].to_bytes(4, "little")) - # Seed the PRNG used for generating keys and plaintexts in batch mode. - if capture_cfg.batch_mode: - # Seed host's PRNG. - random.seed(cfg["test"]["batch_prng_seed"]) - # Seed the target's PRNG. - ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little")) - - return device_id + # Seed the PRNG used for generating keys and plaintexts, only useful for batch mode. + # Seed host's PRNG. + random.seed(cfg["test"]["batch_prng_seed"]) + # Seed the target's PRNG. + ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little")) + return device_id, owner_page, boot_log, boot_measurements, version -def generate_ref_crypto(sample_fixed, mode, key, plaintext): - """ Generate cipher material for the encryption. - This function derives the next key as well as the plaintext for the next - encryption. +def generate_ref_crypto( + sample_fixed, mode, fixed_key, fixed_plaintext, last_ciphertext +): + """Generate cipher material for the encryption. Args: - sample_fixed: Use fixed key or new key. + sample_fixed: Use the fixed or random bucket. mode: The mode of the capture. - key: The current key. - plaintext: The current plaintext. + fixed_key: The fixed key. + fixed_plaintext: The fixed plaintext. + last_ciphertext: The previous ciphertext. Returns: - plaintext: The next plaintext. - key: The next key. - ciphertext: The next ciphertext. + batch_plaintext: The plaintext used AES. + batch_key: The key used for the AES. + batch_ciphertext: The ciphertext used for the AES. + new_sample_fixed: The sample_fixed for the next experiment. """ + if mode == "aes_fvsr_key": - if sample_fixed: - plaintext, ciphertext, key = dg.get_fixed('FVSR_KEY') + if sample_fixed == 1: + batch_key = fixed_key else: - plaintext, ciphertext, key = dg.get_random('FVSR_KEY') + batch_key = [random.randint(0, 255) for _ in range(key_len)] + batch_plaintext = [random.randint(0, 255) for _ in range(plaintext_len)] + new_sample_fixed = random.randint(0, 255) & 0x1 elif mode == "aes_fvsr_data": - if sample_fixed: - plaintext, ciphertext, key = dg.get_fixed('FVSR_DATA') + if sample_fixed == 1: + batch_plaintext = fixed_plaintext else: - plaintext, ciphertext, key = dg.get_random('FVSR_DATA') + batch_plaintext = [random.randint(0, 255) for _ in range(plaintext_len)] + new_sample_fixed = random.randint(0, 255) & 0x1 + batch_key = fixed_key + elif mode == "aes_random": + batch_plaintext = [random.randint(0, 255) for _ in range(plaintext_len)] + batch_key = fixed_key + new_sample_fixed = 1 + elif mode == "daisy_chain": + batch_plaintext = last_ciphertext + batch_key = fixed_key + new_sample_fixed = 1 + elif mode == "single": + batch_plaintext = fixed_plaintext + batch_key = fixed_key + new_sample_fixed = 1 else: - if mode == "aes_random": - cipher = AES.new(bytes(key), AES.MODE_ECB) - ciphertext_bytes = cipher.encrypt(bytes(plaintext)) - ciphertext = [x for x in ciphertext_bytes] + logger.info("Error: Mode not recognized.") + return None, None, None, None + + cipher = AES.new(bytes(batch_key), AES.MODE_ECB) + ciphertext_bytes = cipher.encrypt(bytes(batch_plaintext)) + batch_ciphertext = [x for x in ciphertext_bytes] - return plaintext, key, ciphertext + return batch_plaintext, batch_key, batch_ciphertext, new_sample_fixed -def check_ciphertext(ot_aes, expected_last_ciphertext, ciphertext_len): - """ Compares the received with the generated ciphertext. +def check_ciphertext(target, expected_last_ciphertext): + """Compares the received with the generated ciphertext. Ciphertext is read from the device and compared against the pre-computed generated ciphertext. In batch mode, only the last ciphertext is compared. Asserts on mismatch. Args: - ot_aes: The OpenTitan AES communication interface. + target: The OpenTitan communication interface. expected_last_ciphertext: The pre-computed ciphertext. - ciphertext_len: The length of the ciphertext in bytes. """ - actual_last_ciphertext = ot_aes.read_ciphertext(ciphertext_len) - assert actual_last_ciphertext == expected_last_ciphertext[0:ciphertext_len], ( + actual_last_ciphertext_full = target.read_response() + actual_last_ciphertext_json = json.loads(actual_last_ciphertext_full) + actual_last_ciphertext = actual_last_ciphertext_json["ciphertext"] + assert actual_last_ciphertext == expected_last_ciphertext, ( f"Incorrect encryption result!\n" f"actual: {actual_last_ciphertext}\n" f"expected: {expected_last_ciphertext}" ) -def capture(scope: Scope, ot_aes: OTAES, capture_cfg: CaptureConfig, - project: SCAProject, target: Target): - """ Capture power consumption during AES encryption. +def capture( + scope: Scope, + ot_aes: OTAES, + capture_cfg: CaptureConfig, + project: SCAProject, + target: Target, +): + """Capture power consumption during AES encryption. Supports six different capture types: - * aes_random: Fixed key, random plaintext. - * aes_random_batch: Fixed key, random plaintext in batch mode. - * aes_fvsr_key: Fixed vs. random key. - * aes_fvsr_key_batch: Fixed vs. random key batch. - * aes_fvsr_data: Fixed vs. random data. - * aes_fvsr_data_batch: Fixed vs. random data batch. + * single: Fixed key, fixed plaintext. + * daisy_chain: Fixed key, ciphertext is the next plaintext (batched). + * aes_random: Fixed key, random plaintext (batched). + * aes_fvsr_key: Fixed vs. random key (batched). + * aes_fvsr_data: Fixed vs. random data (batched). Args: scope: The scope class representing a scope (Husky or WaveRunner). @@ -301,27 +335,8 @@ def capture(scope: Scope, ot_aes: OTAES, capture_cfg: CaptureConfig, # Load fixed key. key_fixed = capture_cfg.key_fixed key = key_fixed - logger.info(f"Initializing OT AES with key {binascii.b2a_hex(bytes(key))} ...") - if capture_cfg.capture_mode == "aes_fvsr_key": - dg.set_start('FVSR_KEY') - elif capture_cfg.capture_mode == "aes_fvsr_data": - dg.set_start('FVSR_DATA') - else: - ot_aes.key_set(key) - - # Generate plaintexts and keys for first batch. - if capture_cfg.batch_mode: - if capture_cfg.capture_mode == "aes_fvsr_key": - ot_aes.start_fvsr_batch_generate(1) - ot_aes.write_fvsr_batch_generate(capture_cfg.num_segments) - elif capture_cfg.capture_mode == "aes_fvsr_data": - ot_aes.start_fvsr_batch_generate(2) - elif capture_cfg.capture_mode == "aes_random": - ot_aes.batch_plaintext_set(text) - - # FVSR setup. - sample_fixed = 1 - prng_state = 0x99999999 + # Starting off at plaintext to capture daisy_chain behaviour + ciphertext = text # Optimization for CW trace library. num_segments_storage = 1 @@ -330,89 +345,62 @@ def capture(scope: Scope, ot_aes: OTAES, capture_cfg: CaptureConfig, signal.signal(signal.SIGINT, partial(abort_handler_during_loop, project)) # Main capture with progress bar. remaining_num_traces = capture_cfg.num_traces - with tqdm(total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces") as pbar: + with tqdm( + total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces" + ) as pbar: while remaining_num_traces > 0: # Arm the scope. - scope.arm() - - # Trigger encryption. - if capture_cfg.batch_mode: - # Batch mode. - if capture_cfg.capture_mode == "aes_random": - # Fixed key, random plaintexts. - ot_aes.batch_alternative_encrypt( - capture_cfg.num_segments) - elif capture_cfg.capture_mode == "aes_fvsr_key": - # Fixed vs random key test. - ot_aes.fvsr_key_batch_encrypt( - capture_cfg.num_segments) - else: - # Fixed vs random data test. - ot_aes.fvsr_data_batch_encrypt( - capture_cfg.num_segments) + if scope is not None: + scope.arm() + + if capture_cfg.capture_mode == "single": + ot_aes.single_encrypt(key_fixed, text_fixed) + elif capture_cfg.capture_mode == "daisy_chain": + text = ciphertext + ot_aes.batch_daisy_chain(capture_cfg.num_segments, key_fixed, text) + elif capture_cfg.capture_mode == "aes_random": + ot_aes.batch_random(capture_cfg.num_segments, key_fixed) + elif capture_cfg.capture_mode == "aes_fvsr_key": + ot_aes.batch_fvsr_key(capture_cfg.num_segments, key_fixed) + elif capture_cfg.capture_mode == "aes_fvsr_data": + ot_aes.batch_fvsr_data(capture_cfg.num_segments, key_fixed, text_fixed) else: - # Non batch mode. - if capture_cfg.capture_mode == "aes_fvsr_key" or \ - capture_cfg.capture_mode == "aes_fvsr_data": - # Generate reference crypto material for aes_fvsr_key in non-batch mode - text, key, ciphertext = generate_ref_crypto( - sample_fixed = sample_fixed, - mode = capture_cfg.capture_mode, - key = key, - plaintext = text - ) - if capture_cfg.capture_mode == "aes_fvsr_key": - sample_fixed = text[0] & 0x1 - else: - sample_fixed = prng_state & 0x1 - prng_state = prng_state >> 1 - if sample_fixed: - prng_state ^= 0x80000057 - ot_aes.key_set(key) - - ot_aes.single_encrypt(text) - - # Capture traces. - waves = scope.capture_and_transfer_waves(target) - assert waves.shape[0] == capture_cfg.num_segments - - # Generate reference crypto material for all modes other than aes_fvsr_key - # non-batch mode. - # Store traces + logger.info("Error: Mode not recognized.") + return + + # Capture and store traces + if scope is not None: + waves = scope.capture_and_transfer_waves(target) + assert waves.shape[0] == capture_cfg.num_segments + + # Generate reference crypto material + sample_fixed = 1 for i in range(capture_cfg.num_segments): - if capture_cfg.batch_mode or capture_cfg.capture_mode == "aes_random": - text, key, ciphertext = generate_ref_crypto( - sample_fixed = sample_fixed, - mode = capture_cfg.capture_mode, - key = key, - plaintext = text + text, key, ciphertext, sample_fixed = generate_ref_crypto( + sample_fixed=sample_fixed, + mode=capture_cfg.capture_mode, + fixed_key=key_fixed, + fixed_plaintext=text_fixed, + last_ciphertext=ciphertext, + ) + + if scope is not None: + # Sanity check retrieved data (wave). + assert len(waves[i, :]) >= 1 + # Store trace into database. + project.append_trace( + wave=waves[i, :], + plaintext=bytearray(text), + ciphertext=bytearray(ciphertext), + key=bytearray(key), ) - sample_fixed = text[0] & 0x1 - if capture_cfg.capture_mode == "aes_fvsr_data": - sample_fixed = prng_state & 0x1 - prng_state = prng_state >> 1 - if sample_fixed: - prng_state ^= 0x80000057 - - # Sanity check retrieved data (wave). - assert len(waves[i, :]) >= 1 - # Store trace into database. - project.append_trace(wave = waves[i, :], - plaintext = bytearray(text), - ciphertext = bytearray(ciphertext), - key = bytearray(key)) - - if capture_cfg.capture_mode == "aes_random": - # Use ciphertext as next text, first text is the initial - # one. Convert byte list into int list. - text = [x for x in ciphertext] # Compare received ciphertext with generated. - compare_len = capture_cfg.output_len - check_ciphertext(ot_aes, ciphertext, compare_len) + check_ciphertext(target, ciphertext) - # Memory allocation optimization for CW trace library. - num_segments_storage = project.optimize_capture(num_segments_storage) + if scope is not None: + # Memory allocation optimization for CW trace library. + num_segments_storage = project.optimize_capture(num_segments_storage) # Update the loop variable and the progress bar. remaining_num_traces -= capture_cfg.num_segments @@ -420,7 +408,7 @@ def capture(scope: Scope, ot_aes: OTAES, capture_cfg: CaptureConfig, def print_plot(project: SCAProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to adjust the scope gain and check for clipping. @@ -429,14 +417,18 @@ def print_plot(project: SCAProject, config: dict, file: Path) -> None: config: The capture configuration. file: The output file path. """ - if config["capture"]["show_plot"]: - plot.save_plot_to_file(project.get_waves(0, config["capture"]["plot_traces"]), - set_indices = None, - num_traces = config["capture"]["plot_traces"], - outfile = file, - add_mean_stddev=True) - logger.info(f'Created plot with {config["capture"]["plot_traces"]} traces: ' - f'{Path(str(file) + ".html").resolve()}') + if config["capture"]["show_plot"] and config["capture"]["scope_select"] != "none": + plot.save_plot_to_file( + project.get_waves(0, config["capture"]["plot_traces"]), + set_indices=None, + num_traces=config["capture"]["plot_traces"], + outfile=file, + add_mean_stddev=True, + ) + logger.info( + f'Created plot with {config["capture"]["plot_traces"]} traces: ' + f'{Path(str(file) + ".html").resolve()}' + ) def main(argv=None): @@ -448,42 +440,34 @@ def main(argv=None): # Parse the provided arguments. args = helpers.parse_arguments(argv) - # Check the ChipWhisperer version. - check_version.check_cw("5.7.0") - # Load configuration from file. with open(args.cfg) as f: cfg = yaml.load(f, Loader=yaml.FullLoader) - # Determine the capture mode and configure the current capture. - mode = "aes_fvsr_key" - if "aes_random" in cfg["test"]["which_test"]: - mode = "aes_random" - elif "data" in cfg["test"]["which_test"]: - mode = "aes_fvsr_data" - # Setup the target, scope and project. target, scope, project = setup(cfg, args.project) + if cfg["test"]["which_test"] == "single": + cfg["capture"]["num_segments"] = 1 + # Create capture config object. - capture_cfg = CaptureConfig(capture_mode = mode, - batch_mode = scope.scope_cfg.batch_mode, - num_traces = cfg["capture"]["num_traces"], - num_segments = scope.scope_cfg.num_segments, - output_len = cfg["target"]["output_len_bytes"], - text_fixed = cfg["test"]["text_fixed"], - key_fixed = cfg["test"]["key_fixed"], - key_len_bytes = cfg["test"]["key_len_bytes"], - text_len_bytes = cfg["test"]["text_len_bytes"], - protocol = cfg["target"]["protocol"], - port = cfg["target"].get("port")) - logger.info(f"Setting up capture {capture_cfg.capture_mode} batch={capture_cfg.batch_mode}...") + capture_cfg = CaptureConfig( + capture_mode=cfg["test"]["which_test"], + num_traces=cfg["capture"]["num_traces"], + num_segments=cfg["capture"]["num_segments"], + text_fixed=cfg["test"]["text_fixed"], + key_fixed=cfg["test"]["key_fixed"], + port=cfg["target"].get("port"), + ) + logger.info(f"Setting up capture {capture_cfg.capture_mode} ...") # Open communication with target. - ot_aes, ot_prng, ot_trig = establish_communication(target, capture_cfg) + ot_aes, ot_prng, ot_trig = establish_communication(target) # Configure cipher. - device_id = configure_cipher(cfg, capture_cfg, ot_aes, ot_prng) + device_id, owner_page, boot_log, boot_measurements, version = configure_cipher( + cfg, ot_aes, ot_prng + ) # Configure trigger source. # 0 for HW, 1 for SW. @@ -499,38 +483,47 @@ def main(argv=None): print_plot(project, cfg, args.project) # Save metadata. - metadata = {} - metadata["device_id"] = device_id - metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") - metadata["cfg"] = cfg - metadata["num_samples"] = scope.scope_cfg.num_samples - metadata["offset_samples"] = scope.scope_cfg.offset_samples - metadata["sampling_rate"] = scope.scope_cfg.sampling_rate - metadata["num_traces"] = capture_cfg.num_traces - metadata["scope_gain"] = scope.scope_cfg.scope_gain - metadata["cfg_file"] = str(args.cfg) - # Store bitstream information. - metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") - if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) - if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) - # Store binary information. - metadata["fw_bin_path"] = cfg["target"]["fw_bin"] - metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) - if args.save_binary: - metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) - # Store user provided notes. - metadata["notes"] = args.notes - # Store the Git hash. - metadata["git_hash"] = helpers.get_git_hash() - # Write metadata into project database. - project.write_metadata(metadata) - - # Finale the capture. - project.finalize_capture(capture_cfg.num_traces) - # Save and close project. - project.save() + if cfg["capture"]["scope_select"] != "none": + metadata = {} + metadata["device_id"] = device_id + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version + metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") + metadata["cfg"] = cfg + metadata["num_samples"] = scope.scope_cfg.num_samples + metadata["offset_samples"] = scope.scope_cfg.offset_samples + metadata["sampling_rate"] = scope.scope_cfg.sampling_rate + metadata["num_traces"] = capture_cfg.num_traces + metadata["scope_gain"] = scope.scope_cfg.scope_gain + metadata["cfg_file"] = str(args.cfg) + # Store bitstream information. + metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") + if cfg["target"].get("fpga_bitstream") is not None: + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) + if args.save_bitstream: + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) + # Store binary information. + metadata["fw_bin_path"] = cfg["target"]["fw_bin"] + metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) + if args.save_binary: + metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) + # Store user provided notes. + metadata["notes"] = args.notes + # Store the Git hash. + metadata["git_hash"] = helpers.get_git_hash() + # Write metadata into project database. + project.write_metadata(metadata) + + # Finalize the capture. + project.finalize_capture(capture_cfg.num_traces) + # Save and close project. + project.save() if __name__ == "__main__": diff --git a/capture/capture_hmac.py b/capture/capture_hmac.py index 7152de9d..52c5f755 100755 --- a/capture/capture_hmac.py +++ b/capture/capture_hmac.py @@ -7,6 +7,7 @@ # To be compatible to the other capture scripts, the variable is # called ciphertext +import json import logging import random import signal @@ -42,12 +43,16 @@ >>> ./capture_hmac.py -c configs/hmac_sca_cw310.yaml -p projects/hmac_sca_capture """ +# Byte lengths of the text, key, and tag. +text_length = 16 +key_length = 32 +tag_length = 32 logger = logging.getLogger() def abort_handler_during_loop(this_project, sig, frame): - """ Abort capture and store traces. + """Abort capture and store traces. Args: this_project: Project instance. @@ -60,26 +65,19 @@ def abort_handler_during_loop(this_project, sig, frame): @dataclass class CaptureConfig: - """ Configuration class for the current capture. - """ + """Configuration class for the current capture.""" + capture_mode: str - batch_mode: bool num_traces: int num_segments: int - output_len: int + text_fixed: list[int] key_fixed: list[int] - key_len_bytes: int - msg_len_bytes: int - protocol: str - start_trigger: bool - msg_trigger: bool - process_trigger: bool - finish_trigger: bool + trigger: int port: Optional[str] = "None" def setup(cfg: dict, project: Path): - """ Setup target, scope, and project. + """Setup target, scope, and project. Args: cfg: The configuration for the current experiment. @@ -91,76 +89,89 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + ) + + # Init scope. + scope_type = cfg["capture"]["scope_select"] + + # Check the ChipWhisperer version. + if scope_type == "husky": + check_version.check_cw("5.7.0") # Create target config & setup target. logger.info(f"Initializing target {cfg['target']['target_type']} ...") target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial"), - interface = cfg["target"].get("interface"), - husky_serial = cfg["husky"].get("usb_serial") + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], + pll_frequency=cfg["target"]["pll_frequency"], + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + interface=cfg["target"].get("interface"), + husky_serial = cfg["husky"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) target = Target(target_cfg) - # Init scope. - scope_type = cfg["capture"]["scope_select"] + if scope_type != "none": + # Determine sampling rate, if necessary. + cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) + # Convert number of cycles into number of samples, if necessary. + cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) + # Convert offset in cycles into offset in samples, if necessary. + cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) - # Determine sampling rate, if necessary. - cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) - # Convert number of cycles into number of samples, if necessary. - cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) - # Convert offset in cycles into offset in samples, if necessary. - cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) + logger.info( + f"Initializing scope {scope_type} with a sampling rate of \ + {cfg[scope_type]['sampling_rate']}..." + ) # noqa: E501 - logger.info(f"Initializing scope {scope_type} with a sampling rate of {cfg[scope_type]['sampling_rate']}...") # noqa: E501 - - # Determine if we are in batch mode or not. - batch = False - if "batch" in cfg["test"]["which_test"]: + # Determine if we are in batch mode or not. batch = True - - # Create scope config & setup scope. - scope_cfg = ScopeConfig( - scope_type = scope_type, - batch_mode = batch, - bit = cfg[scope_type].get("bit"), - acqu_channel = cfg[scope_type].get("channel"), - ip = cfg[scope_type].get("waverunner_ip"), - num_samples = cfg[scope_type]["num_samples"], - offset_samples = cfg[scope_type]["offset_samples"], - sampling_rate = cfg[scope_type].get("sampling_rate"), - num_segments = cfg[scope_type].get("num_segments"), - sparsing = cfg[scope_type].get("sparsing"), - scope_gain = cfg[scope_type].get("scope_gain"), - pll_frequency = cfg["target"]["pll_frequency"], - scope_sn = cfg[scope_type].get("usb_serial"), - ) - scope = Scope(scope_cfg) - - # Init project. - project_cfg = ProjectConfig(type = cfg["capture"]["trace_db"], - path = project, - wave_dtype = np.uint16, - overwrite = True, - trace_threshold = cfg["capture"].get("trace_threshold") - ) - project = SCAProject(project_cfg) - project.create_project() + if "singe" in cfg["test"]["which_test"]: + batch = False + + # Create scope config & setup scope. + scope_cfg = ScopeConfig( + scope_type=scope_type, + batch_mode=batch, + bit=cfg[scope_type].get("bit"), + acqu_channel=cfg[scope_type].get("channel"), + ip=cfg[scope_type].get("waverunner_ip"), + num_samples=cfg[scope_type]["num_samples"], + offset_samples=cfg[scope_type]["offset_samples"], + sampling_rate=cfg[scope_type].get("sampling_rate"), + num_segments=cfg["capture"].get("num_segments"), + sparsing=cfg[scope_type].get("sparsing"), + scope_gain=cfg[scope_type].get("scope_gain"), + pll_frequency=cfg["target"]["pll_frequency"], + scope_sn=cfg[scope_type].get("usb_serial"), + ) + scope = Scope(scope_cfg) + + # Init project. + project_cfg = ProjectConfig( + type=cfg["capture"]["trace_db"], + path=project, + wave_dtype=np.uint16, + overwrite=True, + trace_threshold=cfg["capture"].get("trace_threshold"), + ) + project = SCAProject(project_cfg) + project.create_project() + else: + scope = None + project = None return target, scope, project -def establish_communication(target, capture_cfg: CaptureConfig): - """ Establish communication with the target device. +def establish_communication(target): + """Establish communication with the target device. Args: target: The OT target. @@ -171,130 +182,129 @@ def establish_communication(target, capture_cfg: CaptureConfig): ot_prng: The communication interface to the PRNG SCA application. """ # Create communication interface to OT HMAC. - ot_hmac = OTHMAC(target=target, protocol=capture_cfg.protocol) + ot_hmac = OTHMAC(target=target) # Create communication interface to OT PRNG. - ot_prng = OTPRNG(target=target, protocol=capture_cfg.protocol) + ot_prng = OTPRNG(target=target) return ot_hmac, ot_prng -def configure_cipher(cfg, capture_cfg, ot_hmac, ot_prng): - """ Configure the HMAC cipher. +def configure_cipher(cfg, ot_hmac, ot_prng): + """Configure the HMAC cipher. Establish communication with the HMAC cipher and configure the seed. Args: cfg: The project config. - capture_cfg: The capture config. ot_hmac: The communication interface to the HMAC SCA application. ot_prng: The communication interface to the PRNG SCA application. Returns: device_id: The ID of the target device. + owner_page: The owner info page + boot_log: The boot log + boot_measurments: The boot measurements + version: The testOS version """ # Initialize HMAC on the target. - device_id = ot_hmac.init(cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + device_id, owner_page, boot_log, boot_measurements, version = ot_hmac.init( + cfg["test"]["core_config"], cfg["test"]["sensor_config"] + ) # Seed the PRNG used for generating keys and plaintexts in batch mode. - if capture_cfg.batch_mode: - # Seed host's PRNG. - random.seed(cfg["test"]["batch_prng_seed"]) - - # Seed the target's PRNG. - ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little")) + # Seed host's PRNG. + random.seed(cfg["test"]["batch_prng_seed"]) - return device_id + # Seed the target's PRNG. + ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little")) + return device_id, owner_page, boot_log, boot_measurements, version -def generate_ref_crypto(num_segments, mode, batch, key_fixed, key_length, msg_length): - """ Generate cipher material for the encryption. - This function derives the next key as well as the plaintext for the next - encryption. +def generate_ref_crypto(sample_fixed, mode, key_fixed, text_fixed, last_tag): + """Generate cipher material for the encryption. Args: - num_segments: The number of iterations in batch mode. + sample_fixed: Use the fixed or random bucket. mode: The mode of the capture. - batch: Batch or non-batch mode. - key_fixed: The fixed key for FVSR. - key_length: The length of the key. - msg_length: The length of the message. + key_fixed: The fixed key. + text_fixed: The fixed text. + last_tag: The previous tag. Returns: - msg: The next message. - key: The next key. - tag: The next tag. + batch_text: The text used. + batch_key: The key used. + batch_tag: The tag used. + new_sample_fixed: The sample_fixed for the next experiment. """ - # First sample is always fixed. - sample_fixed = True - # Arrays for storing num_segments crypto material. - key_array = [] - msg_array = [] - for it in range(0, num_segments): - if mode == "hmac_random": - # Generate random message and key. - key = [] - for i in range(0, key_length): - key.append(random.randint(0, 255)) - msg = [] - for i in range(0, msg_length): - msg.append(random.randint(0, 255)) + if mode == "single": + batch_text = text_fixed + batch_key = key_fixed + new_sample_fixed = 1 + elif mode == "random": + batch_key = [random.randint(0, 255) for _ in range(32)] + batch_text = [random.randint(0, 255) for _ in range(16)] + new_sample_fixed = 1 + elif mode == "data_fvsr": + if sample_fixed == 1: + batch_key = key_fixed else: - # Generate FvsR key and message. - if sample_fixed: - key = key_fixed - else: - key = [] - for i in range(0, key_length): - key.append(random.randint(0, 255)) - msg = [] - for i in range(0, msg_length): - msg.append(random.randint(0, 255)) - # The next sample is either fixed or random. - sample_fixed = msg[0] & 0x1 - # Generate expected tag for comparison. We only compare the last - # tag. - mac_fixed = HMAC.new(key=bytes(key), digestmod=SHA256) - mac_fixed.update(bytes(msg)) - tag = bytearray(mac_fixed.digest()) - # Append generated material to arrays. - key_array.append(key) - msg_array.append(msg) - - return msg_array, key_array, tag - - -def check_ciphertext(ot_hmac, expected_last_ciphertext): - """ Compares the received with the generated ciphertext. - - Ciphertext is read from the device and compared against the pre-computed - generated ciphertext. In batch mode, only the last ciphertext is compared. + batch_key = [random.randint(0, 255) for _ in range(32)] + batch_text = [random.randint(0, 255) for _ in range(16)] + new_sample_fixed = batch_text[0] & 0x1 + elif mode == "daisy_chain": + batch_text = last_tag + batch_key = key_fixed + new_sample_fixed = 1 + else: + logger.info("Error: Mode not recognized.") + return None, None, None, None + + # Generate expected tag for comparison. We only compare the last + # tag. + mac_fixed = HMAC.new(key=bytes(batch_key), digestmod=SHA256) + mac_fixed.update(bytes(batch_text)) + batch_tag_bytes = mac_fixed.digest() + batch_tag = [x for x in batch_tag_bytes] + + return batch_text, batch_key, batch_tag, new_sample_fixed + + +def check_tag(target, expected_last_tag): + """Compares the received with the generated tag. + + Tag is read from the device and compared against the pre-computed + generated tag. In batch mode, only the last tag is compared. Asserts on mismatch. Args: - ot_hmac: The OpenTitan HMAC communication interface. - expected_last_ciphertext: The pre-computed ciphertext. + target: The OpenTitan communication interface. + expected_last_tag: The pre-computed tag. """ - actual_last_ciphertext = bytearray(ot_hmac.read_tag()) - assert actual_last_ciphertext == expected_last_ciphertext, ( + actual_last_tag_full = target.read_response() + actual_last_tag_json = json.loads(actual_last_tag_full) + actual_last_tag = actual_last_tag_json["tag"] + assert actual_last_tag == expected_last_tag, ( f"Incorrect encryption result!\n" - f"actual: {actual_last_ciphertext}\n" - f"expected: {expected_last_ciphertext}" + f"actual: {actual_last_tag}\n" + f"expected: {expected_last_tag}" ) -def capture(scope: Scope, ot_hmac: OTHMAC, capture_cfg: CaptureConfig, - project: SCAProject, target: Target): - """ Capture power consumption during HMAC Tag computation. +def capture( + scope: Scope, + ot_hmac: OTHMAC, + capture_cfg: CaptureConfig, + project: SCAProject, + target: Target, +): + """Capture power consumption during HMAC Tag computation. Supports four different capture types: - * hmac_batch_random: Random key and message in batch mode. - * hmac_batch_fvsr: Fixed key, random plaintext in batch mode - * hmac_random: Random key and message. - * hmac_fvsr: Fixed key, random plaintext. + * single: Fixed key and fixed message. + * random: Random key and message. + * data_fvsr: Fixed key, random message. + * daisy_chain: Fixed key, chained message. Args: scope: The scope class representing a scope (Husky or WaveRunner). @@ -306,6 +316,15 @@ def capture(scope: Scope, ot_hmac: OTHMAC, capture_cfg: CaptureConfig, # Load fixed key. key_fixed = capture_cfg.key_fixed + # Load fixed message. + text_fixed = capture_cfg.text_fixed + + # Set the tag to text_fixed to start daisy_chaining correctly + tag = text_fixed + + # Load trigger. + trigger = capture_cfg.trigger + # Optimization for CW trace library. num_segments_storage = 1 @@ -313,52 +332,61 @@ def capture(scope: Scope, ot_hmac: OTHMAC, capture_cfg: CaptureConfig, signal.signal(signal.SIGINT, partial(abort_handler_during_loop, project)) # Main capture with progress bar. remaining_num_traces = capture_cfg.num_traces - with tqdm(total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces") as pbar: + with tqdm( + total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces" + ) as pbar: while remaining_num_traces > 0: # Arm the scope. - scope.arm() - - # Generate data for the HMAC test. - msg, key, tag_expected = generate_ref_crypto( - num_segments = capture_cfg.num_segments, - mode = capture_cfg.capture_mode, - batch = capture_cfg.batch_mode, - key_fixed = key_fixed, - key_length = capture_cfg.key_len_bytes, - msg_length = capture_cfg.msg_len_bytes) - - if capture_cfg.batch_mode: - if capture_cfg.capture_mode == "hmac_fvsr": - ot_hmac.fvsr_batch(key_fixed, capture_cfg.num_segments, - capture_cfg.start_trigger, capture_cfg.msg_trigger, - capture_cfg.process_trigger, capture_cfg.finish_trigger) - else: - ot_hmac.random_batch(capture_cfg.num_segments, capture_cfg.start_trigger, - capture_cfg.msg_trigger, capture_cfg.process_trigger, - capture_cfg.finish_trigger) + if scope is not None: + scope.arm() + + if capture_cfg.capture_mode == "single": + ot_hmac.single(text_fixed, key_fixed, trigger) + elif capture_cfg.capture_mode == "random": + ot_hmac.random_batch(capture_cfg.num_segments, trigger) + elif capture_cfg.capture_mode == "data_fvsr": + ot_hmac.fvsr_batch(key_fixed, capture_cfg.num_segments, trigger) + elif capture_cfg.capture_mode == "daisy_chain": + text = tag[:text_length] + ot_hmac.daisy_chain(text, key_fixed, capture_cfg.num_segments, trigger) else: - ot_hmac.single(msg[0], key[0], capture_cfg.start_trigger, capture_cfg.msg_trigger, - capture_cfg.process_trigger, capture_cfg.finish_trigger) - - # Capture traces. - waves = scope.capture_and_transfer_waves(target) - assert waves.shape[0] == capture_cfg.num_segments + logger.info("Error: Mode not recognized.") + return - # Compare received ciphertext with generated. - check_ciphertext(ot_hmac, tag_expected) + # Capture and store traces + if scope is not None: + waves = scope.capture_and_transfer_waves(target) + assert waves.shape[0] == capture_cfg.num_segments - # Store trace and crypto material into database. + # Generate data for the HMAC test. + sample_fixed = 1 for i in range(capture_cfg.num_segments): - # Sanity check retrieved data (wave). - assert len(waves[i, :]) >= 1 - # Store trace into database. - project.append_trace(wave = waves[i, :], - plaintext = bytearray(msg[i]), - ciphertext = bytearray(tag_expected[i]), - key = bytearray(key[i])) - - # Memory allocation optimization for CW trace library. - num_segments_storage = project.optimize_capture(num_segments_storage) + msg, key, tag, sample_fixed = generate_ref_crypto( + sample_fixed=sample_fixed, + mode=capture_cfg.capture_mode, + key_fixed=key_fixed, + text_fixed=text_fixed, + last_tag=tag, + ) + + if scope is not None: + # Store trace and crypto material into database. + # Sanity check retrieved data (wave). + assert len(waves[i, :]) >= 1 + # Store trace into database. + project.append_trace( + wave=waves[i, :], + plaintext=bytearray(msg), + ciphertext=bytearray(tag), + key=bytearray(key), + ) + + # Compare received tag with generated. + check_tag(target, tag) + + if scope is not None: + # Memory allocation optimization for CW trace library. + num_segments_storage = project.optimize_capture(num_segments_storage) # Update the loop variable and the progress bar. remaining_num_traces -= capture_cfg.num_segments @@ -366,7 +394,7 @@ def capture(scope: Scope, ot_hmac: OTHMAC, capture_cfg: CaptureConfig, def print_plot(project: SCAProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to adjust the scope gain and check for clipping. @@ -375,14 +403,18 @@ def print_plot(project: SCAProject, config: dict, file: Path) -> None: config: The capture configuration. file: The output file path. """ - if config["capture"]["show_plot"]: - plot.save_plot_to_file(project.get_waves(0, config["capture"]["plot_traces"]), - set_indices = None, - num_traces = config["capture"]["plot_traces"], - outfile = file, - add_mean_stddev=True) - logger.info(f'Created plot with {config["capture"]["plot_traces"]} traces: ' - f'{Path(str(file) + ".html").resolve()}') + if config["capture"]["show_plot"] and config["capture"]["scope_select"] != "none": + plot.save_plot_to_file( + project.get_waves(0, config["capture"]["plot_traces"]), + set_indices=None, + num_traces=config["capture"]["plot_traces"], + outfile=file, + add_mean_stddev=True, + ) + logger.info( + f'Created plot with {config["capture"]["plot_traces"]} traces: ' + f'{Path(str(file) + ".html").resolve()}' + ) def main(argv=None): @@ -394,43 +426,35 @@ def main(argv=None): # Parse the provided arguments. args = helpers.parse_arguments(argv) - # Check the ChipWhisperer version. - check_version.check_cw("5.7.0") - # Load configuration from file. with open(args.cfg) as f: cfg = yaml.load(f, Loader=yaml.FullLoader) - # Determine the capture mode and configure the current capture. - mode = "hmac_fvsr" - if "random" in cfg["test"]["which_test"]: - mode = "hmac_random" - # Setup the target, scope and project. target, scope, project = setup(cfg, args.project) + if cfg["test"]["which_test"] == "single": + cfg["capture"]["num_segments"] = 1 + # Create capture config object. - capture_cfg = CaptureConfig(capture_mode = mode, - batch_mode = scope.scope_cfg.batch_mode, - num_traces = cfg["capture"]["num_traces"], - num_segments = scope.scope_cfg.num_segments, - output_len = cfg["target"]["output_len_bytes"], - key_fixed = cfg["test"]["key_fixed"], - key_len_bytes = cfg["test"]["key_len_bytes"], - msg_len_bytes = cfg["test"]["msg_len_bytes"], - start_trigger = cfg["test"]["start_trigger"], - msg_trigger = cfg["test"]["msg_trigger"], - process_trigger = cfg["test"]["process_trigger"], - finish_trigger = cfg["test"]["finish_trigger"], - protocol = cfg["target"]["protocol"], - port = cfg["target"].get("port")) - logger.info(f"Setting up capture {capture_cfg.capture_mode} batch={capture_cfg.batch_mode}...") + capture_cfg = CaptureConfig( + capture_mode=cfg["test"]["which_test"], + num_traces=cfg["capture"]["num_traces"], + num_segments=cfg["capture"]["num_segments"], + text_fixed=cfg["test"]["text_fixed"], + key_fixed=cfg["test"]["key_fixed"], + trigger=cfg["test"]["trigger"], + port=cfg["target"].get("port"), + ) + logger.info(f"Setting up capture {capture_cfg.capture_mode} ...") # Open communication with target. - ot_hmac, ot_prng = establish_communication(target, capture_cfg) + ot_hmac, ot_prng = establish_communication(target) # Configure cipher. - device_id = configure_cipher(cfg, capture_cfg, ot_hmac, ot_prng) + device_id, owner_page, boot_log, boot_measurements, version = configure_cipher( + cfg, ot_hmac, ot_prng + ) # Capture traces. capture(scope, ot_hmac, capture_cfg, project, target) @@ -439,38 +463,47 @@ def main(argv=None): print_plot(project, cfg, args.project) # Save metadata. - metadata = {} - metadata["device_id"] = device_id - metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") - metadata["cfg"] = cfg - metadata["num_samples"] = scope.scope_cfg.num_samples - metadata["offset_samples"] = scope.scope_cfg.offset_samples - metadata["sampling_rate"] = scope.scope_cfg.sampling_rate - metadata["num_traces"] = capture_cfg.num_traces - metadata["scope_gain"] = scope.scope_cfg.scope_gain - metadata["cfg_file"] = str(args.cfg) - # Store bitstream information. - metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") - if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) - if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) - # Store binary information. - metadata["fw_bin_path"] = cfg["target"]["fw_bin"] - metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) - if args.save_binary: - metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) - # Store user provided notes. - metadata["notes"] = args.notes - # Store the Git hash. - metadata["git_hash"] = helpers.get_git_hash() - # Write metadata into project database. - project.write_metadata(metadata) - - # Finale the capture. - project.finalize_capture(capture_cfg.num_traces) - # Save and close project. - project.save() + if cfg["capture"]["scope_select"] != "none": + metadata = {} + metadata["device_id"] = device_id + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version + metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") + metadata["cfg"] = cfg + metadata["num_samples"] = scope.scope_cfg.num_samples + metadata["offset_samples"] = scope.scope_cfg.offset_samples + metadata["sampling_rate"] = scope.scope_cfg.sampling_rate + metadata["num_traces"] = capture_cfg.num_traces + metadata["scope_gain"] = scope.scope_cfg.scope_gain + metadata["cfg_file"] = str(args.cfg) + # Store bitstream information. + metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") + if cfg["target"].get("fpga_bitstream") is not None: + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) + if args.save_bitstream: + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) + # Store binary information. + metadata["fw_bin_path"] = cfg["target"]["fw_bin"] + metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) + if args.save_binary: + metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) + # Store user provided notes. + metadata["notes"] = args.notes + # Store the Git hash. + metadata["git_hash"] = helpers.get_git_hash() + # Write metadata into project database. + project.write_metadata(metadata) + + # Finalize the capture. + project.finalize_capture(capture_cfg.num_traces) + # Save and close project. + project.save() if __name__ == "__main__": diff --git a/capture/capture_ibex.py b/capture/capture_ibex.py index 574245e2..5e5ea086 100755 --- a/capture/capture_ibex.py +++ b/capture/capture_ibex.py @@ -3,6 +3,7 @@ # Licensed under the Apache License, Version 2.0, see LICENSE for details. # SPDX-License-Identifier: Apache-2.0 +import json import logging import random import signal @@ -40,7 +41,7 @@ def abort_handler_during_loop(this_project, sig, frame): - """ Abort capture and store traces. + """Abort capture and store traces. Args: this_project: Project instance. @@ -53,18 +54,19 @@ def abort_handler_during_loop(this_project, sig, frame): @dataclass class CaptureConfig: - """ Configuration class for the current capture. - """ + """Configuration class for the current capture.""" + test_mode: str num_traces: int num_segments: int - protocol: str + trigger: int + input_fixed: list[int] port: Optional[str] = "None" batch_prng_seed: Optional[str] = "None" def setup(cfg: dict, project: Path): - """ Setup target, scope, and project. + """Setup target, scope, and project. Args: cfg: The configuration for the current experiment. @@ -76,76 +78,89 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] - - # Create target config & setup target. - logger.info(f"Initializing target {cfg['target']['target_type']} ...") - target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial"), - interface = cfg["target"].get("interface"), - husky_serial = cfg["husky"].get("usb_serial") + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] ) - target = Target(target_cfg) # Init scope. scope_type = cfg["capture"]["scope_select"] - # Will determine sampling rate (for Husky only), if not given in cfg. - cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) - # Will convert number of cycles into number of samples if they are not given in cfg. - cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) - # Will convert offset in cycles into offset in samples, if they are not given in cfg. - cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) - - logger.info(f"Initializing scope {scope_type} with a sampling rate of {cfg[scope_type]['sampling_rate']}...") # noqa: E501 - - # Determine if we are in batch mode or not. - batch = False - if "batch" in cfg["test"]["which_test"]: - batch = True + # Check the ChipWhisperer version. + if scope_type == "husky": + check_version.check_cw("5.7.0") - # Create scope config & setup scope. - scope_cfg = ScopeConfig( - scope_type = scope_type, - batch_mode = batch, - bit = cfg[scope_type].get("bit"), - acqu_channel = cfg[scope_type].get("channel"), - ip = cfg[scope_type].get("waverunner_ip"), - num_samples = cfg[scope_type]["num_samples"], - offset_samples = cfg[scope_type]["offset_samples"], - sampling_rate = cfg[scope_type].get("sampling_rate"), - num_segments = cfg[scope_type].get("num_segments"), - sparsing = cfg[scope_type].get("sparsing"), - scope_gain = cfg[scope_type].get("scope_gain"), - pll_frequency = cfg["target"]["pll_frequency"], - scope_sn = cfg[scope_type].get("usb_serial"), + # Create target config & setup target. + logger.info(f"Initializing target {cfg['target']['target_type']} ...") + target_cfg = TargetConfig( + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], + pll_frequency=cfg["target"]["pll_frequency"], + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + interface=cfg["target"].get("interface"), + husky_serial = cfg["husky"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) - scope = Scope(scope_cfg) - - # Init project. - project_cfg = ProjectConfig(type = cfg["capture"]["trace_db"], - path = project, - wave_dtype = np.uint16, - overwrite = True, - trace_threshold = cfg["capture"].get("trace_threshold") - ) - project = SCAProject(project_cfg) - project.create_project() + target = Target(target_cfg) + + if scope_type != "none": + # Will determine sampling rate (for Husky only), if not given in cfg. + cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) + # Will convert number of cycles into number of samples if they are not given in cfg. + cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) + # Will convert offset in cycles into offset in samples, if they are not given in cfg. + cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) + + logger.info( + f"Initializing scope {scope_type} with a sampling rate of \ + {cfg[scope_type]['sampling_rate']}..." + ) # noqa: E501 + + # Determine if we are in batch mode or not. + batch = False + if "batch" in cfg["test"]["which_test"]: + batch = True + + # Create scope config & setup scope. + scope_cfg = ScopeConfig( + scope_type=scope_type, + batch_mode=batch, + bit=cfg[scope_type].get("bit"), + acqu_channel=cfg[scope_type].get("channel"), + ip=cfg[scope_type].get("waverunner_ip"), + num_samples=cfg[scope_type]["num_samples"], + offset_samples=cfg[scope_type]["offset_samples"], + sampling_rate=cfg[scope_type].get("sampling_rate"), + num_segments=cfg["capture"].get("num_segments"), + sparsing=cfg[scope_type].get("sparsing"), + scope_gain=cfg[scope_type].get("scope_gain"), + pll_frequency=cfg["target"]["pll_frequency"], + scope_sn=cfg[scope_type].get("usb_serial"), + ) + scope = Scope(scope_cfg) + + # Init project. + project_cfg = ProjectConfig( + type=cfg["capture"]["trace_db"], + path=project, + wave_dtype=np.uint16, + overwrite=True, + trace_threshold=cfg["capture"].get("trace_threshold"), + ) + project = SCAProject(project_cfg) + project.create_project() + else: + scope = None + project = None return target, scope, project -def establish_communication(target, capture_cfg: CaptureConfig): - """ Establish communication with the target device. +def establish_communication(target): + """Establish communication with the target device. Args: target: The OT target. @@ -157,48 +172,114 @@ def establish_communication(target, capture_cfg: CaptureConfig): ot_trig: The communication interface to the SCA trigger. """ # Create communication interface to OT Ibex. - ot_ibex = OTIbex(target=target, protocol=capture_cfg.protocol) + ot_ibex = OTIbex(target=target) # Create communication interface to OT PRNG. - ot_prng = OTPRNG(target=target, protocol=capture_cfg.protocol) + ot_prng = OTPRNG(target=target) # Create communication interface to SCA trigger. - ot_trig = OTTRIGGER(target=target, protocol=capture_cfg.protocol) + ot_trig = OTTRIGGER(target=target) return ot_ibex, ot_prng, ot_trig -def generate_data(test_mode, num_data): - """ Returns data used by the test. +def to_signed32(n_unsigned): + n_unsigned = n_unsigned & 0xFFFFFFFF + if n_unsigned >= 0x80000000: + return n_unsigned - 0x100000000 + return n_unsigned + + +def generate_combi_response(fixed_data1, fixed_data2, trigger): + """ + Returns the result of the combi test. + """ + xor = (0, fixed_data1 ^ fixed_data2)[trigger & 1] + add = (0, (fixed_data1 + fixed_data2) & 0xFFFFFFFF)[trigger & 2] + sub = (0, (fixed_data1 - fixed_data2) & 0xFFFFFFFF)[trigger & 4] + shift_operand = (fixed_data2 & 0xFFFFFFFF) % 32 + shift = (fixed_data1 << shift_operand) & 0xFFFFFFFF | ( + fixed_data1 >> (32 - shift_operand) & 0xFFFFFFFF + ) + shift = (0, shift)[trigger & 8] + mult = (0, (fixed_data1 * fixed_data2) & 0xFFFFFFFF)[trigger & 16] + if fixed_data2 == 0: + div = 0xFFFFFFFF + elif to_signed32(fixed_data1) == -2147483648 and to_signed32(fixed_data2) == -1: + div = 0x80000000 + else: + div = int(to_signed32(fixed_data1) / to_signed32(fixed_data2)) & 0xFFFFFFFF + div = (0, div)[trigger & 32] + + data = [ + xor, + add, + sub, + shift, + mult, + div, + (0, fixed_data1)[trigger & 64], + (0, fixed_data1)[trigger & 128], + (0, fixed_data2)[trigger & 256], + (0, fixed_data2)[trigger & 512], + (0, fixed_data2)[trigger & 1024], + (0, fixed_data2)[trigger & 2048], + ] + return data + + +def generate_ref_data(test_mode, fixed_data, num_segments): + """Returns data used by the test. Either a fixed dataset or a random one is generated. Returns: - data: The data set used for the test. - data_fixed: The fixed data set. + data1: The data set used for the test. + data2: The second data input for the combi test. """ - data = [] - data_fixed = 0xABBABABE + + data1 = [] # First sample is always fixed. sample_fixed = True - for i in range(num_data): + for _ in range(num_segments): if "fvsr" in test_mode: if sample_fixed: - data.append(data_fixed) + data1.append(fixed_data[0]) else: - data.append(random.getrandbits(32)) + data1.append(random.getrandbits(32)) sample_fixed = random.getrandbits(32) & 0x1 elif "random" in test_mode: - tmp = random.getrandbits(32) - data.append(tmp) + data1.append(random.getrandbits(32)) + elif "combi" in test_mode: + data1.append(fixed_data[0]) else: - raise RuntimeError("Error: Invalid test mode!") - return data, data_fixed + # The single test + data1.append(fixed_data) + + data2 = [] + if "combi" in test_mode: + sample_fixed = True + for _ in range(num_segments): + if "fvsr" in test_mode: + if sample_fixed: + data2.append(fixed_data[1]) + else: + data2.append(random.getrandbits(32)) + sample_fixed = random.getrandbits(32) & 0x1 + else: + data2.append(fixed_data[1]) + return data1, data2 -def capture(scope: Scope, ot_ibex: OTIbex, ot_prng: OTPRNG, - capture_cfg: CaptureConfig, project: SCAProject, target: Target): - """ Capture power consumption during execution of Ibex SCA penetration tests. +def capture( + scope: Scope, + ot_ibex: OTIbex, + ot_prng: OTPRNG, + capture_cfg: CaptureConfig, + project: SCAProject, + target: Target, +): + """Capture power consumption during execution of Ibex SCA penetration tests. Supports the following captures: * ibex.sca.register_file_read: Read data from registers. @@ -217,84 +298,128 @@ def capture(scope: Scope, ot_ibex: OTIbex, ot_prng: OTPRNG, # Optimization for CW trace library. num_segments_storage = 1 + # Check whether we are in batch mode. + batch = False + if ( + "batch" in capture_cfg.test_mode or + "fvsr" in capture_cfg.test_mode or + "random" in capture_cfg.test_mode + ): + batch = True + # Seed the PRNG used for generating random data. - if "batch" in capture_cfg.test_mode: - # Seed host's PRNG. - random.seed(capture_cfg.batch_prng_seed) + # Seed host's PRNG. + random.seed(capture_cfg.batch_prng_seed) - # Seed the target's PRNG. - ot_prng.seed_prng(capture_cfg.batch_prng_seed.to_bytes(4, "little")) + # Seed the target's PRNG. + ot_prng.seed_prng(capture_cfg.batch_prng_seed.to_bytes(4, "little")) # Register ctrl-c handler to store traces on abort. signal.signal(signal.SIGINT, partial(abort_handler_during_loop, project)) # Main capture with progress bar. remaining_num_traces = capture_cfg.num_traces - with tqdm(total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces") as pbar: + with tqdm( + total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces" + ) as pbar: while remaining_num_traces > 0: # Arm the scope. - scope.arm() - if "batch" in capture_cfg.test_mode: - num_data = capture_cfg.num_segments - else: - # In non-batch mode, 8 uint32 values are used. - num_data = 8 - # Generate data set used for the test. - data, data_fixed = generate_data(capture_cfg.test_mode, num_data) + if scope is not None: + scope.arm() + # Start the test based on the mode. - if "batch" in capture_cfg.test_mode: - if "fvsr" in capture_cfg.test_mode: + if batch: + if "combi" in capture_cfg.test_mode: + # For the combi test, we need to provide the trigger and + # two inputs of fixed data. + ot_ibex.start_test( + capture_cfg.test_mode, + capture_cfg.num_segments, + capture_cfg.trigger, + capture_cfg.input_fixed[0], + capture_cfg.input_fixed[1], + ) + elif "fvsr" in capture_cfg.test_mode: # In FvsR batch, the fixed dataset and the number of segments # is transferred to the device. The rest of the dataset is # generated on the device. Trigger is set number of segments. - ot_ibex.start_test(capture_cfg.test_mode, data_fixed, capture_cfg.num_segments) - elif "random" in capture_cfg.test_mode: - # In Random batch, number of segments is transferred to the + ot_ibex.start_test( + capture_cfg.test_mode, + capture_cfg.input_fixed[0], + capture_cfg.num_segments, + ) + else: + # In random batch, number of segments is transferred to the # device. number of segments random datasets are generated # on the device. Trigger is set number of segments. - ot_ibex.start_test(capture_cfg.test_mode, - capture_cfg.num_segments) + ot_ibex.start_test(capture_cfg.test_mode, capture_cfg.num_segments) else: - # In the non-batch mode, the dataset is generated in ot-sca and - # transferred to the device. Trigger is set once. - ot_ibex.start_test(capture_cfg.test_mode, data) + # We use fixed data. + ot_ibex.start_test(capture_cfg.test_mode, capture_cfg.input_fixed) # Capture traces. - waves = scope.capture_and_transfer_waves(target) - assert waves.shape[0] == capture_cfg.num_segments + if scope is not None: + waves = scope.capture_and_transfer_waves(target) + assert waves.shape[0] == capture_cfg.num_segments - response = ot_ibex.ibex_sca_read_response() - # Check response. 0 for non-batch and the last data element in - # batch mode. - if "batch" in capture_cfg.test_mode: - assert response == data[-1] - else: - assert response == 0 + response_full = target.read_response() + response_json = json.loads(response_full) + response = response_json["result"] + + # Generate data set used for the test. + data1, data2 = generate_ref_data( + capture_cfg.test_mode, capture_cfg.input_fixed, capture_cfg.num_segments + ) # Store traces. - if "batch" in capture_cfg.test_mode: + if scope is not None: for i in range(capture_cfg.num_segments): # Sanity check retrieved data (wave). assert len(waves[i, :]) >= 1 # Store trace into database. - project.append_trace(wave = waves[i, :], - plaintext = data[i].to_bytes(4, 'little'), - ciphertext = None, - key = None) - else: - # Convert data into bytearray for storage in database. - data_bytes = [] - for d in data: - data_bytes.append(d.to_bytes(4, "little")) - # Sanity check retrieved data (wave). - assert len(waves[0, :]) >= 1 - # Store trace into database. - project.append_trace(wave = waves[0, :], - plaintext = b''.join(data_bytes), - ciphertext = None, - key = None) + if "combi" in capture_cfg.test_mode: + project.append_trace( + wave=waves[i, :], + plaintext=data1[i].to_bytes(4, "little"), + ciphertext=data2[i].to_bytes(4, "little"), + key=None, + ) + else: + project.append_trace( + wave=waves[i, :], + plaintext=data1[i].to_bytes(4, "little"), + ciphertext=None, + key=None, + ) # Memory allocation optimization for CW trace library. - num_segments_storage = project.optimize_capture(num_segments_storage) + if scope is not None: + num_segments_storage = project.optimize_capture(num_segments_storage) + + # Check response. 0 for non-batch and the last data element in + # batch mode. + # For the combi test, we generate the output specifically + if batch: + if "combi" in capture_cfg.test_mode: + expected_response = generate_combi_response( + data1[-1], data2[-1], capture_cfg.trigger + ) + assert response == expected_response, ( + f"Incorrect encryption result!\n" + f"actual: {response}\n" + f"expected: {expected_response}" + ) + else: + assert response == data1[-1], ( + f"Incorrect encryption result!\n" + f"actual: {response}\n" + f"expected: {data1[-1]}" + ) + else: + assert response == 0, ( + f"Incorrect encryption result!\n" + f"actual: {response}\n" + f"expected: {0}" + ) # Update the loop variable and the progress bar. remaining_num_traces -= capture_cfg.num_segments @@ -302,7 +427,7 @@ def capture(scope: Scope, ot_ibex: OTIbex, ot_prng: OTPRNG, def print_plot(project: SCAProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to adjust the scope gain and check for clipping. @@ -311,14 +436,18 @@ def print_plot(project: SCAProject, config: dict, file: Path) -> None: config: The capture configuration. file: The output file path. """ - if config["capture"]["show_plot"]: - plot.save_plot_to_file(project.get_waves(0, config["capture"]["plot_traces"]), - set_indices = None, - num_traces = config["capture"]["plot_traces"], - outfile = file, - add_mean_stddev=True) - logger.info(f'Created plot with {config["capture"]["plot_traces"]} traces: ' - f'{Path(str(file) + ".html").resolve()}') + if config["capture"]["show_plot"] and config["capture"]["scope_select"] != "none": + plot.save_plot_to_file( + project.get_waves(0, config["capture"]["plot_traces"]), + set_indices=None, + num_traces=config["capture"]["plot_traces"], + outfile=file, + add_mean_stddev=True, + ) + logger.info( + f'Created plot with {config["capture"]["plot_traces"]} traces: ' + f'{Path(str(file) + ".html").resolve()}' + ) def main(argv=None): @@ -330,9 +459,6 @@ def main(argv=None): # Parse the provided arguments. args = helpers.parse_arguments(argv) - # Check the ChipWhisperer version. - check_version.check_cw("5.7.0") - # Load configuration from file. with open(args.cfg) as f: cfg = yaml.load(f, Loader=yaml.FullLoader) @@ -340,26 +466,35 @@ def main(argv=None): # Setup the target, scope and project. target, scope, project = setup(cfg, args.project) + if not ( + "batch" in cfg["test"]["which_test"] or + "fvsr" in cfg["test"]["which_test"] or + "random" in cfg["test"]["which_test"] + ): + cfg["capture"]["num_segments"] = 1 + # Create capture config object. - capture_cfg = CaptureConfig(test_mode = cfg["test"]["which_test"], - num_traces = cfg["capture"]["num_traces"], - num_segments = scope.scope_cfg.num_segments, - protocol = cfg["target"]["protocol"], - port = cfg["target"].get("port"), - batch_prng_seed = cfg["test"].get("batch_prng_seed")) + capture_cfg = CaptureConfig( + test_mode=cfg["test"]["which_test"], + num_traces=cfg["capture"]["num_traces"], + num_segments=cfg["capture"]["num_segments"], + trigger=cfg["test"]["trigger"], + input_fixed=cfg["test"]["input_fixed"], + port=cfg["target"].get("port"), + batch_prng_seed=cfg["test"].get("batch_prng_seed"), + ) logger.info(f"Setting up capture {capture_cfg.test_mode}...") # Open communication with target. - ot_ibex, ot_prng, ot_trig = establish_communication(target, capture_cfg) + ot_ibex, ot_prng, ot_trig = establish_communication(target) # Configure SW trigger. ot_trig.select_trigger(1) - # Init the pentest framework and read the device ID. - device_id = ot_ibex.init(cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + # Init the pentest framework and read the target info. + device_id, owner_page, boot_log, boot_measurements, version = ot_ibex.init( + cfg["test"]["core_config"], cfg["test"]["sensor_config"] + ) # Capture traces. capture(scope, ot_ibex, ot_prng, capture_cfg, project, target) @@ -367,38 +502,51 @@ def main(argv=None): print_plot(project, cfg, args.project) # Save metadata. - metadata = {} - metadata["device_id"] = device_id - metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") - metadata["cfg"] = cfg - metadata["num_samples"] = scope.scope_cfg.num_samples - metadata["offset_samples"] = scope.scope_cfg.offset_samples - metadata["sampling_rate"] = scope.scope_cfg.sampling_rate - metadata["num_traces"] = capture_cfg.num_traces - metadata["scope_gain"] = scope.scope_cfg.scope_gain - metadata["cfg_file"] = str(args.cfg) - # Store bitstream information. - metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") - if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) - if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) - # Store binary information. - metadata["fw_bin_path"] = cfg["target"]["fw_bin"] - metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) - if args.save_binary: - metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) - # Store user provided notes. - metadata["notes"] = args.notes - # Store the Git hash. - metadata["git_hash"] = helpers.get_git_hash() - # Write metadata into project database. - project.write_metadata(metadata) - - # Finale the capture. - project.finalize_capture(capture_cfg.num_traces) - # Save and close project. - project.save() + if cfg["capture"]["scope_select"] != "none": + metadata = {} + metadata["device_id"] = device_id + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version + metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") + metadata["cfg"] = cfg + metadata["num_samples"] = scope.scope_cfg.num_samples + metadata["offset_samples"] = scope.scope_cfg.offset_samples + metadata["sampling_rate"] = scope.scope_cfg.sampling_rate + metadata["num_traces"] = capture_cfg.num_traces + metadata["scope_gain"] = scope.scope_cfg.scope_gain + metadata["cfg_file"] = str(args.cfg) + # Store bitstream information. + metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") + if cfg["target"].get("fpga_bitstream") is not None: + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) + if args.save_bitstream: + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) + # Store binary information. + metadata["fw_bin_path"] = cfg["target"]["fw_bin"] + metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) + if args.save_binary: + metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) + # Store user provided notes. + metadata["notes"] = args.notes + # Store the Git hash. + metadata["git_hash"] = helpers.get_git_hash() + # Write metadata into project database. + project.write_metadata(metadata) + + # Finalize the capture. + project.finalize_capture(capture_cfg.num_traces) + # Save and close project. + project.save() if __name__ == "__main__": diff --git a/capture/capture_kmac.py b/capture/capture_kmac.py index 310d0d19..b78fbed6 100755 --- a/capture/capture_kmac.py +++ b/capture/capture_kmac.py @@ -8,6 +8,7 @@ # called ciphertext import binascii +import json import logging import random import signal @@ -31,9 +32,7 @@ from target.communication.sca_prng_commands import OTPRNG from target.communication.sca_trigger_commands import OTTRIGGER from target.targets import Target, TargetConfig -from util import check_version -from util import data_generator as dg -from util import plot +from util import check_version, plot """KMAC SCA capture script. @@ -46,12 +45,16 @@ >>> ./capture_kmac.py -c configs/kmac_sca_cw310.yaml -p projects/kmac_sca_capture """ +# Byte lengths of the text, key, and tag. +text_length = 16 +key_length = 16 +tag_length = 32 logger = logging.getLogger() def abort_handler_during_loop(this_project, sig, frame): - """ Abort capture and store traces. + """Abort capture and store traces. Args: this_project: Project instance. @@ -64,23 +67,18 @@ def abort_handler_during_loop(this_project, sig, frame): @dataclass class CaptureConfig: - """ Configuration class for the current capture. - """ + """Configuration class for the current capture.""" + capture_mode: str - batch_mode: bool num_traces: int num_segments: int - output_len: int text_fixed: bytearray key_fixed: bytearray - key_len_bytes: int - text_len_bytes: int - protocol: str port: Optional[str] = "None" def setup(cfg: dict, project: Path): - """ Setup target, scope, and project. + """Setup target, scope, and project. Args: cfg: The configuration for the current experiment. @@ -92,76 +90,92 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + ) + + # Init scope. + scope_type = cfg["capture"]["scope_select"] + + # Check the ChipWhisperer version. + if scope_type == "husky": + check_version.check_cw("5.7.0") # Create target config & setup target. logger.info(f"Initializing target {cfg['target']['target_type']} ...") target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial"), - interface = cfg["target"].get("interface"), - husky_serial = cfg["husky"].get("usb_serial") + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], + pll_frequency=cfg["target"]["pll_frequency"], + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + interface=cfg["target"].get("interface"), + husky_serial = cfg["husky"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) target = Target(target_cfg) - # Init scope. - scope_type = cfg["capture"]["scope_select"] + if scope_type != "none": + # Init scope. + scope_type = cfg["capture"]["scope_select"] - # Determine sampling rate, if necessary. - cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) - # Convert number of cycles into number of samples, if necessary. - cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) - # Convert offset in cycles into offset in samples, if necessary. - cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) + # Determine sampling rate, if necessary. + cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) + # Convert number of cycles into number of samples, if necessary. + cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) + # Convert offset in cycles into offset in samples, if necessary. + cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) - logger.info(f"Initializing scope {scope_type} with a sampling rate of {cfg[scope_type]['sampling_rate']}...") # noqa: E501 + logger.info( + f"Initializing scope {scope_type} with a sampling rate of \ + {cfg[scope_type]['sampling_rate']}..." + ) # noqa: E501 - # Determine if we are in batch mode or not. - batch = False - if "batch" in cfg["test"]["which_test"]: + # Determine if we are in batch mode or not. batch = True - - # Create scope config & setup scope. - scope_cfg = ScopeConfig( - scope_type = scope_type, - batch_mode = batch, - bit = cfg[scope_type].get("bit"), - acqu_channel = cfg[scope_type].get("channel"), - ip = cfg[scope_type].get("waverunner_ip"), - num_samples = cfg[scope_type]["num_samples"], - offset_samples = cfg[scope_type]["offset_samples"], - sampling_rate = cfg[scope_type].get("sampling_rate"), - num_segments = cfg[scope_type].get("num_segments"), - sparsing = cfg[scope_type].get("sparsing"), - scope_gain = cfg[scope_type].get("scope_gain"), - pll_frequency = cfg["target"]["pll_frequency"], - scope_sn = cfg[scope_type].get("usb_serial"), - ) - scope = Scope(scope_cfg) - - # Init project. - project_cfg = ProjectConfig(type = cfg["capture"]["trace_db"], - path = project, - wave_dtype = np.uint16, - overwrite = True, - trace_threshold = cfg["capture"].get("trace_threshold") - ) - project = SCAProject(project_cfg) - project.create_project() + if "single" in cfg["test"]["which_test"]: + batch = False + + # Create scope config & setup scope. + scope_cfg = ScopeConfig( + scope_type=scope_type, + batch_mode=batch, + bit=cfg[scope_type].get("bit"), + acqu_channel=cfg[scope_type].get("channel"), + ip=cfg[scope_type].get("waverunner_ip"), + num_samples=cfg[scope_type]["num_samples"], + offset_samples=cfg[scope_type]["offset_samples"], + sampling_rate=cfg[scope_type].get("sampling_rate"), + num_segments=cfg["capture"].get("num_segments"), + sparsing=cfg[scope_type].get("sparsing"), + scope_gain=cfg[scope_type].get("scope_gain"), + pll_frequency=cfg["target"]["pll_frequency"], + scope_sn=cfg[scope_type].get("usb_serial"), + ) + scope = Scope(scope_cfg) + + # Init project. + project_cfg = ProjectConfig( + type=cfg["capture"]["trace_db"], + path=project, + wave_dtype=np.uint16, + overwrite=True, + trace_threshold=cfg["capture"].get("trace_threshold"), + ) + project = SCAProject(project_cfg) + project.create_project() + else: + scope = None + project = None return target, scope, project -def establish_communication(target, capture_cfg: CaptureConfig): - """ Establish communication with the target device. +def establish_communication(target): + """Establish communication with the target device. Args: target: The OT target. @@ -173,29 +187,32 @@ def establish_communication(target, capture_cfg: CaptureConfig): ot_trig: The communication interface to the SCA trigger. """ # Create communication interface to OT KMAC. - ot_kmac = OTKMAC(target=target, protocol=capture_cfg.protocol) + ot_kmac = OTKMAC(target=target) # Create communication interface to OT PRNG. - ot_prng = OTPRNG(target=target, protocol=capture_cfg.protocol) + ot_prng = OTPRNG(target=target) # Create communication interface to SCA trigger. - ot_trig = OTTRIGGER(target=target, protocol=capture_cfg.protocol) + ot_trig = OTTRIGGER(target=target) return ot_kmac, ot_prng, ot_trig -def configure_cipher(cfg, capture_cfg, ot_kmac, ot_prng): - """ Configure the KMAC cipher. +def configure_cipher(cfg, ot_kmac, ot_prng): + """Configure the KMAC cipher. Establish communication with the KMAC cipher and configure the seed. Args: cfg: The project config. - capture_cfg: The capture config. ot_kmac: The communication interface to the KMAC SCA application. ot_prng: The communication interface to the PRNG SCA application. Returns: device_id: The ID of the target device. + owner_page: The owner info page + boot_log: The boot log + boot_measurments: The boot measurements + version: The testOS version """ # Check if we want to run KMAC SCA for FPGA or discrete. On the FPGA, we # can use functionality helping us to capture cleaner traces. @@ -203,118 +220,103 @@ def configure_cipher(cfg, capture_cfg, ot_kmac, ot_prng): if "cw" in cfg["target"]["target_type"]: fpga_mode_bit = 1 # Initialize KMAC on the target. - device_id = ot_kmac.init(fpga_mode_bit, - cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + device_id, owner_page, boot_log, boot_measurements, version = ot_kmac.init( + fpga_mode_bit, cfg["test"]["core_config"], cfg["test"]["sensor_config"] + ) # Configure PRNGs. # Seed the software LFSR used for initial key masking. ot_kmac.write_lfsr_seed(cfg["test"]["lfsr_seed"].to_bytes(4, "little")) # Seed the PRNG used for generating keys and plaintexts in batch mode. - if capture_cfg.batch_mode: - # Seed host's PRNG. - random.seed(cfg["test"]["batch_prng_seed"]) + # Seed host's PRNG. + random.seed(cfg["test"]["batch_prng_seed"]) - # Seed the target's PRNG. - ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little")) - return device_id + # Seed the target's PRNG. + ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little")) + return device_id, owner_page, boot_log, boot_measurements, version -def generate_ref_crypto(sample_fixed, mode, batch, key, key_fixed, plaintext, - plaintext_fixed, key_length): - """ Generate cipher material for the encryption. - - This function derives the next key as well as the plaintext for the next - encryption. +def generate_ref_crypto(sample_fixed, mode, key_fixed, text_fixed, last_tag): + """Generate cipher material for the encryption. Args: - sample_fixed: Use fixed key or new key. + sample_fixed: Use the fixed or random bucket. mode: The mode of the capture. - batch: Batch or non-batch mode. - key: The current key. - key_fixed: The fixed key for FVSR. - plaintext: The current plaintext. - plaintext_fixed: The fixed plaintext for FVSR. - key_length: Th length of the key. + key_fixed: The fixed key. + text_fixed: The fixed text. + last_tag: The previous tag. Returns: - plaintext: The next plaintext. - key: The next key. - ciphertext: The next ciphertext. - sample_fixed: Is the next sample fixed or not? + batch_text: The text used. + batch_key: The key used. + batch_tag: The tag used. + new_sample_fixed: The sample_fixed for the next experiment. """ - if mode == "kmac_fvsr_key" and not batch: - # returns a pt, ct, key tripple - # does only need the sample_fixed argument - if sample_fixed: - # Expected ciphertext. - plaintext, ciphertext, key = dg.get_kmac_fixed() + if mode == "single": + batch_text = text_fixed + batch_key = key_fixed + new_sample_fixed = 1 + elif mode == "fvsr_key": + if sample_fixed == 1: + batch_key = key_fixed else: - plaintext, ciphertext, key = dg.get_kmac_random() - # The next sample is either fixed or random. - sample_fixed = plaintext[0] & 0x1 + batch_key = [random.randint(0, 255) for _ in range(16)] + batch_text = [random.randint(0, 255) for _ in range(16)] + new_sample_fixed = batch_text[0] & 0x1 + elif mode == "daisy_chain": + batch_text = last_tag[:text_length] + batch_key = key_fixed + new_sample_fixed = 1 else: - if mode == "kmac_random": - # returns pt, ct, key, needs key and pt as arguments - mac = KMAC128.new(key=bytes(key), mac_len=32) - mac.update(bytes(plaintext)) - ciphertext_bytes = mac.digest() - ciphertext = [x for x in ciphertext_bytes] - else: - # returns random pt, ct, key, needs no arguments - if sample_fixed: - # Use fixed_key as this key. - key = key_fixed - else: - # Generate this key from the PRNG. - key = [] - for i in range(0, key_length): - key.append(random.randint(0, 255)) - # Always generate this plaintext from PRNG (including very first one). - plaintext = [] - for i in range(0, 16): - plaintext.append(random.randint(0, 255)) - # Compute ciphertext for this key and plaintext. - mac = KMAC128.new(key=bytes(key), mac_len=32) - mac.update(bytes(plaintext)) - ciphertext_bytes = mac.digest() - ciphertext = [x for x in ciphertext_bytes] - # Determine if next iteration uses fixed_key. - sample_fixed = plaintext[0] & 0x1 - return plaintext, key, ciphertext, sample_fixed - - -def check_ciphertext(ot_kmac, expected_last_ciphertext, ciphertext_len): - """ Compares the received with the generated ciphertext. - - Ciphertext is read from the device and compared against the pre-computed - generated ciphertext. In batch mode, only the last ciphertext is compared. - Asserts on mismatch. + logger.info("Error: Mode not recognized.") + return None, None, None, None + + mac = KMAC128.new(key=bytes(batch_key), mac_len=32) + mac.update(bytes(batch_text)) + tag_bytes = mac.digest() + batch_tag = [x for x in tag_bytes] + return batch_text, batch_key, batch_tag, new_sample_fixed + + +def check_tag(target, expected_last_tag, capture_cfg): + """Compares the received with the generated tag. + + Tag is read from the device and compared against the pre-computed + generated tag. Args: - ot_kmac: The OpenTitan KMAC communication interface. - expected_last_ciphertext: The pre-computed ciphertext. - ciphertext_len: The length of the ciphertext in bytes. + target: The OpenTitan communication interface. + expected_last_tag: The pre-computed tag. """ - actual_last_ciphertext = ot_kmac.read_ciphertext(ciphertext_len) - assert actual_last_ciphertext == expected_last_ciphertext[0:ciphertext_len], ( + + expected_key = "batch_digest" + if capture_cfg.capture_mode == "daisy_chain": + expected_key = "digest" + + actual_last_tag_full = target.read_response() + actual_last_tag_json = json.loads(actual_last_tag_full) + actual_last_tag = actual_last_tag_json[expected_key] + assert actual_last_tag == expected_last_tag, ( f"Incorrect encryption result!\n" - f"actual: {actual_last_ciphertext}\n" - f"expected: {expected_last_ciphertext}" + f"actual: {actual_last_tag}\n" + f"expected: {expected_last_tag}" ) -def capture(scope: Scope, ot_kmac: OTKMAC, capture_cfg: CaptureConfig, - project: SCAProject, target: Target): - """ Capture power consumption during KMAC Tag computation. +def capture( + scope: Scope, + ot_kmac: OTKMAC, + capture_cfg: CaptureConfig, + project: SCAProject, + target: Target, +): + """Capture power consumption during KMAC Tag computation. Supports four different capture types: - * kmac_random: Fixed key, random plaintext. - * kmac_fvsr: Fixed vs. random key. - * kmac_fvsr_batch: Fixed vs. random key batch. + * single: Fixed key, fixed message. + * fvsr_key: Fixed vs. random key. + * daisy_chain: chained message input, fixed key. Args: scope: The scope class representing a scope (Husky or WaveRunner). @@ -330,13 +332,16 @@ def capture(scope: Scope, ot_kmac: OTKMAC, capture_cfg: CaptureConfig, key_fixed = capture_cfg.key_fixed key = key_fixed + # Set the tag to text_fixed to start daisy_chaining correctly + tag = text_fixed + # FVSR setup. # in the kmac_serial.c: `static bool run_fixed = false;` # we should adjust this throughout all scripts. sample_fixed = 0 logger.info(f"Initializing OT KMAC with key {binascii.b2a_hex(bytes(key))} ...") - if capture_cfg.capture_mode == "kmac_fvsr_key": + if capture_cfg.capture_mode == "fvsr_key": ot_kmac.fvsr_key_set(key) else: ot_kmac.write_key(key) @@ -348,77 +353,65 @@ def capture(scope: Scope, ot_kmac: OTKMAC, capture_cfg: CaptureConfig, signal.signal(signal.SIGINT, partial(abort_handler_during_loop, project)) # Main capture with progress bar. remaining_num_traces = capture_cfg.num_traces - with tqdm(total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces") as pbar: + with tqdm( + total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces" + ) as pbar: while remaining_num_traces > 0: # Arm the scope. - scope.arm() - - # Trigger encryption. - if capture_cfg.batch_mode: - # Batch mode. Is always kmac_fvsr_key - ot_kmac.absorb_batch( - capture_cfg.num_segments) + if scope is not None: + scope.arm() + + if capture_cfg.capture_mode == "single": + ot_kmac.absorb(text_fixed) + elif capture_cfg.capture_mode == "fvsr_key": + ot_kmac.absorb_batch(capture_cfg.num_segments) + elif capture_cfg.capture_mode == "daisy_chain": + text = tag[:text_length] + ot_kmac.absorb_daisy_chain(text, key_fixed, capture_cfg.num_segments) else: - # Non batch mode. either random or fvsr - if capture_cfg.capture_mode == "kmac_fvsr_key": - text, key, ciphertext, sample_fixed = generate_ref_crypto( - sample_fixed = sample_fixed, - mode = capture_cfg.capture_mode, - batch = capture_cfg.batch_mode, - key = key, - key_fixed = key_fixed, - plaintext = text, - plaintext_fixed = text_fixed, - key_length = capture_cfg.key_len_bytes - ) - ot_kmac.write_key(key) - ot_kmac.absorb(text) - # Capture traces. - waves = scope.capture_and_transfer_waves(target) - assert waves.shape[0] == capture_cfg.num_segments - - expected_ciphertext = None - # Generate reference crypto material and store trace. + logger.info("Error: Mode not recognized.") + return + + # Capture and store traces + if scope is not None: + waves = scope.capture_and_transfer_waves(target) + assert waves.shape[0] == capture_cfg.num_segments + + # Generate data for the KMAC test. + xor_tag = [0 for _ in range(32)] for i in range(capture_cfg.num_segments): - if capture_cfg.batch_mode or capture_cfg.capture_mode == "kmac_random": - text, key, ciphertext, sample_fixed = generate_ref_crypto( - sample_fixed = sample_fixed, - mode = capture_cfg.capture_mode, - batch = capture_cfg.batch_mode, - key = key, - key_fixed = key_fixed, - plaintext = text, - plaintext_fixed = text_fixed, - key_length = capture_cfg.key_len_bytes + text, key, tag, sample_fixed = generate_ref_crypto( + sample_fixed=sample_fixed, + mode=capture_cfg.capture_mode, + key_fixed=key_fixed, + text_fixed=text_fixed, + last_tag=tag, + ) + xor_tag = [xor_tag[i] ^ tag[i] for i in range(32)] + + if scope is not None: + # Store trace and crypto material into database. + # Sanity check retrieved data (wave). + assert len(waves[i, :]) >= 1 + # Store trace into database. + project.append_trace( + wave=waves[i, :], + plaintext=bytearray(text), + ciphertext=bytearray(tag), + key=bytearray(key), ) - # Sanity check retrieved data (wave). - assert len(waves[i, :]) >= 1 - # Store trace into database. - project.append_trace(wave = waves[i, :], - plaintext = bytearray(text), - ciphertext = bytearray(ciphertext), - key = bytearray(key)) - - if capture_cfg.capture_mode == "kmac_random": - plaintext = bytearray(16) - for i in range(0, 16): - plaintext[i] = random.randint(0, 255) - - if capture_cfg.batch_mode: - exp_cipher_bytes = (ciphertext if expected_ciphertext is - None else (a ^ b for (a, b) in - zip(ciphertext, - expected_ciphertext))) - expected_ciphertext = [x for x in exp_cipher_bytes] - else: - expected_ciphertext = ciphertext - - # Compare received ciphertext with generated. - compare_len = capture_cfg.output_len - check_ciphertext(ot_kmac, expected_ciphertext, compare_len) - - # Memory allocation optimization for CW trace library. - num_segments_storage = project.optimize_capture(num_segments_storage) + + # Compare received tag with generated. + expected_tag = tag + if capture_cfg.capture_mode == "fvsr_key": + expected_tag = xor_tag + if capture_cfg.capture_mode == "daisy_chain": + expected_tag = tag[:text_length] + check_tag(target, expected_tag, capture_cfg) + + if scope is not None: + # Memory allocation optimization for CW trace library. + num_segments_storage = project.optimize_capture(num_segments_storage) # Update the loop variable and the progress bar. remaining_num_traces -= capture_cfg.num_segments @@ -426,7 +419,7 @@ def capture(scope: Scope, ot_kmac: OTKMAC, capture_cfg: CaptureConfig, def print_plot(project: SCAProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to adjust the scope gain and check for clipping. @@ -435,14 +428,18 @@ def print_plot(project: SCAProject, config: dict, file: Path) -> None: config: The capture configuration. file: The output file path. """ - if config["capture"]["show_plot"]: - plot.save_plot_to_file(project.get_waves(0, config["capture"]["plot_traces"]), - set_indices = None, - num_traces = config["capture"]["plot_traces"], - outfile = file, - add_mean_stddev=True) - logger.info(f'Created plot with {config["capture"]["plot_traces"]} traces: ' - f'{Path(str(file) + ".html").resolve()}') + if config["capture"]["show_plot"] and config["capture"]["scope_select"] != "none": + plot.save_plot_to_file( + project.get_waves(0, config["capture"]["plot_traces"]), + set_indices=None, + num_traces=config["capture"]["plot_traces"], + outfile=file, + add_mean_stddev=True, + ) + logger.info( + f'Created plot with {config["capture"]["plot_traces"]} traces: ' + f'{Path(str(file) + ".html").resolve()}' + ) def main(argv=None): @@ -454,40 +451,34 @@ def main(argv=None): # Parse the provided arguments. args = helpers.parse_arguments(argv) - # Check the ChipWhisperer version. - check_version.check_cw("5.7.0") - # Load configuration from file. with open(args.cfg) as f: cfg = yaml.load(f, Loader=yaml.FullLoader) - # Determine the capture mode and configure the current capture. - mode = "kmac_fvsr_key" - if "kmac_random" in cfg["test"]["which_test"]: - mode = "kmac_random" - # Setup the target, scope and project. target, scope, project = setup(cfg, args.project) + if cfg["test"]["which_test"] == "single": + cfg["capture"]["num_segments"] = 1 + # Create capture config object. - capture_cfg = CaptureConfig(capture_mode = mode, - batch_mode = scope.scope_cfg.batch_mode, - num_traces = cfg["capture"]["num_traces"], - num_segments = scope.scope_cfg.num_segments, - output_len = cfg["target"]["output_len_bytes"], - text_fixed = cfg["test"]["text_fixed"], - key_fixed = cfg["test"]["key_fixed"], - key_len_bytes = cfg["test"]["key_len_bytes"], - text_len_bytes = cfg["test"]["text_len_bytes"], - protocol = cfg["target"]["protocol"], - port = cfg["target"].get("port")) - logger.info(f"Setting up capture {capture_cfg.capture_mode} batch={capture_cfg.batch_mode}...") + capture_cfg = CaptureConfig( + capture_mode=cfg["test"]["which_test"], + num_traces=cfg["capture"]["num_traces"], + num_segments=cfg["capture"]["num_segments"], + text_fixed=cfg["test"]["text_fixed"], + key_fixed=cfg["test"]["key_fixed"], + port=cfg["target"].get("port"), + ) + logger.info(f"Setting up capture {capture_cfg.capture_mode} ...") # Open communication with target. - ot_kmac, ot_prng, ot_trig = establish_communication(target, capture_cfg) + ot_kmac, ot_prng, ot_trig = establish_communication(target) # Configure cipher. - device_id = configure_cipher(cfg, capture_cfg, ot_kmac, ot_prng) + device_id, owner_page, boot_log, boot_measurements, version = configure_cipher( + cfg, ot_kmac, ot_prng + ) # Configure trigger source. # 0 for HW, 1 for SW. @@ -503,38 +494,47 @@ def main(argv=None): print_plot(project, cfg, args.project) # Save metadata. - metadata = {} - metadata["device_id"] = device_id - metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") - metadata["cfg"] = cfg - metadata["num_samples"] = scope.scope_cfg.num_samples - metadata["offset_samples"] = scope.scope_cfg.offset_samples - metadata["sampling_rate"] = scope.scope_cfg.sampling_rate - metadata["num_traces"] = capture_cfg.num_traces - metadata["scope_gain"] = scope.scope_cfg.scope_gain - metadata["cfg_file"] = str(args.cfg) - # Store bitstream information. - metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") - if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) - if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) - # Store binary information. - metadata["fw_bin_path"] = cfg["target"]["fw_bin"] - metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) - if args.save_binary: - metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) - # Store user provided notes. - metadata["notes"] = args.notes - # Store the Git hash. - metadata["git_hash"] = helpers.get_git_hash() - # Write metadata into project database. - project.write_metadata(metadata) - - # Finale the capture. - project.finalize_capture(capture_cfg.num_traces) - # Save and close project. - project.save() + if cfg["capture"]["scope_select"] != "none": + metadata = {} + metadata["device_id"] = device_id + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version + metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") + metadata["cfg"] = cfg + metadata["num_samples"] = scope.scope_cfg.num_samples + metadata["offset_samples"] = scope.scope_cfg.offset_samples + metadata["sampling_rate"] = scope.scope_cfg.sampling_rate + metadata["num_traces"] = capture_cfg.num_traces + metadata["scope_gain"] = scope.scope_cfg.scope_gain + metadata["cfg_file"] = str(args.cfg) + # Store bitstream information. + metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") + if cfg["target"].get("fpga_bitstream") is not None: + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) + if args.save_bitstream: + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) + # Store binary information. + metadata["fw_bin_path"] = cfg["target"]["fw_bin"] + metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) + if args.save_binary: + metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) + # Store user provided notes. + metadata["notes"] = args.notes + # Store the Git hash. + metadata["git_hash"] = helpers.get_git_hash() + # Write metadata into project database. + project.write_metadata(metadata) + + # Finalize the capture. + project.finalize_capture(capture_cfg.num_traces) + # Save and close project. + project.save() if __name__ == "__main__": diff --git a/capture/capture_otbn.py b/capture/capture_otbn.py index 036d17de..a47a8eb7 100755 --- a/capture/capture_otbn.py +++ b/capture/capture_otbn.py @@ -22,6 +22,7 @@ import util.helpers as helpers from target.communication.sca_otbn_commands import OTOTBN +from target.communication.sca_prng_commands import OTPRNG from target.communication.sca_trigger_commands import OTTRIGGER from target.targets import Target, TargetConfig from util import check_version @@ -40,11 +41,17 @@ -p projects/otbn_vertical_sca_cw310_keygen """ +# Byte lengths of the text, key, and tag. +plain_text_len_bytes = 40 +text_len_bytes = 40 +key_len_bytes = 40 + + logger = logging.getLogger() def abort_handler_during_loop(this_project, sig, frame): - """ Abort capture and store traces. + """Abort capture and store traces. Args: this_project: Project instance. @@ -57,30 +64,26 @@ def abort_handler_during_loop(this_project, sig, frame): @dataclass class CaptureConfig: - """ Configuration class for the current capture. - """ + """Configuration class for the current capture.""" + capture_mode: str batch_mode: bool num_traces: int num_segments: int - output_len: int text_fixed: bytearray key_fixed: bytearray - key_len_bytes: int - text_len_bytes: int C: Optional[bytearray] seed_fixed: Optional[bytearray] expected_fixed_key: Optional[bytearray] k_fixed: Optional[bytearray] expected_fixed_output: Optional[int] - protocol: str port: Optional[str] = "None" @dataclass class CurveConfig: - """ Configuration class for curve dependant parameters. - """ + """Configuration class for curve dependant parameters.""" + curve_order_n: int key_bytes: int seed_bytes: int @@ -89,7 +92,7 @@ class CurveConfig: def setup(cfg: dict, project: Path): - """ Setup target, scope, and project. + """Setup target, scope, and project. Args: cfg: The configuration for the current experiment. @@ -101,92 +104,101 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg[ - "target"]["target_clk_mult"] - - # Create target config & setup target. - logger.info(f"Initializing target {cfg['target']['target_type']} ...") - target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial"), - interface = cfg["target"].get("interface"), - husky_serial = cfg["husky"].get("usb_serial") + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] ) - target = Target(target_cfg) # Init scope. scope_type = cfg["capture"]["scope_select"] - # Determine sampling rate, if necessary. - cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) - # Convert number of cycles into number of samples, if necessary. - cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) - # Convert offset in cycles into offset in samples, if necessary. - cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) - - logger.info( - f"Initializing scope {scope_type} with a sampling rate of {cfg[scope_type]['sampling_rate']}..." # noqa: E501 - ) + # Check the ChipWhisperer version. + if scope_type == "husky": + check_version.check_cw("5.7.0") - # Determine if we are in batch mode or not. - batch = cfg["test"]["batch_mode"] - - # Create scope config & setup scope. - scope_cfg = ScopeConfig( - scope_type=scope_type, - batch_mode = batch, - bit = cfg[scope_type].get("bit"), - acqu_channel=cfg[scope_type].get("channel"), - ip=cfg[scope_type].get("waverunner_ip"), - num_samples=cfg[scope_type]["num_samples"], - offset_samples=cfg[scope_type]["offset_samples"], - sampling_rate=cfg[scope_type].get("sampling_rate"), - num_segments=cfg[scope_type]["num_segments"], - sparsing=cfg[scope_type].get("sparsing"), - scope_gain=cfg[scope_type].get("scope_gain"), + # Create target config & setup target. + logger.info(f"Initializing target {cfg['target']['target_type']} ...") + target_cfg = TargetConfig( + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], pll_frequency=cfg["target"]["pll_frequency"], - scope_sn = cfg[scope_type].get("usb_serial"), + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + interface=cfg["target"].get("interface"), + husky_serial = cfg["husky"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) - scope = Scope(scope_cfg) + target = Target(target_cfg) + + if scope_type != "none": + # Determine sampling rate, if necessary. + cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) + # Convert number of cycles into number of samples, if necessary. + cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) + # Convert offset in cycles into offset in samples, if necessary. + cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) - # OTBN's public-key operations might not fit into the sample buffer of the scope - # These two parameters allows users to conrol the sampling frequency - # `adc_mul` affects the sample frequency (clock_freq = adc_mul * pll_freq) - # `decimate` is the ADC downsampling factor that allows us to sample at - # every `decimate` cycles. - if scope_type == "husky": - if "adc_mul" in cfg["husky"]: - scope.scope.scope.clock.adc_mul = cfg["husky"]["adc_mul"] - if "decimate" in cfg["husky"]: - scope.scope.scope.adc.decimate = cfg["husky"]["decimate"] - # Print final scope parameter logger.info( - f'Scope setup with final sampling rate of {scope.scope.scope.clock.adc_freq} S/s' + f"Initializing scope {scope_type} with a sampling rate of {cfg[scope_type]['sampling_rate']}..." # noqa: E501 ) - # Init project. - project_cfg = ProjectConfig( - type=cfg["capture"]["trace_db"], - path=project, - wave_dtype=np.uint16, - overwrite=True, - trace_threshold=cfg["capture"].get("trace_threshold")) - project = SCAProject(project_cfg) - project.create_project() + # Determine if we are in batch mode or not. + batch = cfg["test"]["batch_mode"] + + # Create scope config & setup scope. + scope_cfg = ScopeConfig( + scope_type=scope_type, + batch_mode=batch, + bit=cfg[scope_type].get("bit"), + acqu_channel=cfg[scope_type].get("channel"), + ip=cfg[scope_type].get("waverunner_ip"), + num_samples=cfg[scope_type]["num_samples"], + offset_samples=cfg[scope_type]["offset_samples"], + sampling_rate=cfg[scope_type].get("sampling_rate"), + num_segments=1, + sparsing=cfg[scope_type].get("sparsing"), + scope_gain=cfg[scope_type].get("scope_gain"), + pll_frequency=cfg["target"]["pll_frequency"], + scope_sn=cfg[scope_type].get("usb_serial"), + ) + scope = Scope(scope_cfg) + + # OTBN's public-key operations might not fit into the sample buffer of the scope + # These two parameters allows users to conrol the sampling frequency + # `adc_mul` affects the sample frequency (clock_freq = adc_mul * pll_freq) + # `decimate` is the ADC downsampling factor that allows us to sample at + # every `decimate` cycles. + if scope_type == "husky": + if "adc_mul" in cfg["husky"]: + scope.scope.scope.clock.adc_mul = cfg["husky"]["adc_mul"] + if "decimate" in cfg["husky"]: + scope.scope.scope.adc.decimate = cfg["husky"]["decimate"] + # Print final scope parameter + logger.info( + f"Scope setup with final sampling rate of {scope.scope.scope.clock.adc_freq} S/s" + ) + + # Init project. + project_cfg = ProjectConfig( + type=cfg["capture"]["trace_db"], + path=project, + wave_dtype=np.uint16, + overwrite=True, + trace_threshold=cfg["capture"].get("trace_threshold"), + ) + project = SCAProject(project_cfg) + project.create_project() + else: + scope = None + project = None return target, scope, project -def establish_communication(target, capture_cfg: CaptureConfig): - """ Establish communication with the target device. +def establish_communication(target): + """Establish communication with the target device. Args: target: The OT target. @@ -197,17 +209,21 @@ def establish_communication(target, capture_cfg: CaptureConfig): ot_trig: The communication interface to the SCA trigger. """ # Create communication interface to OTBN. - ot_otbn_vert = OTOTBN(target=target, protocol=capture_cfg.protocol) + ot_otbn_vert = OTOTBN(target=target) # Create communication interface to SCA trigger. - ot_trig = OTTRIGGER(target=target, protocol=capture_cfg.protocol) + ot_trig = OTTRIGGER(target=target) - return ot_otbn_vert, ot_trig + # Create communication interface to OT PRNG. + ot_prng = OTPRNG(target=target) + return ot_otbn_vert, ot_trig, ot_prng -def configure_cipher(cfg: dict, target, capture_cfg: CaptureConfig, - ot_otbn_vert) -> OTOTBN: - """ Configure the OTBN app. + +def configure_cipher( + cfg: dict, capture_cfg: CaptureConfig, ot_otbn_vert, ot_prng +) -> OTOTBN: + """Configure the OTBN app. Establish communication with the OTBN keygen app and configure the seed. @@ -225,40 +241,37 @@ def configure_cipher(cfg: dict, target, capture_cfg: CaptureConfig, random.seed(cfg["test"]["batch_prng_seed"]) # Seed the target's PRNGs - ot_otbn_vert.write_batch_prng_seed(cfg["test"]["batch_prng_seed"].to_bytes( - 4, "little")) - - # select the otbn app on the device (0 -> keygen, 1 -> modinv) - ot_otbn_vert.choose_otbn_app(cfg["test"]["app"]) + ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little")) # Initialize some curve-dependent parameters. - if cfg["test"]["curve"] == 'p256': + if cfg["test"]["curve"] == "p256": # Create curve config object curve_cfg = CurveConfig( - curve_order_n= - 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551, + curve_order_n=0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551, key_bytes=256 // 8, seed_bytes=320 // 8, modinv_share_bytes=320 // 8, - modinv_mask_bytes=128 // 8) + modinv_mask_bytes=128 // 8, + ) else: # Create curve config object - curve_cfg = CurveConfig(curve_order_n=0, - key_bytes=0, - seed_bytes=0, - modinv_share_bytes=0, - modinv_mask_bytes=0) + curve_cfg = CurveConfig( + curve_order_n=0, + key_bytes=0, + seed_bytes=0, + modinv_share_bytes=0, + modinv_mask_bytes=0, + ) # TODO: add support for P384 - raise NotImplementedError( - f'Curve {cfg["test"]["curve"]} is not supported') + raise NotImplementedError(f'Curve {cfg["test"]["curve"]} is not supported') if capture_cfg.capture_mode == "keygen": if capture_cfg.batch_mode: # TODO: add support for batch mode - raise NotImplementedError('Batch mode not yet supported.') + raise NotImplementedError("Batch mode not yet supported.") else: # Generate fixed constants for all traces of the keygen operation. - if cfg["test"]["test_type"] == 'KEY': + if cfg["test"]["test_type"] == "KEY": # In fixed-vs-random KEY mode we use two fixed constants: # 1. C - a 320 bit constant redundancy # 2. fixed_number - a 256 bit number used to derive the fixed key @@ -274,7 +287,8 @@ def configure_cipher(cfg: dict, target, capture_cfg: CaptureConfig, seed_fixed_int = int.from_bytes(capture_cfg.C, byteorder='little') + \ int.from_bytes(fixed_number, byteorder='little') capture_cfg.seed_fixed = seed_fixed_int.to_bytes( - curve_cfg.seed_bytes, byteorder='little') + curve_cfg.seed_bytes, byteorder="little" + ) else: # In fixed-vs-random SEED mode we use only one fixed constant: # 1. seed_fixed - A 320 bit constant used to derive the fixed key @@ -287,13 +301,14 @@ def configure_cipher(cfg: dict, target, capture_cfg: CaptureConfig, # Expected key is `seed mod n`, where n is the order of the curve and # `seed` is interpreted as little-endian. - capture_cfg.expected_fixed_key = int.from_bytes( - capture_cfg.seed_fixed, - byteorder='little') % curve_cfg.curve_order_n + capture_cfg.expected_fixed_key = ( + int.from_bytes(capture_cfg.seed_fixed, byteorder="little") + % curve_cfg.curve_order_n + ) elif capture_cfg.capture_mode == "modinv": if capture_cfg.batch_mode: # TODO: add support for batch mode - raise NotImplementedError('Batch mode not supported.') + raise NotImplementedError("Batch mode not supported.") else: # set fixed key and share inputs # (uncomment the desired fixed shares depending on whether @@ -301,21 +316,24 @@ def configure_cipher(cfg: dict, target, capture_cfg: CaptureConfig, # r1, r2, r3 = dg.get_random() # capture_cfg.k_fixed = (bytearray(r1) + bytearray(r2) + # bytearray(r3))[:curve_cfg.key_bytes] - capture_cfg.k_fixed = bytearray(( - 0x2648d0d248b70944dfd84c2f85ea5793729112e7cafa50abdf7ef8b7594fa2a1 - ).to_bytes(curve_cfg.key_bytes, 'little')) - k_fixed_int = int.from_bytes(capture_cfg.k_fixed, - byteorder='little') + capture_cfg.k_fixed = bytearray( + ( + 0x2648D0D248B70944DFD84C2F85EA5793729112E7CAFA50ABDF7EF8B7594FA2A1 + ).to_bytes(curve_cfg.key_bytes, "little") + ) + k_fixed_int = int.from_bytes(capture_cfg.k_fixed, byteorder="little") # Expected fixed output is `(k)^(-1) mod n`, where n is the curve order n - capture_cfg.expected_fixed_output = pow(k_fixed_int, -1, - curve_cfg.curve_order_n) + capture_cfg.expected_fixed_output = pow( + k_fixed_int, -1, curve_cfg.curve_order_n + ) return curve_cfg -def generate_ref_crypto_keygen(cfg: dict, sample_fixed, curve_cfg: CurveConfig, - capture_cfg: CaptureConfig): - """ Generate cipher material for keygen application. +def generate_ref_crypto_keygen( + cfg: dict, sample_fixed, curve_cfg: CurveConfig, capture_cfg: CaptureConfig +): + """Generate cipher material for keygen application. Args: cfg: The configuration for the current experiment. @@ -332,9 +350,9 @@ def generate_ref_crypto_keygen(cfg: dict, sample_fixed, curve_cfg: CurveConfig, if capture_cfg.batch_mode: # TODO: add support for batch mode - raise NotImplementedError('Batch mode not yet supported.') + raise NotImplementedError("Batch mode not yet supported.") else: - if cfg["test"]["masks_off"] == 'True': + if cfg["test"]["masks_off"] == "True": # Use a constant mask for each trace mask = bytearray(curve_cfg.seed_bytes) # all zeros else: @@ -343,7 +361,7 @@ def generate_ref_crypto_keygen(cfg: dict, sample_fixed, curve_cfg: CurveConfig, mask = (bytearray(r1) + bytearray(r2) + bytearray(r3))[:curve_cfg.seed_bytes] # Generate fixed constants for all traces of the keygen operation. - if cfg["test"]["test_type"] == 'KEY': + if cfg["test"]["test_type"] == "KEY": # In fixed-vs-random KEY mode, the fixed set of measurements is # generated using the fixed 320 bit seed. The random set of # measurements is generated in two steps: @@ -387,9 +405,10 @@ def generate_ref_crypto_keygen(cfg: dict, sample_fixed, curve_cfg: CurveConfig, return seed_used, mask, expected_key, sample_fixed -def generate_ref_crypto_modinv(cfg: dict, sample_fixed, curve_cfg: CurveConfig, - capture_cfg: CaptureConfig): - """ Generate cipher material for the modular inverse operation. +def generate_ref_crypto_modinv( + cfg: dict, sample_fixed, curve_cfg: CurveConfig, capture_cfg: CaptureConfig +): + """Generate cipher material for the modular inverse operation. Args: cfg: The configuration for the current experiment. @@ -407,7 +426,7 @@ def generate_ref_crypto_modinv(cfg: dict, sample_fixed, curve_cfg: CurveConfig, if capture_cfg.batch_mode: # TODO: add support for batch mode - raise NotImplementedError('Batch mode not yet supported.') + raise NotImplementedError("Batch mode not yet supported.") else: if sample_fixed: # Compute the fixed input shares: @@ -423,13 +442,14 @@ def generate_ref_crypto_modinv(cfg: dict, sample_fixed, curve_cfg: CurveConfig, # adapt share k1 so that k = (k0 + k1) mod n k_tmp = (k0_fixed + k1_fixed) % curve_cfg.curve_order_n k_tmp_diff = ( - int.from_bytes(capture_cfg.k_fixed, byteorder='little') - - k_tmp) % curve_cfg.curve_order_n + int.from_bytes(capture_cfg.k_fixed, byteorder="little") - k_tmp + ) % curve_cfg.curve_order_n k1_fixed += k_tmp_diff if k1_fixed >= pow(2, 320): k1_fixed -= curve_cfg.curve_order_n input_k1_fixed = bytearray( - (k1_fixed).to_bytes(curve_cfg.modinv_share_bytes, 'little')) + (k1_fixed).to_bytes(curve_cfg.modinv_share_bytes, "little") + ) # Use the fixed input. input_k0_used = input_k0_fixed input_k1_used = input_k1_fixed @@ -444,11 +464,11 @@ def generate_ref_crypto_modinv(cfg: dict, sample_fixed, curve_cfg: CurveConfig, input_k1_used = (bytearray(r1) + bytearray(r2) + bytearray(r3))[:curve_cfg.modinv_share_bytes] # calculate the key from the shares - k_used_int = (int.from_bytes(input_k0_used, byteorder='little') + - int.from_bytes(input_k1_used, byteorder='little') - ) % curve_cfg.curve_order_n - k_used = bytearray( - k_used_int.to_bytes(curve_cfg.key_bytes, 'little')) + k_used_int = ( + int.from_bytes(input_k0_used, byteorder="little") + + int.from_bytes(input_k1_used, byteorder="little") + ) % curve_cfg.curve_order_n + k_used = bytearray(k_used_int.to_bytes(curve_cfg.key_bytes, "little")) expected_output = pow(k_used_int, -1, curve_cfg.curve_order_n) # The next sample is either fixed or random. @@ -458,9 +478,8 @@ def generate_ref_crypto_modinv(cfg: dict, sample_fixed, curve_cfg: CurveConfig, return k_used, input_k0_used, input_k1_used, expected_output, sample_fixed -def check_ciphertext_keygen(ot_otbn_vert: OTOTBN, expected_key, - curve_cfg: CurveConfig): - """ Compares the received with the generated key. +def check_ciphertext_keygen(ot_otbn_vert: OTOTBN, expected_key, curve_cfg: CurveConfig): + """Compares the received with the generated key. Key shares are read from the device and compared against the pre-computed generated key. In batch mode, only the last key is compared. @@ -480,24 +499,27 @@ def check_ciphertext_keygen(ot_otbn_vert: OTOTBN, expected_key, share0 = ot_otbn_vert.read_output(curve_cfg.seed_bytes) share1 = ot_otbn_vert.read_output(curve_cfg.seed_bytes) if share0 is None: - raise RuntimeError('Random share0 is none') + raise RuntimeError("Random share0 is none") if share1 is None: - raise RuntimeError('Random share1 is none') + raise RuntimeError("Random share1 is none") - d0 = int.from_bytes(share0, byteorder='little') - d1 = int.from_bytes(share1, byteorder='little') + d0 = int.from_bytes(share0, byteorder="little") + d1 = int.from_bytes(share1, byteorder="little") actual_key = (d0 + d1) % curve_cfg.curve_order_n - assert actual_key == expected_key, (f"Incorrect encryption result!\n" - f"actual: {actual_key}\n" - f"expected: {expected_key}") + assert actual_key == expected_key, ( + f"Incorrect encryption result!\n" + f"actual: {actual_key}\n" + f"expected: {expected_key}" + ) return share0, share1 -def check_ciphertext_modinv(ot_otbn_vert: OTOTBN, expected_output, - curve_cfg: CurveConfig): - """ Compares the received modular inverse output with the generated output. +def check_ciphertext_modinv( + ot_otbn_vert: OTOTBN, expected_output, curve_cfg: CurveConfig +): + """Compares the received modular inverse output with the generated output. Args: ot_otbn_vert: The OpenTitan OTBN vertical communication interface. @@ -511,26 +533,36 @@ def check_ciphertext_modinv(ot_otbn_vert: OTOTBN, expected_output, kalpha_inv = ot_otbn_vert.read_output(curve_cfg.key_bytes) alpha = ot_otbn_vert.read_output(curve_cfg.modinv_mask_bytes) if kalpha_inv is None: - raise RuntimeError('kaplpha_inv is none') + raise RuntimeError("kaplpha_inv is none") if alpha is None: - raise RuntimeError('alpha is none') + raise RuntimeError("alpha is none") # Actual result (kalpha_inv*alpha) mod n: - actual_output = int.from_bytes( - kalpha_inv, byteorder='little') * int.from_bytes( - alpha, byteorder='little') % curve_cfg.curve_order_n + actual_output = ( + int.from_bytes(kalpha_inv, byteorder="little") * + int.from_bytes(alpha, byteorder="little") % + curve_cfg.curve_order_n + ) - assert actual_output == expected_output, (f"Incorrect modinv result!\n" - f"actual: {actual_output}\n" - f"expected: {expected_output}") + assert actual_output == expected_output, ( + f"Incorrect modinv result!\n" + f"actual: {actual_output}\n" + f"expected: {expected_output}" + ) return actual_output -def capture_keygen(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBN, - capture_cfg: CaptureConfig, curve_cfg: CurveConfig, - project: SCAProject, target: Target): - """ Capture power consumption during selected OTBN operation. +def capture_keygen( + cfg: dict, + scope: Scope, + ot_otbn_vert: OTOTBN, + capture_cfg: CaptureConfig, + curve_cfg: CurveConfig, + project: SCAProject, + target: Target, +): + """Capture power consumption during selected OTBN operation. Args: cfg: The configuration for the current experiment. @@ -558,21 +590,22 @@ def capture_keygen(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBN, signal.signal(signal.SIGINT, partial(abort_handler_during_loop, project)) # Main capture with progress bar. remaining_num_traces = capture_cfg.num_traces - with tqdm(total=remaining_num_traces, - desc="Capturing", - ncols=80, - unit=" traces") as pbar: + with tqdm( + total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces" + ) as pbar: while remaining_num_traces > 0: # Arm the scope. - scope.arm() + if scope is not None: + scope.arm() seed_used, mask, expected_key, sample_fixed = generate_ref_crypto_keygen( - cfg, sample_fixed, curve_cfg, capture_cfg) + cfg, sample_fixed, curve_cfg, capture_cfg + ) # Trigger encryption. if capture_cfg.batch_mode: # TODO: add support for batch mode - raise NotImplementedError('Batch mode not yet supported.') + raise NotImplementedError("Batch mode not yet supported.") else: # Send the seed to ibex. # Ibex receives the seed and the mask and computes the two shares as: @@ -583,32 +616,43 @@ def capture_keygen(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBN, ot_otbn_vert.start_keygen(mask) # Capture traces. - waves = scope.capture_and_transfer_waves(target) - assert waves.shape[0] == capture_cfg.num_segments + if scope is not None: + waves = scope.capture_and_transfer_waves(target) + assert waves.shape[0] == capture_cfg.num_segments # Compare received key with generated key. share0, share1 = check_ciphertext_keygen( - ot_otbn_vert, expected_key, curve_cfg) + ot_otbn_vert, expected_key, curve_cfg + ) # Store trace into database. - project.append_trace(wave=waves[0, :], - plaintext=mask, - ciphertext=share0 + share1, - key=seed_used) + if scope is not None: + project.append_trace( + wave=waves[0, :], + plaintext=mask, + ciphertext=share0 + share1, + key=seed_used, + ) # Memory allocation optimization for CW trace library. - num_segments_storage = project.optimize_capture( - num_segments_storage) + if scope is not None: + num_segments_storage = project.optimize_capture(num_segments_storage) # Update the loop variable and the progress bar. remaining_num_traces -= capture_cfg.num_segments pbar.update(capture_cfg.num_segments) -def capture_modinv(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBN, - capture_cfg: CaptureConfig, curve_cfg: CurveConfig, - project: SCAProject, target: Target): - """ Capture power consumption during selected OTBN operation. +def capture_modinv( + cfg: dict, + scope: Scope, + ot_otbn_vert: OTOTBN, + capture_cfg: CaptureConfig, + curve_cfg: CurveConfig, + project: SCAProject, + target: Target, +): + """Capture power consumption during selected OTBN operation. Args: cfg: The configuration for the current experiment. @@ -634,44 +678,50 @@ def capture_modinv(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBN, signal.signal(signal.SIGINT, partial(abort_handler_during_loop, project)) # Main capture with progress bar. remaining_num_traces = capture_cfg.num_traces - with tqdm(total=remaining_num_traces, - desc="Capturing", - ncols=80, - unit=" traces") as pbar: + with tqdm( + total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces" + ) as pbar: while remaining_num_traces > 0: # Arm the scope. - scope.arm() + if scope is not None: + scope.arm() - k_used, input_k0_used, input_k1_used, expected_output, sample_fixed = \ + k_used, input_k0_used, input_k1_used, expected_output, sample_fixed = ( generate_ref_crypto_modinv(cfg, sample_fixed, curve_cfg, capture_cfg) + ) # Trigger encryption. if capture_cfg.batch_mode: # TODO: add support for batch mode - raise NotImplementedError('Batch mode not supported.') + raise NotImplementedError("Batch mode not supported.") else: # Start modinv device computation ot_otbn_vert.start_modinv(input_k0_used, input_k1_used) # Capture traces. - waves = scope.capture_and_transfer_waves(target) - assert waves.shape[0] == capture_cfg.num_segments + if scope is not None: + waves = scope.capture_and_transfer_waves(target) + assert waves.shape[0] == capture_cfg.num_segments # Compare received key with generated key. actual_output = check_ciphertext_modinv( - ot_otbn_vert, expected_output, curve_cfg) + ot_otbn_vert, expected_output, curve_cfg + ) # Store trace into database. - project.append_trace(wave=waves[0, :], - plaintext=k_used, - ciphertext=bytearray( - actual_output.to_bytes( - curve_cfg.key_bytes, 'little')), - key=k_used) + if scope is not None: + project.append_trace( + wave=waves[0, :], + plaintext=k_used, + ciphertext=bytearray( + actual_output.to_bytes(curve_cfg.key_bytes, "little") + ), + key=k_used, + ) # Memory allocation optimization for CW trace library. - num_segments_storage = project.optimize_capture( - num_segments_storage) + if scope is not None: + num_segments_storage = project.optimize_capture(num_segments_storage) # Update the loop variable and the progress bar. remaining_num_traces -= capture_cfg.num_segments @@ -679,7 +729,7 @@ def capture_modinv(cfg: dict, scope: Scope, ot_otbn_vert: OTOTBN, def print_plot(project: SCAProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to adjust the scope gain and check for clipping. @@ -688,14 +738,18 @@ def print_plot(project: SCAProject, config: dict, file: Path) -> None: config: The capture configuration. file: The output file path. """ - if config["capture"]["show_plot"]: - plot.save_plot_to_file(project.get_waves(0, config["capture"]["plot_traces"]), - set_indices = None, - num_traces = config["capture"]["plot_traces"], - outfile = file, - add_mean_stddev=True) - logger.info(f'Created plot with {config["capture"]["plot_traces"]} traces: ' - f'{Path(str(file) + ".html").resolve()}') + if config["capture"]["show_plot"] and config["capture"]["scope_select"] != "none": + plot.save_plot_to_file( + project.get_waves(0, config["capture"]["plot_traces"]), + set_indices=None, + num_traces=config["capture"]["plot_traces"], + outfile=file, + add_mean_stddev=True, + ) + logger.info( + f'Created plot with {config["capture"]["plot_traces"]} traces: ' + f'{Path(str(file) + ".html").resolve()}' + ) def main(argv=None): @@ -707,9 +761,6 @@ def main(argv=None): # Parse the provided arguments. args = helpers.parse_arguments(argv) - # Check the ChipWhisperer version. - check_version.check_cw("5.7.0") - # Load configuration from file. with open(args.cfg) as f: cfg = yaml.load(f, Loader=yaml.FullLoader) @@ -720,32 +771,30 @@ def main(argv=None): # Setup the target, scope and project. target, scope, project = setup(cfg, args.project) + num_segments = 1 + # Create capture config object. capture_cfg = CaptureConfig( capture_mode=mode, - batch_mode=scope.scope_cfg.batch_mode, + batch_mode=cfg["test"]["batch_mode"], num_traces=cfg["capture"]["num_traces"], - num_segments=scope.scope_cfg.num_segments, - output_len=cfg["target"]["output_len_bytes"], + num_segments=num_segments, text_fixed=bytearray(), key_fixed=bytearray(), - key_len_bytes=cfg["test"]["key_len_bytes"], - text_len_bytes=cfg["test"]["text_len_bytes"], - protocol=cfg["target"]["protocol"], C=bytearray(), seed_fixed=bytearray(), expected_fixed_key=bytearray(), k_fixed=bytearray(), - expected_fixed_output=0) - logger.info( - f"Setting up capture {capture_cfg.capture_mode} batch={capture_cfg.batch_mode}..." + expected_fixed_output=0, + port=cfg["target"].get("port"), ) + logger.info(f"Setting up capture {capture_cfg.capture_mode} ...") # Open communication with target. - ot_otbn_vert, ot_trig = establish_communication(target, capture_cfg) + ot_otbn_vert, ot_trig, ot_prng = establish_communication(target) # Configure cipher. - curve_cfg = configure_cipher(cfg, target, capture_cfg, ot_otbn_vert) + curve_cfg = configure_cipher(cfg, capture_cfg, ot_otbn_vert, ot_prng) # Configure trigger source. # 0 for HW, 1 for SW. @@ -756,55 +805,63 @@ def main(argv=None): # Capture traces. if mode == "keygen": - capture_keygen(cfg, scope, ot_otbn_vert, capture_cfg, curve_cfg, - project, target) + capture_keygen( + cfg, scope, ot_otbn_vert, capture_cfg, curve_cfg, project, target + ) elif mode == "modinv": - capture_modinv(cfg, scope, ot_otbn_vert, capture_cfg, curve_cfg, - project, target) + capture_modinv( + cfg, scope, ot_otbn_vert, capture_cfg, curve_cfg, project, target + ) else: # TODO: add support for modinv app - raise NotImplementedError('Cofigured OTBN app not yet supported.') + raise NotImplementedError("Cofigured OTBN app not yet supported.") # Print plot. print_plot(project, cfg, args.project) # Save metadata. - metadata = {} - metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") - metadata["cfg"] = cfg - metadata["num_samples"] = scope.scope_cfg.num_samples - metadata["offset_samples"] = scope.scope_cfg.offset_samples - metadata["scope_gain"] = scope.scope_cfg.scope_gain - if cfg["capture"]["scope_select"] == "husky": - metadata[ - "sampling_rate"] = scope.scope.scope.clock.adc_freq / scope.scope.scope.adc.decimate - metadata["samples_trigger_high"] = scope.scope.scope.adc.trig_count - else: - metadata["sampling_rate"] = scope.scope_cfg.sampling_rate - metadata["num_traces"] = capture_cfg.num_traces - metadata["cfg_file"] = str(args.cfg) - # Store bitstream information. - metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") - if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) - if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) - # Store binary information. - metadata["fw_bin_path"] = cfg["target"]["fw_bin"] - metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) - if args.save_binary: - metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) - # Store user provided notes. - metadata["notes"] = args.notes - # Store the Git hash. - metadata["git_hash"] = helpers.get_git_hash() - # Write metadata into project database. - project.write_metadata(metadata) - - # Finale the capture. - project.finalize_capture(capture_cfg.num_traces) - # Save and close project. - project.save() + if cfg["capture"]["scope_select"] != "none": + metadata = {} + metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") + metadata["cfg"] = cfg + metadata["num_samples"] = scope.scope_cfg.num_samples + metadata["offset_samples"] = scope.scope_cfg.offset_samples + metadata["scope_gain"] = scope.scope_cfg.scope_gain + if cfg["capture"]["scope_select"] == "husky": + metadata["sampling_rate"] = ( + scope.scope.scope.clock.adc_freq / scope.scope.scope.adc.decimate + ) + metadata["samples_trigger_high"] = scope.scope.scope.adc.trig_count + else: + metadata["sampling_rate"] = scope.scope_cfg.sampling_rate + metadata["num_traces"] = capture_cfg.num_traces + metadata["cfg_file"] = str(args.cfg) + # Store bitstream information. + metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") + if cfg["target"].get("fpga_bitstream") is not None: + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) + if args.save_bitstream: + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) + # Store binary information. + metadata["fw_bin_path"] = cfg["target"]["fw_bin"] + metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) + if args.save_binary: + metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) + # Store user provided notes. + metadata["notes"] = args.notes + # Store the Git hash. + metadata["git_hash"] = helpers.get_git_hash() + # Write metadata into project database. + project.write_metadata(metadata) + + # Finalize the capture. + project.finalize_capture(capture_cfg.num_traces) + # Save and close project. + project.save() if __name__ == "__main__": diff --git a/capture/capture_sha3.py b/capture/capture_sha3.py index 05429628..2ecab008 100755 --- a/capture/capture_sha3.py +++ b/capture/capture_sha3.py @@ -7,6 +7,7 @@ # To be compatible to the other capture scripts, the variable is # called ciphertext +import json import logging import random import signal @@ -30,15 +31,17 @@ from target.communication.sca_sha3_commands import OTSHA3 from target.communication.sca_trigger_commands import OTTRIGGER from target.targets import Target, TargetConfig -from util import check_version -from util import data_generator as dg -from util import plot +from util import check_version, plot + +# Byte lengths of the text and tag. +text_length = 16 +tag_length = 32 logger = logging.getLogger() def abort_handler_during_loop(this_project, sig, frame): - """ Abort capture and store traces. + """Abort capture and store traces. Args: this_project: Project instance. @@ -51,21 +54,17 @@ def abort_handler_during_loop(this_project, sig, frame): @dataclass class CaptureConfig: - """ Configuration class for the current capture. - """ + """Configuration class for the current capture.""" + capture_mode: str - batch_mode: bool num_traces: int num_segments: int - output_len: int text_fixed: bytearray - text_len_bytes: int - protocol: str port: Optional[str] = "None" def setup(cfg: dict, project: Path): - """ Setup target, scope, and project. + """Setup target, scope, and project. Args: cfg: The configuration for the current experiment. @@ -77,76 +76,89 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + ) + + # Init scope. + scope_type = cfg["capture"]["scope_select"] + + # Check the ChipWhisperer version. + if scope_type == "husky": + check_version.check_cw("5.7.0") # Create target config & setup target. logger.info(f"Initializing target {cfg['target']['target_type']} ...") target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial"), - interface = cfg["target"].get("interface"), - husky_serial = cfg["husky"].get("usb_serial") + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], + pll_frequency=cfg["target"]["pll_frequency"], + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + interface=cfg["target"].get("interface"), + husky_serial = cfg["husky"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) target = Target(target_cfg) - # Init scope. - scope_type = cfg["capture"]["scope_select"] - - # Determine sampling rate, if necessary. - cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) - # Convert number of cycles into number of samples, if necessary. - cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) - # Convert offset in cycles into offset in samples, if necessary. - cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) + if scope_type != "none": + # Determine sampling rate, if necessary. + cfg[scope_type]["sampling_rate"] = determine_sampling_rate(cfg, scope_type) + # Convert number of cycles into number of samples, if necessary. + cfg[scope_type]["num_samples"] = convert_num_cycles(cfg, scope_type) + # Convert offset in cycles into offset in samples, if necessary. + cfg[scope_type]["offset_samples"] = convert_offset_cycles(cfg, scope_type) - logger.info(f"Initializing scope {scope_type} with a sampling rate of {cfg[scope_type]['sampling_rate']}...") # noqa: E501 + logger.info( + f"Initializing scope {scope_type} with a sampling rate of \ + {cfg[scope_type]['sampling_rate']}..." + ) # noqa: E501 - # Determine if we are in batch mode or not. - batch = False - if "batch" in cfg["test"]["which_test"]: + # Determine if we are in batch mode or not. batch = True - - # Create scope config & setup scope. - scope_cfg = ScopeConfig( - scope_type = scope_type, - batch_mode = batch, - bit = cfg[scope_type].get("bit"), - acqu_channel = cfg[scope_type].get("channel"), - ip = cfg[scope_type].get("waverunner_ip"), - num_samples = cfg[scope_type]["num_samples"], - offset_samples = cfg[scope_type]["offset_samples"], - sampling_rate = cfg[scope_type].get("sampling_rate"), - num_segments = cfg[scope_type].get("num_segments"), - sparsing = cfg[scope_type].get("sparsing"), - scope_gain = cfg[scope_type].get("scope_gain"), - pll_frequency = cfg["target"]["pll_frequency"], - scope_sn = cfg[scope_type].get("usb_serial"), - ) - scope = Scope(scope_cfg) - - # Init project. - project_cfg = ProjectConfig(type = cfg["capture"]["trace_db"], - path = project, - wave_dtype = np.uint16, - overwrite = True, - trace_threshold = cfg["capture"].get("trace_threshold") - ) - project = SCAProject(project_cfg) - project.create_project() + if "single" in cfg["test"]["which_test"]: + batch = False + + # Create scope config & setup scope. + scope_cfg = ScopeConfig( + scope_type=scope_type, + batch_mode=batch, + bit=cfg[scope_type].get("bit"), + acqu_channel=cfg[scope_type].get("channel"), + ip=cfg[scope_type].get("waverunner_ip"), + num_samples=cfg[scope_type]["num_samples"], + offset_samples=cfg[scope_type]["offset_samples"], + sampling_rate=cfg[scope_type].get("sampling_rate"), + num_segments=cfg["capture"].get("num_segments"), + sparsing=cfg[scope_type].get("sparsing"), + scope_gain=cfg[scope_type].get("scope_gain"), + pll_frequency=cfg["target"]["pll_frequency"], + scope_sn=cfg[scope_type].get("usb_serial"), + ) + scope = Scope(scope_cfg) + + # Init project. + project_cfg = ProjectConfig( + type=cfg["capture"]["trace_db"], + path=project, + wave_dtype=np.uint16, + overwrite=True, + trace_threshold=cfg["capture"].get("trace_threshold"), + ) + project = SCAProject(project_cfg) + project.create_project() + else: + scope = None + project = None return target, scope, project -def establish_communication(target, capture_cfg: CaptureConfig): - """ Establish communication with the target device. +def establish_communication(target): + """Establish communication with the target device. Args: target: The OT target. @@ -158,29 +170,32 @@ def establish_communication(target, capture_cfg: CaptureConfig): ot_trig: The communication interface to the SCA trigger. """ # Create communication interface to OT SHA3. - ot_sha3 = OTSHA3(target=target, protocol=capture_cfg.protocol) + ot_sha3 = OTSHA3(target=target) # Create communication interface to SCA trigger. - ot_trig = OTTRIGGER(target=target, protocol=capture_cfg.protocol) + ot_trig = OTTRIGGER(target=target) # Create communication interface to OT PRNG. - ot_prng = OTPRNG(target=target, protocol=capture_cfg.protocol) + ot_prng = OTPRNG(target=target) return ot_sha3, ot_prng, ot_trig -def configure_cipher(cfg, capture_cfg, ot_sha3, ot_prng): - """ Configure the SHA3 cipher. +def configure_cipher(cfg, ot_sha3, ot_prng): + """Configure the SHA3 cipher. Establish communication with the SHA3 cipher and configure the seed and mask. Args: cfg: The project config. - capture_cfg: The capture config. ot_sha3: The communication interface to the SHA3 SCA application. ot_prng: The communication interface to the PRNG SCA application. Returns: device_id: The ID of the target device. + owner_page: The owner info page + boot_log: The boot log + boot_measurments: The boot measurements + version: The testOS version """ # Check if we want to run KMAC SCA for FPGA or discrete. On the FPGA, we # can use functionality helping us to capture cleaner traces. @@ -188,11 +203,9 @@ def configure_cipher(cfg, capture_cfg, ot_sha3, ot_prng): if "cw" in cfg["target"]["target_type"]: fpga_mode_bit = 1 # Initialize KMAC on the target. - device_id = ot_sha3.init(fpga_mode_bit, - cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + device_id, owner_page, boot_log, boot_measurements, version = ot_sha3.init( + fpga_mode_bit, cfg["test"]["core_config"], cfg["test"]["sensor_config"] + ) if cfg["test"]["masks_off"] is True: logger.info("Configure device to use constant, fast entropy!") @@ -205,18 +218,16 @@ def configure_cipher(cfg, capture_cfg, ot_sha3, ot_prng): ot_sha3.write_lfsr_seed(cfg["test"]["lfsr_seed"].to_bytes(4, "little")) # Seed the PRNG used for generating plaintexts in batch mode. - if capture_cfg.batch_mode: - # Seed host's PRNG. - random.seed(cfg["test"]["batch_prng_seed"]) + # Seed host's PRNG. + random.seed(cfg["test"]["batch_prng_seed"]) - # Seed the target's PRNG. - ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little")) - return device_id + # Seed the target's PRNG. + ot_prng.seed_prng(cfg["test"]["batch_prng_seed"].to_bytes(4, "little")) + return device_id, owner_page, boot_log, boot_measurements, version -def generate_ref_crypto(sample_fixed, mode, batch, plaintext, - plaintext_fixed, text_len_bytes): - """ Generate cipher material for the encryption. +def generate_ref_crypto(sample_fixed, mode, text_fixed): + """Generate cipher material for the encryption. This function derives the next key as well as the plaintext for the next encryption. @@ -224,76 +235,54 @@ def generate_ref_crypto(sample_fixed, mode, batch, plaintext, Args: sample_fixed: Use fixed key or new key. mode: The mode of the capture. - batch: Batch or non-batch mode. - plaintext: The current plaintext. - plaintext_fixed: The fixed plaintext for FVSR. - text_len_bytes: Th length of the plaintext. + text_fixed: The fixed plaintext. Returns: - plaintext: The next plaintext. - ciphertext: The next ciphertext. + batch_text: The used text. + batch_output: The returned output. sample_fixed: Is the next sample fixed or not? """ - if mode == "sha3_fvsr_data" and not batch: - # returns a pt, ct, key (not used) tripple - # does only need the sample_fixed argument - if sample_fixed: - # Expected ciphertext. - plaintext, ciphertext, key = dg.get_sha3_fixed() + if mode == "single_absorb": + new_sample_fixed = 1 + batch_text = text_fixed + elif mode == "batch_absorb": + if sample_fixed == 1: + batch_text = text_fixed else: - plaintext, ciphertext, key = dg.get_sha3_random() - # The next sample is either fixed or random. - sample_fixed = plaintext[0] & 0x1 + batch_text = [random.randint(0, 255) for _ in range(16)] + dummy = [random.randint(0, 255) for _ in range(16)] + new_sample_fixed = dummy[0] & 0x1 else: - if mode == "sha3_random": - # returns pt, ct, needs pt as arguments - sha3 = SHA3_256.new(bytes(plaintext)) - ciphertext_bytes = sha3.digest() - ciphertext = [x for x in ciphertext_bytes] - else: # mode = sha3_fvsr_data_batch - # returns random pt, ct, needs no arguments - if sample_fixed: - plaintext = plaintext_fixed - else: - random_plaintext = [] - for i in range(0, text_len_bytes): - random_plaintext.append(random.randint(0, 255)) - plaintext = random_plaintext - - # needed to be in sync with ot lfsr and for sample_fixed generation - dummy_plaintext = [] - for i in range(0, 16): - dummy_plaintext.append(random.randint(0, 255)) - # Compute ciphertext for this plaintext. - sha3 = SHA3_256.new(bytes(plaintext)) - ciphertext_bytes = sha3.digest() - ciphertext = [x for x in ciphertext_bytes] - # Determine if next iteration uses fixed_key. - sample_fixed = dummy_plaintext[0] & 0x1 - return plaintext, ciphertext, sample_fixed - - -def check_ciphertext(received_ciphertext, expected_last_ciphertext, ciphertext_len): - """ Compares the received with the generated ciphertext. - - Received ciphertext is compared against the pre-computed generated - ciphertext. In batch mode, only the last ciphertext is compared. + logger.info("Error: Mode not recognized.") + return None, None, None + + sha3 = SHA3_256.new(bytes(batch_text)) + output_bytes = sha3.digest() + batch_output = [x for x in output_bytes] + + return batch_text, batch_output, new_sample_fixed + + +def check_digest(received_output, expected_output): + """Compares the received with the generated ciphertext. + + Received output is compared against the pre-computed generated + output. In batch mode, only the last output is compared. Asserts on mismatch. Args: - received_ciphertext: The received ciphertext. - expected_last_ciphertext: The pre-computed ciphertext. - ciphertext_len: The length of the ciphertext in bytes. + received_output: The received output. + expected_output: The pre-computed output. """ - assert received_ciphertext == expected_last_ciphertext[0:ciphertext_len], ( + assert received_output == expected_output, ( f"Incorrect encryption result!\n" - f"actual: {received_ciphertext}\n" - f"expected: {expected_last_ciphertext}" + f"actual: {received_output}\n" + f"expected: {expected_output}" ) def init_target(cfg: dict, capture_cfg: CaptureConfig, target: Target, text_fixed): - """ Initializes the target. + """Initializes the target. Establish a communication interface with the target and configure the cipher. @@ -307,10 +296,12 @@ def init_target(cfg: dict, capture_cfg: CaptureConfig, target: Target, text_fixe device_id: The ID of the target device. """ # Open communication with target. - ot_sha3, ot_prng, ot_trig = establish_communication(target, capture_cfg) + ot_sha3, ot_prng, ot_trig = establish_communication(target) # Configure cipher. - device_id = configure_cipher(cfg, capture_cfg, ot_sha3, ot_prng) + device_id, owner_page, boot_log, boot_measurements, version = configure_cipher( + cfg, ot_sha3, ot_prng + ) # Configure trigger source. # 0 for HW, 1 for SW. @@ -320,20 +311,24 @@ def init_target(cfg: dict, capture_cfg: CaptureConfig, target: Target, text_fixe ot_trig.select_trigger(trigger_source) # Configure the fixed text for FVSR in the batch mode. - if capture_cfg.batch_mode: + if "batch" in capture_cfg.capture_mode: ot_sha3.fvsr_fixed_msg_set(text_fixed) - return ot_sha3, device_id + return ot_sha3, device_id, owner_page, boot_log, boot_measurements, version -def capture(scope: Scope, cfg: dict, capture_cfg: CaptureConfig, - project: SCAProject, target: Target): - """ Capture power consumption during SHA3 digest computation. +def capture( + scope: Scope, + cfg: dict, + capture_cfg: CaptureConfig, + project: SCAProject, + target: Target, +): + """Capture power consumption during SHA3 digest computation. Supports four different capture types: - * sha3_random: random plaintext. - * sha3_fvsr: Fixed vs. random data. - * sha3_fvsr_batch: Fixed vs. random data batch. + * batch_absorb: Fixed vs. random data. + * single_absorb: Fixed data. Args: scope: The scope class representing a scope (Husky or WaveRunner). @@ -357,99 +352,75 @@ def capture(scope: Scope, cfg: dict, capture_cfg: CaptureConfig, num_segments_storage = 1 # Initialize target. - ot_sha3, device_id = init_target(cfg, capture_cfg, target, text_fixed) + ot_sha3, device_id, owner_page, boot_log, boot_measurements, version = init_target( + cfg, capture_cfg, target, text_fixed + ) # Register ctrl-c handler to store traces on abort. signal.signal(signal.SIGINT, partial(abort_handler_during_loop, project)) # Main capture with progress bar. remaining_num_traces = capture_cfg.num_traces - with tqdm(total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces") as pbar: + with tqdm( + total=remaining_num_traces, desc="Capturing", ncols=80, unit=" traces" + ) as pbar: while remaining_num_traces > 0: # Arm the scope. - scope.arm() + if scope is not None: + scope.arm() # Trigger encryption. - if capture_cfg.batch_mode: + if capture_cfg.capture_mode == "batch_absorb": # Batch mode. Is always sha3_fvsr_data ot_sha3.absorb_batch(capture_cfg.num_segments) - else: - # Non batch mode. either random or fvsr - if capture_cfg.capture_mode == "sha3_fvsr_data": - text, ciphertext, sample_fixed = generate_ref_crypto( - sample_fixed = sample_fixed, - mode = capture_cfg.capture_mode, - batch = capture_cfg.batch_mode, - plaintext = text, - plaintext_fixed = text_fixed, - text_len_bytes = capture_cfg.text_len_bytes - ) + elif capture_cfg.capture_mode == "single_absorb": ot_sha3.absorb(text) - # Capture traces. - waves = scope.capture_and_transfer_waves(target) - assert waves.shape[0] == capture_cfg.num_segments + else: + logger.info("Error: Mode not recognized.") + return + + # Capture and store traces + if scope is not None: + waves = scope.capture_and_transfer_waves(target) + assert waves.shape[0] == capture_cfg.num_segments - expected_ciphertext = None - text_array = [] - ciphertext_array = [] # Generate reference crypto material and store trace. + xor_output = [0 for _ in range(32)] for i in range(capture_cfg.num_segments): - if capture_cfg.batch_mode or capture_cfg.capture_mode == "sha3_random": - text, ciphertext, sample_fixed = generate_ref_crypto( - sample_fixed = sample_fixed, - mode = capture_cfg.capture_mode, - batch = capture_cfg.batch_mode, - plaintext = text, - plaintext_fixed = text_fixed, - text_len_bytes = capture_cfg.text_len_bytes + text, output, sample_fixed = generate_ref_crypto( + sample_fixed=sample_fixed, + mode=capture_cfg.capture_mode, + text_fixed=text_fixed, + ) + xor_output = [xor_output[i] ^ output[i] for i in range(32)] + + if scope is not None: + # Sanity check retrieved data (wave). + assert len(waves[i, :]) >= 1 + + project.append_trace( + wave=waves[i, :], + plaintext=bytearray(text), + ciphertext=bytearray(output), + key=None, ) - # Sanity check retrieved data (wave). - assert len(waves[i, :]) >= 1 - - # Append text and ciphertext to result array. - text_array.append(text) - ciphertext_array.append(ciphertext) - - if capture_cfg.capture_mode == "sha3_random": - plaintext = bytearray(16) - for i in range(0, 16): - plaintext[i] = random.randint(0, 255) - - if capture_cfg.batch_mode: - exp_cipher_bytes = (ciphertext if expected_ciphertext is - None else (a ^ b for (a, b) in - zip(ciphertext, - expected_ciphertext))) - expected_ciphertext = [x for x in exp_cipher_bytes] - else: - expected_ciphertext = ciphertext - - # Receive ciphertext and compare against expected one. If - # successful, store into database. - compare_len = capture_cfg.output_len - rcv_ctx, rcv_resp = ot_sha3.read_ciphertext(compare_len) - if rcv_resp: - # Check response and store into database - check_ciphertext(rcv_ctx, expected_ciphertext, compare_len) - for i in range(capture_cfg.num_segments): - project.append_trace(wave = waves[i, :], - plaintext = bytearray(text_array[i]), - ciphertext = bytearray(ciphertext_array[i]), - key = None) - # Update the loop variable and the progress bar. - remaining_num_traces -= capture_cfg.num_segments - pbar.update(capture_cfg.num_segments) - else: - # No response, reset device and start over. - logger.info("No response received, resetting device!") - target.reset_target() - ot_sha3, device_id = init_target(cfg, capture_cfg, target, text_fixed) + + response_full = target.read_response() + reponse_json = json.loads(response_full) + response = reponse_json["batch_digest"] + check_digest(response, xor_output) # Memory allocation optimization for CW trace library. - num_segments_storage = project.optimize_capture(num_segments_storage) - return device_id + if scope is not None: + num_segments_storage = project.optimize_capture(num_segments_storage) + + # Update the loop variable and the progress bar. + remaining_num_traces -= capture_cfg.num_segments + pbar.update(capture_cfg.num_segments) + + return device_id, owner_page, boot_log, boot_measurements, version def print_plot(project: SCAProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to adjust the scope gain and check for clipping. @@ -458,14 +429,18 @@ def print_plot(project: SCAProject, config: dict, file: Path) -> None: config: The capture configuration. file: The output file path. """ - if config["capture"]["show_plot"]: - plot.save_plot_to_file(project.get_waves(0, config["capture"]["plot_traces"]), - set_indices = None, - num_traces = config["capture"]["plot_traces"], - outfile = file, - add_mean_stddev=True) - print(f'Created plot with {config["capture"]["plot_traces"]} traces: ' - f'{Path(str(file) + ".html").resolve()}') + if config["capture"]["show_plot"] and config["capture"]["scope_select"] != "none": + plot.save_plot_to_file( + project.get_waves(0, config["capture"]["plot_traces"]), + set_indices=None, + num_traces=config["capture"]["plot_traces"], + outfile=file, + add_mean_stddev=True, + ) + print( + f'Created plot with {config["capture"]["plot_traces"]} traces: ' + f'{Path(str(file) + ".html").resolve()}' + ) def main(argv=None): @@ -477,72 +452,76 @@ def main(argv=None): # Parse the provided arguments. args = helpers.parse_arguments(argv) - # Check the ChipWhisperer version. - check_version.check_cw("5.7.0") - # Load configuration from file. with open(args.cfg) as f: cfg = yaml.load(f, Loader=yaml.FullLoader) - # Determine the capture mode and configure the current capture. - mode = "sha3_fvsr_data" - if "sha3_random" in cfg["test"]["which_test"]: - mode = "sha3_random" - # Setup the target, scope and project. target, scope, project = setup(cfg, args.project) + if "single" in cfg["test"]["which_test"]: + cfg["capture"]["num_segments"] = 1 + # Create capture config object. - capture_cfg = CaptureConfig(capture_mode = mode, - batch_mode = scope.scope_cfg.batch_mode, - num_traces = cfg["capture"]["num_traces"], - num_segments = scope.scope_cfg.num_segments, - output_len = cfg["target"]["output_len_bytes"], - text_fixed = cfg["test"]["text_fixed"], - text_len_bytes = cfg["test"]["text_len_bytes"], - protocol = cfg["target"]["protocol"], - port = cfg["target"].get("port")) - logger.info(f"Setting up capture {capture_cfg.capture_mode} batch={capture_cfg.batch_mode}...") + capture_cfg = CaptureConfig( + capture_mode=cfg["test"]["which_test"], + num_traces=cfg["capture"]["num_traces"], + num_segments=cfg["capture"]["num_segments"], + text_fixed=cfg["test"]["text_fixed"], + port=cfg["target"].get("port"), + ) + logger.info(f"Setting up capture {capture_cfg.capture_mode} ...") # Capture traces. - device_id = capture(scope, cfg, capture_cfg, project, target) + device_id, owner_page, boot_log, boot_measurements, version = capture( + scope, cfg, capture_cfg, project, target + ) # Print plot. print_plot(project, cfg, args.project) # Save metadata. - metadata = {} - metadata["device_id"] = device_id - metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") - metadata["cfg"] = cfg - metadata["num_samples"] = scope.scope_cfg.num_samples - metadata["offset_samples"] = scope.scope_cfg.offset_samples - metadata["sampling_rate"] = scope.scope_cfg.sampling_rate - metadata["num_traces"] = capture_cfg.num_traces - metadata["scope_gain"] = scope.scope_cfg.scope_gain - metadata["cfg_file"] = str(args.cfg) - # Store bitstream information. - metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") - if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) - if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) - # Store binary information. - metadata["fw_bin_path"] = cfg["target"]["fw_bin"] - metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) - if args.save_binary: - metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) - # Store user provided notes. - metadata["notes"] = args.notes - # Store the Git hash. - metadata["git_hash"] = helpers.get_git_hash() - # Write metadata into project database. - project.write_metadata(metadata) - - # Finale the capture. - project.finalize_capture(capture_cfg.num_traces) - # Save and close project. - project.save() + if cfg["capture"]["scope_select"] != "none": + metadata = {} + metadata["device_id"] = device_id + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version + metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") + metadata["cfg"] = cfg + metadata["num_samples"] = scope.scope_cfg.num_samples + metadata["offset_samples"] = scope.scope_cfg.offset_samples + metadata["sampling_rate"] = scope.scope_cfg.sampling_rate + metadata["num_traces"] = capture_cfg.num_traces + metadata["scope_gain"] = scope.scope_cfg.scope_gain + metadata["cfg_file"] = str(args.cfg) + # Store bitstream information. + metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") + if cfg["target"].get("fpga_bitstream") is not None: + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) + if args.save_bitstream: + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) + # Store binary information. + metadata["fw_bin_path"] = cfg["target"]["fw_bin"] + metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) + if args.save_binary: + metadata["fw_bin"] = helpers.get_binary_blob(cfg["target"]["fw_bin"]) + # Store user provided notes. + metadata["notes"] = args.notes + # Store the Git hash. + metadata["git_hash"] = helpers.get_git_hash() + # Write metadata into project database. + project.write_metadata(metadata) + + # Finalize the capture. + project.finalize_capture(capture_cfg.num_traces) + # Save and close project. + project.save() if __name__ == "__main__": diff --git a/capture/project_library/ot_trace_library/trace_library.py b/capture/project_library/ot_trace_library/trace_library.py index 3c1de271..60a05a5b 100644 --- a/capture/project_library/ot_trace_library/trace_library.py +++ b/capture/project_library/ot_trace_library/trace_library.py @@ -14,21 +14,23 @@ @dataclass class Metadata: - """ Metadata for capture. + """Metadata for capture. Stores information about the capture of the traces. """ + data: bytearray @dataclass class Trace: - """ Trace. + """Trace. Defines the trace format. """ + wave: bytearray plaintext: bytearray ciphertext: bytearray @@ -39,14 +41,16 @@ class Trace: class TraceLibrary: - """ Class for writing/reading traces to a database. + """Class for writing/reading traces to a database. Either a new database is created or traces are appended to the existing one. Traces are first written into memory and the flushed into the database after reaching a trace memory threshold. """ - def __init__(self, db_name, trace_threshold, wave_datatype = np.uint16, - overwrite = False): + + def __init__( + self, db_name, trace_threshold, wave_datatype=np.uint16, overwrite=False + ): # If .db extension is not provided, add it to the file. if not db_name.endswith(".db"): db_name = db_name + ".db" @@ -62,8 +66,7 @@ def __init__(self, db_name, trace_threshold, wave_datatype = np.uint16, self.traces_table = db.Table( "traces", self.metadata, - db.Column("trace_id", db.Integer, primary_key=True, - autoincrement=True), + db.Column("trace_id", db.Integer, primary_key=True, autoincrement=True), db.Column("wave", db.LargeBinary), db.Column("plaintext", db.LargeBinary), db.Column("ciphertext", db.LargeBinary), @@ -72,9 +75,7 @@ def __init__(self, db_name, trace_threshold, wave_datatype = np.uint16, db.Column("y_pos", db.Integer), ) self.metadata_table = db.Table( - "metadata", - self.metadata, - db.Column("data", db.PickleType) + "metadata", self.metadata, db.Column("data", db.PickleType) ) self.metadata.create_all(self.engine, checkfirst=True) self.trace_mem = [] @@ -82,7 +83,7 @@ def __init__(self, db_name, trace_threshold, wave_datatype = np.uint16, self.wave_datatype = wave_datatype def close(self, save: bool): - """ Close database. + """Close database. Args: save: Save data to database. """ @@ -91,8 +92,7 @@ def close(self, save: bool): self.engine.dispose() def flush_to_disk(self): - """ Writes traces from memory into database. - """ + """Writes traces from memory into database.""" if self.trace_mem: query = db.insert(self.traces_table) traces = [] @@ -105,7 +105,7 @@ def flush_to_disk(self): self.trace_mem = [] def write_to_buffer(self, trace): - """ Write traces into memory or into storage. + """Write traces into memory or into storage. The trace is first written into memory. When the length of the buffer reaches the memory threshold, the traces are flushed into the database @@ -118,9 +118,8 @@ def write_to_buffer(self, trace): if len(self.trace_mem) >= self.trace_mem_thr: self.flush_to_disk() - def get_traces(self, start: Optional[int] = None, - end: Optional[int] = None): - """ Get traces from database and stored into RAM. + def get_traces(self, start: Optional[int] = None, end: Optional[int] = None): + """Get traces from database and stored into RAM. Fetch traces from start to end from database storage into RAM. @@ -137,21 +136,25 @@ def get_traces(self, start: Optional[int] = None, start = start + 1 query = db.select(self.traces_table).where( (self.traces_table.c.trace_id >= start) & - (self.traces_table.c.trace_id <= end)) - elif (start is not None): + (self.traces_table.c.trace_id <= end) + ) + elif start is not None: # SQL ID starts at 1. start = start + 1 query = db.select(self.traces_table).where( - self.traces_table.c.trace_id == start) + self.traces_table.c.trace_id == start + ) else: query = db.select(self.traces_table) - return [Trace(**trace._mapping) - for trace in self.session.execute(query).fetchall()] + return [ + Trace(**trace._mapping) for trace in self.session.execute(query).fetchall() + ] - def get_waves_bytearray(self, start: Optional[int] = None, - end: Optional[int] = None): - """ Get all waves from the database. + def get_waves_bytearray( + self, start: Optional[int] = None, end: Optional[int] = None + ): + """Get all waves from the database. Returns: The bytearray waves from the database. @@ -159,67 +162,77 @@ def get_waves_bytearray(self, start: Optional[int] = None, return [trace.wave for trace in self.get_traces(start, end)] def get_waves(self, start: Optional[int] = None, end: Optional[int] = None): - """ Get all waves from the database in the trace array format. + """Get all waves from the database in the trace array format. Returns: The waves from the database in the type wave_datatype. """ - waves = [np.frombuffer(b, self.wave_datatype) - for b in self.get_waves_bytearray(start, end)] + waves = [ + np.frombuffer(b, self.wave_datatype) + for b in self.get_waves_bytearray(start, end) + ] if len(waves) == 1: return waves[0] else: return waves - def get_plaintexts(self, start: Optional[int] = None, - end: Optional[int] = None): - """ Get all plaintexts between start and end from the database in the + def get_plaintexts(self, start: Optional[int] = None, end: Optional[int] = None): + """Get all plaintexts between start and end from the database in the int8 array format. Returns: The int plaintexts from the database. """ - plaintexts = [(None if trace.plaintext is None else - np.frombuffer(trace.plaintext, np.uint8)) for trace in - self.get_traces(start, end)] + plaintexts = [ + ( + None + if trace.plaintext is None + else np.frombuffer(trace.plaintext, np.uint8) + ) + for trace in self.get_traces(start, end) + ] if len(plaintexts) == 1: return plaintexts[0] else: return plaintexts - def get_ciphertexts(self, start: Optional[int] = None, - end: Optional[int] = None): - """ Get all ciphertexts between start and end from the database in the + def get_ciphertexts(self, start: Optional[int] = None, end: Optional[int] = None): + """Get all ciphertexts between start and end from the database in the int8 array format. Returns: The int ciphertexts from the database. """ - ciphertexts = [(None if trace.ciphertext is None else - np.frombuffer(trace.ciphertext, np.uint8)) for trace in - self.get_traces(start, end)] + ciphertexts = [ + ( + None + if trace.ciphertext is None + else np.frombuffer(trace.ciphertext, np.uint8) + ) + for trace in self.get_traces(start, end) + ] if len(ciphertexts) == 1: return ciphertexts[0] else: return ciphertexts - def get_keys(self, start: Optional[int] = None, - end: Optional[int] = None): - """ Get all keys between start and end from the database in the int8 + def get_keys(self, start: Optional[int] = None, end: Optional[int] = None): + """Get all keys between start and end from the database in the int8 array format. Returns: The int keys from the database. """ - keys = [(None if trace.key is None else - np.frombuffer(trace.key, np.uint8)) for trace in - self.get_traces(start, end)] + keys = [ + (None if trace.key is None else np.frombuffer(trace.key, np.uint8)) + for trace in self.get_traces(start, end) + ] if len(keys) == 1: return keys[0] else: return keys def write_metadata(self, metadata): - """ Write metadata into database. + """Write metadata into database. Args: metadata: The metadata to store. @@ -235,7 +248,7 @@ def write_metadata(self, metadata): self.session.commit() def get_metadata(self): - """ Get metadata from database. + """Get metadata from database. Returns: The metadata from the database. diff --git a/capture/project_library/project.py b/capture/project_library/project.py index a26692dd..deb243dd 100644 --- a/capture/project_library/project.py +++ b/capture/project_library/project.py @@ -18,9 +18,10 @@ @dataclass class ProjectConfig: - """ Project configuration. + """Project configuration. Stores information about the project. """ + type: str path: Path wave_dtype: np.dtype @@ -29,34 +30,38 @@ class ProjectConfig: class SCAProject: - """ Project class. + """Project class. Used to manage a SCA project. """ + def __init__(self, project_cfg: ProjectConfig) -> None: self.project_cfg = project_cfg self.project = None def create_project(self): - """ Create project. + """Create project. Create project using the provided path. """ if self.project_cfg.type == "cw": - self.project = cw.create_project(self.project_cfg.path, - overwrite=self.project_cfg.overwrite) + self.project = cw.create_project( + self.project_cfg.path, overwrite=self.project_cfg.overwrite + ) elif self.project_cfg.type == "ot_trace_library": self.project = TraceLibrary( str(self.project_cfg.path), trace_threshold=self.project_cfg.trace_threshold, wave_datatype=self.project_cfg.wave_dtype, - overwrite=self.project_cfg.overwrite) + overwrite=self.project_cfg.overwrite, + ) else: - raise RuntimeError("Only trace_db='cw' or trace_db='ot_trace_library' supported.") + raise RuntimeError( + "Only trace_db='cw' or trace_db='ot_trace_library' supported." + ) def open_project(self) -> None: - """ Open project. - """ + """Open project.""" if self.project_cfg.type == "cw": self.project = cw.open_project(self.project_cfg.path) elif self.project_cfg.type == "ot_trace_library": @@ -64,42 +69,38 @@ def open_project(self) -> None: str(self.project_cfg.path), trace_threshold=self.project_cfg.trace_threshold, wave_datatype=self.project_cfg.wave_dtype, - overwrite=self.project_cfg.overwrite) + overwrite=self.project_cfg.overwrite, + ) def close(self, save: bool) -> None: - """ Close project. - """ + """Close project.""" if self.project_cfg.type == "cw": - self.project.close(save = save) + self.project.close(save=save) elif self.project_cfg.type == "ot_trace_library": - self.project.close(save = save) + self.project.close(save=save) self.project = None def save(self) -> None: - """ Save project. - """ + """Save project.""" if self.project_cfg.type == "cw": self.project.save() elif self.project_cfg.type == "ot_trace_library": self.project.flush_to_disk() def append_trace(self, wave, plaintext, ciphertext, key) -> None: - """ Append trace to trace storage in project. - """ + """Append trace to trace storage in project.""" if self.project_cfg.type == "cw": trace = cw.Trace(wave, plaintext, ciphertext, key) self.project.traces.append(trace, dtype=self.project_cfg.wave_dtype) elif self.project_cfg.type == "ot_trace_library": - trace = Trace(wave=wave.tobytes(), - plaintext=plaintext, - ciphertext=ciphertext, - key=key) + trace = Trace( + wave=wave.tobytes(), plaintext=plaintext, ciphertext=ciphertext, key=key + ) self.project.write_to_buffer(trace) def get_waves(self, start: Optional[int] = None, end: Optional[int] = None): - """ Get waves from project. - """ + """Get waves from project.""" if self.project_cfg.type == "cw": if (start is not None) and (end is not None): return self.project.waves[start:end] @@ -111,8 +112,7 @@ def get_waves(self, start: Optional[int] = None, end: Optional[int] = None): return self.project.get_waves(start, end) def get_keys(self, start: Optional[int] = None, end: Optional[int] = None): - """ Get keys[start, end] from project. - """ + """Get keys[start, end] from project.""" if self.project_cfg.type == "cw": if (start is not None) and (end is not None): return self.project.keys[start:end] @@ -124,8 +124,7 @@ def get_keys(self, start: Optional[int] = None, end: Optional[int] = None): return self.project.get_keys(start, end) def get_plaintexts(self, start: Optional[int] = None, end: Optional[int] = None): - """ Get plaintexts[start, end] from project. - """ + """Get plaintexts[start, end] from project.""" if self.project_cfg.type == "cw": if (start is not None) and (end is not None): return self.project.textins[start:end] @@ -137,8 +136,7 @@ def get_plaintexts(self, start: Optional[int] = None, end: Optional[int] = None) return self.project.get_plaintexts(start, end) def get_ciphertexts(self, start: Optional[int] = None, end: Optional[int] = None): - """ Get ciphertexts[start, end] from project. - """ + """Get ciphertexts[start, end] from project.""" if self.project_cfg.type == "cw": if (start is not None) and (end is not None): return self.project.textouts[start:end] @@ -150,16 +148,14 @@ def get_ciphertexts(self, start: Optional[int] = None, end: Optional[int] = None return self.project.get_ciphertexts(start, end) def write_metadata(self, metadata: dict) -> None: - """ Write metadata to project. - """ + """Write metadata to project.""" if self.project_cfg.type == "cw": self.project.settingsDict.update(metadata) elif self.project_cfg.type == "ot_trace_library": self.project.write_metadata(metadata) def get_metadata(self) -> dict: - """ Get metadata from project. - """ + """Get metadata from project.""" if self.project_cfg.type == "cw": return self.project.settingsDict elif self.project_cfg.type == "ot_trace_library": @@ -186,7 +182,9 @@ def optimize_capture(self, num_segments_storage): # re-enabled using finalize_capture(). if num_segments_storage != len(self.project.segments): if num_segments_storage >= 2: - self.project.traces.tm.setTraceSegmentStatus(num_segments_storage - 2, False) + self.project.traces.tm.setTraceSegmentStatus( + num_segments_storage - 2, False + ) num_segments_storage = len(self.project.segments) return num_segments_storage diff --git a/capture/scopes/chipwhisperer/cw_segmented.py b/capture/scopes/chipwhisperer/cw_segmented.py index f62b25d5..dfedd101 100644 --- a/capture/scopes/chipwhisperer/cw_segmented.py +++ b/capture/scopes/chipwhisperer/cw_segmented.py @@ -50,8 +50,15 @@ class CwSegmented: this many trigger events. Read-only. """ - def __init__(self, num_samples=1200, offset_samples=0, scope_gain=23, scope=None, - clkgen_freq=100e6, adc_mul=2): + def __init__( + self, + num_samples=1200, + offset_samples=0, + scope_gain=23, + scope=None, + clkgen_freq=100e6, + adc_mul=2, + ): """Inits a CwSegmented. Args: @@ -127,7 +134,7 @@ def _configure_scope(self, scope_gain, offset_samples, clkgen_freq, adc_mul): self._scope.adc.basic_mode = "rising_edge" self._scope.clock.adc_mul = adc_mul self._scope.clock.clkgen_freq = clkgen_freq - self._scope.clock.clkgen_src = 'extclk' + self._scope.clock.clkgen_src = "extclk" self._scope.trigger.triggers = "tio4" self._scope.io.tio1 = "serial_tx" diff --git a/capture/scopes/chipwhisperer/husky.py b/capture/scopes/chipwhisperer/husky.py index fee5dbba..75bd8a7b 100644 --- a/capture/scopes/chipwhisperer/husky.py +++ b/capture/scopes/chipwhisperer/husky.py @@ -14,8 +14,17 @@ class Husky: - def __init__(self, scope_gain, batch_mode, num_samples, num_segments, - offset_samples, sampling_rate, pll_frequency, scope_sn): + def __init__( + self, + scope_gain, + batch_mode, + num_samples, + num_segments, + offset_samples, + sampling_rate, + pll_frequency, + scope_sn, + ): check_version.check_husky("1.5.0", sn=scope_sn) self.scope = None self.sn = scope_sn @@ -27,7 +36,9 @@ def __init__(self, scope_gain, batch_mode, num_samples, num_segments, self.clkgen_freq = pll_frequency self.sampling_rate = sampling_rate if self.sampling_rate % self.clkgen_freq: - raise RuntimeError("sampling_rate % (target_frequency / target_clk_mult) != 0") + raise RuntimeError( + "sampling_rate % (target_frequency / target_clk_mult) != 0" + ) self.adc_mul = int(self.sampling_rate / self.clkgen_freq) self.offset_samples = offset_samples @@ -46,7 +57,7 @@ def initialize_scope(self): if not scope._is_husky: raise RuntimeError("Only ChipWhisperer Husky is supported!") - scope.clock.clkgen_src = 'extclk' + scope.clock.clkgen_src = "extclk" scope.clock.clkgen_freq = self.clkgen_freq scope.clock.adc_mul = self.adc_mul scope.clock.extclk_monitor_enabled = False @@ -62,50 +73,56 @@ def initialize_scope(self): scope.io.hs2 = "disabled" # Make sure that clkgen_locked is true. - scope.clock.clkgen_src = 'extclk' + scope.clock.clkgen_src = "extclk" # Wait for ADC to lock. ping_cnt = 0 while not scope.clock.adc_locked: if ping_cnt == 3: - raise RuntimeError( - f'ADC failed to lock (attempts: {ping_cnt}).') + raise RuntimeError(f"ADC failed to lock (attempts: {ping_cnt}).") ping_cnt += 1 time.sleep(0.5) self.scope = scope def configure_batch_mode(self): if self.batch_mode: - self.scope = CwSegmented(num_samples=self.num_samples, - offset_samples=self.offset_samples, - scope_gain=self.scope.gain.db, - scope=self.scope, - clkgen_freq=self.scope.clock.clkgen_freq, - adc_mul=self.adc_mul) + self.scope = CwSegmented( + num_samples=self.num_samples, + offset_samples=self.offset_samples, + scope_gain=self.scope.gain.db, + scope=self.scope, + clkgen_freq=self.scope.clock.clkgen_freq, + adc_mul=self.adc_mul, + ) # Determine max. possible number of segments. - num_segments_max = (self.scope._scope.adc.oa.hwMaxSegmentSamples // - self.scope._scope.adc.samples) + num_segments_max = ( + self.scope._scope.adc.oa.hwMaxSegmentSamples // + self.scope._scope.adc.samples + ) # If num_segments is not provided in the config file, set it to # max. number of segments. if self.num_segments is None: self.num_segments = num_segments_max print( - f'Info: num_segments not provided, setting to ' - f'num_segments_max={num_segments_max}.') + f"Info: num_segments not provided, setting to " + f"num_segments_max={num_segments_max}." + ) self.scope.num_segments = self.num_segments # Sanity check manually set num_segments. Check, if we can keep the # num_segements * num_samples in memory. - if (self.num_segments > num_segments_max): - raise RuntimeError("num_segments too large, cannot keep\ - samples in CW Husky sample memory.") + if self.num_segments > num_segments_max: + raise RuntimeError( + "num_segments too large, cannot keep\ + samples in CW Husky sample memory." + ) def arm(self): self.scope.arm() def capture_and_transfer_waves(self, target=None): - if self.num_segments == 1: + if not self.batch_mode: ret = self.scope.capture(poll_done=False) i = 0 while not target.is_done(): diff --git a/capture/scopes/scope.py b/capture/scopes/scope.py index e0bbf26a..597c3b5c 100644 --- a/capture/scopes/scope.py +++ b/capture/scopes/scope.py @@ -13,9 +13,10 @@ @dataclass class ScopeConfig: - """ Scope configuration. + """Scope configuration. Stores information about the scope. """ + scope_type: str num_segments: int batch_mode: bool @@ -32,17 +33,18 @@ class ScopeConfig: class Scope: - """ Scope class. + """Scope class. Represents a Husky or WaveRunner scope and provides functionality to initialize and use the scope. """ + def __init__(self, scope_cfg: ScopeConfig) -> None: self.scope_cfg = scope_cfg self.scope = self._init_scope() def _init_scope(self): - """ Init scope. + """Init scope. Configure Husky or WaveRunner scope with the user provided scope settings. @@ -51,15 +53,16 @@ def _init_scope(self): self._sanitize_num_segments() # Configure Scopes. if self.scope_cfg.scope_type == "husky": - scope = Husky(scope_gain = self.scope_cfg.scope_gain, - batch_mode = self.scope_cfg.batch_mode, - num_samples = self.scope_cfg.num_samples, - num_segments = self.scope_cfg.num_segments, - offset_samples = self.scope_cfg.offset_samples, - sampling_rate = self.scope_cfg.sampling_rate, - pll_frequency = self.scope_cfg.pll_frequency, - scope_sn = self.scope_cfg.scope_sn - ) + scope = Husky( + scope_gain=self.scope_cfg.scope_gain, + batch_mode=self.scope_cfg.batch_mode, + num_samples=self.scope_cfg.num_samples, + num_segments=self.scope_cfg.num_segments, + offset_samples=self.scope_cfg.offset_samples, + sampling_rate=self.scope_cfg.sampling_rate, + pll_frequency=self.scope_cfg.pll_frequency, + scope_sn=self.scope_cfg.scope_sn, + ) scope.initialize_scope() scope.configure_batch_mode() # Update num_segments. @@ -75,22 +78,27 @@ def _init_scope(self): # Get current sampling rate from scope compare to cfg for sanity setup_data = scope._ask("PANEL_SETUP?") scope._get_and_print_cmd_error() - tmp_sampling_rate = int(re.findall(r'SampleRate = \d+', setup_data)[0][13:]) + tmp_sampling_rate = int( + re.findall(r"SampleRate = \d+", setup_data)[0][13:] + ) # Sanitize inputs. if self.scope_cfg.sampling_rate is not None: if self.scope_cfg.sampling_rate != tmp_sampling_rate: - raise RuntimeError("WAVERUNNER: Error: WaveRunner sampling " - "rate does not match given configuration!") + raise RuntimeError( + "WAVERUNNER: Error: WaveRunner sampling " + "rate does not match given configuration!" + ) if self.scope_cfg.num_segments is None: - raise RuntimeError("WAVERUNNER: Error: num_segments needs to " - "be provided!") + raise RuntimeError( + "WAVERUNNER: Error: num_segments needs to " "be provided!" + ) # Configure WaveRunner. scope.configure_waveform_transfer_general( - num_segments = self.scope_cfg.num_segments, - sparsing = self.scope_cfg.sparsing, - num_samples = self.scope_cfg.num_samples, - first_point = self.scope_cfg.offset_samples, - acqu_channel = self.scope_cfg.acqu_channel + num_segments=self.scope_cfg.num_segments, + sparsing=self.scope_cfg.sparsing, + num_samples=self.scope_cfg.num_samples, + first_point=self.scope_cfg.offset_samples, + acqu_channel=self.scope_cfg.acqu_channel, ) return scope else: @@ -99,23 +107,23 @@ def _init_scope(self): raise RuntimeError("Error: Scope not supported!") def _sanitize_num_segments(self) -> None: - """ Sanitize num_segments. + """Sanitize num_segments. When in non-batch mode, num_segments needs to be 1. """ if not self.scope_cfg.batch_mode and self.scope_cfg.num_segments != 1: self.scope_cfg.num_segments = 1 - print("Warning: num_segments needs to be 1 in non-batch mode. " - "Setting num_segments=1.") + print( + "Warning: num_segments needs to be 1 in non-batch mode. " + "Setting num_segments=1." + ) def arm(self) -> None: - """ Arm the scope. - """ + """Arm the scope.""" self.scope.arm() def capture_and_transfer_waves(self, target=None): - """ Wait until capture is finished and return traces. - """ + """Wait until capture is finished and return traces.""" if self.scope_cfg.scope_type == "husky": return self.scope.capture_and_transfer_waves(target) else: @@ -123,7 +131,7 @@ def capture_and_transfer_waves(self, target=None): def convert_num_cycles(cfg: dict, scope_type: str) -> int: - """ Converts number of cycles to number of samples if samples not given. + """Converts number of cycles to number of samples if samples not given. As the scopes are configured in number of samples, this function converts the number of cycles to samples. @@ -138,7 +146,9 @@ def convert_num_cycles(cfg: dict, scope_type: str) -> int: The number of samples. """ if cfg[scope_type].get("num_samples") is None: - sampl_target_rat = cfg[scope_type].get("sampling_rate") / cfg["target"].get("target_freq") + sampl_target_rat = cfg[scope_type].get("sampling_rate") / cfg["target"].get( + "target_freq" + ) num_samples = int(cfg[scope_type].get("num_cycles") * sampl_target_rat) if scope_type == "husky": @@ -151,7 +161,7 @@ def convert_num_cycles(cfg: dict, scope_type: str) -> int: def convert_offset_cycles(cfg: dict, scope_type: str) -> int: - """ Converts offset in cycles to offset in samples if not given in samples. + """Converts offset in cycles to offset in samples if not given in samples. Args: dict: The scope configuration. @@ -161,14 +171,16 @@ def convert_offset_cycles(cfg: dict, scope_type: str) -> int: The offset in samples. """ if cfg[scope_type].get("offset_samples") is None: - sampl_target_rat = cfg[scope_type].get("sampling_rate") / cfg["target"].get("target_freq") + sampl_target_rat = cfg[scope_type].get("sampling_rate") / cfg["target"].get( + "target_freq" + ) return int(cfg[scope_type].get("offset_cycles") * sampl_target_rat) else: return cfg[scope_type].get("offset_samples") def determine_sampling_rate(cfg: dict, scope_type: str) -> int: - """ Determine sampling rate. + """Determine sampling rate. If no sampling rate is provided, calculate for Husky or receive from WaveRunner. @@ -187,10 +199,12 @@ def determine_sampling_rate(cfg: dict, scope_type: str) -> int: # calculate the maximum possible sampling rate. SAMPLING_RATE_MAX = 200e6 adc_mul = int(SAMPLING_RATE_MAX // cfg["target"]["pll_frequency"]) - return (adc_mul * cfg["target"]["pll_frequency"]) + return adc_mul * cfg["target"]["pll_frequency"] else: # Waverunner init not done yet, so cannot be read from WaveRunner. - raise RuntimeError("WAVERUNNER: ERROR: Sampling rate for WaveRunner " - "not given in configuration.") + raise RuntimeError( + "WAVERUNNER: ERROR: Sampling rate for WaveRunner " + "not given in configuration." + ) else: return cfg[scope_type].get("sampling_rate") diff --git a/capture/scopes/waverunner/test_waverunner.py b/capture/scopes/waverunner/test_waverunner.py index e8612501..f6eb6353 100755 --- a/capture/scopes/waverunner/test_waverunner.py +++ b/capture/scopes/waverunner/test_waverunner.py @@ -9,7 +9,7 @@ from waverunner import WaveRunner -if __name__ == '__main__': +if __name__ == "__main__": # Create WaveRunner waverunner = WaveRunner("172.26.111.125") diff --git a/capture/scopes/waverunner/waverunner.py b/capture/scopes/waverunner/waverunner.py index 10416000..402930fd 100755 --- a/capture/scopes/waverunner/waverunner.py +++ b/capture/scopes/waverunner/waverunner.py @@ -115,21 +115,23 @@ def _get_and_print_cmd_error(self): # https://cdn.teledynelecroy.com/files/manuals/maui-remote-control-and-automation-manual.pdf # Note: Scope error log under Utilities/Remote/Show Remote Control Log # Note: Beware of numbering; idx starts at 0 - error_msg = ["OK.", - "Unrecognized command/query header.", - "Illegal header path.", - "Illegal number.", - "Illegal number suffix.", - "Unrecognized keyword.", - "String error.", - "GET embedded in another message.", - "", - "", - "Arbitrary data block expected.", - "Non-digit character in byte count field of arbitrary data block.", - "EOI detected during definite length data block transfer.", - "Extra bytes detected during definite length data block transfer"] - return_code = int((re.findall(r'\d+', self._ask("CMR?")))[0]) + error_msg = [ + "OK.", + "Unrecognized command/query header.", + "Illegal header path.", + "Illegal number.", + "Illegal number suffix.", + "Unrecognized keyword.", + "String error.", + "GET embedded in another message.", + "", + "", + "Arbitrary data block expected.", + "Non-digit character in byte count field of arbitrary data block.", + "EOI detected during definite length data block transfer.", + "Extra bytes detected during definite length data block transfer", + ] + return_code = int((re.findall(r"\d+", self._ask("CMR?")))[0]) if return_code > 13 or return_code in [8, 9]: return_msg = f"{return_code} Unkown error code" else: @@ -166,7 +168,7 @@ def save_setup_to_local_file(self, file_name_local): self._get_and_print_cmd_error() # remove echoed command characters from beginning setup_data = setup_data[5:] - local_file = open(file_name_local, "w", encoding='utf-8') + local_file = open(file_name_local, "w", encoding="utf-8") local_file.write(setup_data) local_file.close() @@ -174,7 +176,7 @@ def load_setup_from_local_file(self, file_name_local): # Note: Preserve line endings so that lenght matches # File probably received/stored from Windows scope with \r\n print("WAVERUNNER: Loading setup from " + file_name_local) - local_file = open(file_name_local, "r", newline='', encoding='utf-8') + local_file = open(file_name_local, "r", newline="", encoding="utf-8") data_read_from_file = local_file.read() file_name_scope = "'D:\\Temporary_setup.lss'" self._write_to_file_on_scope(file_name_scope, data_read_from_file) @@ -196,12 +198,17 @@ def _populate_device_info(self): def _print_device_info(self): def print_info(manufacturer, model, serial, version, opts): # TODO: logging - print(f"WAVERUNNER: Connected to {manufacturer} {model} (ip: " - f"{self._ip_addr}, serial: {serial}, " - f"version: {version}, options: {opts})") + print( + f"WAVERUNNER: Connected to {manufacturer} {model} (ip: " + f"{self._ip_addr}, serial: {serial}, " + f"version: {version}, options: {opts})" + ) if opts == "WARNING : CURRENT REMOTE CONTROL INTERFACE IS TCPIP": - print("ERROR: WAVERUNNER: Must set remote control to VXI11 on scope under: " - "Utilities > Utilities Setup > Remote") + print( + "ERROR: WAVERUNNER: Must set remote control to VXI11 on scope under: " + "Utilities > Utilities Setup > Remote" + ) + print_info(**self._device_info) def _default_setup(self): @@ -239,9 +246,13 @@ def _configure_power_channel(self): f"{self.acqu_channel}:OFST 105MV", ] self._write(";".join(commands)) - self._write(f"vbs 'app.Acquisition.{self.acqu_channel}.BandwidthLimit = \"200MHz\"'") + self._write( + f"vbs 'app.Acquisition.{self.acqu_channel}.BandwidthLimit = \"200MHz\"'" + ) # Noise filtering - reduces bandwidth. - self._write(f"vbs 'app.Acquisition.{self.acqu_channel}.EnhanceResType = \"2.5bits\"'") + self._write( + f"vbs 'app.Acquisition.{self.acqu_channel}.EnhanceResType = \"2.5bits\"'" + ) def _configure_trigger_channel(self): # Note this is a default configuration and might not be meaningfull always @@ -303,16 +314,15 @@ def _configure_waveform_transfer(self): ] self._write(";".join(commands)) - def configure_waveform_transfer_general(self, - num_segments, - sparsing, - num_samples, - first_point, - acqu_channel): + def configure_waveform_transfer_general( + self, num_segments, sparsing, num_samples, first_point, acqu_channel + ): """Configures the oscilloscope for acqu with given parameters.""" - print(f"WAVERUNNER: Configuring with num_segments={num_segments}, " - f"sparsing={sparsing}, num_samples={num_samples}, " - f"first_point={first_point}, acqu_channel=" + acqu_channel) + print( + f"WAVERUNNER: Configuring with num_segments={num_segments}, " + f"sparsing={sparsing}, num_samples={num_samples}, " + f"first_point={first_point}, acqu_channel=" + acqu_channel + ) self.num_samples = num_samples self.num_segments = num_segments self.acqu_channel = acqu_channel @@ -378,11 +388,15 @@ def _parse_waveform(self, data): # Note: We use frombufer to minimize processing overhead. waves = np.frombuffer(data, dtype, len_, 22) # Reshape - waves = waves.reshape((self.num_segments, int(waves.shape[0] / self.num_segments))) + waves = waves.reshape( + (self.num_segments, int(waves.shape[0] / self.num_segments)) + ) if waves.shape[1] != self.num_samples: - print("WAVERUNNER: ERROR: scope returned too many samples per trace or segment") + print( + "WAVERUNNER: ERROR: scope returned too many samples per trace or segment" + ) # Truncate, but means scope returns more samples than expected! - waves = waves[:, 0:self.num_samples] + waves = waves[:, 0: self.num_samples] return waves def capture_and_transfer_waves(self): diff --git a/ci/ci_trace_check/ci_compare_aes_traces.py b/ci/ci_trace_check/ci_compare_aes_traces.py index df8ca679..dd4b0105 100755 --- a/ci/ci_trace_check/ci_compare_aes_traces.py +++ b/ci/ci_trace_check/ci_compare_aes_traces.py @@ -30,12 +30,13 @@ def analyze_traces(file_proj, file_gold_proj, corr_coeff) -> bool: True if trace comparison succeeds, False otherwise. """ # Open the current project - project_curr_cfg = ProjectConfig(type = "ot_trace_library", - path = file_proj, - wave_dtype = np.uint16, - overwrite = False, - trace_threshold = 10000 - ) + project_curr_cfg = ProjectConfig( + type="ot_trace_library", + path=file_proj, + wave_dtype=np.uint16, + overwrite=False, + trace_threshold=10000, + ) proj_curr = SCAProject(project_curr_cfg) proj_curr.open_project() # Calculate mean of new traces @@ -43,12 +44,13 @@ def analyze_traces(file_proj, file_gold_proj, corr_coeff) -> bool: curr_trace = np.mean(curr_waves, axis=0) # Import the golden project - project_gold_cfg = ProjectConfig(type = "ot_trace_library", - path = file_gold_proj, - wave_dtype = np.uint16, - overwrite = False, - trace_threshold = 10000 - ) + project_gold_cfg = ProjectConfig( + type="ot_trace_library", + path=file_gold_proj, + wave_dtype=np.uint16, + overwrite=False, + trace_threshold=10000, + ) proj_gold = SCAProject(project_gold_cfg) proj_gold.open_project() # Calculate mean of golden traces @@ -57,7 +59,7 @@ def analyze_traces(file_proj, file_gold_proj, corr_coeff) -> bool: # Pearson correlation: golden trace vs. mean of new traces calc_coeff = scipy.stats.pearsonr(gold_trace, curr_trace).correlation - print(f'Correlation={round(calc_coeff,3)}') + print(f"Correlation={round(calc_coeff, 3)}") # Fail / pass if calc_coeff < corr_coeff: return False @@ -73,23 +75,17 @@ def parse_args(): coefficient is below user threshold.""" ) parser.add_argument( - "-f", - "--file_proj", - required=True, - help="chipwhisperer project file" + "-f", "--file_proj", required=True, help="chipwhisperer project file" ) parser.add_argument( - "-g", - "--file_gold_proj", - required=True, - help="chipwhisperergolden project file" + "-g", "--file_gold_proj", required=True, help="chipwhisperergolden project file" ) parser.add_argument( "-c", "--corr_coeff", type=float, required=True, - help="specifies the correlation coefficient threshold" + help="specifies the correlation coefficient threshold", ) return parser.parse_args() @@ -99,9 +95,9 @@ def main() -> int: args = parse_args() if analyze_traces(**vars(args)): - print('Traces OK.') + print("Traces OK.") else: - print('Traces correlation below threshold.') + print("Traces correlation below threshold.") sys.exit(1) diff --git a/cw/capture.py b/cw/capture.py index 066bb483..ec1e3f3f 100755 --- a/cw/capture.py +++ b/cw/capture.py @@ -38,11 +38,15 @@ class ScopeType(str, Enum): app_capture = typer.Typer() app.add_typer(app_capture, name="capture", help="Capture traces for SCA") # Shared options for capture commands -opt_force_program_bitstream = typer.Option(None, help=("Force program FPGA with the bitstream.")) +opt_force_program_bitstream = typer.Option( + None, help=("Force program FPGA with the bitstream.") +) opt_num_traces = typer.Option(None, help="Number of traces to capture.") opt_plot_traces = typer.Option(None, help="Number of traces to plot.") opt_scope_type = typer.Option(ScopeType.cw, help=("Scope type")) -opt_ciphertexts_store = typer.Option(False, help=("Store all ciphertexts for batch capture.")) +opt_ciphertexts_store = typer.Option( + False, help=("Store all ciphertexts for batch capture.") +) def create_waverunner(ot, capture_cfg): @@ -52,12 +56,14 @@ def create_waverunner(ot, capture_cfg): def create_cw_segmented(ot, capture_cfg, device_cfg): """Create CwSegmented object to be used for batch capture.""" - return CwSegmented(num_samples=ot.num_samples, - offset_samples=ot.offset_samples, - scope_gain=capture_cfg["scope_gain"], - scope=ot.scope, - clkgen_freq=ot.clkgen_freq, - adc_mul=ot.adc_mul) + return CwSegmented( + num_samples=ot.num_samples, + offset_samples=ot.offset_samples, + scope_gain=capture_cfg["scope_gain"], + scope=ot.scope, + clkgen_freq=ot.clkgen_freq, + adc_mul=ot.adc_mul, + ) SCOPE_FACTORY = { @@ -67,12 +73,12 @@ def create_cw_segmented(ot, capture_cfg, device_cfg): def abort_handler(project, sig, frame): - """ Handler for ctrl-c keyboard interrupts: - Saves capture project before exiting, in case abort is intended. - Needs to be registered in every capture function before capture loop. - To register handler use: - signal.signal(signal.SIGINT, partial(abort_handler, project)) - where 'project' is the variable for the capture project """ + """Handler for ctrl-c keyboard interrupts: + Saves capture project before exiting, in case abort is intended. + Needs to be registered in every capture function before capture loop. + To register handler use: + signal.signal(signal.SIGINT, partial(abort_handler, project)) + where 'project' is the variable for the capture project""" if project is not None: print("\nCaught keyboard interrupt -> saving project (traces)...") project.close(save=True) @@ -82,7 +88,7 @@ def abort_handler(project, sig, frame): def save_metadata(project, device_cfg, capture_cfg, trigger_cycles, sample_rate): # Save metadata to project file if sample_rate is not None: - project.settingsDict['sample_rate'] = sample_rate + project.settingsDict["sample_rate"] = sample_rate if device_cfg is not None: for entry in device_cfg: project.settingsDict[entry] = device_cfg[entry] @@ -91,51 +97,64 @@ def save_metadata(project, device_cfg, capture_cfg, trigger_cycles, sample_rate) project.settingsDict[entry] = capture_cfg[entry] # store last number of cycles where the trigger signal was high to metadata if trigger_cycles is not None: - project.settingsDict['samples_trigger_high'] = trigger_cycles - project.settingsDict['datetime'] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") + project.settingsDict["samples_trigger_high"] = trigger_cycles + project.settingsDict["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") # Note: initialize_capture and plot_results are also used by other scripts. def initialize_capture(device_cfg, capture_cfg): """Initialize capture.""" - ot = device.OpenTitan(device_cfg["fpga_bitstream"], - device_cfg["force_program_bitstream"], - device_cfg["fw_bin"], - device_cfg["pll_frequency"], - device_cfg["target_clk_mult"], - device_cfg["baudrate"], - capture_cfg["scope_gain"], - capture_cfg["num_cycles"], - capture_cfg["offset_cycles"], - capture_cfg["output_len_bytes"]) - print(f'Scope setup with sampling rate {ot.scope.clock.adc_freq} S/s') + ot = device.OpenTitan( + device_cfg["fpga_bitstream"], + device_cfg["force_program_bitstream"], + device_cfg["fw_bin"], + device_cfg["pll_frequency"], + device_cfg["target_clk_mult"], + device_cfg["baudrate"], + capture_cfg["scope_gain"], + capture_cfg["num_cycles"], + capture_cfg["offset_cycles"], + capture_cfg["output_len_bytes"], + ) + print(f"Scope setup with sampling rate {ot.scope.clock.adc_freq} S/s") # Ping target - print('Reading from FPGA using simpleserial protocol.') + print("Reading from FPGA using simpleserial protocol.") version = None ping_cnt = 0 while not version: if ping_cnt == 3: - raise RuntimeError( - f'No response from the target (attempts: {ping_cnt}).') - ot.target.write('v' + '\n') + raise RuntimeError(f"No response from the target (attempts: {ping_cnt}).") + ot.target.write("v" + "\n") ping_cnt += 1 time.sleep(0.5) version = ot.target.read().strip() - print(f'Target simpleserial version: {version} (attempts: {ping_cnt}).') + print(f"Target simpleserial version: {version} (attempts: {ping_cnt}).") return ot def check_range(waves, bits_per_sample): - """ The ADC output is in the interval [0, 2**bits_per_sample-1]. Check that the recorded - traces are within [1, 2**bits_per_sample-2] to ensure the ADC doesn't saturate. """ + """The ADC output is in the interval [0, 2**bits_per_sample-1]. Check that the recorded + traces are within [1, 2**bits_per_sample-2] to ensure the ADC doesn't saturate.""" adc_range = np.array([0, 2**bits_per_sample]) - if not (np.all(np.greater(waves[:], adc_range[0])) and - np.all(np.less(waves[:], adc_range[1] - 1))): - print('\nWARNING: Some samples are outside the range [' + - str(adc_range[0] + 1) + ', ' + str(adc_range[1] - 2) + '].') - print('The ADC has a max range of [' + - str(adc_range[0]) + ', ' + str(adc_range[1] - 1) + '] and might saturate.') - print('It is recommended to reduce the scope gain (see device.py).') + if not ( + np.all(np.greater(waves[:], adc_range[0])) and + np.all(np.less(waves[:], adc_range[1] - 1)) + ): + print( + "\nWARNING: Some samples are outside the range [" + + str(adc_range[0] + 1) + + ", " + + str(adc_range[1] - 2) + + "]." + ) + print( + "The ADC has a max range of [" + + str(adc_range[0]) + + ", " + + str(adc_range[1] - 1) + + "] and might saturate." + ) + print("It is recommended to reduce the scope gain (see device.py).") def plot_results(plot_cfg, project_name): @@ -143,11 +162,12 @@ def plot_results(plot_cfg, project_name): project = cw.open_project(project_name) if len(project.waves) == 0: - print('Project contains no traces. Did the capture fail?') + print("Project contains no traces. Did the capture fail?") return - plot.save_plot_to_file(project.waves, None, plot_cfg["num_traces"], - plot_cfg["trace_image_filename"]) + plot.save_plot_to_file( + project.waves, None, plot_cfg["num_traces"], plot_cfg["trace_image_filename"] + ) print( f'Created plot with {plot_cfg["num_traces"]} traces: ' f'{Path(plot_cfg["trace_image_filename"]).resolve()}' @@ -197,7 +217,7 @@ def capture_loop(trace_gen, ot, capture_cfg, device_cfg): # register ctrl-c handler to not lose already recorded traces if measurement is aborted signal.signal(signal.SIGINT, partial(abort_handler, project)) - for _ in tqdm(range(capture_cfg["num_traces"]), desc='Capturing', ncols=80): + for _ in tqdm(range(capture_cfg["num_traces"]), desc="Capturing", ncols=80): traces = next(trace_gen) check_range(traces.wave, ot.scope.adc.bits_per_sample) project.traces.append(traces, dtype=np.uint16) @@ -222,34 +242,76 @@ def capture_aes_static(ot): Args: ot: Initialized OpenTitan target. """ - key = bytearray([0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, - 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9]) - text = bytearray([0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA]) + key = bytearray( + [ + 0x81, + 0x1E, + 0x37, + 0x31, + 0xB0, + 0x12, + 0x0A, + 0x78, + 0x42, + 0x78, + 0x1E, + 0x22, + 0xB2, + 0x5C, + 0xDD, + 0xF9, + ] + ) + text = bytearray( + [ + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + ] + ) - tqdm.write(f'Fixed key: {binascii.b2a_hex(bytes(key))}') + tqdm.write(f"Fixed key: {binascii.b2a_hex(bytes(key))}") while True: cipher = AES.new(bytes(key), AES.MODE_ECB) ret = cw.capture_trace(ot.scope, ot.target, text, key, ack=False, as_int=True) if not ret: - raise RuntimeError('Capture failed.') + raise RuntimeError("Capture failed.") expected = binascii.b2a_hex(cipher.encrypt(bytes(text))) got = binascii.b2a_hex(ret.textout) if got != expected: - raise RuntimeError(f'Bad ciphertext: {got} != {expected}.') + raise RuntimeError(f"Bad ciphertext: {got} != {expected}.") yield ret @app_capture.command() -def aes_static(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def aes_static( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): """Capture AES traces from a target that runs the `aes_serial` program.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_loop(capture_aes_static(ctx.obj.ot), ctx.obj.ot, - ctx.obj.cfg["capture"], ctx.obj.cfg["device"]) + capture_loop( + capture_aes_static(ctx.obj.ot), + ctx.obj.ot, + ctx.obj.cfg["capture"], + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @@ -262,7 +324,7 @@ def capture_aes_random(ot, ktp): ktp: Key and plaintext generator. """ key, _ = ktp.next() - tqdm.write(f'Using key: {binascii.b2a_hex(bytes(key))}') + tqdm.write(f"Using key: {binascii.b2a_hex(bytes(key))}") cipher = AES.new(bytes(key), AES.MODE_ECB) # Select the trigger type: # 0 - precise, hardware-generated trigger - default @@ -272,23 +334,29 @@ def capture_aes_random(ot, ktp): _, text = ktp.next() ret = cw.capture_trace(ot.scope, ot.target, text, key, ack=False, as_int=True) if not ret: - raise RuntimeError('Capture failed.') + raise RuntimeError("Capture failed.") expected = binascii.b2a_hex(cipher.encrypt(bytes(text))) got = binascii.b2a_hex(ret.textout) if got != expected: - raise RuntimeError(f'Bad ciphertext: {got} != {expected}.') + raise RuntimeError(f"Bad ciphertext: {got} != {expected}.") yield ret @app_capture.command() -def aes_random(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def aes_random( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): """Capture AES traces from a target that runs the `aes_serial` program.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_loop(capture_aes_random(ctx.obj.ot, ctx.obj.ktp), ctx.obj.ot, - ctx.obj.cfg["capture"], ctx.obj.cfg["device"]) + capture_loop( + capture_aes_random(ctx.obj.ot, ctx.obj.ktp), + ctx.obj.ot, + ctx.obj.cfg["capture"], + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @@ -339,10 +407,12 @@ def capture_aes_random_batch(ot, ktp, capture_cfg, scope_type, device_cfg): random.seed(capture_cfg["batch_prng_seed"]) # Set the target's key key = ktp.next_key() - tqdm.write(f'Using key: {binascii.b2a_hex(bytes(key))}') + tqdm.write(f"Using key: {binascii.b2a_hex(bytes(key))}") ot.target.simpleserial_write("k", key) # Seed the target's PRNG - ot.target.simpleserial_write("s", capture_cfg["batch_prng_seed"].to_bytes(4, "little")) + ot.target.simpleserial_write( + "s", capture_cfg["batch_prng_seed"].to_bytes(4, "little") + ) # Create the ChipWhisperer project. project = cw.create_project(capture_cfg["project_name"], overwrite=True) @@ -390,7 +460,7 @@ def capture_aes_random_batch(ot, ktp, capture_cfg, scope_type, device_cfg): for wave, plaintext, ciphertext in zip(waves, plaintexts, ciphertexts): project.traces.append( cw.common.traces.Trace(wave, plaintext, ciphertext, key), - dtype=np.uint16 + dtype=np.uint16, ) # Update the loop variable and the progress bar. @@ -411,15 +481,22 @@ def capture_aes_random_batch(ot, ktp, capture_cfg, scope_type, device_cfg): @app_capture.command() -def aes_random_batch(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces, - scope_type: ScopeType = opt_scope_type): +def aes_random_batch( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, + scope_type: ScopeType = opt_scope_type, +): """Capture AES traces in batch mode. Fixed key random texts.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_aes_random_batch(ctx.obj.ot, ctx.obj.ktp, ctx.obj.cfg["capture"], - scope_type, ctx.obj.cfg["device"]) + capture_aes_random_batch( + ctx.obj.ot, + ctx.obj.ktp, + ctx.obj.cfg["capture"], + scope_type, + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @@ -435,19 +512,109 @@ def capture_aes_fvsr_key(ot): Args: ot: Initialized OpenTitan target. """ - key_generation = bytearray([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1, - 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xE0, 0xF0]) + key_generation = bytearray( + [ + 0x12, + 0x34, + 0x56, + 0x78, + 0x9A, + 0xBC, + 0xDE, + 0xF1, + 0x23, + 0x45, + 0x67, + 0x89, + 0xAB, + 0xCD, + 0xE0, + 0xF0, + ] + ) cipher_gen = AES.new(bytes(key_generation), AES.MODE_ECB) - text_fixed = bytearray([0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA]) - text_random = bytearray([0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, - 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC]) - key_fixed = bytearray([0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, - 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9]) - key_random = bytearray([0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, - 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53]) + text_fixed = bytearray( + [ + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + ] + ) + text_random = bytearray( + [ + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + ] + ) + key_fixed = bytearray( + [ + 0x81, + 0x1E, + 0x37, + 0x31, + 0xB0, + 0x12, + 0x0A, + 0x78, + 0x42, + 0x78, + 0x1E, + 0x22, + 0xB2, + 0x5C, + 0xDD, + 0xF9, + ] + ) + key_random = bytearray( + [ + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + ] + ) - tqdm.write(f'Fixed key: {binascii.b2a_hex(bytes(key_fixed))}') + tqdm.write(f"Fixed key: {binascii.b2a_hex(bytes(key_fixed))}") sample_fixed = 1 while True: @@ -463,27 +630,35 @@ def capture_aes_fvsr_key(ot): cipher = AES.new(bytes(key), AES.MODE_ECB) ret = cw.capture_trace(ot.scope, ot.target, text, key, ack=False, as_int=True) if not ret: - raise RuntimeError('Capture failed.') + raise RuntimeError("Capture failed.") expected = binascii.b2a_hex(cipher.encrypt(bytes(text))) got = binascii.b2a_hex(ret.textout) if got != expected: - raise RuntimeError(f'Bad ciphertext: {got} != {expected}.') + raise RuntimeError(f"Bad ciphertext: {got} != {expected}.") yield ret @app_capture.command() -def aes_fvsr_key(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def aes_fvsr_key( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): """Capture AES traces from a target that runs the `aes_serial` program.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_loop(capture_aes_fvsr_key(ctx.obj.ot), ctx.obj.ot, - ctx.obj.cfg["capture"], ctx.obj.cfg["device"]) + capture_loop( + capture_aes_fvsr_key(ctx.obj.ot), + ctx.obj.ot, + ctx.obj.cfg["capture"], + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) -def capture_aes_fvsr_key_batch(ot, ktp, capture_cfg, scope_type, gen_ciphertexts, device_cfg): +def capture_aes_fvsr_key_batch( + ot, ktp, capture_cfg, scope_type, gen_ciphertexts, device_cfg +): """A generator for capturing AES traces for fixed vs random key test in batch mode. The data collection method is based on the derived test requirements (DTR) for TVLA: https://www.rambus.com/wp-content/uploads/2015/08/TVLA-DTR-with-AES.pdf @@ -503,15 +678,35 @@ def capture_aes_fvsr_key_batch(ot, ktp, capture_cfg, scope_type, gen_ciphertexts random.seed(capture_cfg["batch_prng_seed"]) # Seed the target's PRNGs ot.target.simpleserial_write("l", capture_cfg["lfsr_seed"].to_bytes(4, "little")) - ot.target.simpleserial_write("s", capture_cfg["batch_prng_seed"].to_bytes(4, "little")) + ot.target.simpleserial_write( + "s", capture_cfg["batch_prng_seed"].to_bytes(4, "little") + ) # Set and transfer the fixed key. # Without the sleep statement, the CW305 seems to fail to configure the batch PRNG # seed and/or the fixed key and then gets completely out of sync. time.sleep(0.5) - key_fixed = bytearray([0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, - 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9]) - tqdm.write(f'Fixed key: {binascii.b2a_hex(bytes(key_fixed))}') + key_fixed = bytearray( + [ + 0x81, + 0x1E, + 0x37, + 0x31, + 0xB0, + 0x12, + 0x0A, + 0x78, + 0x42, + 0x78, + 0x1E, + 0x22, + 0xB2, + 0x5C, + 0xDD, + 0xF9, + ] + ) + tqdm.write(f"Fixed key: {binascii.b2a_hex(bytes(key_fixed))}") ot.target.simpleserial_write("f", key_fixed) sample_fixed = 1 @@ -538,9 +733,13 @@ def capture_aes_fvsr_key_batch(ot, ktp, capture_cfg, scope_type, gen_ciphertexts # encryption, the device will start automatically to generate random keys and plaintexts # when this script is getting waves from the scope. if is_first_batch: - ot.target.simpleserial_write("g", scope.num_segments_actual.to_bytes(4, "little")) + ot.target.simpleserial_write( + "g", scope.num_segments_actual.to_bytes(4, "little") + ) is_first_batch = False - ot.target.simpleserial_write("e", scope.num_segments_actual.to_bytes(4, "little")) + ot.target.simpleserial_write( + "e", scope.num_segments_actual.to_bytes(4, "little") + ) # Transfer traces. waves = scope.capture_and_transfer_waves() @@ -567,7 +766,9 @@ def capture_aes_fvsr_key_batch(ot, ktp, capture_cfg, scope_type, gen_ciphertexts if gen_ciphertexts: expected_last_ciphertext = ciphertexts[-1] else: - expected_last_ciphertext = np.asarray(scared.aes.base.encrypt(plaintext, key)) + expected_last_ciphertext = np.asarray( + scared.aes.base.encrypt(plaintext, key) + ) check_ciphertext(ot, expected_last_ciphertext, 4) @@ -578,16 +779,18 @@ def capture_aes_fvsr_key_batch(ot, ktp, capture_cfg, scope_type, gen_ciphertexts # substantially reduces capture performance. It should therefore only be enabled if # absolutely needed. if gen_ciphertexts: - for wave, plaintext, ciphertext, key in zip(waves, plaintexts, ciphertexts, keys): + for wave, plaintext, ciphertext, key in zip( + waves, plaintexts, ciphertexts, keys + ): project.traces.append( cw.common.traces.Trace(wave, plaintext, ciphertext, key), - dtype=np.uint16 + dtype=np.uint16, ) else: for wave, plaintext, key in zip(waves, plaintexts, keys): project.traces.append( cw.common.traces.Trace(wave, plaintext, None, key), - dtype=np.uint16 + dtype=np.uint16, ) # Update the loop variable and the progress bar. @@ -608,25 +811,34 @@ def capture_aes_fvsr_key_batch(ot, ktp, capture_cfg, scope_type, gen_ciphertexts @app_capture.command() -def aes_fvsr_key_batch(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces, - scope_type: ScopeType = opt_scope_type, - gen_ciphertexts: bool = opt_ciphertexts_store): +def aes_fvsr_key_batch( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, + scope_type: ScopeType = opt_scope_type, + gen_ciphertexts: bool = opt_ciphertexts_store, +): """Capture AES traces in batch mode. Fixed vs random keys, random texts.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_aes_fvsr_key_batch(ctx.obj.ot, ctx.obj.ktp, ctx.obj.cfg["capture"], - scope_type, gen_ciphertexts, - ctx.obj.cfg["device"]) + capture_aes_fvsr_key_batch( + ctx.obj.ot, + ctx.obj.ktp, + ctx.obj.cfg["capture"], + scope_type, + gen_ciphertexts, + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @app_capture.command() -def aes_mix_column(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def aes_mix_column( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): """Capture AES traces. Fixed key, Random texts. 4 sets of traces. Mix Column HD CPA Attack. Attack implemented by ChipWhisperer: Repo: https://github.com/newaetech/chipwhisperer-jupyter/blob/master/experiments/MixColumn%20Attack.ipynb # noqa: E501 @@ -636,17 +848,20 @@ def aes_mix_column(ctx: typer.Context, capture_init(ctx, force_program_bitstream, num_traces, plot_traces) ctx.obj.ktp = cw.ktp.VarVec() - ctx.obj.ktp.key_len = ctx.obj.cfg['capture']['key_len_bytes'] - ctx.obj.ktp.text_len = ctx.obj.cfg['capture']['plain_text_len_bytes'] - project_name = ctx.obj.cfg["capture"]['project_name'] + ctx.obj.ktp.key_len = ctx.obj.cfg["capture"]["key_len_bytes"] + ctx.obj.ktp.text_len = ctx.obj.cfg["capture"]["plain_text_len_bytes"] + project_name = ctx.obj.cfg["capture"]["project_name"] # For each iteration, run a capture where only the bytes specified in # `text_range` are set to random values. All other bytes are set to a # fixed value. for var_vec in range(4): - ctx.obj.cfg['capture']['project_name'] = f'{project_name}_{var_vec}' + ctx.obj.cfg["capture"]["project_name"] = f"{project_name}_{var_vec}" ctx.obj.ktp.var_vec = var_vec - capture_loop(capture_aes_random( - ctx.obj.ot, ctx.obj.ktp), ctx.obj.ot, ctx.obj.cfg["capture"], ctx.obj.cfg["device"] + capture_loop( + capture_aes_random(ctx.obj.ot, ctx.obj.ktp), + ctx.obj.ot, + ctx.obj.cfg["capture"], + ctx.obj.cfg["device"], ) capture_end(ctx.obj.cfg) @@ -676,14 +891,16 @@ def capture_sha3_random(ot, ktp, capture_cfg): tqdm.write("No key used, as we are doing sha3 hashing") while True: _, text = ktp.next() - ret = cw.capture_trace(ot.scope, ot.target, text, key=None, ack=False, as_int=True) + ret = cw.capture_trace( + ot.scope, ot.target, text, key=None, ack=False, as_int=True + ) if not ret: - raise RuntimeError('Capture failed.') + raise RuntimeError("Capture failed.") sha3 = SHA3_256.new(text) expected = binascii.b2a_hex(sha3.digest()) got = binascii.b2a_hex(ret.textout) if got != expected: - raise RuntimeError(f'Bad digest: {got} != {expected}.') + raise RuntimeError(f"Bad digest: {got} != {expected}.") yield ret @@ -714,8 +931,26 @@ def capture_sha3_fvsr_data_batch(ot, ktp, capture_cfg, scope_type, device_cfg): raise Exception("Batch mode acknowledge error: Device and host not in sync") # Value defined under Section 5.3 in the derived test requirements (DTR) for TVLA. - plaintext_fixed = bytearray([0xDA, 0x39, 0xA3, 0xEE, 0x5E, 0x6B, 0x4B, 0x0D, - 0x32, 0x55, 0xBF, 0xEF, 0x95, 0x60, 0x18, 0x90]) + plaintext_fixed = bytearray( + [ + 0xDA, + 0x39, + 0xA3, + 0xEE, + 0x5E, + 0x6B, + 0x4B, + 0x0D, + 0x32, + 0x55, + 0xBF, + 0xEF, + 0x95, + 0x60, + 0x18, + 0x90, + ] + ) # Note that - at least on FPGA - the DTR value above may lead to "fake" leakage as for the # fixed trace set, the number of bits set in the first (37) and second 64-bit word (31), as @@ -740,7 +975,9 @@ def capture_sha3_fvsr_data_batch(ot, ktp, capture_cfg, scope_type, device_cfg): plaintext = plaintext_fixed random.seed(capture_cfg["batch_prng_seed"]) ot.target.simpleserial_write("l", capture_cfg["lfsr_seed"].to_bytes(4, "little")) - ot.target.simpleserial_write("s", capture_cfg["batch_prng_seed"].to_bytes(4, "little")) + ot.target.simpleserial_write( + "s", capture_cfg["batch_prng_seed"].to_bytes(4, "little") + ) # Create the ChipWhisperer project. project_file = capture_cfg["project_name"] @@ -768,7 +1005,9 @@ def capture_sha3_fvsr_data_batch(ot, ktp, capture_cfg, scope_type, device_cfg): # This wait ist crucial to be in sync with the device ack_ret = ot.target.simpleserial_wait_ack(5000) if ack_ret is None: - raise Exception("Batch mode acknowledge error: Device and host not in sync") + raise Exception( + "Batch mode acknowledge error: Device and host not in sync" + ) plaintexts = [] ciphertexts = [] @@ -788,8 +1027,11 @@ def capture_sha3_fvsr_data_batch(ot, ktp, capture_cfg, scope_type, device_cfg): sha3 = SHA3_256.new(plaintext) ciphertext = sha3.digest() - batch_digest = (ciphertext if batch_digest is None else - bytes(a ^ b for (a, b) in zip(ciphertext, batch_digest))) + batch_digest = ( + ciphertext + if batch_digest is None + else bytes(a ^ b for (a, b) in zip(ciphertext, batch_digest)) + ) plaintexts.append(plaintext) ciphertexts.append(binascii.b2a_hex(ciphertext)) sample_fixed = dummy_plaintext[0] & 1 @@ -808,8 +1050,10 @@ def capture_sha3_fvsr_data_batch(ot, ktp, capture_cfg, scope_type, device_cfg): # Add traces of this batch to the project. for wave, plaintext, ciphertext in zip(waves, plaintexts, ciphertexts): project.traces.append( - cw.common.traces.Trace(wave, plaintext, bytearray(ciphertext), None), - dtype=np.uint16 + cw.common.traces.Trace( + wave, plaintext, bytearray(ciphertext), None + ), + dtype=np.uint16, ) # Update the loop variable and the progress bar. rem_num_traces -= scope.num_segments @@ -828,14 +1072,20 @@ def capture_sha3_fvsr_data_batch(ot, ktp, capture_cfg, scope_type, device_cfg): @app_capture.command() -def sha3_random(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def sha3_random( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): """Capture sha3 traces from a target that runs the `sha3_serial` program.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_loop(capture_sha3_random(ctx.obj.ot, ctx.obj.ktp, ctx.obj.cfg["capture"]), - ctx.obj.ot, ctx.obj.cfg["capture"], ctx.obj.cfg["device"]) + capture_loop( + capture_sha3_random(ctx.obj.ot, ctx.obj.ktp, ctx.obj.cfg["capture"]), + ctx.obj.ot, + ctx.obj.cfg["capture"], + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @@ -851,13 +1101,67 @@ def capture_sha3_fvsr_data(ot, capture_cfg): """ # we are using AES in ECB mode for generating random texts - key_generation = bytearray([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1, - 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xE0, 0xF0]) + key_generation = bytearray( + [ + 0x12, + 0x34, + 0x56, + 0x78, + 0x9A, + 0xBC, + 0xDE, + 0xF1, + 0x23, + 0x45, + 0x67, + 0x89, + 0xAB, + 0xCD, + 0xE0, + 0xF0, + ] + ) cipher = AES.new(bytes(key_generation), AES.MODE_ECB) - text_fixed = bytearray([0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA]) - text_random = bytearray([0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, - 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC]) + text_fixed = bytearray( + [ + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + ] + ) + text_random = bytearray( + [ + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + ] + ) sha3 = SHA3_256.new(text_fixed) digest_fixed = binascii.b2a_hex(sha3.digest()) @@ -881,51 +1185,64 @@ def capture_sha3_fvsr_data(ot, capture_cfg): sample_fixed = 1 while True: if sample_fixed: - ret = cw.capture_trace(ot.scope, ot.target, text_fixed, key=None, ack=False, - as_int=True) + ret = cw.capture_trace( + ot.scope, ot.target, text_fixed, key=None, ack=False, as_int=True + ) if not ret: - raise RuntimeError('Capture failed.') + raise RuntimeError("Capture failed.") expected = digest_fixed got = binascii.b2a_hex(ret.textout) else: text_random = bytearray(cipher.encrypt(text_random)) - ret = cw.capture_trace(ot.scope, ot.target, text_random, key=None, ack=False, - as_int=True) + ret = cw.capture_trace( + ot.scope, ot.target, text_random, key=None, ack=False, as_int=True + ) if not ret: - raise RuntimeError('Capture failed.') + raise RuntimeError("Capture failed.") sha3 = SHA3_256.new(text_random) expected = binascii.b2a_hex(sha3.digest()) got = binascii.b2a_hex(ret.textout) sample_fixed = random.randint(0, 1) if got != expected: - raise RuntimeError(f'Bad digest: {got} != {expected}.') + raise RuntimeError(f"Bad digest: {got} != {expected}.") yield ret @app_capture.command() -def sha3_fvsr_data(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def sha3_fvsr_data( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): """Capture sha3 traces from a target that runs the `sha3_serial` program.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_loop(capture_sha3_fvsr_data(ctx.obj.ot, ctx.obj.cfg["capture"]), - ctx.obj.ot, ctx.obj.cfg["capture"], ctx.obj.cfg["device"]) + capture_loop( + capture_sha3_fvsr_data(ctx.obj.ot, ctx.obj.cfg["capture"]), + ctx.obj.ot, + ctx.obj.cfg["capture"], + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @app_capture.command() -def sha3_fvsr_data_batch(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces, - scope_type: ScopeType = opt_scope_type): +def sha3_fvsr_data_batch( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, + scope_type: ScopeType = opt_scope_type, +): """Capture sha3 traces in batch mode. Fixed vs Random.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_sha3_fvsr_data_batch(ctx.obj.ot, ctx.obj.ktp, - ctx.obj.cfg["capture"], - scope_type, - ctx.obj.cfg["device"]) + capture_sha3_fvsr_data_batch( + ctx.obj.ot, + ctx.obj.ktp, + ctx.obj.cfg["capture"], + scope_type, + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @@ -938,19 +1255,19 @@ def capture_kmac_random(ot, ktp): ktp: Key and plaintext generator. """ key, _ = ktp.next() - tqdm.write(f'Using key: {binascii.b2a_hex(bytes(key))}') + tqdm.write(f"Using key: {binascii.b2a_hex(bytes(key))}") while True: _, text = ktp.next() ret = cw.capture_trace(ot.scope, ot.target, text, key, ack=False, as_int=True) if not ret: - raise RuntimeError('Capture failed.') + raise RuntimeError("Capture failed.") mac = KMAC128.new(key=key, mac_len=32) mac.update(text) expected = mac.hexdigest() - expected = expected.encode('ascii') + expected = expected.encode("ascii") got = binascii.b2a_hex(ret.textout) if got != expected: - raise RuntimeError(f'Bad digest: {got} != {expected}.') + raise RuntimeError(f"Bad digest: {got} != {expected}.") yield ret @@ -970,13 +1287,33 @@ def capture_kmac_fvsr_key_batch(ot, ktp, capture_cfg, scope_type, device_cfg): scope_type: cw or waverunner as a scope for batch capture. """ - key_fixed = bytearray([0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, - 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9]) + key_fixed = bytearray( + [ + 0x81, + 0x1E, + 0x37, + 0x31, + 0xB0, + 0x12, + 0x0A, + 0x78, + 0x42, + 0x78, + 0x1E, + 0x22, + 0xB2, + 0x5C, + 0xDD, + 0xF9, + ] + ) ot.target.simpleserial_write("f", key_fixed) key = key_fixed random.seed(capture_cfg["batch_prng_seed"]) ot.target.simpleserial_write("l", capture_cfg["lfsr_seed"].to_bytes(4, "little")) - ot.target.simpleserial_write("s", capture_cfg["batch_prng_seed"].to_bytes(4, "little")) + ot.target.simpleserial_write( + "s", capture_cfg["batch_prng_seed"].to_bytes(4, "little") + ) # Create the ChipWhisperer project. project_file = capture_cfg["project_name"] @@ -1020,8 +1357,11 @@ def capture_kmac_fvsr_key_batch(ot, ktp, capture_cfg, scope_type, device_cfg): mac = KMAC128.new(key=key, mac_len=32) mac.update(plaintext) ciphertext = bytearray.fromhex(mac.hexdigest()) - batch_digest = (ciphertext if batch_digest is None else - bytes(a ^ b for (a, b) in zip(ciphertext, batch_digest))) + batch_digest = ( + ciphertext + if batch_digest is None + else bytes(a ^ b for (a, b) in zip(ciphertext, batch_digest)) + ) plaintexts.append(plaintext) ciphertexts.append(binascii.b2a_hex(ciphertext)) keys.append(key) @@ -1039,10 +1379,12 @@ def capture_kmac_fvsr_key_batch(ot, ktp, capture_cfg, scope_type, device_cfg): num_segments_storage = optimize_cw_capture(project, num_segments_storage) # Add traces of this batch to the project. - for wave, plaintext, ciphertext, key in zip(waves, plaintexts, ciphertexts, keys): + for wave, plaintext, ciphertext, key in zip( + waves, plaintexts, ciphertexts, keys + ): project.traces.append( cw.common.traces.Trace(wave, plaintext, bytearray(ciphertext), key), - dtype=np.uint16 + dtype=np.uint16, ) # Update the loop variable and the progress bar. rem_num_traces -= scope.num_segments @@ -1061,14 +1403,20 @@ def capture_kmac_fvsr_key_batch(ot, ktp, capture_cfg, scope_type, device_cfg): @app_capture.command() -def kmac_random(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def kmac_random( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): """Capture KMAC-128 traces from a target that runs the `kmac_serial` program.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_loop(capture_kmac_random(ctx.obj.ot, ctx.obj.ktp), ctx.obj.ot, - ctx.obj.cfg["capture"], ctx.obj.cfg["device"]) + capture_loop( + capture_kmac_random(ctx.obj.ot, ctx.obj.ktp), + ctx.obj.ot, + ctx.obj.cfg["capture"], + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @@ -1085,19 +1433,109 @@ def capture_kmac_fvsr_key(ot, capture_cfg): ot: Initialized OpenTitan target. """ - key_generation = bytearray([0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF1, - 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xE0, 0xF0]) + key_generation = bytearray( + [ + 0x12, + 0x34, + 0x56, + 0x78, + 0x9A, + 0xBC, + 0xDE, + 0xF1, + 0x23, + 0x45, + 0x67, + 0x89, + 0xAB, + 0xCD, + 0xE0, + 0xF0, + ] + ) cipher = AES.new(bytes(key_generation), AES.MODE_ECB) - text_fixed = bytearray([0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA]) - text_random = bytearray([0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, - 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC]) - key_fixed = bytearray([0x81, 0x1E, 0x37, 0x31, 0xB0, 0x12, 0x0A, 0x78, - 0x42, 0x78, 0x1E, 0x22, 0xB2, 0x5C, 0xDD, 0xF9]) - key_random = bytearray([0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, - 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53]) - - tqdm.write(f'Using fixed key: {binascii.b2a_hex(bytes(key_fixed))}') + text_fixed = bytearray( + [ + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + 0xAA, + ] + ) + text_random = bytearray( + [ + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + 0xCC, + ] + ) + key_fixed = bytearray( + [ + 0x81, + 0x1E, + 0x37, + 0x31, + 0xB0, + 0x12, + 0x0A, + 0x78, + 0x42, + 0x78, + 0x1E, + 0x22, + 0xB2, + 0x5C, + 0xDD, + 0xF9, + ] + ) + key_random = bytearray( + [ + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + 0x53, + ] + ) + + tqdm.write(f"Using fixed key: {binascii.b2a_hex(bytes(key_fixed))}") ot.target.simpleserial_write("l", capture_cfg["lfsr_seed"].to_bytes(4, "little")) # Start sampling with the fixed key. @@ -1105,57 +1543,70 @@ def capture_kmac_fvsr_key(ot, capture_cfg): while True: if sample_fixed: text_fixed = bytearray(cipher.encrypt(text_fixed)) - ret = cw.capture_trace(ot.scope, ot.target, text_fixed, key_fixed, ack=False, - as_int=True) + ret = cw.capture_trace( + ot.scope, ot.target, text_fixed, key_fixed, ack=False, as_int=True + ) if not ret: - raise RuntimeError('Capture failed.') + raise RuntimeError("Capture failed.") mac = KMAC128.new(key=key_fixed, mac_len=32) mac.update(text_fixed) expected = mac.hexdigest() - expected = expected.encode('ascii') + expected = expected.encode("ascii") got = binascii.b2a_hex(ret.textout) else: text_random = bytearray(cipher.encrypt(text_random)) key_random = bytearray(cipher.encrypt(key_random)) - ret = cw.capture_trace(ot.scope, ot.target, text_random, key_random, ack=False, - as_int=True) + ret = cw.capture_trace( + ot.scope, ot.target, text_random, key_random, ack=False, as_int=True + ) if not ret: - raise RuntimeError('Capture failed.') + raise RuntimeError("Capture failed.") mac = KMAC128.new(key=key_random, mac_len=32) mac.update(text_random) expected = mac.hexdigest() - expected = expected.encode('ascii') + expected = expected.encode("ascii") got = binascii.b2a_hex(ret.textout) sample_fixed = random.randint(0, 1) if got != expected: - raise RuntimeError(f'Bad digest: {got} != {expected}.') + raise RuntimeError(f"Bad digest: {got} != {expected}.") yield ret @app_capture.command() -def kmac_fvsr_key(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def kmac_fvsr_key( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): """Capture KMAC-128 traces from a target that runs the `kmac_serial` program.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_loop(capture_kmac_fvsr_key(ctx.obj.ot, ctx.obj.cfg["capture"]), - ctx.obj.ot, ctx.obj.cfg["capture"], ctx.obj.cfg["device"]) + capture_loop( + capture_kmac_fvsr_key(ctx.obj.ot, ctx.obj.cfg["capture"]), + ctx.obj.ot, + ctx.obj.cfg["capture"], + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @app_capture.command() -def kmac_fvsr_key_batch(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces, - scope_type: ScopeType = opt_scope_type): +def kmac_fvsr_key_batch( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, + scope_type: ScopeType = opt_scope_type, +): """Capture KMAC-128 traces in batch mode. Fixed vs Random.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_kmac_fvsr_key_batch(ctx.obj.ot, ctx.obj.ktp, - ctx.obj.cfg["capture"], - scope_type, - ctx.obj.cfg["device"]) + capture_kmac_fvsr_key_batch( + ctx.obj.ot, + ctx.obj.ktp, + ctx.obj.cfg["capture"], + scope_type, + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @@ -1180,15 +1631,15 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf # For backwards compatibility this must be set in the capture config file. # This is a workaroung for https://github.com/lowRISC/ot-sca/issues/116 if "use_fixed_key_iter" not in capture_cfg: - raise RuntimeError('use_fixed_key_iter not set!') + raise RuntimeError("use_fixed_key_iter not set!") if capture_cfg["use_fixed_key_iter"] is not False: - raise RuntimeError('use_fixed_key_iter must be set to false!') + raise RuntimeError("use_fixed_key_iter must be set to false!") # OTBN operations are long. CW-Husky can store only 131070 samples # in the non-stream mode. fifo_size = 131070 if ot.num_samples > fifo_size: - raise RuntimeError('Current setup only supports up to 130k samples') + raise RuntimeError("Current setup only supports up to 130k samples") # Be sure we don't use the stream mode ot.scope.adc.stream_mode = False @@ -1199,8 +1650,10 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf project = cw.create_project(capture_cfg["project_name"], overwrite=True) # Initialize some curve-dependent parameters. - if capture_cfg["curve"] == 'p256': - curve_order_n = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 + if capture_cfg["curve"] == "p256": + curve_order_n = ( + 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 + ) key_bytes = 256 // 8 seed_bytes = 320 // 8 modinv_share_bytes = 320 // 8 @@ -1212,17 +1665,18 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf # register ctrl-c handler to not lose already recorded traces if measurement is aborted signal.signal(signal.SIGINT, partial(abort_handler, project)) - if capture_cfg["app"] == 'keygen': + if capture_cfg["app"] == "keygen": # Check the lengths in the key/plaintext generator. In this case, "key" # means seed and "plaintext" means mask. if ktp.keyLen() != seed_bytes: raise ValueError( - f'Unexpected seed length: {ktp.keyLen()}.\n' - f'Hint: set key len={seed_bytes} in the configuration file.') + f"Unexpected seed length: {ktp.keyLen()}.\n" + f"Hint: set key len={seed_bytes} in the configuration file." + ) if ktp.textLen() != seed_bytes: raise ValueError( - f'Unexpected mask length: {ktp.textLen()}.\n' - f'Hint: set plaintext len={seed_bytes} in the configuration file.' + f"Unexpected mask length: {ktp.textLen()}.\n" + f"Hint: set plaintext len={seed_bytes} in the configuration file." ) # select the otbn app on the device (0 -> keygen, 1 -> modinv) @@ -1233,7 +1687,7 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf random.seed(capture_cfg["batch_prng_seed"]) # Generate fixed constants for all traces of the keygen operation. - if capture_cfg["test_type"] == 'KEY': + if capture_cfg["test_type"] == "KEY": # In fixed-vs-random KEY mode we use two fixed constants: # 1. C - a 320 bit constant redundancy # 2. fixed_number - a 256 bit number used to derive the fixed key @@ -1242,16 +1696,21 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf # (C + fixed_number) mod curve_order_n C = ktp.next_key() if len(C) != seed_bytes: - raise ValueError(f'Fixed seed length is {len(C)}, expected {seed_bytes}') + raise ValueError( + f"Fixed seed length is {len(C)}, expected {seed_bytes}" + ) ktp.key_len = key_bytes fixed_number = ktp.next_key() if len(fixed_number) != key_bytes: - raise ValueError(f'Fixed key length is {len(fixed_number)}, expected {key_bytes}') + raise ValueError( + f"Fixed key length is {len(fixed_number)}, expected {key_bytes}" + ) ktp.key_len = seed_bytes - seed_fixed_int = int.from_bytes(C, byteorder='little') + \ - int.from_bytes(fixed_number, byteorder='little') - seed_fixed = seed_fixed_int.to_bytes(seed_bytes, byteorder='little') + seed_fixed_int = int.from_bytes(C, byteorder="little") + int.from_bytes( + fixed_number, byteorder="little" + ) + seed_fixed = seed_fixed_int.to_bytes(seed_bytes, byteorder="little") else: # In fixed-vs-random SEED mode we use only one fixed constant: # 1. seed_fixed - A 320 bit constant used to derive the fixed key @@ -1260,33 +1719,33 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf # seed_fixed mod curve_order_n seed_fixed = ktp.next_key() if len(seed_fixed) != seed_bytes: - raise ValueError(f'Fixed seed length is {len(seed_fixed)}, expected {seed_bytes}') + raise ValueError( + f"Fixed seed length is {len(seed_fixed)}, expected {seed_bytes}" + ) # Expected key is `seed mod n`, where n is the order of the curve and # `seed` is interpreted as little-endian. - expected_fixed_key = int.from_bytes(seed_fixed, - byteorder='little') % curve_order_n + expected_fixed_key = ( + int.from_bytes(seed_fixed, byteorder="little") % curve_order_n + ) sample_fixed = 1 # Loop to collect each power trace - for _ in tqdm(range(capture_cfg["num_traces"]), - desc='Capturing', - ncols=80): + for _ in tqdm(range(capture_cfg["num_traces"]), desc="Capturing", ncols=80): ot.scope.adc.offset = ot.offset_samples if capture_cfg["masks_off"] is True: # Use a constant mask for each trace - mask = bytearray( - capture_cfg["plain_text_len_bytes"]) # all zeros + mask = bytearray(capture_cfg["plain_text_len_bytes"]) # all zeros else: # Generate a new random mask for each trace. mask = ktp.next_text() tqdm.write("Starting new trace....") - tqdm.write(f'mask = {mask.hex()}') + tqdm.write(f"mask = {mask.hex()}") - if capture_cfg["test_type"] == 'KEY': + if capture_cfg["test_type"] == "KEY": # In fixed-vs-random KEY mode, the fixed set of measurements is # generated using the fixed 320 bit seed. The random set of # measurements is generated in two steps: @@ -1301,10 +1760,13 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf ktp.key_len = key_bytes random_number = ktp.next_key() ktp.key_len = seed_bytes - seed_used_int = int.from_bytes(C, byteorder='little') + \ - int.from_bytes(random_number, byteorder='little') - seed_used = seed_used_int.to_bytes(seed_bytes, byteorder='little') - expected_key = int.from_bytes(seed_used, byteorder='little') % curve_order_n + seed_used_int = int.from_bytes( + C, byteorder="little" + ) + int.from_bytes(random_number, byteorder="little") + seed_used = seed_used_int.to_bytes(seed_bytes, byteorder="little") + expected_key = ( + int.from_bytes(seed_used, byteorder="little") % curve_order_n + ) else: # In fixed-vs-random SEED mode, the fixed set of measurements is # generated using the fixed 320 bit seed. The random set of @@ -1316,7 +1778,9 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf expected_key = expected_fixed_key else: seed_used = ktp.next_key() - expected_key = int.from_bytes(seed_used, byteorder='little') % curve_order_n + expected_key = ( + int.from_bytes(seed_used, byteorder="little") % curve_order_n + ) # Decide for next round if we use the fixed or a random seed. sample_fixed = random.randint(0, 1) @@ -1326,24 +1790,24 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf # Share0 = seed XOR mask # Share1 = mask # These shares are then forwarded to OTBN. - ot.target.simpleserial_write('x', seed_used) - tqdm.write(f'seed = {seed_used.hex()}') + ot.target.simpleserial_write("x", seed_used) + tqdm.write(f"seed = {seed_used.hex()}") # Check for errors. err = ot.target.read() if err: - raise RuntimeError(f'Error writing seed: {err}') + raise RuntimeError(f"Error writing seed: {err}") # Arm the scope ot.scope.arm() # Send the mask and start the keygen operation. - ot.target.simpleserial_write('k', mask) + ot.target.simpleserial_write("k", mask) # Wait until operation is done. ret = ot.scope.capture(poll_done=True) if ret: - raise RuntimeError('Timeout during capture') + raise RuntimeError("Timeout during capture") # Check the number of cycles where the trigger signal was high. cycles = ot.scope.adc.trig_count @@ -1355,21 +1819,23 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf share0 = ot.target.simpleserial_read("r", seed_bytes, ack=False) share1 = ot.target.simpleserial_read("r", seed_bytes, ack=False) if share0 is None: - raise RuntimeError('Random share0 is none') + raise RuntimeError("Random share0 is none") if share1 is None: - raise RuntimeError('Random share1 is none') + raise RuntimeError("Random share1 is none") - d0 = int.from_bytes(share0, byteorder='little') - d1 = int.from_bytes(share1, byteorder='little') + d0 = int.from_bytes(share0, byteorder="little") + d1 = int.from_bytes(share1, byteorder="little") actual_key = (d0 + d1) % curve_order_n - tqdm.write(f'share0 = {share0.hex()}') - tqdm.write(f'share1 = {share1.hex()}') + tqdm.write(f"share0 = {share0.hex()}") + tqdm.write(f"share1 = {share1.hex()}") if actual_key != expected_key: - raise RuntimeError('Bad generated key:\n' - f'Expected: {hex(expected_key)}\n' - f'Actual: {hex(actual_key)}') + raise RuntimeError( + "Bad generated key:\n" + f"Expected: {hex(expected_key)}\n" + f"Actual: {hex(actual_key)}" + ) # Create a chipwhisperer trace object and save it to the project # Args/fields of Trace object: waves, textin, textout, key @@ -1377,14 +1843,14 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf trace = Trace(waves, mask, textout, seed_used) check_range(waves, ot.scope.adc.bits_per_sample) project.traces.append(trace, dtype=np.uint16) - elif capture_cfg["app"] == 'modinv': + elif capture_cfg["app"] == "modinv": # Check the lengths in the key/plaintext generator. In this case, "key" # is the input to the modinv app. We only use the key part of the ktp # to generate the key share inputs to the modinv app. if ktp.keyLen() != modinv_share_bytes: raise ValueError( - f'Unexpected input (share) length: {ktp.keyLen()}.\n' - f'Hint: set key len={modinv_share_bytes} in the configuration file.' + f"Unexpected input (share) length: {ktp.keyLen()}.\n" + f"Hint: set key len={modinv_share_bytes} in the configuration file." ) # select the otbn app on the device (0 -> keygen, 1 -> modinv) @@ -1399,9 +1865,11 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf # you want a random fixed key or a hardcoded fixed key) # k_fixed_barray = ktp.next_key()[:256] k_fixed_barray = bytearray( - (0x2648d0d248b70944dfd84c2f85ea5793729112e7cafa50abdf7ef8b7594fa2a1 - ).to_bytes(key_bytes, 'little')) - k_fixed = int.from_bytes(k_fixed_barray, byteorder='little') + ( + 0x2648D0D248B70944DFD84C2F85EA5793729112E7CAFA50ABDF7EF8B7594FA2A1 + ).to_bytes(key_bytes, "little") + ) + k_fixed = int.from_bytes(k_fixed_barray, byteorder="little") print("Fixed input:") print("k: " + hex(k_fixed) + "\n") @@ -1411,9 +1879,7 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf sample_fixed = 1 # Loop to collect each power trace - for _ in tqdm(range(capture_cfg["num_traces"]), - desc='Capturing', - ncols=80): + for _ in tqdm(range(capture_cfg["num_traces"]), desc="Capturing", ncols=80): ot.scope.adc.offset = ot.offset_samples @@ -1422,16 +1888,17 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf # generate two random 320-bit shares input_k0_fixed = ktp.next_key() input_k1_fixed = ktp.next_key() - k0_fixed = int.from_bytes(input_k0_fixed, byteorder='little') - k1_fixed = int.from_bytes(input_k1_fixed, byteorder='little') + k0_fixed = int.from_bytes(input_k0_fixed, byteorder="little") + k1_fixed = int.from_bytes(input_k1_fixed, byteorder="little") # adapt share k1 so that k = (k0 + k1) mod n k_tmp = (k0_fixed + k1_fixed) % curve_order_n k_tmp_diff = (k_fixed - k_tmp) % curve_order_n k1_fixed += k_tmp_diff if k1_fixed >= pow(2, 320): k1_fixed -= curve_order_n - input_k1_fixed = bytearray((k1_fixed).to_bytes(modinv_share_bytes, - 'little')) + input_k1_fixed = bytearray( + (k1_fixed).to_bytes(modinv_share_bytes, "little") + ) # Use the fixed input. input_k0_used = input_k0_fixed input_k1_used = input_k1_fixed @@ -1442,17 +1909,14 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf input_k0_used = ktp.next_key() input_k1_used = ktp.next_key() # calculate the key from the shares - k_used = (int.from_bytes(input_k0_used, byteorder='little') + - int.from_bytes(input_k1_used, - byteorder='little')) % curve_order_n + k_used = ( + int.from_bytes(input_k0_used, byteorder="little") + + int.from_bytes(input_k1_used, byteorder="little") + ) % curve_order_n expected_output = pow(k_used, -1, curve_order_n) - tqdm.write( - f'k0 = {hex(int.from_bytes(input_k0_used, byteorder="little"))}' - ) - tqdm.write( - f'k1 = {hex(int.from_bytes(input_k1_used, byteorder="little"))}' - ) + tqdm.write(f'k0 = {hex(int.from_bytes(input_k0_used, byteorder="little"))}') + tqdm.write(f'k1 = {hex(int.from_bytes(input_k1_used, byteorder="little"))}') # Decide for next round if we use the fixed or a random seed. sample_fixed = random.randint(0, 1) @@ -1461,12 +1925,12 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf ot.scope.arm() # Start modinv device computation - ot.target.simpleserial_write('q', input_k0_used + input_k1_used) + ot.target.simpleserial_write("q", input_k0_used + input_k1_used) # Wait until operation is done. ret = ot.scope.capture(poll_done=True) if ret: - raise RuntimeError('Timeout during capture') + raise RuntimeError("Timeout during capture") # Check the number of cycles where the trigger signal was high. cycles = ot.scope.adc.trig_count @@ -1477,31 +1941,35 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf # expectations. kalpha_inv = ot.target.simpleserial_read("r", key_bytes, ack=False) if kalpha_inv is None: - raise RuntimeError('Modinv device output (k*alpha)^-1 is none') - alpha = ot.target.simpleserial_read("r", - modinv_mask_bytes, - ack=False) + raise RuntimeError("Modinv device output (k*alpha)^-1 is none") + alpha = ot.target.simpleserial_read("r", modinv_mask_bytes, ack=False) if alpha is None: - raise RuntimeError('Modinv device output alpha is none') + raise RuntimeError("Modinv device output alpha is none") # Actual result (kalpha_inv*alpha) mod n: - actual_output = int.from_bytes( - kalpha_inv, byteorder='little') * int.from_bytes( - alpha, byteorder='little') % curve_order_n + actual_output = ( + int.from_bytes(kalpha_inv, byteorder="little") * + int.from_bytes(alpha, byteorder="little") % + curve_order_n + ) - tqdm.write(f'k^-1 = {hex(actual_output)}\n') + tqdm.write(f"k^-1 = {hex(actual_output)}\n") if actual_output != expected_output: - raise RuntimeError('Bad computed modinv output:\n' - f'Expected: {hex(expected_output)}\n' - f'Actual: {hex(actual_output)}') + raise RuntimeError( + "Bad computed modinv output:\n" + f"Expected: {hex(expected_output)}\n" + f"Actual: {hex(actual_output)}" + ) # Create a chipwhisperer trace object and save it to the project # Args/fields of Trace object: waves, textin, textout, key trace = cw.common.traces.Trace( - waves, bytearray(k_used.to_bytes(key_bytes, 'little')), - bytearray(actual_output.to_bytes(key_bytes, 'little')), - bytearray(k_used.to_bytes(key_bytes, 'little'))) + waves, + bytearray(k_used.to_bytes(key_bytes, "little")), + bytearray(actual_output.to_bytes(key_bytes, "little")), + bytearray(k_used.to_bytes(key_bytes, "little")), + ) check_range(waves, ot.scope.adc.bits_per_sample) project.traces.append(trace, dtype=np.uint16) else: @@ -1515,10 +1983,12 @@ def capture_otbn_vertical(ot, ktp, fw_bin, pll_frequency, capture_cfg, device_cf @app_capture.command() -def otbn_vertical(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def otbn_vertical( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): """Capture ECDSA secret key generation traces.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) @@ -1536,19 +2006,19 @@ def otbn_vertical(ctx: typer.Context, # Print the params print( - f'Target setup with clock frequency {ctx.obj.cfg["device"]["pll_frequency"]/1000000} MHz' - ) - print( - f'Scope setup with sampling rate {ctx.obj.ot.scope.clock.adc_freq} S/s' + f'Target setup with clock frequency {ctx.obj.cfg["device"]["pll_frequency"] / 1000000} MHz' ) + print(f"Scope setup with sampling rate {ctx.obj.ot.scope.clock.adc_freq} S/s") # Call the capture loop - capture_otbn_vertical(ctx.obj.ot, - ctx.obj.ktp, - ctx.obj.cfg["device"]["fw_bin"], - ctx.obj.cfg["device"]["pll_frequency"], - ctx.obj.cfg["capture"], - ctx.obj.cfg["device"]) + capture_otbn_vertical( + ctx.obj.ot, + ctx.obj.ktp, + ctx.obj.cfg["device"]["fw_bin"], + ctx.obj.cfg["device"]["pll_frequency"], + ctx.obj.cfg["capture"], + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) @@ -1570,28 +2040,29 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): # For backwards compatibility this must be set in the capture config file. # This is a workaroung for https://github.com/lowRISC/ot-sca/issues/116 if "use_fixed_key_iter" not in capture_cfg: - raise RuntimeError('use_fixed_key_iter not se set!') + raise RuntimeError("use_fixed_key_iter not se set!") if capture_cfg["use_fixed_key_iter"] is not False: - raise RuntimeError('use_fixed_key_iter must be set to false!') + raise RuntimeError("use_fixed_key_iter must be set to false!") # OTBN operations are long. CW-Husky can store only 131070 samples # in the non-stream mode. fifo_size = 131070 if ot.num_samples > fifo_size: - raise RuntimeError('Current setup only supports up to 130k samples') + raise RuntimeError("Current setup only supports up to 130k samples") # Create a cw project to keep the data and traces project = cw.create_project(capture_cfg["project_name"], overwrite=True) # Initialize some curve-dependent parameters. - if capture_cfg["curve"] == 'p256': - curve_order_n = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 + if capture_cfg["curve"] == "p256": + curve_order_n = ( + 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 + ) key_bytes = 256 // 8 seed_bytes = 320 // 8 else: # TODO: add support for P384 - raise NotImplementedError( - f'Curve {capture_cfg["curve"]} is not supported') + raise NotImplementedError(f'Curve {capture_cfg["curve"]} is not supported') # Capture traces. rem_num_traces = capture_cfg["num_traces"] @@ -1612,24 +2083,23 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): scope._scope.adc.decimate = capture_cfg["decimate"] # Print final scope parameter - print( - f'Scope setup with final sampling rate of {scope._scope.clock.adc_freq} S/s' - ) + print(f"Scope setup with final sampling rate of {scope._scope.clock.adc_freq} S/s") # register ctrl-c handler to not lose already recorded traces if measurement is aborted signal.signal(signal.SIGINT, partial(abort_handler, project)) - if capture_cfg["app"] == 'keygen': + if capture_cfg["app"] == "keygen": # Check the lengths in the key/plaintext generator. In this case, "key" # means seed and "plaintext" means mask. if ktp.keyLen() != seed_bytes: raise ValueError( - f'Unexpected seed length: {ktp.keyLen()}.\n' - f'Hint: set key len={seed_bytes} in the configuration file.') + f"Unexpected seed length: {ktp.keyLen()}.\n" + f"Hint: set key len={seed_bytes} in the configuration file." + ) if ktp.textLen() != seed_bytes: raise ValueError( - f'Unexpected mask length: {ktp.textLen()}.\n' - f'Hint: set plaintext len={seed_bytes} in the configuration file.' + f"Unexpected mask length: {ktp.textLen()}.\n" + f"Hint: set plaintext len={seed_bytes} in the configuration file." ) # select the otbn app on the device (0 -> keygen, 1 -> modinv) @@ -1639,12 +2109,14 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): # set PRNG seed prior to setting fixed seed to have the same input sequence every time # running this function with the same batch_prng_seed random.seed(capture_cfg["batch_prng_seed"]) - ot.target.simpleserial_write("s", capture_cfg["batch_prng_seed"].to_bytes(4, "little")) + ot.target.simpleserial_write( + "s", capture_cfg["batch_prng_seed"].to_bytes(4, "little") + ) time.sleep(0.3) # Generate fixed constants for all traces of the keygen operation. - if capture_cfg["test_type"] == 'KEY': + if capture_cfg["test_type"] == "KEY": # In fixed-vs-random KEY mode we use two fixed constants: # 1. C - a 320 bit constant redundancy # 2. fixed_number - a 256 bit number used to derive the fixed key @@ -1653,15 +2125,19 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): # (C + fixed_number) mod curve_order_n C = ktp.next_key() if len(C) != seed_bytes: - raise ValueError(f'Fixed seed length is {len(C)}, expected {seed_bytes}') + raise ValueError( + f"Fixed seed length is {len(C)}, expected {seed_bytes}" + ) ktp.key_len = key_bytes fixed_number = ktp.next_key() if len(fixed_number) != key_bytes: - raise ValueError(f'Fixed key length is {len(fixed_number)}, expected {key_bytes}') + raise ValueError( + f"Fixed key length is {len(fixed_number)}, expected {key_bytes}" + ) ktp.key_len = seed_bytes - C_int = int.from_bytes(C, byteorder='little') - seed_fixed_int = C_int + int.from_bytes(fixed_number, byteorder='little') - seed_fixed = seed_fixed_int.to_bytes(seed_bytes, byteorder='little') + C_int = int.from_bytes(C, byteorder="little") + seed_fixed_int = C_int + int.from_bytes(fixed_number, byteorder="little") + seed_fixed = seed_fixed_int.to_bytes(seed_bytes, byteorder="little") print("Constant redundancy:") print(binascii.b2a_hex(C)) @@ -1675,7 +2151,9 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): # seed_fixed mod curve_order_n seed_fixed = ktp.next_key() if len(seed_fixed) != seed_bytes: - raise ValueError(f'Fixed seed length is {len(seed_fixed)}, expected {seed_bytes}') + raise ValueError( + f"Fixed seed length is {len(seed_fixed)}, expected {seed_bytes}" + ) print("Fixed seed:") print(binascii.b2a_hex(seed_fixed)) @@ -1692,28 +2170,30 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): # Re-seeding the PRNG in the KEY mode. In this mode, the PRNG produces additional 32 bytes # to set up the fixed_number. # This is a necessary step to sync with the PRNG on the capture side. - if capture_cfg["test_type"] == 'KEY': + if capture_cfg["test_type"] == "KEY": random.seed(capture_cfg["batch_prng_seed"]) - ot.target.simpleserial_write("s", capture_cfg["batch_prng_seed"].to_bytes(4, "little")) + ot.target.simpleserial_write( + "s", capture_cfg["batch_prng_seed"].to_bytes(4, "little") + ) time.sleep(0.3) - with tqdm(total=rem_num_traces, - desc="Capturing", - ncols=80, - unit=" traces") as pbar: + with tqdm( + total=rem_num_traces, desc="Capturing", ncols=80, unit=" traces" + ) as pbar: while rem_num_traces > 0: # Determine the number of traces for this batch and arm the oscilloscope. - scope.num_segments = min(rem_num_traces, - scope.num_segments_max) + scope.num_segments = min(rem_num_traces, scope.num_segments_max) scope.arm() # Start batch keygen - if capture_cfg["test_type"] == 'KEY': + if capture_cfg["test_type"] == "KEY": ot.target.simpleserial_write( - "e", scope.num_segments_actual.to_bytes(4, "little")) + "e", scope.num_segments_actual.to_bytes(4, "little") + ) else: ot.target.simpleserial_write( - "b", scope.num_segments_actual.to_bytes(4, "little")) + "b", scope.num_segments_actual.to_bytes(4, "little") + ) # Transfer traces waves = scope.capture_and_transfer_waves() @@ -1721,7 +2201,7 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): # Check the number of cycles where the trigger signal was high. cycles = ot.scope.adc.trig_count // scope.num_segments_actual - if (rem_num_traces <= scope.num_segments_max): + if rem_num_traces <= scope.num_segments_max: tqdm.write("No. of cycles with trigger high: %d" % cycles) seeds = [] @@ -1732,7 +2212,7 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): batch_digest = None for i in range(scope.num_segments_actual): - if capture_cfg["test_type"] == 'KEY': + if capture_cfg["test_type"] == "KEY": if sample_fixed: seed_barray = seed_fixed seed = int.from_bytes(seed_barray, "little") @@ -1740,9 +2220,12 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): ktp.key_len = key_bytes random_number = ktp.next_key() ktp.key_len = seed_bytes - seed_barray_int = C_int + \ - int.from_bytes(random_number, byteorder='little') - seed_barray = seed_barray_int.to_bytes(seed_bytes, byteorder='little') + seed_barray_int = C_int + int.from_bytes( + random_number, byteorder="little" + ) + seed_barray = seed_barray_int.to_bytes( + seed_bytes, byteorder="little" + ) seed = seed_barray_int else: if sample_fixed: @@ -1753,8 +2236,7 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): seed = int.from_bytes(seed_barray, "little") if capture_cfg["masks_off"] is True: - mask_barray = bytearray( - capture_cfg["plain_text_len_bytes"]) + mask_barray = bytearray(capture_cfg["plain_text_len_bytes"]) mask = int.from_bytes(mask_barray, "little") else: mask_barray = ktp.next_text() @@ -1772,8 +2254,7 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): d1 = mask % mod # calculate batch digest - batch_digest = (d0 if batch_digest is None else d0 ^ - batch_digest) + batch_digest = d0 if batch_digest is None else d0 ^ batch_digest seeds.append(seed_barray) d0s.append(bytearray(d0.to_bytes(seed_bytes, "little"))) @@ -1782,23 +2263,25 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): # Check the batch digest to make sure we are in sync. check_ciphertext( - ot, bytearray(batch_digest.to_bytes(seed_bytes, "little")), - seed_bytes) + ot, + bytearray(batch_digest.to_bytes(seed_bytes, "little")), + seed_bytes, + ) num_segments_storage = optimize_cw_capture( - project, num_segments_storage) + project, num_segments_storage + ) # Create a chipwhisperer trace object and save it to the project # Args/fields of Trace object: waves, textin, textout, key - for wave, seed, mask, d0, d1 in zip(waves, seeds, masks, d0s, - d1s): + for wave, seed, mask, d0, d1 in zip(waves, seeds, masks, d0s, d1s): d = d0 + d1 trace = cw.common.traces.Trace(wave, d, mask, seed) project.traces.append(trace, dtype=np.uint16) # Update the loop variable and the progress bar. rem_num_traces -= scope.num_segments pbar.update(scope.num_segments) - elif capture_cfg["app"] == 'modinv': + elif capture_cfg["app"] == "modinv": print("Batch mode capture is not implemented for 'modinv' app.") else: print("Invalid app configured in config file.") @@ -1817,22 +2300,29 @@ def capture_otbn_vertical_batch(ot, ktp, capture_cfg, scope_type, device_cfg): @app_capture.command() -def otbn_vertical_batch(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces, - scope_type: ScopeType = opt_scope_type): +def otbn_vertical_batch( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, + scope_type: ScopeType = opt_scope_type, +): """Capture vertical otbn (ecc256 keygen) traces in batch mode. Fixed vs Random.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) - capture_otbn_vertical_batch(ctx.obj.ot, ctx.obj.ktp, - ctx.obj.cfg["capture"], - scope_type, - ctx.obj.cfg["device"]) + capture_otbn_vertical_batch( + ctx.obj.ot, + ctx.obj.ktp, + ctx.obj.cfg["capture"], + scope_type, + ctx.obj.cfg["device"], + ) capture_end(ctx.obj.cfg) -def capture_ecdsa_sections(ot, fw_bin, pll_frequency, num_sections, secret_k, priv_key_d, msg): - """ A utility function to collect the full OTBN trace section by section +def capture_ecdsa_sections( + ot, fw_bin, pll_frequency, num_sections, secret_k, priv_key_d, msg +): + """A utility function to collect the full OTBN trace section by section ECDSA is a long operation (e.g, ECDSA-256 takes ~7M samples) that doesn't fit into the 130k-sample trace buffer of CW-Husky. This function allows us @@ -1861,17 +2351,17 @@ def capture_ecdsa_sections(ot, fw_bin, pll_frequency, num_sections, secret_k, pr ot.scope.adc.offset = ii * 131070 # Optional commands to overwrite the default values declared in the C code. - ot.target.simpleserial_write('d', priv_key_d) + ot.target.simpleserial_write("d", priv_key_d) # Message to sign - ot.target.simpleserial_write('n', msg) + ot.target.simpleserial_write("n", msg) # Send the ephemeral secret k and trigger the signature geneartion - ot.target.simpleserial_write('k', secret_k) + ot.target.simpleserial_write("k", secret_k) # Arm the scope ot.scope.arm() # Start the ECDSA operation - ot.target.simpleserial_write('p', bytearray([0x01])) + ot.target.simpleserial_write("p", bytearray([0x01])) # Wait until operation is done ret = ot.scope.capture(poll_done=True) @@ -1879,7 +2369,7 @@ def capture_ecdsa_sections(ot, fw_bin, pll_frequency, num_sections, secret_k, pr # adding a sufficient sleep below here appears to fix things time.sleep(1) if ret: - raise RuntimeError('Timeout during capture') + raise RuntimeError("Timeout during capture") # Check the number of cycles, where the trigger signal was high cycles = ot.scope.adc.trig_count print("Observed number of cycles: %d" % cycles) @@ -1916,7 +2406,7 @@ def capture_ecdsa_simple(ot, fw_bin, pll_frequency, capture_cfg): ot.scope.adc.bits_per_sample = 12 ot.scope.adc.samples = 131070 else: - raise RuntimeError('Only CW-Husky is supported now') + raise RuntimeError("Only CW-Husky is supported now") # OTBN operations are long. CW-Husky can store only 131070 samples # in the non-stream mode. In case we want to collect more samples, @@ -1934,8 +2424,7 @@ def capture_ecdsa_simple(ot, fw_bin, pll_frequency, capture_cfg): signal.signal(signal.SIGINT, partial(abort_handler, project)) # Loop to collect each power trace - for _ in tqdm(range(capture_cfg["num_traces"]), desc='Capturing', - ncols=80): + for _ in tqdm(range(capture_cfg["num_traces"]), desc="Capturing", ncols=80): # This part can be modified to create a new command. # For example, a random secret scalar can be set using the following @@ -1947,69 +2436,365 @@ def capture_ecdsa_simple(ot, fw_bin, pll_frequency, capture_cfg): # ECDSA-384 if capture_cfg["key_len_bytes"] == 48: # Set two shares of the private key d - priv_key_d0 = bytearray([ - 0x6B, 0x9D, 0x3D, 0xAD, 0x2E, 0x1B, 0x8C, 0x1C, - 0x05, 0xB1, 0x98, 0x75, 0xB6, 0x65, 0x9F, 0x4D, - 0xE2, 0x3C, 0x3B, 0x66, 0x7B, 0xF2, 0x97, 0xBA, - 0x9A, 0xA4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xD8, - 0x96, 0xD5, 0x72, 0x4E, 0x4C, 0x70, 0xA8, 0x25, - 0xF8, 0x72, 0xC9, 0xEA, 0x60, 0xD2, 0xED, 0xF5 - ]) - priv_key_d1 = bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) + priv_key_d0 = bytearray( + [ + 0x6B, + 0x9D, + 0x3D, + 0xAD, + 0x2E, + 0x1B, + 0x8C, + 0x1C, + 0x05, + 0xB1, + 0x98, + 0x75, + 0xB6, + 0x65, + 0x9F, + 0x4D, + 0xE2, + 0x3C, + 0x3B, + 0x66, + 0x7B, + 0xF2, + 0x97, + 0xBA, + 0x9A, + 0xA4, + 0x77, + 0x40, + 0x78, + 0x71, + 0x37, + 0xD8, + 0x96, + 0xD5, + 0x72, + 0x4E, + 0x4C, + 0x70, + 0xA8, + 0x25, + 0xF8, + 0x72, + 0xC9, + 0xEA, + 0x60, + 0xD2, + 0xED, + 0xF5, + ] + ) + priv_key_d1 = bytearray( + [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) # Set two shares of the scalar secret_k - secret_k0 = bytearray([ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) - secret_k1 = bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) + secret_k0 = bytearray( + [ + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) + secret_k1 = bytearray( + [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) # ECDSA-256 elif capture_cfg["key_len_bytes"] == 32: # Set two shares of the private key d - priv_key_d0 = bytearray([ - 0xcd, 0xb4, 0x57, 0xaf, 0x1c, 0x9f, 0x4c, 0x74, - 0x02, 0x0c, 0x7e, 0x8b, 0xe9, 0x93, 0x3e, 0x28, - 0x0c, 0xf0, 0x18, 0x0d, 0xf4, 0x6c, 0x0b, 0xda, - 0x7a, 0xbb, 0xe6, 0x8f, 0xb7, 0xa0, 0x45, 0x55 - ]) - priv_key_d1 = bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) + priv_key_d0 = bytearray( + [ + 0xCD, + 0xB4, + 0x57, + 0xAF, + 0x1C, + 0x9F, + 0x4C, + 0x74, + 0x02, + 0x0C, + 0x7E, + 0x8B, + 0xE9, + 0x93, + 0x3E, + 0x28, + 0x0C, + 0xF0, + 0x18, + 0x0D, + 0xF4, + 0x6C, + 0x0B, + 0xDA, + 0x7A, + 0xBB, + 0xE6, + 0x8F, + 0xB7, + 0xA0, + 0x45, + 0x55, + ] + ) + priv_key_d1 = bytearray( + [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) # Set two shares of the scalar secret_k - secret_k0 = bytearray([ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) - secret_k1 = bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) + secret_k0 = bytearray( + [ + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) + secret_k1 = bytearray( + [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) else: - raise RuntimeError('priv_key_d must be either 32B or 48B') + raise RuntimeError("priv_key_d must be either 32B or 48B") # Combine the two shares of d and k priv_key_d = priv_key_d0 + priv_key_d1 @@ -2017,19 +2802,18 @@ def capture_ecdsa_simple(ot, fw_bin, pll_frequency, capture_cfg): # Create a clean array to keep the collected traces waves = np.array([]) - waves = capture_ecdsa_sections(ot, fw_bin, pll_frequency, num_sections, - secret_k, - priv_key_d, - msg) + waves = capture_ecdsa_sections( + ot, fw_bin, pll_frequency, num_sections, secret_k, priv_key_d, msg + ) # Read 32 bytes of signature_r and signature_s back from the device - sig_r = ot.target.simpleserial_read("r", - capture_cfg["output_len_bytes"], - ack=False) + sig_r = ot.target.simpleserial_read( + "r", capture_cfg["output_len_bytes"], ack=False + ) print(f"sig_r = {''.join('{:02x}'.format(x) for x in sig_r)}") - sig_s = ot.target.simpleserial_read("r", - capture_cfg["output_len_bytes"], - ack=False) + sig_s = ot.target.simpleserial_read( + "r", capture_cfg["output_len_bytes"], ack=False + ) print(f"sig_s = {''.join('{:02x}'.format(x) for x in sig_s)}") # Create a chipwhisperer trace object and save it to the project @@ -2045,10 +2829,12 @@ def capture_ecdsa_simple(ot, fw_bin, pll_frequency, capture_cfg): @app_capture.command() -def ecdsa_simple(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def ecdsa_simple( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): # OTBN-specific settings """Capture OTBN-ECDSA-256/384 traces from a target that runs the `ecc384_serial` program.""" @@ -2067,16 +2853,17 @@ def ecdsa_simple(ctx: typer.Context, ctx.obj.ot.scope.adc.decimate = ctx.obj.cfg["capture"]["decimate"] # Print the params print( - f'Target setup with clock frequency {ctx.obj.cfg["device"]["pll_frequency"]/1000000} MHz' - ) - print( - f'Scope setup with sampling rate {ctx.obj.ot.scope.clock.adc_freq} S/s' + f'Target setup with clock frequency {ctx.obj.cfg["device"]["pll_frequency"] / 1000000} MHz' ) + print(f"Scope setup with sampling rate {ctx.obj.ot.scope.clock.adc_freq} S/s") # Call the capture loop - capture_ecdsa_simple(ctx.obj.ot, ctx.obj.cfg["device"]["fw_bin"], - ctx.obj.cfg["device"]["pll_frequency"], - ctx.obj.cfg["capture"]) + capture_ecdsa_simple( + ctx.obj.ot, + ctx.obj.cfg["device"]["fw_bin"], + ctx.obj.cfg["device"]["pll_frequency"], + ctx.obj.cfg["capture"], + ) capture_end(ctx.obj.cfg) @@ -2112,14 +2899,13 @@ def capture_ecdsa_stream(ot, fw_bin, pll_frequency, capture_cfg): ot.scope.adc.bits_per_sample = 12 else: # We support only CW-Husky for now. - raise RuntimeError('Only CW-Husky is supported now') + raise RuntimeError("Only CW-Husky is supported now") # register ctrl-c handler to not lose already recorded traces if measurement is aborted signal.signal(signal.SIGINT, partial(abort_handler, project)) # Loop to collect traces - for _ in tqdm(range(capture_cfg["num_traces"]), desc='Capturing', - ncols=80): + for _ in tqdm(range(capture_cfg["num_traces"]), desc="Capturing", ncols=80): # This part can be modified to create a new command. # For example, a random secret scalar can be set using the following # from numpy.random import default_rng @@ -2130,69 +2916,365 @@ def capture_ecdsa_stream(ot, fw_bin, pll_frequency, capture_cfg): # ECDSA-384 if capture_cfg["key_len_bytes"] == 48: # Set two shares of the private key d - priv_key_d0 = bytearray([ - 0x6B, 0x9D, 0x3D, 0xAD, 0x2E, 0x1B, 0x8C, 0x1C, - 0x05, 0xB1, 0x98, 0x75, 0xB6, 0x65, 0x9F, 0x4D, - 0xE2, 0x3C, 0x3B, 0x66, 0x7B, 0xF2, 0x97, 0xBA, - 0x9A, 0xA4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xD8, - 0x96, 0xD5, 0x72, 0x4E, 0x4C, 0x70, 0xA8, 0x25, - 0xF8, 0x72, 0xC9, 0xEA, 0x60, 0xD2, 0xED, 0xF5 - ]) - priv_key_d1 = bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) + priv_key_d0 = bytearray( + [ + 0x6B, + 0x9D, + 0x3D, + 0xAD, + 0x2E, + 0x1B, + 0x8C, + 0x1C, + 0x05, + 0xB1, + 0x98, + 0x75, + 0xB6, + 0x65, + 0x9F, + 0x4D, + 0xE2, + 0x3C, + 0x3B, + 0x66, + 0x7B, + 0xF2, + 0x97, + 0xBA, + 0x9A, + 0xA4, + 0x77, + 0x40, + 0x78, + 0x71, + 0x37, + 0xD8, + 0x96, + 0xD5, + 0x72, + 0x4E, + 0x4C, + 0x70, + 0xA8, + 0x25, + 0xF8, + 0x72, + 0xC9, + 0xEA, + 0x60, + 0xD2, + 0xED, + 0xF5, + ] + ) + priv_key_d1 = bytearray( + [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) # Set two shares of the scalar secret_k - secret_k0 = bytearray([ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) - secret_k1 = bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) + secret_k0 = bytearray( + [ + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) + secret_k1 = bytearray( + [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) # ECDSA-256 elif capture_cfg["key_len_bytes"] == 32: # Set two shares of the private key d - priv_key_d0 = bytearray([ - 0xcd, 0xb4, 0x57, 0xaf, 0x1c, 0x9f, 0x4c, 0x74, - 0x02, 0x0c, 0x7e, 0x8b, 0xe9, 0x93, 0x3e, 0x28, - 0x0c, 0xf0, 0x18, 0x0d, 0xf4, 0x6c, 0x0b, 0xda, - 0x7a, 0xbb, 0xe6, 0x8f, 0xb7, 0xa0, 0x45, 0x55 - ]) - priv_key_d1 = bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) + priv_key_d0 = bytearray( + [ + 0xCD, + 0xB4, + 0x57, + 0xAF, + 0x1C, + 0x9F, + 0x4C, + 0x74, + 0x02, + 0x0C, + 0x7E, + 0x8B, + 0xE9, + 0x93, + 0x3E, + 0x28, + 0x0C, + 0xF0, + 0x18, + 0x0D, + 0xF4, + 0x6C, + 0x0B, + 0xDA, + 0x7A, + 0xBB, + 0xE6, + 0x8F, + 0xB7, + 0xA0, + 0x45, + 0x55, + ] + ) + priv_key_d1 = bytearray( + [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) # Set two shares of the scalar secret_k - secret_k0 = bytearray([ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) - secret_k1 = bytearray([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]) + secret_k0 = bytearray( + [ + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) + secret_k1 = bytearray( + [ + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + ] + ) else: - raise RuntimeError('priv_key_d must be either 32B or 48B') + raise RuntimeError("priv_key_d must be either 32B or 48B") # Combine the two shares of d and k priv_key_d = priv_key_d0 + priv_key_d1 @@ -2202,11 +3284,11 @@ def capture_ecdsa_stream(ot, fw_bin, pll_frequency, capture_cfg): waves = np.array([]) # Optional commands to overwrite the default values declared in the C code. - ot.target.simpleserial_write('d', priv_key_d) + ot.target.simpleserial_write("d", priv_key_d) # Message to sign - ot.target.simpleserial_write('n', msg) + ot.target.simpleserial_write("n", msg) # Send the ephemeral secret k and trigger the signature geneartion - ot.target.simpleserial_write('k', secret_k) + ot.target.simpleserial_write("k", secret_k) time.sleep(0.2) @@ -2214,7 +3296,7 @@ def capture_ecdsa_stream(ot, fw_bin, pll_frequency, capture_cfg): ot.scope.arm() # Start the ECDSA operation - ot.target.simpleserial_write('p', bytearray([0x01])) + ot.target.simpleserial_write("p", bytearray([0x01])) # Wait until operation is done ret = ot.scope.capture(poll_done=True) @@ -2222,7 +3304,7 @@ def capture_ecdsa_stream(ot, fw_bin, pll_frequency, capture_cfg): # adding a sufficient sleep below here appears to fix things time.sleep(1) if ret: - raise RuntimeError('Timeout during capture') + raise RuntimeError("Timeout during capture") # Check the number of cycles, where the trigger signal was high cycles = ot.scope.adc.trig_count print("Observed number of cycles: %d" % cycles) @@ -2231,13 +3313,13 @@ def capture_ecdsa_stream(ot, fw_bin, pll_frequency, capture_cfg): waves = np.append(waves, ot.scope.get_last_trace(as_int=True)) # Read signature_r and signature_s back from the device - sig_r = ot.target.simpleserial_read("r", - capture_cfg["output_len_bytes"], - ack=False) + sig_r = ot.target.simpleserial_read( + "r", capture_cfg["output_len_bytes"], ack=False + ) print(f"sig_r = {''.join('{:02x}'.format(x) for x in sig_r)}") - sig_s = ot.target.simpleserial_read("r", - capture_cfg["output_len_bytes"], - ack=False) + sig_s = ot.target.simpleserial_read( + "r", capture_cfg["output_len_bytes"], ack=False + ) print(f"sig_s = {''.join('{:02x}'.format(x) for x in sig_s)}") # Create a chipwhisperer trace object and save it to the project @@ -2253,10 +3335,12 @@ def capture_ecdsa_stream(ot, fw_bin, pll_frequency, capture_cfg): @app_capture.command() -def ecdsa_stream(ctx: typer.Context, - force_program_bitstream: bool = opt_force_program_bitstream, - num_traces: int = opt_num_traces, - plot_traces: int = opt_plot_traces): +def ecdsa_stream( + ctx: typer.Context, + force_program_bitstream: bool = opt_force_program_bitstream, + num_traces: int = opt_num_traces, + plot_traces: int = opt_plot_traces, +): """Use cw-husky stream mode to capture OTBN-ECDSA-256/384 traces from a target that runs the `ecc384_serial` program.""" capture_init(ctx, force_program_bitstream, num_traces, plot_traces) @@ -2273,15 +3357,16 @@ def ecdsa_stream(ctx: typer.Context, if "decimate" in ctx.obj.cfg["capture"]: ctx.obj.ot.scope.adc.decimate = ctx.obj.cfg["capture"]["decimate"] print( - f'Target setup with clock frequency {ctx.obj.cfg["device"]["pll_frequency"]/1000000} MHz' - ) - print( - f'Scope setup with sampling rate {ctx.obj.ot.scope.clock.adc_freq} S/s' + f'Target setup with clock frequency {ctx.obj.cfg["device"]["pll_frequency"] / 1000000} MHz' ) + print(f"Scope setup with sampling rate {ctx.obj.ot.scope.clock.adc_freq} S/s") - capture_ecdsa_stream(ctx.obj.ot, ctx.obj.cfg["device"]["fw_bin"], - ctx.obj.cfg["device"]["pll_frequency"], - ctx.obj.cfg["capture"]) + capture_ecdsa_stream( + ctx.obj.ot, + ctx.obj.cfg["device"]["fw_bin"], + ctx.obj.cfg["device"]["pll_frequency"], + ctx.obj.cfg["capture"], + ) capture_end(ctx.obj.cfg) @@ -2298,7 +3383,7 @@ def plot_cmd(ctx: typer.Context, num_traces: int = opt_plot_traces): def main(ctx: typer.Context, cfg_file: str = None): """Capture traces for side-channel analysis.""" - cfg_file = 'capture_aes_cw310.yaml' if cfg_file is None else cfg_file + cfg_file = "capture_aes_cw310.yaml" if cfg_file is None else cfg_file with open(cfg_file) as f: cfg = yaml.load(f, Loader=yaml.FullLoader) diff --git a/cw/mix_columns_cpa_attack.py b/cw/mix_columns_cpa_attack.py index 4b8d6f5a..2876c7f1 100755 --- a/cw/mix_columns_cpa_attack.py +++ b/cw/mix_columns_cpa_attack.py @@ -8,34 +8,39 @@ from chipwhisperer.analyzer.attacks.attack_mix_columns import AttackMixColumns PROJECTS = [ - 'projects/opentitan_simple_aes_0', - 'projects/opentitan_simple_aes_1', - 'projects/opentitan_simple_aes_2', - 'projects/opentitan_simple_aes_3', + "projects/opentitan_simple_aes_0", + "projects/opentitan_simple_aes_1", + "projects/opentitan_simple_aes_2", + "projects/opentitan_simple_aes_3", ] -print('loading projects') +print("loading projects") projects = [cw.open_project(p) for p in PROJECTS] attack = AttackMixColumns(projects) results = attack.run() known_key_bytes = projects[0].keys[0] -key_guess_bytes = results['guess'] +key_guess_bytes = results["guess"] known_key = binascii.b2a_hex(bytearray(known_key_bytes)) -print('known_key: {}'.format(known_key)) +print("known_key: {}".format(known_key)) key_guess = binascii.b2a_hex(bytearray(key_guess_bytes)) -print('key guess: {}'.format(key_guess)) +print("key guess: {}".format(key_guess)) if key_guess != known_key: num_bytes_match = 0 for i in range(len(known_key_bytes)): if known_key_bytes[i] == key_guess_bytes[i]: num_bytes_match += 1 - print('FAILED: key_guess != known_key') - print(' ' + str(num_bytes_match) + '/' + - str(len(known_key_bytes)) + ' bytes guessed correctly.') + print("FAILED: key_guess != known_key") + print( + " " + + str(num_bytes_match) + + "/" + + str(len(known_key_bytes)) + + " bytes guessed correctly." + ) else: - print('SUCCESS!') + print("SUCCESS!") diff --git a/cw/save_waverunner_config_to_file.py b/cw/save_waverunner_config_to_file.py index d52334f8..f3cd972d 100755 --- a/cw/save_waverunner_config_to_file.py +++ b/cw/save_waverunner_config_to_file.py @@ -9,7 +9,7 @@ from waverunner import WaveRunner -if __name__ == '__main__': +if __name__ == "__main__": waverunner = WaveRunner("172.26.111.125") # Save WaveRunner setup to timestamped file diff --git a/cw/test_capture.sh b/cw/test_capture.sh index fcee016a..93cc9ae0 100755 --- a/cw/test_capture.sh +++ b/cw/test_capture.sh @@ -4,11 +4,7 @@ # SPDX-License-Identifier: Apache-2.0 # Simple script to test all relevant capture modes supported by capture.py. -# To test capture modes on the CW305 board, type -# -# ./test_capture.sh cw305 -# -# For the CW310, simply type +# To test capture modes on the CW310 board, type # # ./test_capture.sh # diff --git a/doc/ci.md b/doc/ci.md index 6f5cf9af..2bc3bf6c 100644 --- a/doc/ci.md +++ b/doc/ci.md @@ -8,19 +8,13 @@ Actions workflow that uses these FPGAs and runs on each pull request. ## Selecting FPGAs -The pool of FPGAs contains both a CW305 and CW310 runner. +The pool of FPGAs contain CW310 runners. -To run a job on a machine with a particular FPGA, you must specify either the -`cw305` or `cw310` labels in addition to `ubuntu-22.04-fpga` in the YAML +To run a job on a machine with a particular FPGA, you must specify the `cw310` labels in addition to `ubuntu-22.04-fpga` in the YAML specification file: ```yaml jobs: - some_cw305_job: - runs-on: [ubuntu-22.04-fpga, cw305] - steps: - - ... - some_cw310_job: runs-on: [ubuntu-22.04-fpga, cw310] steps: diff --git a/doc/getting_started.md b/doc/getting_started.md index 5b705dd7..ae357c00 100644 --- a/doc/getting_started.md +++ b/doc/getting_started.md @@ -21,7 +21,7 @@ equipment is required: OpenTitan implemented on the target board. The capture board comes with SMA and 20-pin ChipWhisperer cable required to connect to the target board. -The following, alternative hardware equipment is partially supported: +The following, alternative hardware equipment is no longer supported: * [ChipWhisperer CW305-A100 FPGA Board](https://rtfm.newae.com/Targets/CW305%20Artix%20FPGA/) @@ -36,6 +36,8 @@ The following, alternative hardware equipment is partially supported: that also for this board there exist different versions of which of which only the board with the bigger FPGA device (XC7A100T-2FTG256) is supported. + **Support:** Older versions of the repo support this target. + ### Hardware Setup To setup the hardware, first connect the target and capture board together. You @@ -77,18 +79,6 @@ source. The CW-Husky should also have a green blinking status LED at this point. If LEDs are solid it may mean the device has not enumerated, which might require additional setup (see UDEV Rules below). -#### CW305 - -1. Connect the `X4` output of the CW305 (rightmost SMA) to the CW-Husky `Pos` - input. -2. Connect the `ChipWhisperer 20-Pin Connector` on the CW305 to the - `ChipWhisperer 20-Pin Connector` on the capture board. On the CW-Husky this - is the connector on the *SIDE* not the connector on the *FRONT*. - -Make sure the `S1` jumper on the back of the CW305 is set to `111` such that -the FPGA bitstream can be reconfigured via USB. Connect the two boards to your -PC via USB. - ### UDEV Rules You might need to setup the following `udev` rules to gain access to the two @@ -101,9 +91,6 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="2b3e", ATTRS{idProduct}=="c310", MODE="0666" # CW-Husky SUBSYSTEM=="usb", ATTRS{idVendor}=="2b3e", ATTRS{idProduct}=="ace5", MODE="0666" SYMLINK+="opentitan/cw_husky" - -# CW305 (Artix Target) -SUBSYSTEM=="usb", ATTRS{idVendor}=="2b3e", ATTRS{idProduct}=="c305", MODE="0666", SYMLINK+="opentitan/cw_305" ``` To activate the rules, type @@ -171,7 +158,7 @@ to install the specific `apt` packages required by ChipWhisperer. **Notes:** - We recommend to use Python 3.10. Later versions might also work. -- CW-Husky requires ChipWhisperer 5.6.1 or later. The default +- CW-Husky requires ChipWhisperer 5.7.0 or later. The default `python_requirements.txt` will install a version supporting CW-Husky. ##### Git Large File Storage (LFS) @@ -278,7 +265,7 @@ you can regenerate them from the [OpenTitan](https://github.com/lowRISC/OpenTitan) repository. Below, we quickly outline the necessary steps for building the binaries for the -CW310 and CW305 boards from the sources. For more information on the build +CW310 board from the sources. For more information on the build steps, refer to the [OpenTitan FPGA documentation](https://docs.opentitan.org/doc/ug/getting_started_fpga/). Note that below we use `$REPO_TOP` to refer to the main OpenTitan repository @@ -288,64 +275,11 @@ top, not this `ot-sca` repo. To build FPGA bitstreams and penetration testing framework binaries for CW310, please follow this [guide](./building_fpga_bitstreams.md). -#### English Breakfast for CW305 - -To build the binaries for performing SCA of e.g. AES on the reduced English -Breakfast top level of OpenTitan using the CW305, follow these steps: - -1. Go to the root directory of the OpenTitan repository. -1. Before generating the OpenTitan FPGA bitstream for the CW305 target board, you first have to run: - ```console - $ cd $REPO_TOP - $ ./util/topgen-fusesoc.py --files-root=. --topname=top_englishbreakfast - ``` - to generate top-level specific versions of some IP cores such as RV_PLIC, - TL-UL crossbars etc. -1. Then run - ```console - $ cd $REPO_TOP - $ ./hw/top_englishbreakfast/util/prepare_sw.py --build --top=englishbreakfast - ``` - in order to prepare the OpenTitan software build flow for English - Breakfast and build the required binaries. More precisely, this script - runs some code generators, patches some auto-generated source files and - finally generates the boot ROM needed for bitstream generation. -1. Finally, the bitstream generation can be started by running - ```console - $ cd $REPO_TOP - $ fusesoc --cores-root . run --flag=fileset_topgen --target=synth lowrisc:systems:chip_englishbreakfast_cw305 - ``` - The generated bitstream can be found in - ``` - build/lowrisc_systems_chip_englishbreakfast_cw305_0.1/synth-vivado/lowrisc_systems_chip_englishbreakfast_cw305_0.1.bit - ``` - and will be loaded to the FPGA using the ChipWhisperer Python API. - -1. To generate the OpenTitan application binary for recording AES power traces, - make sure the `prepare_sw.py` script has been run before executing - ```console - $ cd $REPO_TOP - $ ./bazelisk.sh build //sw/device/sca:aes_serial --copt=-DOT_IS_ENGLISH_BREAKFAST_REDUCED_SUPPORT_FOR_INTERNAL_USE_ONLY_ - ``` -1. The path to the generated binary will be printed to the terminal after running - ```console - $ cd $REPO_TOP - $ ci/scripts/target-location.sh //sw/device/sca:aes_serial - ``` - -If you need to generate binaries for CW310 after you generate binaries for -CW305, use the following command: -```console -$ ./hw/top_englishbreakfast/util/prepare_sw.py --delete -``` -and clean the auto-generated files with a checkout. - ## Configuration The main configuration of the OpenTitan SCA setup is stored in the files ``` capture/configs/aes_sca_cw310.yaml -capture/configs/aes_sca_cw305.yaml ``` for AES. @@ -360,10 +294,7 @@ the specified file paths. both bitstream and application binaries from the OpenTitan repository. Otherwise you might risk to end up with an incompatible combination of bitstream and application binary. -* The default configurations target the CW310 board. When using - the CW305 FPGA board, the config file `capture/configs/aes_sca_cw305.yaml` - must be used to select a different bitstream and application binary, and - adjust the ADC gain. +* The default configurations target the CW310 board. ## Capturing Power Traces diff --git a/fault_injection/fi_crypto.py b/fault_injection/fi_crypto.py index 6e11b517..7ee0a488 100755 --- a/fault_injection/fi_crypto.py +++ b/fault_injection/fi_crypto.py @@ -5,15 +5,19 @@ import json import logging +import struct from datetime import datetime from pathlib import Path import yaml +from Crypto.Cipher import AES +from Crypto.Hash import HMAC, SHA256, SHA384, SHA512 from fi_gear.fi_gear import FIGear -from project_library.project import FIProject, FISuccess, ProjectConfig from tqdm import tqdm import util.helpers as helpers +from fault_injection.project_library.project import (FIProject, FISuccess, + ProjectConfig) from target.communication.fi_crypto_commands import OTFICrypto from target.targets import Target, TargetConfig from util import plot @@ -21,8 +25,34 @@ logger = logging.getLogger() +def words_to_bytes(dword_array): + if not isinstance(dword_array, list): + raise TypeError("Input must be a list of 32-bit integers.") + + byte_list = bytearray() + for dword in dword_array: + if not isinstance(dword, int) or not (0 <= dword <= 0xFFFFFFFF): + raise ValueError( + "Each element in the array must be a 32-bit integer (0 to 0xFFFFFFFF)." + ) + byte_list.extend(struct.pack(">I", dword)) + return bytes(byte_list) + + +def bytes_to_words(byte_array): + if not isinstance(byte_array, (bytes, bytearray)): + raise TypeError("Input must be a bytes object or bytearray.") + + word_list = [] + for i in range(0, len(byte_array), 4): + chunk = byte_array[i: i + 4] + word = struct.unpack(">I", chunk)[0] + word_list.append(word) + return word_list + + def setup(cfg: dict, project: Path): - """ Setup target, FI gear, and project. + """Setup target, FI gear, and project. Args: cfg: The configuration for the current experiment. @@ -34,23 +64,24 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + ) # Create target config & setup target. logger.info(f"Initializing target {cfg['target']['target_type']} ...") target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial"), - interface = cfg["target"].get("interface"), - husky_serial = cfg["fisetup"].get("husky_serial") + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], + pll_frequency=cfg["target"]["pll_frequency"], + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + interface=cfg["target"].get("interface"), + husky_serial = cfg["fisetup"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) target = Target(target_cfg) @@ -58,11 +89,12 @@ def setup(cfg: dict, project: Path): fi_gear = FIGear(cfg) # Init project. - project_cfg = ProjectConfig(type = cfg["fiproject"]["project_db"], - path = project, - overwrite = True, - fi_threshold = cfg["fiproject"].get("project_mem_threshold") - ) + project_cfg = ProjectConfig( + type=cfg["fiproject"]["project_db"], + path=project, + overwrite=True, + fi_threshold=cfg["fiproject"].get("project_mem_threshold"), + ) project = FIProject(project_cfg) project.create_project() @@ -70,7 +102,7 @@ def setup(cfg: dict, project: Path): def print_fi_statistic(fi_results: list) -> None: - """ Print FI Statistic. + """Print FI Statistic. Prints the number of FISuccess.SUCCESS, FISuccess.EXPRESPONSE, and FISuccess.NORESPONSE. @@ -82,15 +114,18 @@ def print_fi_statistic(fi_results: list) -> None: num_succ = round((fi_results.count(FISuccess.SUCCESS) / num_total) * 100, 2) num_exp = round((fi_results.count(FISuccess.EXPRESPONSE) / num_total) * 100, 2) num_no = round((fi_results.count(FISuccess.NORESPONSE) / num_total) * 100, 2) - logger.info(f"{num_total} faults, {fi_results.count(FISuccess.SUCCESS)}" - f"({num_succ}%) successful, {fi_results.count(FISuccess.EXPRESPONSE)}" - f"({num_exp}%) expected, and {fi_results.count(FISuccess.NORESPONSE)}" - f"({num_no}%) no response.") + logger.info( + f"{num_total} faults, {fi_results.count(FISuccess.SUCCESS)}" + f"({num_succ}%) successful, {fi_results.count(FISuccess.EXPRESPONSE)}" + f"({num_exp}%) expected, and {fi_results.count(FISuccess.NORESPONSE)}" + f"({num_no}%) no response." + ) -def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, - project: FIProject, ot_communication: OTFICrypto) -> None: - """ Fault parameter sweep. +def fi_parameter_sweep( + cfg: dict, target: Target, fi_gear, project: FIProject, ot_communication: OTFICrypto +) -> None: + """Fault parameter sweep. Sweep through the fault parameter space. @@ -101,19 +136,29 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, project: The project to store the results. ot_communication: The OpenTitan Crypto FI communication interface. Returns: - device_cfg: The ID and countermeasure configuration of the target device. + device_id: The ID of the target device. + sensors: The sensor info. + alerts: The alert info. + owner_page: The owner info page. + boot_log: The boot log. + boot_measurments: The boot measurements. + version: The testOS version. """ # Configure the Crypto FI code on the target. - device_cfg = ot_communication.init(cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = ( + ot_communication.init( + cfg["test"]["core_config"], + cfg["test"]["sensor_config"], + cfg["test"]["alert_config"], + ) + ) # Store results in array for a quick access. fi_results = [] # Start the parameter sweep. remaining_iterations = fi_gear.get_num_fault_injections() - with tqdm(total=remaining_iterations, desc="Injecting", ncols=80, - unit=" different faults") as pbar: + with tqdm( + total=remaining_iterations, desc="Injecting", ncols=80, unit=" different faults" + ) as pbar: while remaining_iterations > 0: # Get fault parameters (e.g., trigger delay, glitch voltage). fault_parameters = fi_gear.generate_fi_parameters() @@ -121,13 +166,95 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # Arm the FI gear. fi_gear.arm_trigger(fault_parameters) + # Get the input arguments. + args = {} + if "aes" in cfg["test"]["which_test"]: + args["plaintext"] = cfg["test"]["plaintext"] + args["key"] = cfg["test"]["key"] + elif "hmac" in cfg["test"]["which_test"]: + args["msg"] = cfg["test"]["msg"] + args["key"] = cfg["test"]["key"] + args["trigger"] = cfg["test"]["trigger"] + args["enable_hmac"] = cfg["test"]["enable_hmac"] + args["hash_mode"] = cfg["test"]["hash_mode"] + # These are hard coded for now. + args["message_endianness_big"] = False + args["digest_endianness_big"] = False + args["key_endianness_big"] = False + # Start test on OpenTitan. - ot_communication.start_test(cfg) + ot_communication.start_test(cfg, **args) # Read response. - response = ot_communication.read_response(max_tries=30) + response = target.read_response() response_compare = response - expected_response = cfg["test"]["expected_result"] + + if "aes" in cfg["test"]["which_test"]: + cipher_gen = AES.new(bytes(cfg["test"]["key"]), AES.MODE_ECB) + expected_response = [ + x for x in cipher_gen.encrypt(bytes(cfg["test"]["plaintext"])) + ] + exp_json = { + "ciphertext": expected_response, + "err_status": 0, + "alerts": [0, 0, 0], + "ast_alerts": [0, 0], + } + expected_response = json.dumps(exp_json, separators=(",", ":")) + elif "hmac" in cfg["test"]["which_test"]: + if not cfg["test"]["enable_hmac"]: + if cfg["test"]["hash_mode"] == 0: + sha = SHA256.new() + elif cfg["test"]["hash_mode"] == 1: + sha = SHA384.new() + elif cfg["test"]["hash_mode"] == 2: + sha = SHA512.new() + else: + logger.info("Error: Hash mode not recognized.") + return + sha.update(bytes(cfg["test"]["msg"])) + expected_response = bytes_to_words(bytearray(sha.digest())) + expected_response.reverse() + if cfg["test"]["hash_mode"] == 0: + expected_response += [0] * 8 + elif cfg["test"]["hash_mode"] == 1: + expected_response += [0] * 4 + else: + if cfg["test"]["hash_mode"] == 0: + hmac = HMAC.new( + key=bytes(words_to_bytes(cfg["test"]["key"])), + digestmod=SHA256, + ) + elif cfg["test"]["hash_mode"] == 1: + hmac = HMAC.new( + key=bytes(words_to_bytes(cfg["test"]["key"])), + digestmod=SHA384, + ) + elif cfg["test"]["hash_mode"] == 2: + hmac = HMAC.new( + key=bytes(words_to_bytes(cfg["test"]["key"])), + digestmod=SHA512, + ) + else: + logger.info("Error: Hash mode not recognized.") + return + hmac.update(bytes(cfg["test"]["msg"])) + expected_response = bytes_to_words(bytearray(hmac.digest())) + expected_response.reverse() + if cfg["test"]["hash_mode"] == 0: + expected_response += [0] * 8 + elif cfg["test"]["hash_mode"] == 1: + expected_response += [0] * 4 + expected_response = json.dumps(exp_json, separators=(",", ":")) + elif "kmac" in cfg["test"]["which_test"]: + expected_response = '{"digest":[184,34,91,108,231,47,251,27], \ + "err_status":0,"alerts":[0,0,0],"ast_alerts":[0,0]}' + exp_json = json.loads(expected_response) + elif "shadow_reg_access" in cfg["test"]["which_test"]: + expected_response = ( + '{"result":[68162304,0,0],"err_status":0,"ast_alerts":[0,0]}' + ) + exp_json = json.loads(expected_response) # Compare response. If no response is received, the device mostly # crashed or was resetted. @@ -135,14 +262,15 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # No UART response received. fi_result = FISuccess.NORESPONSE # Resetting OT as it most likely crashed. - ot_communication = target.reset_target(com_reset = True) + ot_communication = target.reset_target(com_reset=True) # Re-establish UART connection. ot_communication = OTFICrypto(target) # Configure the Crypto FI code on the target. - ot_communication.init(cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + ot_communication.init( + cfg["test"]["core_config"], + cfg["test"]["sensor_config"], + cfg["test"]["alert_config"], + ) # Reset FIGear if necessary. fi_gear.reset() else: @@ -152,15 +280,12 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # further diagnosis. if cfg["test"]["ignore_alerts"]: resp_json = json.loads(response_compare) - exp_json = json.loads(expected_response) if "alerts" in resp_json: del resp_json["alerts"] - response_compare = json.dumps(resp_json, - separators=(',', ':')) + response_compare = json.dumps(resp_json, separators=(",", ":")) if "alerts" in exp_json: del exp_json["alerts"] - expected_response = json.dumps(exp_json, - separators=(',', ':')) + expected_response = json.dumps(exp_json, separators=(",", ":")) # Check if result is expected result (FI failed) or unexpected # result (FI successful). @@ -171,24 +296,24 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # Store result into FIProject. project.append_firesult( - response = response, - fi_result = fi_result, - trigger_delay = fault_parameters.get("trigger_delay"), - glitch_voltage = fault_parameters.get("glitch_voltage"), - glitch_width = fault_parameters.get("glitch_width"), - x_pos = fault_parameters.get("x_pos"), - y_pos = fault_parameters.get("y_pos") + response=response, + fi_result=fi_result, + trigger_delay=fault_parameters.get("trigger_delay"), + glitch_voltage=fault_parameters.get("glitch_voltage"), + glitch_width=fault_parameters.get("glitch_width"), + x_pos=fault_parameters.get("x_pos"), + y_pos=fault_parameters.get("y_pos"), ) fi_results.append(fi_result) remaining_iterations -= 1 pbar.update(1) print_fi_statistic(fi_results) - return device_cfg + return device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version def print_plot(project: FIProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to narrow down the fault injection parameters. @@ -200,8 +325,7 @@ def print_plot(project: FIProject, config: dict, file: Path) -> None: if config["fiproject"]["show_plot"]: plot.save_fi_plot_to_file(config, project, file) logger.info("Created plot.") - logger.info(f'Created plot: ' - f'{Path(str(file) + ".html").resolve()}') + logger.info(f"Created plot: " f'{Path(str(file) + ".html").resolve()}') def main(argv=None): @@ -224,22 +348,37 @@ def main(argv=None): ot_communication = OTFICrypto(target) # FI parameter sweep. - device_cfg = fi_parameter_sweep(cfg, target, fi_gear, project, ot_communication) + device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = ( + fi_parameter_sweep(cfg, target, fi_gear, project, ot_communication) + ) # Print plot. - print_plot(project.get_firesults(start=0, end=cfg["fiproject"]["num_plots"]), - cfg, args.project) + print_plot( + project.get_firesults(start=0, end=cfg["fiproject"]["num_plots"]), + cfg, + args.project, + ) # Save metadata. metadata = {} - metadata["device_cfg"] = device_cfg + metadata["device_id"] = device_id + metadata["sensors"] = sensors + metadata["alerts"] = alerts + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") # Store bitstream information. metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) # Store binary information. metadata["fw_bin_path"] = cfg["target"]["fw_bin"] metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) diff --git a/fault_injection/fi_gear/chipshouter/chipshouter.py b/fault_injection/fi_gear/chipshouter/chipshouter.py index 716b0f98..1cd0bb71 100644 --- a/fault_injection/fi_gear/chipshouter/chipshouter.py +++ b/fault_injection/fi_gear/chipshouter/chipshouter.py @@ -6,11 +6,19 @@ import time import chipwhisperer as cw -from chipshouter import ChipSHOUTER -from chipshouter.com_tools import Reset_Exception -from chipshover import ChipShover from fi_gear.utility import random_float_range +# We allow to skip this loading if not used. +try: + from chipshover import ChipShover +except ImportError: + print("ChipShover library not found. Skipping its use.") +try: + from chipshouter import ChipSHOUTER + from chipshouter.com_tools import Reset_Exception +except ImportError: + print("ChipShouter library not found. Skipping its use.") + sys.path.append("../") from util import check_version # noqa: E402 @@ -19,15 +27,30 @@ class ChipShouterEMFI: - def __init__(self, x_position_min: float, x_position_max: float, - x_position_step: float, y_position_min: float, y_position_max: float, - y_position_step: float, z_position: float, voltage_min: float, - voltage_max: float, voltage_step: float, pulse_width_min: float, - pulse_width_max: float, pulse_width_step: float, - trigger_delay_min: float, trigger_delay_max: float, - trigger_step: float, num_iterations: float, - parameter_generation: str, chipshover_port: str, - chipshouter_port: str, husky_sn: str): + def __init__( + self, + x_position_min: float, + x_position_max: float, + x_position_step: float, + y_position_min: float, + y_position_max: float, + y_position_step: float, + z_position: float, + voltage_min: float, + voltage_max: float, + voltage_step: float, + pulse_width_min: float, + pulse_width_max: float, + pulse_width_step: float, + trigger_delay_min: float, + trigger_delay_max: float, + trigger_step: float, + num_iterations: float, + parameter_generation: str, + chipshover_port: str, + chipshouter_port: str, + husky_sn: str, + ): self.x_position_min = x_position_min self.x_position_max = x_position_max self.x_position_step = x_position_step @@ -84,21 +107,21 @@ def __init__(self, x_position_min: float, x_position_max: float, if not self.cwh._is_husky: raise RuntimeError("No ChipWhisperer Husky is attached!") # Configure the Husky to generate the pulse that is fed into the ChipShouter. - self.cwh.clock.clkgen_src = 'system' + self.cwh.clock.clkgen_src = "system" self.cwh.clock.clkgen_freq = 50e6 self.cwh.clock.adc_mul = 1 self.cwh.adc.basic_mode = "rising_edge" self.cwh.io.hs2 = "glitch" self.cwh.glitch.enabled = True - self.cwh.glitch.clk_src = 'pll' + self.cwh.glitch.clk_src = "pll" self.cwh.clock.pll.update_fpga_vco(600e6) # Each glitch is one clock cycle long (e.g., 1/50MHz = 20ns) # Use repeat to have repeat * 20ns glitch lengths and ext_offset to # have a delay of ext_offset * 20ns trigger delay. - self.cwh.glitch.output = 'enable_only' + self.cwh.glitch.output = "enable_only" # Route the pulse to the HS2 (Trigger/Glitch out SMB) output. - self.cwh.io.aux_io_mcx = 'hs2' - self.cwh.io.glitch_trig_mcx = 'glitch' + self.cwh.io.aux_io_mcx = "hs2" + self.cwh.io.glitch_trig_mcx = "glitch" # Trigger by using the IO4 input pin that comes from the DUT. self.cwh.trigger.triggers = "tio4" self.cwh.glitch.trigger_src = "ext_single" @@ -108,18 +131,30 @@ def __init__(self, x_position_min: float, x_position_max: float, min_ns = int((1 / self.cwh.clock.clkgen_freq) * 1e9) print(min_ns) if self.pulse_width_min < min_ns: - raise RuntimeError("Min pulse width shorter than supported (" + str(min_ns) + " ns)") + raise RuntimeError( + "Min pulse width shorter than supported (" + str(min_ns) + " ns)" + ) # Check pulse step. - if (self.pulse_width_min != self.pulse_width_max) and (self.pulse_width_step % min_ns != 0): - raise RuntimeError("Only a pulse step width of " + str(min_ns) + " ns is supported") + if (self.pulse_width_min != self.pulse_width_max) and ( + self.pulse_width_step % min_ns != 0 + ): + raise RuntimeError( + "Only a pulse step width of " + str(min_ns) + " ns is supported" + ) # Check trigger delay min. if self.trigger_delay_min < min_ns: - raise RuntimeError("Min trigger delay shorter than supported (" + str(min_ns) + " ns)") + raise RuntimeError( + "Min trigger delay shorter than supported (" + str(min_ns) + " ns)" + ) # Check trigger delay step. - if (self.trigger_delay_min != self.trigger_delay_max) and (self.trigger_step % min_ns != 0): - raise RuntimeError("Only a trigger delay step of " + str(min_ns) + " ns is supported") + if (self.trigger_delay_min != self.trigger_delay_max) and ( + self.trigger_step % min_ns != 0 + ): + raise RuntimeError( + "Only a trigger delay step of " + str(min_ns) + " ns is supported" + ) def init_cs(self) -> None: time.sleep(1) @@ -140,7 +175,7 @@ def init_cs(self) -> None: time.sleep(1) def arm_trigger(self, fault_parameters: dict) -> None: - """ Arm the trigger. + """Arm the trigger. Args: A dict containing the FI parameters. @@ -155,12 +190,15 @@ def arm_trigger(self, fault_parameters: dict) -> None: self.init_cs() # Move ChipShouter to XZY position. - if (self.pos_y != fault_parameters['y_pos'] or - self.pos_x != fault_parameters['x_pos']): - self.pos_y = fault_parameters['y_pos'] - self.pos_x = fault_parameters['x_pos'] - self.shv.move(fault_parameters['x_pos'], - fault_parameters['y_pos'], self.z_position) + if ( + self.pos_y != fault_parameters["y_pos"] or + self.pos_x != fault_parameters["x_pos"] + ): + self.pos_y = fault_parameters["y_pos"] + self.pos_x = fault_parameters["x_pos"] + self.shv.move( + fault_parameters["x_pos"], fault_parameters["y_pos"], self.z_position + ) # Set the EMFI voltage parameter. try: @@ -170,10 +208,12 @@ def arm_trigger(self, fault_parameters: dict) -> None: self.init_cs() # Configure the glitch delay and length. - self.cwh.glitch.ext_offset = int(fault_parameters["trigger_delay"] * - 1e-9 / (1 / self.cwh.clock.clkgen_freq)) - self.cwh.glitch.repeat = int(fault_parameters["glitch_width"] * 1e-9 / - (1 / self.cwh.clock.clkgen_freq)) + self.cwh.glitch.ext_offset = int( + fault_parameters["trigger_delay"] * 1e-9 / (1 / self.cwh.clock.clkgen_freq) + ) + self.cwh.glitch.repeat = int( + fault_parameters["glitch_width"] * 1e-9 / (1 / self.cwh.clock.clkgen_freq) + ) # Arm the ChipWhisperer Husky. self.cwh.arm() @@ -182,19 +222,19 @@ def arm_trigger(self, fault_parameters: dict) -> None: # uses this pulse as a template to generate the EM pulse. def generate_fi_parameters(self) -> dict: - """ Generate EMFI parameters within the provided limits. + """Generate EMFI parameters within the provided limits. Returns: A dict containing the FI parameters. """ parameters = {} if self.parameter_generation == "random": - parameters["x_pos"] = random_float_range(self.x_position_min, - self.x_position_max, - self.x_position_step) - parameters["y_pos"] = random_float_range(self.y_position_min, - self.y_position_max, - self.y_position_step) + parameters["x_pos"] = random_float_range( + self.x_position_min, self.x_position_max, self.x_position_step + ) + parameters["y_pos"] = random_float_range( + self.y_position_min, self.y_position_max, self.y_position_step + ) elif self.parameter_generation == "deterministic": if self.curr_iteration == self.num_iterations: self.curr_iteration = 0 @@ -213,38 +253,46 @@ def generate_fi_parameters(self) -> dict: parameters["y_pos"] = self.curr_y_position self.curr_iteration += 1 else: - raise Exception("ChipShouter EMFI only supports random/deterministic" - "parameter generation") - - parameters["glitch_voltage"] = random_float_range(self.voltage_min, - self.voltage_max, - self.voltage_step) - parameters["glitch_width"] = random_float_range(self.pulse_width_min, - self.pulse_width_max, - self.pulse_width_step) - parameters["trigger_delay"] = random_float_range(self.trigger_delay_min, - self.trigger_delay_max, - self.trigger_step) + raise Exception( + "ChipShouter EMFI only supports random/deterministic" + "parameter generation" + ) + + parameters["glitch_voltage"] = random_float_range( + self.voltage_min, self.voltage_max, self.voltage_step + ) + parameters["glitch_width"] = random_float_range( + self.pulse_width_min, self.pulse_width_max, self.pulse_width_step + ) + parameters["trigger_delay"] = random_float_range( + self.trigger_delay_min, self.trigger_delay_max, self.trigger_step + ) return parameters def reset(self) -> None: - """ Reset XZY position. - """ + """Reset XZY position.""" self.shv.stop() self.shv.home() self.init_cs() def get_num_fault_injections(self) -> int: - """ Get number of fault injections. + """Get number of fault injections. Returns: The total number of fault injections performed with ChipShouter EMFI. """ if self.parameter_generation == "random": return self.num_iterations elif self.parameter_generation == "deterministic": - return ((self.x_position_max - self.x_position_min + 1) / - self.x_position_step) * ((self.y_position_max - self.y_position_min + 1) / - self.y_position_step) * (self.num_iterations) + return ( + ((self.x_position_max - self.x_position_min + 1) / self.x_position_step) * + ( + (self.y_position_max - self.y_position_min + 1) / + self.y_position_step + ) * + (self.num_iterations) + ) else: - raise Exception("ChipShouter EMFI only supports random/deterministic" - "parameter generation") + raise Exception( + "ChipShouter EMFI only supports random/deterministic" + "parameter generation" + ) diff --git a/fault_injection/fi_gear/dummy/dummy_clk.py b/fault_injection/fi_gear/dummy/dummy_clk.py index 90dd1faa..3bd5b150 100644 --- a/fault_injection/fi_gear/dummy/dummy_clk.py +++ b/fault_injection/fi_gear/dummy/dummy_clk.py @@ -10,10 +10,17 @@ class DummyCLK: - def __init__(self, glitch_width_min: int, glitch_width_max: int, - glitch_width_step: int, trigger_delay_min: int, - trigger_delay_max: int, trigger_step: int, - num_iterations: int, parameter_generation: str): + def __init__( + self, + glitch_width_min: int, + glitch_width_max: int, + glitch_width_step: int, + trigger_delay_min: int, + trigger_delay_max: int, + trigger_step: int, + num_iterations: int, + parameter_generation: str, + ): self.glitch_width_min = glitch_width_min self.glitch_width_max = glitch_width_max self.glitch_width_step = glitch_width_step @@ -24,37 +31,38 @@ def __init__(self, glitch_width_min: int, glitch_width_max: int, self.parameter_generation = parameter_generation def arm_trigger(self, fault_parameters: dict) -> None: - """ Arm the trigger. + """Arm the trigger. Args: A dict containing the FI parameters. """ - print(f"Arming DummyCLK trigger with" - f"glitch_width={fault_parameters['glitch_width']}, and " - f"trigger_delay={fault_parameters['trigger_delay']}") + print( + f"Arming DummyCLK trigger with" + f"glitch_width={fault_parameters['glitch_width']}, and " + f"trigger_delay={fault_parameters['trigger_delay']}" + ) def generate_fi_parameters(self) -> dict: - """ Generate clock glitching parameters within the provided limits. + """Generate clock glitching parameters within the provided limits. Returns: A dict containing the FI parameters. """ parameters = {} - parameters["glitch_width"] = random_float_range(self.glitch_width_min, - self.glitch_width_max, - self.glitch_width_step) - parameters["trigger_delay"] = random_float_range(self.trigger_delay_min, - self.trigger_delay_max, - self.trigger_step) + parameters["glitch_width"] = random_float_range( + self.glitch_width_min, self.glitch_width_max, self.glitch_width_step + ) + parameters["trigger_delay"] = random_float_range( + self.trigger_delay_min, self.trigger_delay_max, self.trigger_step + ) return parameters def reset(self) -> None: - """ No reset is required for dummy clock glitching FI gear. - """ + """No reset is required for dummy clock glitching FI gear.""" pass def get_num_fault_injections(self) -> int: - """ Get number of fault injections. + """Get number of fault injections. Returns: The total number of fault injections performed with DummyCLK. """ diff --git a/fault_injection/fi_gear/dummy/dummy_emfi.py b/fault_injection/fi_gear/dummy/dummy_emfi.py index e73185f0..92fdb707 100644 --- a/fault_injection/fi_gear/dummy/dummy_emfi.py +++ b/fault_injection/fi_gear/dummy/dummy_emfi.py @@ -10,14 +10,26 @@ class DummyEMFI: - def __init__(self, x_position_min: int, x_position_max: int, - x_position_step: int, y_position_min: int, y_position_max: int, - y_position_step: int, voltage_min: int, voltage_max: int, - voltage_step: int, pulse_width_min: int, - pulse_width_max: int, pulse_width_step: int, - trigger_delay_min: int, trigger_delay_max: int, - trigger_step: int, num_iterations: int, - parameter_generation: str): + def __init__( + self, + x_position_min: int, + x_position_max: int, + x_position_step: int, + y_position_min: int, + y_position_max: int, + y_position_step: int, + voltage_min: int, + voltage_max: int, + voltage_step: int, + pulse_width_min: int, + pulse_width_max: int, + pulse_width_step: int, + trigger_delay_min: int, + trigger_delay_max: int, + trigger_step: int, + num_iterations: int, + parameter_generation: str, + ): self.x_position_min = x_position_min self.x_position_max = x_position_max self.x_position_step = x_position_step @@ -44,32 +56,34 @@ def __init__(self, x_position_min: int, x_position_max: int, self.curr_iteration = 0 def arm_trigger(self, fault_parameters: dict) -> None: - """ Arm the trigger. + """Arm the trigger. Args: A dict containing the FI parameters. """ - print(f"Arming DummyEMFI trigger with " - f"x_position={fault_parameters['x_position']} " - f"y_position={fault_parameters['y_position']}, " - f"voltage={fault_parameters['voltage']}, " - f"pulse_width={fault_parameters['pulse_width']}, and " - f"trigger_delay={fault_parameters['trigger_delay']}") + print( + f"Arming DummyEMFI trigger with " + f"x_position={fault_parameters['x_position']} " + f"y_position={fault_parameters['y_position']}, " + f"voltage={fault_parameters['voltage']}, " + f"pulse_width={fault_parameters['pulse_width']}, and " + f"trigger_delay={fault_parameters['trigger_delay']}" + ) def generate_fi_parameters(self) -> dict: - """ Generate EMFI parameters within the provided limits. + """Generate EMFI parameters within the provided limits. Returns: A dict containing the FI parameters. """ parameters = {} if self.parameter_generation == "random": - parameters["x_position"] = random_float_range(self.x_position_min, - self.x_position_max, - self.x_position_step) - parameters["y_position"] = random_float_range(self.y_position_min, - self.y_position_max, - self.y_position_step) + parameters["x_position"] = random_float_range( + self.x_position_min, self.x_position_max, self.x_position_step + ) + parameters["y_position"] = random_float_range( + self.y_position_min, self.y_position_max, self.y_position_step + ) elif self.parameter_generation == "deterministic": if self.curr_iteration == self.num_iterations: self.curr_iteration = 0 @@ -83,34 +97,42 @@ def generate_fi_parameters(self) -> dict: parameters["y_position"] = self.curr_y_position self.curr_iteration += 1 else: - raise Exception("DummyEMFI only supports random/deterministic parameter generation") + raise Exception( + "DummyEMFI only supports random/deterministic parameter generation" + ) - parameters["voltage"] = random_float_range(self.voltage_min, - self.voltage_max, - self.voltage_step) - parameters["pulse_width"] = random_float_range(self.pulse_width_min, - self.pulse_width_max, - self.pulse_width_step) - parameters["trigger_delay"] = random_float_range(self.trigger_delay_min, - self.trigger_delay_max, - self.trigger_step) + parameters["voltage"] = random_float_range( + self.voltage_min, self.voltage_max, self.voltage_step + ) + parameters["pulse_width"] = random_float_range( + self.pulse_width_min, self.pulse_width_max, self.pulse_width_step + ) + parameters["trigger_delay"] = random_float_range( + self.trigger_delay_min, self.trigger_delay_max, self.trigger_step + ) return parameters def reset(self) -> None: - """ No reset is required for dummy EMFI gear. - """ + """No reset is required for dummy EMFI gear.""" pass def get_num_fault_injections(self) -> int: - """ Get number of fault injections. + """Get number of fault injections. Returns: The total number of fault injections performed with DummyEMFI. """ if self.parameter_generation == "random": return self.num_iterations elif self.parameter_generation == "deterministic": - return ((self.x_position_max - self.x_position_min + 1) / - self.x_position_step) * ((self.y_position_max - self.y_position_min + 1) / - self.y_position_step) * (self.num_iterations) + return ( + ((self.x_position_max - self.x_position_min + 1) / self.x_position_step) * + ( + (self.y_position_max - self.y_position_min + 1) / + self.y_position_step + ) * + (self.num_iterations) + ) else: - raise Exception("DummyEMFI only supports random/deterministic parameter generation") + raise Exception( + "DummyEMFI only supports random/deterministic parameter generation" + ) diff --git a/fault_injection/fi_gear/dummy/dummy_lfi.py b/fault_injection/fi_gear/dummy/dummy_lfi.py index 4f128bef..514bc169 100644 --- a/fault_injection/fi_gear/dummy/dummy_lfi.py +++ b/fault_injection/fi_gear/dummy/dummy_lfi.py @@ -10,14 +10,26 @@ class DummyLFI: - def __init__(self, x_position_min: int, x_position_max: int, - x_position_step: int, y_position_min: int, y_position_max: int, - y_position_step: int, attenuation_min: int, attenuation_max: int, - attenuation_step: int, pulse_width_min: int, - pulse_width_max: int, pulse_width_step: int, - trigger_delay_min: int, trigger_delay_max: int, - trigger_step: int, num_iterations: int, - parameter_generation: str): + def __init__( + self, + x_position_min: int, + x_position_max: int, + x_position_step: int, + y_position_min: int, + y_position_max: int, + y_position_step: int, + attenuation_min: int, + attenuation_max: int, + attenuation_step: int, + pulse_width_min: int, + pulse_width_max: int, + pulse_width_step: int, + trigger_delay_min: int, + trigger_delay_max: int, + trigger_step: int, + num_iterations: int, + parameter_generation: str, + ): self.x_position_min = x_position_min self.x_position_max = x_position_max self.x_position_step = x_position_step @@ -44,32 +56,34 @@ def __init__(self, x_position_min: int, x_position_max: int, self.curr_iteration = 0 def arm_trigger(self, fault_parameters: dict) -> None: - """ Arm the trigger. + """Arm the trigger. Args: A dict containing the FI parameters. """ - print(f"Arming DummyLFI trigger with" - f"x_position={fault_parameters['x_position']} " - f"y_position={fault_parameters['y_position']}, " - f"attenuation={fault_parameters['attenuation']}, " - f"pulse_width={fault_parameters['pulse_width']}, and " - f"trigger_delay={fault_parameters['trigger_delay']}") + print( + f"Arming DummyLFI trigger with" + f"x_position={fault_parameters['x_position']} " + f"y_position={fault_parameters['y_position']}, " + f"attenuation={fault_parameters['attenuation']}, " + f"pulse_width={fault_parameters['pulse_width']}, and " + f"trigger_delay={fault_parameters['trigger_delay']}" + ) def generate_fi_parameters(self) -> dict: - """ Generate LFI parameters within the provided limits. + """Generate LFI parameters within the provided limits. Returns: A dict containing the FI parameters. """ parameters = {} if self.parameter_generation == "random": - parameters["x_position"] = random_float_range(self.x_position_min, - self.x_position_max, - self.x_position_step) - parameters["y_position"] = random_float_range(self.y_position_min, - self.y_position_max, - self.y_position_step) + parameters["x_position"] = random_float_range( + self.x_position_min, self.x_position_max, self.x_position_step + ) + parameters["y_position"] = random_float_range( + self.y_position_min, self.y_position_max, self.y_position_step + ) elif self.parameter_generation == "deterministic": if self.curr_iteration == self.num_iterations: self.curr_iteration = 0 @@ -83,34 +97,42 @@ def generate_fi_parameters(self) -> dict: parameters["y_position"] = self.curr_y_position self.curr_iteration += 1 else: - raise Exception("DummyLFI only supports random/deterministic parameter generation") + raise Exception( + "DummyLFI only supports random/deterministic parameter generation" + ) - parameters["attenuation"] = random_float_range(self.attenuation_min, - self.attenuation_max, - self.attenuation_step) - parameters["pulse_width"] = random_float_range(self.pulse_width_min, - self.pulse_width_max, - self.pulse_width_step) - parameters["trigger_delay"] = random_float_range(self.trigger_delay_min, - self.trigger_delay_max, - self.trigger_step) + parameters["attenuation"] = random_float_range( + self.attenuation_min, self.attenuation_max, self.attenuation_step + ) + parameters["pulse_width"] = random_float_range( + self.pulse_width_min, self.pulse_width_max, self.pulse_width_step + ) + parameters["trigger_delay"] = random_float_range( + self.trigger_delay_min, self.trigger_delay_max, self.trigger_step + ) return parameters def reset(self) -> None: - """ No reset is required for dummy LFI gear. - """ + """No reset is required for dummy LFI gear.""" pass def get_num_fault_injections(self) -> int: - """ Get number of fault injections. + """Get number of fault injections. Returns: The total number of fault injections performed with DummyEMFI. """ if self.parameter_generation == "random": return self.num_iterations elif self.parameter_generation == "deterministic": - return ((self.x_position_max - self.x_position_min + 1) / - self.x_position_step) * ((self.y_position_max - self.y_position_min + 1) / - self.y_position_step) * (self.num_iterations) + return ( + ((self.x_position_max - self.x_position_min + 1) / self.x_position_step) * + ( + (self.y_position_max - self.y_position_min + 1) / + self.y_position_step + ) * + (self.num_iterations) + ) else: - raise Exception("DummyEMFI only supports random/deterministic parameter generation") + raise Exception( + "DummyEMFI only supports random/deterministic parameter generation" + ) diff --git a/fault_injection/fi_gear/dummy/dummy_vcc.py b/fault_injection/fi_gear/dummy/dummy_vcc.py index 7718df3a..e9e98007 100644 --- a/fault_injection/fi_gear/dummy/dummy_vcc.py +++ b/fault_injection/fi_gear/dummy/dummy_vcc.py @@ -10,12 +10,20 @@ class DummyVCC: - def __init__(self, glitch_voltage_min: float, glitch_voltage_max: float, - glitch_voltage_step: float, glitch_width_min: float, - glitch_width_max: float, glitch_width_step: float, - trigger_delay_min: int, trigger_delay_max: int, - trigger_step: int, num_iterations: int, - parameter_generation: str): + def __init__( + self, + glitch_voltage_min: float, + glitch_voltage_max: float, + glitch_voltage_step: float, + glitch_width_min: float, + glitch_width_max: float, + glitch_width_step: float, + trigger_delay_min: int, + trigger_delay_max: int, + trigger_step: int, + num_iterations: int, + parameter_generation: str, + ): self.glitch_voltage_min = glitch_voltage_min self.glitch_voltage_max = glitch_voltage_max self.glitch_voltage_step = glitch_voltage_step @@ -29,18 +37,20 @@ def __init__(self, glitch_voltage_min: float, glitch_voltage_max: float, self.parameter_generation = parameter_generation def arm_trigger(self, fault_parameters: dict) -> None: - """ Arm the trigger. + """Arm the trigger. Args: A dict containing the FI parameters. """ - print(f"Arming DummyVCC trigger with" - f"glitch_voltage={fault_parameters['glitch_voltage']}, " - f"glitch_width={fault_parameters['glitch_width']}, and " - f"trigger_delay={fault_parameters['trigger_delay']}") + print( + f"Arming DummyVCC trigger with " + f"glitch_voltage={fault_parameters['glitch_voltage']}, " + f"glitch_width={fault_parameters['glitch_width']}, and " + f"trigger_delay={fault_parameters['trigger_delay']}" + ) def generate_fi_parameters(self) -> dict: - """ Generate random voltage glitch parameters within the provided + """Generate random voltage glitch parameters within the provided limits. Returns: @@ -48,27 +58,28 @@ def generate_fi_parameters(self) -> dict: """ if self.parameter_generation == "random": parameters = {} - parameters["glitch_voltage"] = random_float_range(self.glitch_voltage_min, - self.glitch_voltage_max, - self.glitch_voltage_step) - parameters["glitch_width"] = random_float_range(self.glitch_width_min, - self.glitch_width_max, - self.glitch_width_step) - parameters["trigger_delay"] = random_float_range(self.trigger_delay_min, - self.trigger_delay_max, - self.trigger_step) + parameters["glitch_voltage"] = random_float_range( + self.glitch_voltage_min, + self.glitch_voltage_max, + self.glitch_voltage_step, + ) + parameters["glitch_width"] = random_float_range( + self.glitch_width_min, self.glitch_width_max, self.glitch_width_step + ) + parameters["trigger_delay"] = random_float_range( + self.trigger_delay_min, self.trigger_delay_max, self.trigger_step + ) else: raise Exception("DummyVCC only supports random parameter generation") return parameters def reset(self) -> None: - """ No reset is required for dummy VCC glitch gear. - """ + """No reset is required for dummy VCC glitch gear.""" pass def get_num_fault_injections(self) -> int: - """ Get number of fault injections. + """Get number of fault injections. Returns: The total number of fault injections performed with the DummyVCCFI gear. diff --git a/fault_injection/fi_gear/fi_gear.py b/fault_injection/fi_gear/fi_gear.py index 162dad83..dda59763 100644 --- a/fault_injection/fi_gear/fi_gear.py +++ b/fault_injection/fi_gear/fi_gear.py @@ -12,10 +12,11 @@ class FIGear: - """ Fault Injection Gear class. + """Fault Injection Gear class. This class represents a FI gear (e.g. LFI, EMFI, ...). """ + def __init__(self, cfg: dict) -> None: self.gear_type = cfg["fisetup"]["fi_gear"] self.fi_type = cfg["fisetup"]["fi_type"] @@ -23,103 +24,109 @@ def __init__(self, cfg: dict) -> None: if self.gear_type == "dummy" and self.fi_type == "voltage_glitch": self.gear = DummyVCC( - glitch_voltage_min = cfg["fisetup"]["glitch_voltage_min"], - glitch_voltage_max = cfg["fisetup"]["glitch_voltage_max"], - glitch_voltage_step = cfg["fisetup"]["glitch_voltage_step"], - glitch_width_min = cfg["fisetup"]["glitch_width_min"], - glitch_width_max = cfg["fisetup"]["glitch_width_max"], - glitch_width_step = cfg["fisetup"]["glitch_width_step"], - trigger_delay_min = cfg["fisetup"]["trigger_delay_min"], - trigger_delay_max = cfg["fisetup"]["trigger_delay_max"], - trigger_step = cfg["fisetup"]["trigger_step"], - num_iterations = cfg["fisetup"]["num_iterations"], - parameter_generation = cfg["fisetup"]["parameter_generation"]) + glitch_voltage_min=cfg["fisetup"]["glitch_voltage_min"], + glitch_voltage_max=cfg["fisetup"]["glitch_voltage_max"], + glitch_voltage_step=cfg["fisetup"]["glitch_voltage_step"], + glitch_width_min=cfg["fisetup"]["glitch_width_min"], + glitch_width_max=cfg["fisetup"]["glitch_width_max"], + glitch_width_step=cfg["fisetup"]["glitch_width_step"], + trigger_delay_min=cfg["fisetup"]["trigger_delay_min"], + trigger_delay_max=cfg["fisetup"]["trigger_delay_max"], + trigger_step=cfg["fisetup"]["trigger_step"], + num_iterations=cfg["fisetup"]["num_iterations"], + parameter_generation=cfg["fisetup"]["parameter_generation"], + ) elif self.gear_type == "dummy" and self.fi_type == "clock_glitch": self.gear = DummyCLK( - glitch_width_min = cfg["fisetup"]["glitch_width_min"], - glitch_width_max = cfg["fisetup"]["glitch_width_max"], - glitch_width_step = cfg["fisetup"]["glitch_width_step"], - trigger_delay_min = cfg["fisetup"]["trigger_delay_min"], - trigger_delay_max = cfg["fisetup"]["trigger_delay_max"], - trigger_step = cfg["fisetup"]["trigger_step"], - num_iterations = cfg["fisetup"]["num_iterations"], - parameter_generation = cfg["fisetup"]["parameter_generation"]) + glitch_width_min=cfg["fisetup"]["glitch_width_min"], + glitch_width_max=cfg["fisetup"]["glitch_width_max"], + glitch_width_step=cfg["fisetup"]["glitch_width_step"], + trigger_delay_min=cfg["fisetup"]["trigger_delay_min"], + trigger_delay_max=cfg["fisetup"]["trigger_delay_max"], + trigger_step=cfg["fisetup"]["trigger_step"], + num_iterations=cfg["fisetup"]["num_iterations"], + parameter_generation=cfg["fisetup"]["parameter_generation"], + ) elif self.gear_type == "dummy" and self.fi_type == "lfi": self.gear = DummyLFI( - x_position_min = cfg["fisetup"]["x_position_min"], - x_position_max = cfg["fisetup"]["x_position_max"], - x_position_step = cfg["fisetup"]["x_position_step"], - y_position_min = cfg["fisetup"]["y_position_min"], - y_position_max = cfg["fisetup"]["y_position_max"], - y_position_step = cfg["fisetup"]["y_position_step"], - attenuation_min = cfg["fisetup"]["attenuation_min"], - attenuation_max = cfg["fisetup"]["attenuation_max"], - attenuation_step = cfg["fisetup"]["attenuation_step"], - pulse_width_min = cfg["fisetup"]["pulse_width_min"], - pulse_width_max = cfg["fisetup"]["pulse_width_max"], - pulse_width_step = cfg["fisetup"]["pulse_width_step"], - trigger_delay_min = cfg["fisetup"]["trigger_delay_min"], - trigger_delay_max = cfg["fisetup"]["trigger_delay_max"], - trigger_step = cfg["fisetup"]["trigger_step"], - num_iterations = cfg["fisetup"]["num_iterations"], - parameter_generation = cfg["fisetup"]["parameter_generation"]) + x_position_min=cfg["fisetup"]["x_position_min"], + x_position_max=cfg["fisetup"]["x_position_max"], + x_position_step=cfg["fisetup"]["x_position_step"], + y_position_min=cfg["fisetup"]["y_position_min"], + y_position_max=cfg["fisetup"]["y_position_max"], + y_position_step=cfg["fisetup"]["y_position_step"], + attenuation_min=cfg["fisetup"]["attenuation_min"], + attenuation_max=cfg["fisetup"]["attenuation_max"], + attenuation_step=cfg["fisetup"]["attenuation_step"], + pulse_width_min=cfg["fisetup"]["pulse_width_min"], + pulse_width_max=cfg["fisetup"]["pulse_width_max"], + pulse_width_step=cfg["fisetup"]["pulse_width_step"], + trigger_delay_min=cfg["fisetup"]["trigger_delay_min"], + trigger_delay_max=cfg["fisetup"]["trigger_delay_max"], + trigger_step=cfg["fisetup"]["trigger_step"], + num_iterations=cfg["fisetup"]["num_iterations"], + parameter_generation=cfg["fisetup"]["parameter_generation"], + ) elif self.gear_type == "dummy" and self.fi_type == "emfi": self.gear = DummyEMFI( - x_position_min = cfg["fisetup"]["x_position_min"], - x_position_max = cfg["fisetup"]["x_position_max"], - x_position_step = cfg["fisetup"]["x_position_step"], - y_position_min = cfg["fisetup"]["y_position_min"], - y_position_max = cfg["fisetup"]["y_position_max"], - y_position_step = cfg["fisetup"]["y_position_step"], - voltage_min = cfg["fisetup"]["voltage_min"], - voltage_max = cfg["fisetup"]["voltage_max"], - voltage_step = cfg["fisetup"]["voltage_step"], - pulse_width_min = cfg["fisetup"]["pulse_width_min"], - pulse_width_max = cfg["fisetup"]["pulse_width_max"], - pulse_width_step = cfg["fisetup"]["pulse_width_step"], - trigger_delay_min = cfg["fisetup"]["trigger_delay_min"], - trigger_delay_max = cfg["fisetup"]["trigger_delay_max"], - trigger_step = cfg["fisetup"]["trigger_step"], - num_iterations = cfg["fisetup"]["num_iterations"], - parameter_generation = cfg["fisetup"]["parameter_generation"]) + x_position_min=cfg["fisetup"]["x_position_min"], + x_position_max=cfg["fisetup"]["x_position_max"], + x_position_step=cfg["fisetup"]["x_position_step"], + y_position_min=cfg["fisetup"]["y_position_min"], + y_position_max=cfg["fisetup"]["y_position_max"], + y_position_step=cfg["fisetup"]["y_position_step"], + voltage_min=cfg["fisetup"]["voltage_min"], + voltage_max=cfg["fisetup"]["voltage_max"], + voltage_step=cfg["fisetup"]["voltage_step"], + pulse_width_min=cfg["fisetup"]["pulse_width_min"], + pulse_width_max=cfg["fisetup"]["pulse_width_max"], + pulse_width_step=cfg["fisetup"]["pulse_width_step"], + trigger_delay_min=cfg["fisetup"]["trigger_delay_min"], + trigger_delay_max=cfg["fisetup"]["trigger_delay_max"], + trigger_step=cfg["fisetup"]["trigger_step"], + num_iterations=cfg["fisetup"]["num_iterations"], + parameter_generation=cfg["fisetup"]["parameter_generation"], + ) elif self.gear_type == "husky" and self.fi_type == "voltage_glitch": self.gear = HuskyVCC( - pll_frequency = cfg["target"]["pll_frequency"], - serial_number = cfg["fisetup"].get("fi_gear_sn"), - glitch_width_min = cfg["fisetup"]["glitch_width_min"], - glitch_width_max = cfg["fisetup"]["glitch_width_max"], - glitch_width_step = cfg["fisetup"]["glitch_width_step"], - trigger_delay_min = cfg["fisetup"]["trigger_delay_min"], - trigger_delay_max = cfg["fisetup"]["trigger_delay_max"], - trigger_step = cfg["fisetup"]["trigger_step"], - num_iterations = cfg["fisetup"]["num_iterations"], - parameter_generation = cfg["fisetup"]["parameter_generation"]) + pll_frequency=cfg["target"]["pll_frequency"], + serial_number=cfg["fisetup"].get("fi_gear_sn"), + glitch_width_min=cfg["fisetup"]["glitch_width_min"], + glitch_width_max=cfg["fisetup"]["glitch_width_max"], + glitch_width_step=cfg["fisetup"]["glitch_width_step"], + trigger_delay_min=cfg["fisetup"]["trigger_delay_min"], + trigger_delay_max=cfg["fisetup"]["trigger_delay_max"], + trigger_step=cfg["fisetup"]["trigger_step"], + num_iterations=cfg["fisetup"]["num_iterations"], + parameter_generation=cfg["fisetup"]["parameter_generation"], + ) elif self.gear_type == "chipshouter" and self.fi_type == "emfi": self.gear = ChipShouterEMFI( - chipshover_port = cfg["fisetup"]["chipshover_port"], - chipshouter_port = cfg["fisetup"]["chipshouter_port"], - husky_sn = cfg["fisetup"].get("husky_sn"), - x_position_min = cfg["fisetup"]["x_position_min"], - x_position_max = cfg["fisetup"]["x_position_max"], - x_position_step = cfg["fisetup"]["x_position_step"], - y_position_min = cfg["fisetup"]["y_position_min"], - y_position_max = cfg["fisetup"]["y_position_max"], - y_position_step = cfg["fisetup"]["y_position_step"], - z_position = cfg["fisetup"]["z_position"], - voltage_min = cfg["fisetup"]["voltage_min"], - voltage_max = cfg["fisetup"]["voltage_max"], - voltage_step = cfg["fisetup"]["voltage_step"], - pulse_width_min = cfg["fisetup"]["pulse_width_min"], - pulse_width_max = cfg["fisetup"]["pulse_width_max"], - pulse_width_step = cfg["fisetup"]["pulse_width_step"], - trigger_delay_min = cfg["fisetup"]["trigger_delay_min"], - trigger_delay_max = cfg["fisetup"]["trigger_delay_max"], - trigger_step = cfg["fisetup"]["trigger_step"], - num_iterations = cfg["fisetup"]["num_iterations"], - parameter_generation = cfg["fisetup"]["parameter_generation"]) + chipshover_port=cfg["fisetup"]["chipshover_port"], + chipshouter_port=cfg["fisetup"]["chipshouter_port"], + husky_sn=cfg["fisetup"].get("husky_sn"), + x_position_min=cfg["fisetup"]["x_position_min"], + x_position_max=cfg["fisetup"]["x_position_max"], + x_position_step=cfg["fisetup"]["x_position_step"], + y_position_min=cfg["fisetup"]["y_position_min"], + y_position_max=cfg["fisetup"]["y_position_max"], + y_position_step=cfg["fisetup"]["y_position_step"], + z_position=cfg["fisetup"]["z_position"], + voltage_min=cfg["fisetup"]["voltage_min"], + voltage_max=cfg["fisetup"]["voltage_max"], + voltage_step=cfg["fisetup"]["voltage_step"], + pulse_width_min=cfg["fisetup"]["pulse_width_min"], + pulse_width_max=cfg["fisetup"]["pulse_width_max"], + pulse_width_step=cfg["fisetup"]["pulse_width_step"], + trigger_delay_min=cfg["fisetup"]["trigger_delay_min"], + trigger_delay_max=cfg["fisetup"]["trigger_delay_max"], + trigger_step=cfg["fisetup"]["trigger_step"], + num_iterations=cfg["fisetup"]["num_iterations"], + parameter_generation=cfg["fisetup"]["parameter_generation"], + ) def arm_trigger(self, fi_parameters: dict) -> None: - """ Arm the trigger. + """Arm the trigger. Args: A dict containing the FI parameters. @@ -127,7 +134,7 @@ def arm_trigger(self, fi_parameters: dict) -> None: self.gear.arm_trigger(fi_parameters) def generate_fi_parameters(self) -> dict: - """ Generate random fault parameters within the provided limits. + """Generate random fault parameters within the provided limits. Returns: A dict containing the FI parameters. @@ -135,14 +142,14 @@ def generate_fi_parameters(self) -> dict: return self.gear.generate_fi_parameters() def reset(self) -> None: - """ Reset the FI gear. + """Reset the FI gear. Some FI gear (Husky) needs to be resettet. """ self.gear.reset() def get_num_fault_injections(self) -> int: - """ Get number of fault injections. + """Get number of fault injections. Returns: The total number of fault injections performed with the FI gear. """ diff --git a/fault_injection/fi_gear/husky/husky_vcc.py b/fault_injection/fi_gear/husky/husky_vcc.py index c90d9eba..cb594220 100644 --- a/fault_injection/fi_gear/husky/husky_vcc.py +++ b/fault_injection/fi_gear/husky/husky_vcc.py @@ -12,7 +12,7 @@ class HuskyVCC: - """ Initialize Husky for VCC glitching. + """Initialize Husky for VCC glitching. Args: pll_frequency: The PLL frequency of the target. @@ -24,11 +24,20 @@ class HuskyVCC: trigger_delay_max: Upper bound for the trigger delay. trigger_step: Step for the trigger delay. """ - def __init__(self, pll_frequency: int, serial_number: str, - glitch_width_min: float, glitch_width_max: float, - glitch_width_step: float, trigger_delay_min: int, - trigger_delay_max: int, trigger_step: int, num_iterations: int, - parameter_generation: str): + + def __init__( + self, + pll_frequency: int, + serial_number: str, + glitch_width_min: float, + glitch_width_max: float, + glitch_width_step: float, + trigger_delay_min: int, + trigger_delay_max: int, + trigger_step: int, + num_iterations: int, + parameter_generation: str, + ): # Set Husky parameters. self.scope = None self.pll_frequency = pll_frequency @@ -54,7 +63,7 @@ def __init__(self, pll_frequency: int, serial_number: str, self.init_husky() def init_husky(self) -> None: - """ Initialize husky. + """Initialize husky. Configure Husky crowbar in such a way that the glitcher uses the HP MOSFET and a single glitch is clkgen_freq long. @@ -71,7 +80,7 @@ def init_husky(self) -> None: # Configure the clock. self.scope.clock.clkgen_freq = self.pll_frequency # Initialize the voltage glitching. - self.scope.vglitch_setup('hp', default_setup=False) + self.scope.vglitch_setup("hp", default_setup=False) # Glitch output is high for glitch.repeat cycles. One cylce is # clkgen_freq. self.scope.glitch.output = "enable_only" @@ -81,7 +90,7 @@ def init_husky(self) -> None: self.scope.trigger.triggers = "tio4" def arm_trigger(self, fault_parameters: dict) -> None: - """ Arm the trigger. + """Arm the trigger. Configures the glitcher to inject a fault of width glitch.repeat cycles after the trigger delay. @@ -89,12 +98,12 @@ def arm_trigger(self, fault_parameters: dict) -> None: Args: A dict containing the FI parameters. """ - self.scope.glitch.repeat = fault_parameters['glitch_width'] - self.scope.glitch.ext_offset = fault_parameters['trigger_delay'] + self.scope.glitch.repeat = fault_parameters["glitch_width"] + self.scope.glitch.ext_offset = fault_parameters["trigger_delay"] self.scope.arm() def generate_fi_parameters(self) -> dict: - """ Generate random voltage glitch parameters within the provided + """Generate random voltage glitch parameters within the provided limits. Random generation: randomly generate glitch_width & trigger_delay. @@ -106,9 +115,9 @@ def generate_fi_parameters(self) -> dict: """ parameters = {} if self.parameter_generation == "random": - parameters["glitch_width"] = random_float_range(self.glitch_width_min, - self.glitch_width_max, - self.glitch_width_step) + parameters["glitch_width"] = random_float_range( + self.glitch_width_min, self.glitch_width_max, self.glitch_width_step + ) elif self.parameter_generation == "deterministic": if self.curr_iteration == self.num_iterations: self.curr_iteration = 0 @@ -116,23 +125,25 @@ def generate_fi_parameters(self) -> dict: parameters["glitch_width"] = self.curr_glitch_width self.curr_iteration += 1 else: - raise Exception("HuskyVCC only supports random/deterministic parameter generation") + raise Exception( + "HuskyVCC only supports random/deterministic parameter generation" + ) # Randomly generate the trigger delay for both cases. - parameters["trigger_delay"] = random_float_range(self.trigger_delay_min, - self.trigger_delay_max, - self.trigger_step) + parameters["trigger_delay"] = random_float_range( + self.trigger_delay_min, self.trigger_delay_max, self.trigger_step + ) return parameters def reset(self) -> None: - """ Initialize husky. + """Initialize husky. If the target crashes, Husky needs to be again initialized. """ self.init_husky() def get_num_fault_injections(self) -> int: - """ Get number of fault injections. + """Get number of fault injections. Returns: The total number of fault injections performed with the Husky glitcher. @@ -140,7 +151,10 @@ def get_num_fault_injections(self) -> int: if self.parameter_generation == "random": return self.num_iterations elif self.parameter_generation == "deterministic": - return ((self.glitch_width_max - self.glitch_width_min) / - self.glitch_width_step) * self.num_iterations + return ( + (self.glitch_width_max - self.glitch_width_min) / self.glitch_width_step + ) * self.num_iterations else: - raise Exception("HuskyVCC only supports random/deterministic parameter generation") + raise Exception( + "HuskyVCC only supports random/deterministic parameter generation" + ) diff --git a/fault_injection/fi_gear/utility.py b/fault_injection/fi_gear/utility.py index 8eb2e289..29648f5e 100644 --- a/fault_injection/fi_gear/utility.py +++ b/fault_injection/fi_gear/utility.py @@ -6,6 +6,5 @@ def random_float_range(min: float, max: float, step: float) -> float: - """ Returns a random float between min and max with step. - """ + """Returns a random float between min and max with step.""" return round(random.randint(0, int(round((max - min) / step))) * step + min, 4) diff --git a/fault_injection/fi_ibex.py b/fault_injection/fi_ibex.py index 13264c2f..8862e92b 100755 --- a/fault_injection/fi_ibex.py +++ b/fault_injection/fi_ibex.py @@ -22,7 +22,7 @@ def setup(cfg: dict, project: Path): - """ Setup target, FI gear, and project. + """Setup target, FI gear, and project. Args: cfg: The configuration for the current experiment. @@ -34,23 +34,24 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + ) # Create target config & setup target. logger.info(f"Initializing target {cfg['target']['target_type']} ...") target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial"), - interface = cfg["target"].get("interface"), - husky_serial = cfg["fisetup"].get("husky_serial") + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], + pll_frequency=cfg["target"]["pll_frequency"], + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + interface=cfg["target"].get("interface"), + husky_serial = cfg["fisetup"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) target = Target(target_cfg) @@ -58,11 +59,12 @@ def setup(cfg: dict, project: Path): fi_gear = FIGear(cfg) # Init project. - project_cfg = ProjectConfig(type = cfg["fiproject"]["project_db"], - path = project, - overwrite = True, - fi_threshold = cfg["fiproject"].get("project_mem_threshold") - ) + project_cfg = ProjectConfig( + type=cfg["fiproject"]["project_db"], + path=project, + overwrite=True, + fi_threshold=cfg["fiproject"].get("project_mem_threshold"), + ) project = FIProject(project_cfg) project.create_project() @@ -70,7 +72,7 @@ def setup(cfg: dict, project: Path): def print_fi_statistic(fi_results: list) -> None: - """ Print FI Statistic. + """Print FI Statistic. Prints the number of FISuccess.SUCCESS, FISuccess.EXPRESPONSE, and FISuccess.NORESPONSE. @@ -82,15 +84,18 @@ def print_fi_statistic(fi_results: list) -> None: num_succ = round((fi_results.count(FISuccess.SUCCESS) / num_total) * 100, 2) num_exp = round((fi_results.count(FISuccess.EXPRESPONSE) / num_total) * 100, 2) num_no = round((fi_results.count(FISuccess.NORESPONSE) / num_total) * 100, 2) - logger.info(f"{num_total} faults, {fi_results.count(FISuccess.SUCCESS)}" - f"({num_succ}%) successful, {fi_results.count(FISuccess.EXPRESPONSE)}" - f"({num_exp}%) expected, and {fi_results.count(FISuccess.NORESPONSE)}" - f"({num_no}%) no response.") + logger.info( + f"{num_total} faults, {fi_results.count(FISuccess.SUCCESS)}" + f"({num_succ}%) successful, {fi_results.count(FISuccess.EXPRESPONSE)}" + f"({num_exp}%) expected, and {fi_results.count(FISuccess.NORESPONSE)}" + f"({num_no}%) no response." + ) -def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, - project: FIProject, ot_communication: OTFIIbex) -> None: - """ Fault parameter sweep. +def fi_parameter_sweep( + cfg: dict, target: Target, fi_gear, project: FIProject, ot_communication: OTFIIbex +) -> None: + """Fault parameter sweep. Sweep through the fault parameter space. @@ -101,19 +106,29 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, project: The project to store the results. ot_communication: The OpenTitan Ibex FI communication interface. Returns: - device_cfg: The ID and countermeasure configuration of the target device. + device_id: The ID of the target device. + sensors: The sensor info. + alerts: The alert info. + owner_page: The owner info page. + boot_log: The boot log. + boot_measurments: The boot measurements. + version: The testOS version. """ # Configure the Ibex FI code on the target. - device_cfg = ot_communication.init(cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = ( + ot_communication.init( + cfg["test"]["core_config"], + cfg["test"]["sensor_config"], + cfg["test"]["alert_config"], + ) + ) # Store results in array for a quick access. fi_results = [] # Start the parameter sweep. remaining_iterations = fi_gear.get_num_fault_injections() - with tqdm(total=remaining_iterations, desc="Injecting", ncols=80, - unit=" different faults") as pbar: + with tqdm( + total=remaining_iterations, desc="Injecting", ncols=80, unit=" different faults" + ) as pbar: while remaining_iterations > 0: # Get fault parameters (e.g., trigger delay, glitch voltage). fault_parameters = fi_gear.generate_fi_parameters() @@ -125,7 +140,7 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, ot_communication.start_test(cfg) # Read response. - response = ot_communication.read_response() + response = target.read_response() response_compare = response expected_response = cfg["test"]["expected_result"] @@ -134,14 +149,15 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # No UART response received. fi_result = FISuccess.NORESPONSE # Resetting OT as it most likely crashed. - ot_communication = target.reset_target(com_reset = True) + ot_communication = target.reset_target(com_reset=True) # Re-establish UART connection. ot_communication = OTFIIbex(target) # Configure the Ibex FI code on the target. - ot_communication.init(cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + ot_communication.init( + cfg["test"]["core_config"], + cfg["test"]["sensor_config"], + cfg["test"]["alert_config"], + ) # Reset FIGear if necessary. fi_gear.reset() else: @@ -152,7 +168,7 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, resp_json = json.loads(response_compare) if "registers" in resp_json: del resp_json["registers"] - response_compare = json.dumps(resp_json, separators=(',', ':')) + response_compare = json.dumps(resp_json, separators=(",", ":")) # If the test decides to ignore alerts triggered by the alert # handler, remove it from the received and expected response. # In the database, the received alert is still available for @@ -162,12 +178,10 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, exp_json = json.loads(expected_response) if "alerts" in resp_json: del resp_json["alerts"] - response_compare = json.dumps(resp_json, - separators=(',', ':')) + response_compare = json.dumps(resp_json, separators=(",", ":")) if "alerts" in exp_json: del exp_json["alerts"] - expected_response = json.dumps(exp_json, - separators=(',', ':')) + expected_response = json.dumps(exp_json, separators=(",", ":")) # Check if result is expected result (FI failed), unexpected result # (FI successful), or no response (FI failed.) @@ -178,24 +192,24 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # Store result into FIProject. project.append_firesult( - response = response, - fi_result = fi_result, - trigger_delay = fault_parameters.get("trigger_delay"), - glitch_voltage = fault_parameters.get("glitch_voltage"), - glitch_width = fault_parameters.get("glitch_width"), - x_pos = fault_parameters.get("x_pos"), - y_pos = fault_parameters.get("y_pos") + response=response, + fi_result=fi_result, + trigger_delay=fault_parameters.get("trigger_delay"), + glitch_voltage=fault_parameters.get("glitch_voltage"), + glitch_width=fault_parameters.get("glitch_width"), + x_pos=fault_parameters.get("x_pos"), + y_pos=fault_parameters.get("y_pos"), ) fi_results.append(fi_result) remaining_iterations -= 1 pbar.update(1) print_fi_statistic(fi_results) - return device_cfg + return device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version def print_plot(project: FIProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to narrow down the fault injection parameters. @@ -207,8 +221,7 @@ def print_plot(project: FIProject, config: dict, file: Path) -> None: if config["fiproject"]["show_plot"]: plot.save_fi_plot_to_file(config, project, file) logger.info("Created plot.") - logger.info(f'Created plot: ' - f'{Path(str(file) + ".html").resolve()}') + logger.info(f"Created plot: " f'{Path(str(file) + ".html").resolve()}') def main(argv=None): @@ -231,22 +244,37 @@ def main(argv=None): ot_communication = OTFIIbex(target) # FI parameter sweep. - device_cfg = fi_parameter_sweep(cfg, target, fi_gear, project, ot_communication) + device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = ( + fi_parameter_sweep(cfg, target, fi_gear, project, ot_communication) + ) # Print plot. - print_plot(project.get_firesults(start=0, end=cfg["fiproject"]["num_plots"]), - cfg, args.project) + print_plot( + project.get_firesults(start=0, end=cfg["fiproject"]["num_plots"]), + cfg, + args.project, + ) # Save metadata. metadata = {} - metadata["device_cfg"] = device_cfg + metadata["device_id"] = device_id + metadata["sensors"] = sensors + metadata["alerts"] = alerts + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") # Store bitstream information. metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) # Store binary information. metadata["fw_bin_path"] = cfg["target"]["fw_bin"] metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) diff --git a/fault_injection/fi_otbn.py b/fault_injection/fi_otbn.py index c740e40c..b386a119 100755 --- a/fault_injection/fi_otbn.py +++ b/fault_injection/fi_otbn.py @@ -22,7 +22,7 @@ def setup(cfg: dict, project: Path): - """ Setup target, FI gear, and project. + """Setup target, FI gear, and project. Args: cfg: The configuration for the current experiment. @@ -34,23 +34,24 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + ) # Create target config & setup target. logger.info(f"Initializing target {cfg['target']['target_type']} ...") target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial"), - interface = cfg["target"].get("interface"), - husky_serial = cfg["fisetup"].get("husky_serial") + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], + pll_frequency=cfg["target"]["pll_frequency"], + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + interface=cfg["target"].get("interface"), + husky_serial = cfg["fisetup"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) target = Target(target_cfg) @@ -58,11 +59,12 @@ def setup(cfg: dict, project: Path): fi_gear = FIGear(cfg) # Init project. - project_cfg = ProjectConfig(type = cfg["fiproject"]["project_db"], - path = project, - overwrite = True, - fi_threshold = cfg["fiproject"].get("project_mem_threshold") - ) + project_cfg = ProjectConfig( + type=cfg["fiproject"]["project_db"], + path=project, + overwrite=True, + fi_threshold=cfg["fiproject"].get("project_mem_threshold"), + ) project = FIProject(project_cfg) project.create_project() @@ -70,7 +72,7 @@ def setup(cfg: dict, project: Path): def print_fi_statistic(fi_results: list) -> None: - """ Print FI Statistic. + """Print FI Statistic. Prints the number of FISuccess.SUCCESS, FISuccess.EXPRESPONSE, and FISuccess.NORESPONSE. @@ -82,15 +84,18 @@ def print_fi_statistic(fi_results: list) -> None: num_succ = round((fi_results.count(FISuccess.SUCCESS) / num_total) * 100, 2) num_exp = round((fi_results.count(FISuccess.EXPRESPONSE) / num_total) * 100, 2) num_no = round((fi_results.count(FISuccess.NORESPONSE) / num_total) * 100, 2) - logger.info(f"{num_total} faults, {fi_results.count(FISuccess.SUCCESS)}" - f"({num_succ}%) successful, {fi_results.count(FISuccess.EXPRESPONSE)}" - f"({num_exp}%) expected, and {fi_results.count(FISuccess.NORESPONSE)}" - f"({num_no}%) no response.") + logger.info( + f"{num_total} faults, {fi_results.count(FISuccess.SUCCESS)}" + f"({num_succ}%) successful, {fi_results.count(FISuccess.EXPRESPONSE)}" + f"({num_exp}%) expected, and {fi_results.count(FISuccess.NORESPONSE)}" + f"({num_no}%) no response." + ) -def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, - project: FIProject, ot_communication: OTFIOtbn) -> None: - """ Fault parameter sweep. +def fi_parameter_sweep( + cfg: dict, target: Target, fi_gear, project: FIProject, ot_communication: OTFIOtbn +) -> None: + """Fault parameter sweep. Sweep through the fault parameter space. @@ -101,13 +106,22 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, project: The project to store the results. ot_communication: The OpenTitan OTBN FI communication interface. Returns: - device_cfg: The ID and countermeasure configuration of the target device. + device_id: The ID of the target device. + sensors: The sensor info. + alerts: The alert info. + owner_page: The owner info page. + boot_log: The boot log. + boot_measurments: The boot measurements. + version: The testOS version. """ # Configure the OTBN FI code on the target. - device_cfg = ot_communication.init(cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = ( + ot_communication.init( + cfg["test"]["core_config"], + cfg["test"]["sensor_config"], + cfg["test"]["alert_config"], + ) + ) # Setup key manager if needed by test. ot_communication.init_keymgr(cfg["test"]["which_test"]) # Store results in array for a quick access. @@ -117,8 +131,9 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # Helper variable tracking whether we already transmitted the test config # if one exists. config_transmitted = False - with tqdm(total=remaining_iterations, desc="Injecting", ncols=80, - unit=" different faults") as pbar: + with tqdm( + total=remaining_iterations, desc="Injecting", ncols=80, unit=" different faults" + ) as pbar: while remaining_iterations > 0: # Get fault parameters (e.g., trigger delay, glitch voltage). fault_parameters = fi_gear.generate_fi_parameters() @@ -137,7 +152,7 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, ot_communication.write_payload(cfg["test"]["input"]) # Read response. - response = ot_communication.read_response() + response = target.read_response() response_compare = response # By default, assume that the fault was successful fi_result = FISuccess.SUCCESS @@ -147,14 +162,15 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # No UART response received. fi_result = FISuccess.NORESPONSE # Resetting OT as it most likely crashed. - ot_communication = target.reset_target(com_reset = True) + ot_communication = target.reset_target(com_reset=True) # Re-establish UART connection. ot_communication = OTFIOtbn(target) # Configure the OTBN FI code on the target. - ot_communication.init(cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + ot_communication.init( + cfg["test"]["core_config"], + cfg["test"]["sensor_config"], + cfg["test"]["alert_config"], + ) # Setup key manager if needed by test. ot_communication.init_keymgr(cfg["test"]["which_test"]) # Reset FIGear if necessary. @@ -168,7 +184,7 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, resp_json = json.loads(response_compare) if "data" in resp_json: del resp_json["data"] - response_compare = json.dumps(resp_json, separators=(',', ':')) + response_compare = json.dumps(resp_json, separators=(",", ":")) # Most but not all tests (e.g., tests returning random data) # expect a certain response. expected_response = cfg["test"]["expected_result"] @@ -181,12 +197,10 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, exp_json = json.loads(expected_response) if "alerts" in resp_json: del resp_json["alerts"] - response_compare = json.dumps(resp_json, - separators=(',', ':')) + response_compare = json.dumps(resp_json, separators=(",", ":")) if "alerts" in exp_json: del exp_json["alerts"] - expected_response = json.dumps(exp_json, - separators=(',', ':')) + expected_response = json.dumps(exp_json, separators=(",", ":")) # Check if result is expected result (FI failed), unexpected result # (FI successful), or no response (FI failed.) @@ -197,24 +211,24 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # Store result into FIProject. project.append_firesult( - response = response, - fi_result = fi_result, - trigger_delay = fault_parameters.get("trigger_delay"), - glitch_voltage = fault_parameters.get("glitch_voltage"), - glitch_width = fault_parameters.get("glitch_width"), - x_pos = fault_parameters.get("x_pos"), - y_pos = fault_parameters.get("y_pos") + response=response, + fi_result=fi_result, + trigger_delay=fault_parameters.get("trigger_delay"), + glitch_voltage=fault_parameters.get("glitch_voltage"), + glitch_width=fault_parameters.get("glitch_width"), + x_pos=fault_parameters.get("x_pos"), + y_pos=fault_parameters.get("y_pos"), ) fi_results.append(fi_result) remaining_iterations -= 1 pbar.update(1) print_fi_statistic(fi_results) - return device_cfg + return device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version def print_plot(project: FIProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to narrow down the fault injection parameters. @@ -226,8 +240,7 @@ def print_plot(project: FIProject, config: dict, file: Path) -> None: if config["fiproject"]["show_plot"]: plot.save_fi_plot_to_file(config, project, file) logger.info("Created plot.") - logger.info(f'Created plot: ' - f'{Path(str(file) + ".html").resolve()}') + logger.info(f"Created plot: " f'{Path(str(file) + ".html").resolve()}') def main(argv=None): @@ -250,22 +263,37 @@ def main(argv=None): ot_communication = OTFIOtbn(target) # FI parameter sweep. - device_cfg = fi_parameter_sweep(cfg, target, fi_gear, project, ot_communication) + device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = ( + fi_parameter_sweep(cfg, target, fi_gear, project, ot_communication) + ) # Print plot. - print_plot(project.get_firesults(start=0, end=cfg["fiproject"]["num_plots"]), - cfg, args.project) + print_plot( + project.get_firesults(start=0, end=cfg["fiproject"]["num_plots"]), + cfg, + args.project, + ) # Save metadata. metadata = {} - metadata["device_cfg"] = device_cfg + metadata["device_id"] = device_id + metadata["sensors"] = sensors + metadata["alerts"] = alerts + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") # Store bitstream information. metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) # Store binary information. metadata["fw_bin_path"] = cfg["target"]["fw_bin"] metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) diff --git a/fault_injection/fi_otp.py b/fault_injection/fi_otp.py index ddd6d16e..0e375dda 100755 --- a/fault_injection/fi_otp.py +++ b/fault_injection/fi_otp.py @@ -22,7 +22,7 @@ def setup(cfg: dict, project: Path): - """ Setup target, FI gear, and project. + """Setup target, FI gear, and project. Args: cfg: The configuration for the current experiment. @@ -34,21 +34,22 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + ) # Create target config & setup target. logger.info(f"Initializing target {cfg['target']['target_type']} ...") target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial") + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], + pll_frequency=cfg["target"]["pll_frequency"], + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) target = Target(target_cfg) @@ -56,11 +57,12 @@ def setup(cfg: dict, project: Path): fi_gear = FIGear(cfg) # Init project. - project_cfg = ProjectConfig(type = cfg["fiproject"]["project_db"], - path = project, - overwrite = True, - fi_threshold = cfg["fiproject"].get("project_mem_threshold") - ) + project_cfg = ProjectConfig( + type=cfg["fiproject"]["project_db"], + path=project, + overwrite=True, + fi_threshold=cfg["fiproject"].get("project_mem_threshold"), + ) project = FIProject(project_cfg) project.create_project() @@ -68,7 +70,7 @@ def setup(cfg: dict, project: Path): def print_fi_statistic(fi_results: list) -> None: - """ Print FI Statistic. + """Print FI Statistic. Prints the number of FISuccess.SUCCESS, FISuccess.EXPRESPONSE, and FISuccess.NORESPONSE. @@ -80,15 +82,18 @@ def print_fi_statistic(fi_results: list) -> None: num_succ = round((fi_results.count(FISuccess.SUCCESS) / num_total) * 100, 2) num_exp = round((fi_results.count(FISuccess.EXPRESPONSE) / num_total) * 100, 2) num_no = round((fi_results.count(FISuccess.NORESPONSE) / num_total) * 100, 2) - logger.info(f"{num_total} faults, {fi_results.count(FISuccess.SUCCESS)}" - f"({num_succ}%) successful, {fi_results.count(FISuccess.EXPRESPONSE)}" - f"({num_exp}%) expected, and {fi_results.count(FISuccess.NORESPONSE)}" - f"({num_no}%) no response.") + logger.info( + f"{num_total} faults, {fi_results.count(FISuccess.SUCCESS)}" + f"({num_succ}%) successful, {fi_results.count(FISuccess.EXPRESPONSE)}" + f"({num_exp}%) expected, and {fi_results.count(FISuccess.NORESPONSE)}" + f"({num_no}%) no response." + ) -def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, - project: FIProject, ot_communication: OTFIOtp) -> None: - """ Fault parameter sweep. +def fi_parameter_sweep( + cfg: dict, target: Target, fi_gear, project: FIProject, ot_communication: OTFIOtp +) -> None: + """Fault parameter sweep. Sweep through the fault parameter space. @@ -98,15 +103,30 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, fi_gear: The FI gear to use. project: The project to store the results. ot_communication: The OpenTitan Otp FI communication interface. + Returns: + device_id: The ID of the target device. + sensors: The sensor info. + alerts: The alert info. + owner_page: The owner info page. + boot_log: The boot log. + boot_measurments: The boot measurements. + version: The testOS version. """ # Configure the Otp FI code on the target. - ot_communication.init() + device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = ( + ot_communication.init( + cfg["test"]["core_config"], + cfg["test"]["sensor_config"], + cfg["test"]["alert_config"], + ) + ) # Store results in array for a quick access. fi_results = [] # Start the parameter sweep. remaining_iterations = fi_gear.get_num_fault_injections() - with tqdm(total=remaining_iterations, desc="Injecting", ncols=80, - unit=" different faults") as pbar: + with tqdm( + total=remaining_iterations, desc="Injecting", ncols=80, unit=" different faults" + ) as pbar: while remaining_iterations > 0: # Get fault parameters (e.g., trigger delay, glitch voltage). fault_parameters = fi_gear.generate_fi_parameters() @@ -118,7 +138,7 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, ot_communication.start_test(cfg) # Read response. - response = ot_communication.read_response() + response = target.read_response() response_compare = response expected_response = cfg["test"]["expected_result"] @@ -127,11 +147,15 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # No UART response received. fi_result = FISuccess.NORESPONSE # Resetting OT as it most likely crashed. - ot_communication = target.reset_target(com_reset = True) + ot_communication = target.reset_target(com_reset=True) # Re-establish UART connection. ot_communication = OTFIOtp(target) # Configure the Otp FI code on the target. - ot_communication.init() + ot_communication.init( + cfg["test"]["core_config"], + cfg["test"]["sensor_config"], + cfg["test"]["alert_config"], + ) # Reset FIGear if necessary. fi_gear.reset() else: @@ -144,49 +168,30 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, exp_json = json.loads(expected_response) if "alerts" in resp_json: del resp_json["alerts"] - response_compare = json.dumps(resp_json, - separators=(',', ':')) + response_compare = json.dumps(resp_json, separators=(",", ":")) if "alerts" in exp_json: del exp_json["alerts"] - expected_response = json.dumps(exp_json, - separators=(',', ':')) + expected_response = json.dumps(exp_json, separators=(",", ":")) resp_json = json.loads(response_compare) - print("\nUjson response from device:") - print(resp_json) - - match cfg["test"]["which_test"]: - case "otp_fi_vendor_test": - otp_mem_comp = resp_json["vendor_test_comp"] - otp_mem_fi = resp_json["vendor_test_fi"] - case "otp_fi_owner_sw_cfg": - otp_mem_comp = resp_json["owner_sw_cfg_comp"] - otp_mem_fi = resp_json["owner_sw_cfg_fi"] - case "otp_fi_hw_cfg": - otp_mem_comp = resp_json["hw_cfg_comp"] - otp_mem_fi = resp_json["hw_cfg_fi"] - case "otp_fi_life_cycle": - otp_mem_comp = resp_json["life_cycle_comp"] - otp_mem_fi = resp_json["life_cycle_fi"] - case _: - pass + exp_json = json.loads(expected_response) # Check if result is expected result (FI failed), unexpected result # (FI successful), or no response (FI failed.) fi_result = FISuccess.SUCCESS - if otp_mem_comp == otp_mem_fi: + if resp_json["data_faulty"] == exp_json["data_faulty"]: # Expected result received. No FI effect. fi_result = FISuccess.EXPRESPONSE # Store result into FIProject. project.append_firesult( - response = response, - fi_result = fi_result, - trigger_delay = fault_parameters.get("trigger_delay"), - glitch_voltage = fault_parameters.get("glitch_voltage"), - glitch_width = fault_parameters.get("glitch_width"), - x_pos = fault_parameters.get("x_pos"), - y_pos = fault_parameters.get("y_pos") + response=response, + fi_result=fi_result, + trigger_delay=fault_parameters.get("trigger_delay"), + glitch_voltage=fault_parameters.get("glitch_voltage"), + glitch_width=fault_parameters.get("glitch_width"), + x_pos=fault_parameters.get("x_pos"), + y_pos=fault_parameters.get("y_pos"), ) fi_results.append(fi_result) @@ -194,9 +199,11 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, pbar.update(1) print_fi_statistic(fi_results) + return device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version + def print_plot(project: FIProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to narrow down the fault injection parameters. @@ -208,8 +215,7 @@ def print_plot(project: FIProject, config: dict, file: Path) -> None: if config["fiproject"]["show_plot"]: plot.save_fi_plot_to_file(config, project, file) logger.info("Created plot.") - logger.info(f'Created plot: ' - f'{Path(str(file) + ".html").resolve()}') + logger.info(f"Created plot: " f'{Path(str(file) + ".html").resolve()}') def main(argv=None): @@ -232,21 +238,37 @@ def main(argv=None): ot_communication = OTFIOtp(target) # FI parameter sweep. - fi_parameter_sweep(cfg, target, fi_gear, project, ot_communication) + device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = ( + fi_parameter_sweep(cfg, target, fi_gear, project, ot_communication) + ) # Print plot. - print_plot(project.get_firesults(start=0, end=cfg["fiproject"]["num_plots"]), - cfg, args.project) + print_plot( + project.get_firesults(start=0, end=cfg["fiproject"]["num_plots"]), + cfg, + args.project, + ) # Save metadata. metadata = {} + metadata["device_id"] = device_id + metadata["sensors"] = sensors + metadata["alerts"] = alerts + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") # Store bitstream information. metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) # Store binary information. metadata["fw_bin_path"] = cfg["target"]["fw_bin"] metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) diff --git a/fault_injection/fi_rng.py b/fault_injection/fi_rng.py index 4e004388..d437185c 100755 --- a/fault_injection/fi_rng.py +++ b/fault_injection/fi_rng.py @@ -22,7 +22,7 @@ def setup(cfg: dict, project: Path): - """ Setup target, FI gear, and project. + """Setup target, FI gear, and project. Args: cfg: The configuration for the current experiment. @@ -34,23 +34,24 @@ def setup(cfg: dict, project: Path): # Calculate pll_frequency of the target. # target_freq = pll_frequency * target_clk_mult # target_clk_mult is a hardcoded constant in the FPGA bitstream. - cfg["target"]["pll_frequency"] = cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + cfg["target"]["pll_frequency"] = ( + cfg["target"]["target_freq"] / cfg["target"]["target_clk_mult"] + ) # Create target config & setup target. logger.info(f"Initializing target {cfg['target']['target_type']} ...") target_cfg = TargetConfig( - target_type = cfg["target"]["target_type"], - fw_bin = cfg["target"]["fw_bin"], - protocol = cfg["target"]["protocol"], - pll_frequency = cfg["target"]["pll_frequency"], - bitstream = cfg["target"].get("fpga_bitstream"), - force_program_bitstream = cfg["target"].get("force_program_bitstream"), - baudrate = cfg["target"].get("baudrate"), - port = cfg["target"].get("port"), - output_len = cfg["target"].get("output_len_bytes"), - usb_serial = cfg["target"].get("usb_serial"), - interface = cfg["target"].get("interface"), - husky_serial = cfg["fisetup"].get("husky_serial") + target_type=cfg["target"]["target_type"], + fw_bin=cfg["target"]["fw_bin"], + pll_frequency=cfg["target"]["pll_frequency"], + bitstream=cfg["target"].get("fpga_bitstream"), + force_program_bitstream=cfg["target"].get("force_program_bitstream"), + baudrate=cfg["target"].get("baudrate"), + port=cfg["target"].get("port"), + usb_serial=cfg["target"].get("usb_serial"), + interface=cfg["target"].get("interface"), + husky_serial = cfg["fisetup"].get("usb_serial"), + opentitantool=cfg["target"]["opentitantool"], ) target = Target(target_cfg) @@ -58,11 +59,12 @@ def setup(cfg: dict, project: Path): fi_gear = FIGear(cfg) # Init project. - project_cfg = ProjectConfig(type = cfg["fiproject"]["project_db"], - path = project, - overwrite = True, - fi_threshold = cfg["fiproject"].get("project_mem_threshold") - ) + project_cfg = ProjectConfig( + type=cfg["fiproject"]["project_db"], + path=project, + overwrite=True, + fi_threshold=cfg["fiproject"].get("project_mem_threshold"), + ) project = FIProject(project_cfg) project.create_project() @@ -70,7 +72,7 @@ def setup(cfg: dict, project: Path): def print_fi_statistic(fi_results: list) -> None: - """ Print FI Statistic. + """Print FI Statistic. Prints the number of FISuccess.SUCCESS, FISuccess.EXPRESPONSE, and FISuccess.NORESPONSE. @@ -82,15 +84,18 @@ def print_fi_statistic(fi_results: list) -> None: num_succ = round((fi_results.count(FISuccess.SUCCESS) / num_total) * 100, 2) num_exp = round((fi_results.count(FISuccess.EXPRESPONSE) / num_total) * 100, 2) num_no = round((fi_results.count(FISuccess.NORESPONSE) / num_total) * 100, 2) - logger.info(f"{num_total} faults, {fi_results.count(FISuccess.SUCCESS)}" - f"({num_succ}%) successful, {fi_results.count(FISuccess.EXPRESPONSE)}" - f"({num_exp}%) expected, and {fi_results.count(FISuccess.NORESPONSE)}" - f"({num_no}%) no response.") + logger.info( + f"{num_total} faults, {fi_results.count(FISuccess.SUCCESS)}" + f"({num_succ}%) successful, {fi_results.count(FISuccess.EXPRESPONSE)}" + f"({num_exp}%) expected, and {fi_results.count(FISuccess.NORESPONSE)}" + f"({num_no}%) no response." + ) -def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, - project: FIProject, ot_communication: OTFIRng) -> None: - """ Fault parameter sweep. +def fi_parameter_sweep( + cfg: dict, target: Target, fi_gear, project: FIProject, ot_communication: OTFIRng +) -> None: + """Fault parameter sweep. Sweep through the fault parameter space. @@ -101,19 +106,30 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, project: The project to store the results. ot_communication: The OpenTitan RNG FI communication interface. Returns: - device_cfg: The ID and countermeasure configuration of the target device. + device_id: The ID of the target device. + sensors: The sensor info. + alerts: The alert info. + owner_page: The owner info page. + boot_log: The boot log. + boot_measurments: The boot measurements. + version: The testOS version. """ # Configure the RNG FI code on the target. - device_cfg = ot_communication.init(cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = ( + ot_communication.init( + cfg["test"]["which_test"], + cfg["test"]["core_config"], + cfg["test"]["sensor_config"], + cfg["test"]["alert_config"], + ) + ) # Store results in array for a quick access. fi_results = [] # Start the parameter sweep. remaining_iterations = fi_gear.get_num_fault_injections() - with tqdm(total=remaining_iterations, desc="Injecting", ncols=80, - unit=" different faults") as pbar: + with tqdm( + total=remaining_iterations, desc="Injecting", ncols=80, unit=" different faults" + ) as pbar: while remaining_iterations > 0: # Get fault parameters (e.g., trigger delay, glitch voltage). fault_parameters = fi_gear.generate_fi_parameters() @@ -121,11 +137,16 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # Arm the FI gear. fi_gear.arm_trigger(fault_parameters) + # Get the input arguments. + args = {} + if cfg["test"]["which_test"] == "rng_csrng_bias": + args["trigger"] = cfg["test"]["trigger"] + # Start test on OpenTitan. - ot_communication.start_test(cfg) + ot_communication.start_test(cfg, **args) # Read response. - response = ot_communication.read_response(max_tries=30) + response = target.read_response() response_compare = response expected_response = cfg["test"]["expected_result"] @@ -135,14 +156,16 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # No UART response received. fi_result = FISuccess.NORESPONSE # Resetting OT as it most likely crashed. - ot_communication = target.reset_target(com_reset = True) + ot_communication = target.reset_target(com_reset=True) # Re-establish UART connection. ot_communication = OTFIRng(target) # Configure the RNG FI code on the target. - ot_communication.init(cfg["test"]["enable_icache"], - cfg["test"]["enable_dummy_instr"], - cfg["test"]["enable_jittery_clock"], - cfg["test"]["sram_readback_enable"]) + ot_communication.init( + cfg["test"]["which_test"], + cfg["test"]["core_config"], + cfg["test"]["sensor_config"], + cfg["test"]["alert_config"], + ) # Reset FIGear if necessary. fi_gear.reset() else: @@ -155,12 +178,10 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, exp_json = json.loads(expected_response) if "alerts" in resp_json: del resp_json["alerts"] - response_compare = json.dumps(resp_json, - separators=(',', ':')) + response_compare = json.dumps(resp_json, separators=(",", ":")) if "alerts" in exp_json: del exp_json["alerts"] - expected_response = json.dumps(exp_json, - separators=(',', ':')) + expected_response = json.dumps(exp_json, separators=(",", ":")) # Check if result is expected result (FI failed) or unexpected # result (FI successful). @@ -171,24 +192,24 @@ def fi_parameter_sweep(cfg: dict, target: Target, fi_gear, # Store result into FIProject. project.append_firesult( - response = response, - fi_result = fi_result, - trigger_delay = fault_parameters.get("trigger_delay"), - glitch_voltage = fault_parameters.get("glitch_voltage"), - glitch_width = fault_parameters.get("glitch_width"), - x_pos = fault_parameters.get("x_pos"), - y_pos = fault_parameters.get("y_pos") + response=response, + fi_result=fi_result, + trigger_delay=fault_parameters.get("trigger_delay"), + glitch_voltage=fault_parameters.get("glitch_voltage"), + glitch_width=fault_parameters.get("glitch_width"), + x_pos=fault_parameters.get("x_pos"), + y_pos=fault_parameters.get("y_pos"), ) fi_results.append(fi_result) remaining_iterations -= 1 pbar.update(1) print_fi_statistic(fi_results) - return device_cfg + return device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version def print_plot(project: FIProject, config: dict, file: Path) -> None: - """ Print plot of traces. + """Print plot of traces. Printing the plot helps to narrow down the fault injection parameters. @@ -200,8 +221,7 @@ def print_plot(project: FIProject, config: dict, file: Path) -> None: if config["fiproject"]["show_plot"]: plot.save_fi_plot_to_file(config, project, file) logger.info("Created plot.") - logger.info(f'Created plot: ' - f'{Path(str(file) + ".html").resolve()}') + logger.info(f"Created plot: " f'{Path(str(file) + ".html").resolve()}') def main(argv=None): @@ -224,22 +244,37 @@ def main(argv=None): ot_communication = OTFIRng(target) # FI parameter sweep. - device_cfg = fi_parameter_sweep(cfg, target, fi_gear, project, ot_communication) + device_id, sensors, alerts, owner_page, boot_log, boot_measurements, version = ( + fi_parameter_sweep(cfg, target, fi_gear, project, ot_communication) + ) # Print plot. - print_plot(project.get_firesults(start=0, end=cfg["fiproject"]["num_plots"]), - cfg, args.project) + print_plot( + project.get_firesults(start=0, end=cfg["fiproject"]["num_plots"]), + cfg, + args.project, + ) # Save metadata. metadata = {} - metadata["device_cfg"] = device_cfg + metadata["device_id"] = device_id + metadata["sensors"] = sensors + metadata["alerts"] = alerts + metadata["owner_page"] = owner_page + metadata["boot_log"] = boot_log + metadata["boot_measurements"] = boot_measurements + metadata["version"] = version metadata["datetime"] = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") # Store bitstream information. metadata["fpga_bitstream_path"] = cfg["target"].get("fpga_bitstream") if cfg["target"].get("fpga_bitstream") is not None: - metadata["fpga_bitstream_crc"] = helpers.file_crc(cfg["target"]["fpga_bitstream"]) + metadata["fpga_bitstream_crc"] = helpers.file_crc( + cfg["target"]["fpga_bitstream"] + ) if args.save_bitstream: - metadata["fpga_bitstream"] = helpers.get_binary_blob(cfg["target"]["fpga_bitstream"]) + metadata["fpga_bitstream"] = helpers.get_binary_blob( + cfg["target"]["fpga_bitstream"] + ) # Store binary information. metadata["fw_bin_path"] = cfg["target"]["fw_bin"] metadata["fw_bin_crc"] = helpers.file_crc(cfg["target"]["fw_bin"]) diff --git a/fault_injection/project_library/project.py b/fault_injection/project_library/project.py index c8eba165..aff2994c 100644 --- a/fault_injection/project_library/project.py +++ b/fault_injection/project_library/project.py @@ -20,9 +20,10 @@ class FISuccess(IntEnum): @dataclass class ProjectConfig: - """ Project configuration. + """Project configuration. Stores information about the project. """ + type: str path: Path overwrite: bool @@ -30,16 +31,17 @@ class ProjectConfig: class FIProject: - """ Project class. + """Project class. Used to manage a FI project. """ + def __init__(self, project_cfg: ProjectConfig) -> None: self.project_cfg = project_cfg self.project = None def create_project(self): - """ Create project. + """Create project. Create project using the provided path. """ @@ -47,51 +49,56 @@ def create_project(self): self.project = FILibrary( str(self.project_cfg.path), fi_threshold=self.project_cfg.fi_threshold, - overwrite=self.project_cfg.overwrite) + overwrite=self.project_cfg.overwrite, + ) else: raise RuntimeError("Only project_db='ot_fi_project' supported.") def open_project(self) -> None: - """ Open project. - """ + """Open project.""" if self.project_cfg.type == "ot_fi_project": self.project = FILibrary( str(self.project_cfg.path), fi_threshold=self.project_cfg.fi_threshold, - overwrite=self.project_cfg.overwrite) + overwrite=self.project_cfg.overwrite, + ) def close(self, save: bool) -> None: - """ Close project. - """ + """Close project.""" if self.project_cfg.type == "ot_fi_project": self.project.flush_to_disk() self.project = None def save(self) -> None: - """ Save project. - """ + """Save project.""" if self.project_cfg.type == "ot_fi_project": self.project.flush_to_disk() - def append_firesult(self, response: str, fi_result: int, trigger_delay: int, - glitch_voltage: Optional[float] = 0, - glitch_width: Optional[float] = 0, - x_pos: Optional[int] = 0, - y_pos: Optional[int] = 0) -> None: - """ Append FI result to storage in project. - """ + def append_firesult( + self, + response: str, + fi_result: int, + trigger_delay: int, + glitch_voltage: Optional[float] = 0, + glitch_width: Optional[float] = 0, + x_pos: Optional[int] = 0, + y_pos: Optional[int] = 0, + ) -> None: + """Append FI result to storage in project.""" if self.project_cfg.type == "ot_fi_project": - firesult = FIResult(response = response, - fi_result = int(fi_result), - trigger_delay = trigger_delay, - glitch_width = glitch_width, - glitch_voltage = glitch_voltage, - x_pos = x_pos, y_pos = y_pos) + firesult = FIResult( + response=response, + fi_result=int(fi_result), + trigger_delay=trigger_delay, + glitch_width=glitch_width, + glitch_voltage=glitch_voltage, + x_pos=x_pos, + y_pos=y_pos, + ) self.project.write_to_buffer(firesult) - def get_firesults(self, start: Optional[int] = None, - end: Optional[int] = None): - """ Get FI results from database and stored into RAM. + def get_firesults(self, start: Optional[int] = None, end: Optional[int] = None): + """Get FI results from database and stored into RAM. Fetch FI results from start to end from database storage into RAM. @@ -106,13 +113,11 @@ def get_firesults(self, start: Optional[int] = None, return self.project.get_firesults(start, end) def write_metadata(self, metadata: dict) -> None: - """ Write metadata to project. - """ + """Write metadata to project.""" if self.project_cfg.type == "ot_fi_project": self.project.write_metadata(metadata) def get_metadata(self) -> dict: - """ Get metadata from project. - """ + """Get metadata from project.""" if self.project_cfg.type == "ot_fi_project": return self.project.get_metadata() diff --git a/python-requirements.txt b/python-requirements.txt index b107873e..5d3e3fef 100644 --- a/python-requirements.txt +++ b/python-requirements.txt @@ -26,6 +26,7 @@ typer==0.9.0 wheel==0.41.3 # can be removed after switching to ray joblib==1.3.2 +gitpython==3.1.40 # Development version of ChipWhisperer toolchain with latest features and # bug fixes - Needs to be installed in editable mode. We fix the version @@ -37,9 +38,9 @@ joblib==1.3.2 # for improved stability and manually update if necessary. -e git+https://github.com/newaetech/ChipShover.git@f824426668b2d1f74367fdb7071058d27b17ded4#egg=chipshover&subdirectory=host-python -# Development version of ChipShouter toolchain with latest features and -# bug fixes - Needs to be installed in editable mode. We fix the version -# for improved stability and manually update if necessary. +# # Development version of ChipShouter toolchain with latest features and +# # bug fixes - Needs to be installed in editable mode. We fix the version +# # for improved stability and manually update if necessary. -e git+https://github.com/newaetech/ChipSHOUTER-python.git@9ba55f5b12c746fcb31d675b4784d5f339760965#egg=chipshouter # Linters diff --git a/target/chip.py b/target/chip.py index bc7d506f..975ab62e 100644 --- a/target/chip.py +++ b/target/chip.py @@ -3,74 +3,94 @@ # SPDX-License-Identifier: Apache-2.0 """OpenTitan chip utility functions.""" import time -from subprocess import PIPE, Popen +from subprocess import Popen from typing import Optional -class Chip(): +class Chip: """Class for the discrete chip. Initializes OpenTitan with the provided firmware & provides helper functions. """ - def __init__(self, firmware, opentitantool_path, - boot_delay: Optional[int] = 1, - usb_serial: Optional[str] = None, - interface: Optional[str] = "hyper310"): - self.firmware = firmware + + def __init__(self, opentitantool_path, interface: Optional[str] = "hyper310"): self.opentitantool = opentitantool_path - self.boot_delay = boot_delay - self.usb_serial = usb_serial self.interface = interface - self._initialize_chip() - def _initialize_chip(self): - """Initializes the chip.""" - # Flash the chip using the opentitantool with the provided firmware. - if self.usb_serial is not None and self.usb_serial != "": - flash_process = Popen([self.opentitantool, - "--usb-serial=" + str(self.usb_serial), - "--rcfile=", - "--interface=" + str(self.interface), - "--exec", "transport init", - "--exec", "bootstrap " + self.firmware, "no-op"], - stdout=PIPE, stderr=PIPE) + # Command to flash the target given the location of the opentitantool and the firmware + # For example, opentitantool = + # "/path/to/opentitan/bazel-bin/sw/host/opentitantool/opentitantool" + # Firmware is the pre-compiled and signed binary + def flash_target(self, firmware, boot_delay=4): + flash_process = Popen( + [ + self.opentitantool, + "--rcfile=", + "--interface=" + self.interface, + "--exec", + "transport init", + "--exec", + "bootstrap " + firmware, + "no-op", + ] + ) + flash_process.communicate() + rc = flash_process.returncode + if rc != 0: + raise RuntimeError("Error: Failed to flash chip.") + return 0 else: - flash_process = Popen([self.opentitantool, - "--rcfile=", - "--interface=" + str(self.interface), - "--exec", "transport init", - "--exec", "bootstrap " + self.firmware, "no-op"], - stdout=PIPE, stderr=PIPE) + # Wait until chip finished booting. + time.sleep(boot_delay) + print(f"Info: Chip flashed with {firmware}.") + return 1 + + # Command to flash the target given the location of the opentitantool and the firmware + # Firmware is the pre-compiled and signed binary + # This uses the rescue protocol in order to flash the binary + def flash_rescue_target(self, firmware, boot_delay=50): + flash_process = Popen( + [ + self.opentitantool, + "--rcfile=", + "--interface=" + self.interface, + "--exec", + "transport init", + "--exec", + "rescue firmware " + firmware, + "no-op", + ] + ) flash_process.communicate() rc = flash_process.returncode if rc != 0: - raise RuntimeError('Error: Failed to flash OpenTitan chip.') + raise RuntimeError("Error: Failed to flash OpenTitan chip.") else: # Wait until chip finished booting. - time.sleep(self.boot_delay) - print(f'Info: OpenTitan flashed with {self.firmware}.') + time.sleep(boot_delay) + print(f"Info: OpenTitan flashed with {firmware}.") - def reset_target(self, boot_delay: Optional[int] = 1): + # Command to reset the target given the location of the opentitantool + # For example, opentitantool = + # "/path/to/opentitan/bazel-bin/sw/host/opentitantool/opentitantool" + def reset_target(self, reset_delay=0.005): """Reset OpenTitan by triggering the reset pin using opentitantool.""" - if self.usb_serial is not None and self.usb_serial != "": - reset_process = Popen([self.opentitantool, - "--usb-serial=" + str(self.usb_serial), - "--interface=" + str(self.interface), - "--exec", "transport init", - "--exec", "gpio write RESET false", - "--exec", "gpio write RESET true", "no-op"], - stdout=PIPE, stderr=PIPE) - else: - reset_process = Popen([self.opentitantool, - "--interface=" + str(self.interface), - "--exec", "transport init", - "--exec", "gpio write RESET false", - "--exec", "gpio write RESET true", "no-op"], - stdout=PIPE, stderr=PIPE) + reset_process = Popen( + [ + self.opentitantool, + "--rcfile=", + "--interface=" + self.interface, + "--exec", + "transport init", + "--exec", + "gpio write RESET false", + "--exec", + "gpio write RESET true", + "no-op", + ] + ) reset_process.communicate() rc = reset_process.returncode if rc != 0: - raise RuntimeError('Error: Failed to reset OpenTitan chip.') + raise RuntimeError("Error: Failed to reset chip.") else: - print("Info: Resetting OpenTitan.") - # Wait until chip finished booting. - time.sleep(boot_delay) + time.sleep(reset_delay) diff --git a/target/communication/common_library.py b/target/communication/common_library.py new file mode 100644 index 00000000..bfb48a09 --- /dev/null +++ b/target/communication/common_library.py @@ -0,0 +1,311 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +default_core_config = { + "enable_icache": True, + "enable_dummy_instr": True, + "dummy_instr_count": 3, + "enable_jittery_clock": True, + "enable_sram_readback": True, + "enable_data_ind_timing": True, +} +default_sensor_config = { + "sensor_ctrl_enable": True, + "sensor_ctrl_en_fatal": [ + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + False, + ], +} +default_alert_config = { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + True, # "flash_ctrl_recov_err", + True, # "flash_ctrl_fatal_std_err", + True, # "flash_ctrl_fatal_err", + True, # "flash_ctrl_fatal_prim_flash_alert", + True, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, +} + +default_fpga_friendly_alert_config = { + "alert_classes": [ + 2, # "uart0_fatal_fault", + 2, # "uart1_fatal_fault", + 2, # "uart2_fatal_fault", + 2, # "uart3_fatal_fault", + 0, # "gpio_fatal_fault", + 0, # "spi_device_fatal_fault", + 2, # "i2c0_fatal_fault", + 2, # "i2c1_fatal_fault", + 2, # "i2c2_fatal_fault", + 2, # "pattgen_fatal_fault", + 0, # "rv_timer_fatal_fault", + 0, # "otp_ctrl_fatal_macro_error", + 0, # "otp_ctrl_fatal_check_error", + 0, # "otp_ctrl_fatal_bus_integ_error", + 0, # "otp_ctrl_fatal_prim_otp_alert", + 1, # "otp_ctrl_recov_prim_otp_alert", + 0, # "lc_ctrl_fatal_prog_error", + 0, # "lc_ctrl_fatal_state_error", + 0, # "lc_ctrl_fatal_bus_integ_error", + 2, # "spi_host0_fatal_fault", + 2, # "spi_host1_fatal_fault", + 2, # "usbdev_fatal_fault", + 0, # "pwrmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_fault", + 0, # "rstmgr_aon_fatal_cnsty_fault", + 1, # "clkmgr_aon_recov_fault", + 0, # "clkmgr_aon_fatal_fault", + 2, # "sysrst_ctrl_aon_fatal_fault", + 2, # "adc_ctrl_aon_fatal_fault", + 2, # "pwm_aon_fatal_fault", + 2, # "pinmux_aon_fatal_fault", + 0, # "aon_timer_aon_fatal_fault", + 1, # "sensor_ctrl_recov_alert", + 0, # "sensor_ctrl_fatal_alert", + 0, # "sram_ctrl_ret_aon_fatal_error", + 1, # "flash_ctrl_recov_err", + 0, # "flash_ctrl_fatal_std_err", + 0, # "flash_ctrl_fatal_err", + 0, # "flash_ctrl_fatal_prim_flash_alert", + 1, # "flash_ctrl_recov_prim_flash_alert", + 0, # "rv_dm_fatal_fault", + 0, # "rv_plic_fatal_fault", + 1, # "aes_recov_ctrl_update_err", + 0, # "aes_fatal_fault", + 0, # "hmac_fatal_fault", + 1, # "kmac_recov_operation_err", + 0, # "kmac_fatal_fault_err", + 0, # "otbn_fatal", + 1, # "otbn_recov", + 1, # "keymgr_recov_operation_err", + 0, # "keymgr_fatal_fault_err", + 1, # "csrng_recov_alert", + 0, # "csrng_fatal_alert", + 1, # "entropy_src_recov_alert", + 0, # "entropy_src_fatal_alert", + 1, # "edn0_recov_alert", + 0, # "edn0_fatal_alert", + 1, # "edn1_recov_alert", + 0, # "edn1_fatal_alert", + 0, # "sram_ctrl_main_fatal_error", + 0, # "rom_ctrl_fatal", + 0, # "rv_core_ibex_fatal_sw_err", + 1, # "rv_core_ibex_recov_sw_err", + 0, # "rv_core_ibex_fatal_hw_err", + 1, # "rv_core_ibex_recov_hw_err" + ], + "enable_alerts": [ + True, # "uart0_fatal_fault", + True, # "uart1_fatal_fault", + True, # "uart2_fatal_fault", + True, # "uart3_fatal_fault", + True, # "gpio_fatal_fault", + True, # "spi_device_fatal_fault", + True, # "i2c0_fatal_fault", + True, # "i2c1_fatal_fault", + True, # "i2c2_fatal_fault", + True, # "pattgen_fatal_fault", + True, # "rv_timer_fatal_fault", + True, # "otp_ctrl_fatal_macro_error", + True, # "otp_ctrl_fatal_check_error", + True, # "otp_ctrl_fatal_bus_integ_error", + True, # "otp_ctrl_fatal_prim_otp_alert", + True, # "otp_ctrl_recov_prim_otp_alert", + True, # "lc_ctrl_fatal_prog_error", + True, # "lc_ctrl_fatal_state_error", + True, # "lc_ctrl_fatal_bus_integ_error", + True, # "spi_host0_fatal_fault", + True, # "spi_host1_fatal_fault", + True, # "usbdev_fatal_fault", + True, # "pwrmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_fault", + True, # "rstmgr_aon_fatal_cnsty_fault", + True, # "clkmgr_aon_recov_fault", + True, # "clkmgr_aon_fatal_fault", + True, # "sysrst_ctrl_aon_fatal_fault", + True, # "adc_ctrl_aon_fatal_fault", + True, # "pwm_aon_fatal_fault", + True, # "pinmux_aon_fatal_fault", + True, # "aon_timer_aon_fatal_fault", + True, # "sensor_ctrl_recov_alert", + True, # "sensor_ctrl_fatal_alert", + True, # "sram_ctrl_ret_aon_fatal_error", + True, # "flash_ctrl_recov_err", + True, # "flash_ctrl_fatal_std_err", + True, # "flash_ctrl_fatal_err", + False, # "flash_ctrl_fatal_prim_flash_alert", + True, # "flash_ctrl_recov_prim_flash_alert", + True, # "rv_dm_fatal_fault", + True, # "rv_plic_fatal_fault", + True, # "aes_recov_ctrl_update_err", + True, # "aes_fatal_fault", + True, # "hmac_fatal_fault", + True, # "kmac_recov_operation_err", + True, # "kmac_fatal_fault_err", + True, # "otbn_fatal", + True, # "otbn_recov", + True, # "keymgr_recov_operation_err", + True, # "keymgr_fatal_fault_err", + True, # "csrng_recov_alert", + True, # "csrng_fatal_alert", + True, # "entropy_src_recov_alert", + True, # "entropy_src_fatal_alert", + True, # "edn0_recov_alert", + True, # "edn0_fatal_alert", + True, # "edn1_recov_alert", + True, # "edn1_fatal_alert", + True, # "sram_ctrl_main_fatal_error", + True, # "rom_ctrl_fatal", + True, # "rv_core_ibex_fatal_sw_err", + True, # "rv_core_ibex_recov_sw_err", + True, # "rv_core_ibex_fatal_hw_err", + True, # "rv_core_ibex_recov_hw_err" + ], + "enable_classes": [True, True, False, False], + "accumulation_thresholds": [2, 2, 2, 2], + "signals": [4294967295, 0, 2, 3], + "duration_cycles": [0, 7200, 48, 48], + "ping_timeout": 1200, +} diff --git a/target/communication/fi_alert_commands.py b/target/communication/fi_alert_commands.py new file mode 100644 index 00000000..6471612b --- /dev/null +++ b/target/communication/fi_alert_commands.py @@ -0,0 +1,89 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""Communication interface for OpenTitan Alert FI framework. + +Communication with OpenTitan happens over the uJSON command interface. +""" +import json +import time + +from target.communication import common_library + + +class OTFIAlert: + def __init__(self, target) -> None: + self.target = target + + def _ujson_alert_fi_cmd(self) -> None: + time.sleep(0.01) + self.target.write(json.dumps("AlertFi").encode("ascii")) + + def handle_alert_trigger(self, alert) -> None: + # AlertFi command. + self._ujson_alert_fi_cmd() + # Trigger command. + time.sleep(0.01) + self.target.write(json.dumps("Trigger").encode("ascii")) + alert_data = {"alert": alert} + self.target.write(json.dumps(alert_data).encode("ascii")) + + def handle_alert_sensor_ctrl_trigger(self) -> None: + # AlertFi command. + self._ujson_alert_fi_cmd() + # SensorCtrlTrigger command. + time.sleep(0.01) + self.target.write(json.dumps("SensorCtrlTrigger").encode("ascii")) + + def handle_alert_ibex_sw_fatal(self) -> None: + # AlertFi command. + self._ujson_alert_fi_cmd() + # IbexSwFatal command. + time.sleep(0.01) + self.target.write(json.dumps("IbexSwFatal").encode("ascii")) + + def init( + self, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + alert_config: dict = common_library.default_alert_config, + ) -> tuple: + """Initialize the ALERT FI code on the chip. + Args: + cfg: Config dict containing the selected test. + + Returns: + Device id + The owner info page + The boot log + The boot measurements + The testOS version + """ + + # AlertFi command. + self._ujson_alert_fi_cmd() + # Init command. + time.sleep(0.01) + self.target.write(json.dumps("Init").encode("ascii")) + + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + self.target.write(json.dumps(alert_config).encode("ascii")) + + device_id = self.target.read_response() + sensors = self.target.read_response() + alerts = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return ( + device_id, + sensors, + alerts, + owner_page, + boot_log, + boot_measurements, + version, + ) diff --git a/target/communication/fi_crypto_commands.py b/target/communication/fi_crypto_commands.py index 98f1b2f7..b5cc163c 100644 --- a/target/communication/fi_crypto_commands.py +++ b/target/communication/fi_crypto_commands.py @@ -7,7 +7,8 @@ """ import json import time -from typing import Optional + +from target.communication import common_library class OTFICrypto: @@ -15,112 +16,150 @@ def __init__(self, target) -> None: self.target = target def _ujson_crypto_cmd(self) -> None: - time.sleep(0.01) self.target.write(json.dumps("CryptoFi").encode("ascii")) time.sleep(0.01) - def init(self, enable_icache: bool, enable_dummy_instr: bool, - enable_jittery_clock: bool, enable_sram_readback: bool) -> list: - """ Initialize the Crypto FI code on the chip. - Args: - enable_icache: If true, enable the iCache. - enable_dummy_instr: If true, enable the dummy instructions. - enable_jittery_clock: If true, enable the jittery clock. - enable_sram_readback: If true, enable the SRAM readback feature. + def init( + self, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + alert_config: dict = common_library.default_alert_config, + ) -> tuple: + """Initialize the Crypto FI code on the chip. + Returns: - The device ID and countermeasure config of the device. + Device id + The owner info page + The boot log + The boot measurements + The testOS version """ + # CryptoFi command. self._ujson_crypto_cmd() # Init command. - time.sleep(0.01) self.target.write(json.dumps("Init").encode("ascii")) - # Configure device and countermeasures. - time.sleep(0.01) - data = {"enable_icache": enable_icache, "enable_dummy_instr": enable_dummy_instr, - "enable_jittery_clock": enable_jittery_clock, - "enable_sram_readback": enable_sram_readback} - self.target.write(json.dumps(data).encode("ascii")) - # Read back device ID and countermeasure configuration from device. - device_config = self.read_response(max_tries=30) - # Read flash owner page. - device_config += self.read_response(max_tries=30) - # Read boot log. - device_config += self.read_response(max_tries=30) - # Read boot measurements. - device_config += self.read_response(max_tries=30) - # Read pentest framework version. - device_config += self.read_response(max_tries=30) - return device_config + + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + self.target.write(json.dumps(alert_config).encode("ascii")) + + device_id = self.target.read_response() + sensors = self.target.read_response() + alerts = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return ( + device_id, + sensors, + alerts, + owner_page, + boot_log, + boot_measurements, + version, + ) def crypto_shadow_reg_access(self) -> None: - """ Starts the crypto.fi.shadow_reg_access test. - """ + """Starts the crypto.fi.shadow_reg_access test.""" # CryptoFi command. self._ujson_crypto_cmd() # ShadowRegAccess command. time.sleep(0.01) self.target.write(json.dumps("ShadowRegAccess").encode("ascii")) - def crypto_aes_key(self) -> None: - """ Starts the crypto.fi.aes_key test. - """ + def crypto_shadow_reg_read(self) -> None: + """Starts the crypto.fi.shadow_reg_read test.""" + # CryptoFi command. + self._ujson_crypto_cmd() + # ShadowRegRead command. + time.sleep(0.01) + self.target.write(json.dumps("ShadowRegRead").encode("ascii")) + + def crypto_aes_key(self, plaintext, key) -> None: + """Starts the crypto.fi.aes_key test.""" # CryptoFi command. self._ujson_crypto_cmd() # Aes command. time.sleep(0.01) self.target.write(json.dumps("Aes").encode("ascii")) + # Plaintext and key + input_data = {"plaintext": plaintext, "key": key} + self.target.write(json.dumps(input_data).encode("ascii")) # Mode payload. time.sleep(0.01) - mode = {"key_trigger": True, "plaintext_trigger": False, - "encrypt_trigger": False, "ciphertext_trigger": False} + mode = { + "key_trigger": True, + "plaintext_trigger": False, + "encrypt_trigger": False, + "ciphertext_trigger": False, + } self.target.write(json.dumps(mode).encode("ascii")) - def crypto_aes_plaintext(self) -> None: - """ Starts the crypto.fi.aes_plaintext test. - """ + def crypto_aes_plaintext(self, plaintext, key) -> None: + """Starts the crypto.fi.aes_plaintext test.""" # CryptoFi command. self._ujson_crypto_cmd() # Aes command. time.sleep(0.01) self.target.write(json.dumps("Aes").encode("ascii")) + # Plaintext and key + input_data = {"plaintext": plaintext, "key": key} + self.target.write(json.dumps(input_data).encode("ascii")) # Mode payload. time.sleep(0.01) - mode = {"key_trigger": False, "plaintext_trigger": True, - "encrypt_trigger": False, "ciphertext_trigger": False} + mode = { + "key_trigger": False, + "plaintext_trigger": True, + "encrypt_trigger": False, + "ciphertext_trigger": False, + } self.target.write(json.dumps(mode).encode("ascii")) - def crypto_aes_encrypt(self) -> None: - """ Starts the crypto.fi.aes_encrypt test. - """ + def crypto_aes_encrypt(self, plaintext, key) -> None: + """Starts the crypto.fi.aes_encrypt test.""" # CryptoFi command. self._ujson_crypto_cmd() # Aes command. time.sleep(0.01) self.target.write(json.dumps("Aes").encode("ascii")) + # Plaintext and key + input_data = {"plaintext": plaintext, "key": key} + self.target.write(json.dumps(input_data).encode("ascii")) # Mode payload. time.sleep(0.01) - mode = {"key_trigger": False, "plaintext_trigger": False, - "encrypt_trigger": True, "ciphertext_trigger": False} + mode = { + "key_trigger": False, + "plaintext_trigger": False, + "encrypt_trigger": True, + "ciphertext_trigger": False, + } self.target.write(json.dumps(mode).encode("ascii")) - def crypto_aes_ciphertext(self) -> None: - """ Starts the crypto.fi.aes_ciphertext test. - """ + def crypto_aes_ciphertext(self, plaintext, key) -> None: + """Starts the crypto.fi.aes_ciphertext test.""" # CryptoFi command. self._ujson_crypto_cmd() # Aes command. time.sleep(0.01) self.target.write(json.dumps("Aes").encode("ascii")) + # Plaintext and key + input_data = {"plaintext": plaintext, "key": key} + self.target.write(json.dumps(input_data).encode("ascii")) # Mode payload. time.sleep(0.01) - mode = {"key_trigger": False, "plaintext_trigger": False, - "encrypt_trigger": False, "ciphertext_trigger": True} + mode = { + "key_trigger": False, + "plaintext_trigger": False, + "encrypt_trigger": False, + "ciphertext_trigger": True, + } self.target.write(json.dumps(mode).encode("ascii")) def crypto_kmac_key(self) -> None: - """ Starts the crypto.fi.kmac_key test. - """ + """Starts the crypto.fi.kmac_key test.""" # CryptoFi command. self._ujson_crypto_cmd() # Kmac command. @@ -128,13 +167,16 @@ def crypto_kmac_key(self) -> None: self.target.write(json.dumps("Kmac").encode("ascii")) # Mode payload. time.sleep(0.01) - mode = {"key_trigger": True, "absorb_trigger": False, - "static_trigger": False, "squeeze_trigger": False} + mode = { + "key_trigger": True, + "absorb_trigger": False, + "static_trigger": False, + "squeeze_trigger": False, + } self.target.write(json.dumps(mode).encode("ascii")) def crypto_kmac_absorb(self) -> None: - """ Starts the crypto.fi.kmac_absorb test. - """ + """Starts the crypto.fi.kmac_absorb test.""" # CryptoFi command. self._ujson_crypto_cmd() # Kmac command. @@ -142,13 +184,16 @@ def crypto_kmac_absorb(self) -> None: self.target.write(json.dumps("Kmac").encode("ascii")) # Mode payload. time.sleep(0.01) - mode = {"key_trigger": False, "absorb_trigger": True, - "static_trigger": False, "squeeze_trigger": False} + mode = { + "key_trigger": False, + "absorb_trigger": True, + "static_trigger": False, + "squeeze_trigger": False, + } self.target.write(json.dumps(mode).encode("ascii")) def crypto_kmac_squeeze(self) -> None: - """ Starts the crypto.fi.kmac_squeeze test. - """ + """Starts the crypto.fi.kmac_squeeze test.""" # CryptoFi command. self._ujson_crypto_cmd() # Kmac command. @@ -156,13 +201,16 @@ def crypto_kmac_squeeze(self) -> None: self.target.write(json.dumps("Kmac").encode("ascii")) # Mode payload. time.sleep(0.01) - mode = {"key_trigger": False, "absorb_trigger": False, - "static_trigger": False, "squeeze_trigger": True} + mode = { + "key_trigger": False, + "absorb_trigger": False, + "static_trigger": False, + "squeeze_trigger": True, + } self.target.write(json.dumps(mode).encode("ascii")) def crypto_kmac_static(self) -> None: - """ Starts the crypto.fi.kmac_static test. - """ + """Starts the crypto.fi.kmac_static test.""" # CryptoFi command. self._ujson_crypto_cmd() # Kmac command. @@ -170,110 +218,101 @@ def crypto_kmac_static(self) -> None: self.target.write(json.dumps("Kmac").encode("ascii")) # Mode payload. time.sleep(0.01) - mode = {"key_trigger": False, "absorb_trigger": False, - "static_trigger": True, "squeeze_trigger": False} + mode = { + "key_trigger": False, + "absorb_trigger": False, + "static_trigger": True, + "squeeze_trigger": False, + } self.target.write(json.dumps(mode).encode("ascii")) - def crypto_sha256_start(self) -> None: - """ Starts the crypto.fi.sha256_start test with a hardcoded msg of 0. - """ + def crypto_kmac_state(self) -> None: + """Starts the crypto.fi.kmac_state test.""" # CryptoFi command. self._ujson_crypto_cmd() - # Sha256 command. + # KmacState command. time.sleep(0.01) - self.target.write(json.dumps("Sha256").encode("ascii")) - # Data payload. - time.sleep(0.01) - data = {"message": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} - self.target.write(json.dumps(data).encode("ascii")) - time.sleep(0.01) - # Trigger payload. - time.sleep(0.01) - mode = {"start_trigger": True, "msg_trigger": False, "process_trigger": False, - "finish_trigger": False} - self.target.write(json.dumps(mode).encode("ascii")) + self.target.write(json.dumps("KmacState").encode("ascii")) - def crypto_sha256_msg(self) -> None: - """ Starts the crypto.fi.sha256_msg test with a hardcoded msg of 0. - """ - # CryptoFi command. - self._ujson_crypto_cmd() - # Sha256 command. - time.sleep(0.01) - self.target.write(json.dumps("Sha256").encode("ascii")) - # Data payload. - time.sleep(0.01) - data = {"message": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} - self.target.write(json.dumps(data).encode("ascii")) - time.sleep(0.01) - # Trigger payload. - time.sleep(0.01) - mode = {"start_trigger": False, "msg_trigger": True, "process_trigger": False, - "finish_trigger": False} - self.target.write(json.dumps(mode).encode("ascii")) - - def crypto_sha256_process(self) -> None: - """ Starts the crypto.fi.sha256_process test with a hardcoded msg of 0. - """ - # CryptoFi command. - self._ujson_crypto_cmd() - # Sha256 command. - time.sleep(0.01) - self.target.write(json.dumps("Sha256").encode("ascii")) - # Data payload. - time.sleep(0.01) - data = {"message": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} - self.target.write(json.dumps(data).encode("ascii")) - time.sleep(0.01) - # Trigger payload. - time.sleep(0.01) - mode = {"start_trigger": False, "msg_trigger": False, "process_trigger": True, - "finish_trigger": False} - self.target.write(json.dumps(mode).encode("ascii")) - - def crypto_sha256_finish(self) -> None: - """ Starts the crypto.fi.sha256_finish test with a hardcoded msg of 0. - """ + def crypto_hmac( + self, + msg, + key, + trigger, + enable_hmac, + message_endianness_big, + digest_endianness_big, + key_endianness_big, + hash_mode, + ) -> None: # CryptoFi command. self._ujson_crypto_cmd() - # Sha256 command. + # Sha2 command. + self.target.write(json.dumps("Hmac").encode("ascii")) time.sleep(0.01) - self.target.write(json.dumps("Sha256").encode("ascii")) - # Data payload. - time.sleep(0.01) - data = {"message": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]} + data = {"message": msg, "key": key} self.target.write(json.dumps(data).encode("ascii")) time.sleep(0.01) - # Trigger payload. - time.sleep(0.01) - mode = {"start_trigger": False, "msg_trigger": False, "process_trigger": False, - "finish_trigger": True} + if trigger == 0: + mode = { + "start_trigger": True, + "msg_trigger": False, + "process_trigger": False, + "finish_trigger": False, + "enable_hmac": enable_hmac, + "message_endianness_big": message_endianness_big, + "digest_endianness_big": digest_endianness_big, + "key_endianness_big": key_endianness_big, + "hash_mode": hash_mode, + } + elif trigger == 1: + mode = { + "start_trigger": False, + "msg_trigger": True, + "process_trigger": False, + "finish_trigger": False, + "enable_hmac": enable_hmac, + "message_endianness_big": message_endianness_big, + "digest_endianness_big": digest_endianness_big, + "key_endianness_big": key_endianness_big, + "hash_mode": hash_mode, + } + elif trigger == 2: + mode = { + "start_trigger": False, + "msg_trigger": False, + "process_trigger": True, + "finish_trigger": False, + "enable_hmac": enable_hmac, + "message_endianness_big": message_endianness_big, + "digest_endianness_big": digest_endianness_big, + "key_endianness_big": key_endianness_big, + "hash_mode": hash_mode, + } + else: + mode = { + "start_trigger": False, + "msg_trigger": False, + "process_trigger": False, + "finish_trigger": True, + "enable_hmac": enable_hmac, + "message_endianness_big": message_endianness_big, + "digest_endianness_big": digest_endianness_big, + "key_endianness_big": key_endianness_big, + "hash_mode": hash_mode, + } self.target.write(json.dumps(mode).encode("ascii")) - def start_test(self, cfg: dict) -> None: - """ Start the selected test. + def start_test(self, cfg: dict, *args, **kwargs) -> None: + """Start the selected test. Call the function selected in the config file. Uses the getattr() construct to call the function. Args: cfg: Config dict containing the selected test. + *args: Variable length argument list to be passed to the test function. + **kwargs: Arbitrary keyword arguments to be passed to the test function. """ test_function = getattr(self, cfg["test"]["which_test"]) - test_function() - - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from Crypto FI framework. - Args: - max_tries: Maximum number of attempts to read from UART. - - Returns: - The JSON response of OpenTitan. - """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" + test_function(*args, **kwargs) diff --git a/target/communication/fi_ibex_commands.py b/target/communication/fi_ibex_commands.py index fed47998..47d4102e 100644 --- a/target/communication/fi_ibex_commands.py +++ b/target/communication/fi_ibex_commands.py @@ -7,7 +7,8 @@ """ import json import time -from typing import Optional + +from target.communication import common_library class OTFIIbex: @@ -19,26 +20,15 @@ def _ujson_ibex_fi_cmd(self) -> None: self.target.write(json.dumps("IbexFi").encode("ascii")) def ibex_char_unrolled_reg_op_loop(self) -> None: - """ Starts the ibex.char.unrolled_reg_op_loop test. - """ + """Starts the ibex.char.unrolled_reg_op_loop test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharUnrolledRegOpLoop command. time.sleep(0.01) self.target.write(json.dumps("CharUnrolledRegOpLoop").encode("ascii")) - def ibex_char_unrolled_reg_op_loop_chain(self) -> None: - """ Starts the ibex.char.unrolled_reg_op_loop_chain test. - """ - # IbexFi command. - self._ujson_ibex_fi_cmd() - # CharUnrolledRegOpLoopChain command. - time.sleep(0.01) - self.target.write(json.dumps("CharUnrolledRegOpLoopChain").encode("ascii")) - def ibex_char_unrolled_mem_op_loop(self) -> None: - """ Starts the ibex.char.unrolled_mem_op_loop test. - """ + """Starts the ibex.char.unrolled_mem_op_loop test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharUnrolledMemOpLoop command. @@ -46,53 +36,67 @@ def ibex_char_unrolled_mem_op_loop(self) -> None: self.target.write(json.dumps("CharUnrolledMemOpLoop").encode("ascii")) def ibex_char_reg_op_loop(self) -> None: - """ Starts the ibex.char.reg_op_loop test. - """ + """Starts the ibex.char.reg_op_loop test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharRegOpLoop command. time.sleep(0.01) self.target.write(json.dumps("CharRegOpLoop").encode("ascii")) + def ibex_char_unrolled_reg_op_loop_chain(self) -> None: + """Starts the ibex.char.reg_op_loop_chain test.""" + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharUnrolledRegOpLoopChain command. + time.sleep(0.01) + self.target.write(json.dumps("CharUnrolledRegOpLoopChain").encode("ascii")) + def ibex_char_mem_op_loop(self) -> None: - """ Starts the ibex.char.mem_op_loop test. - """ + """Starts the ibex.char.mem_op_loop test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharMemOpLoop command. time.sleep(0.01) self.target.write(json.dumps("CharMemOpLoop").encode("ascii")) - def ibex_char_flash_read(self) -> None: - """ Starts the ibex.char.flash_read test. - """ + def ibex_char_flash_read(self, flash_region=3) -> None: + """Starts the ibex.char.flash_read test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharFlashRead command. time.sleep(0.01) self.target.write(json.dumps("CharFlashRead").encode("ascii")) + parameters = {"flash_region": flash_region} + self.target.write(json.dumps(parameters).encode("ascii")) - def ibex_char_flash_write(self) -> None: - """ Starts the ibex.char.flash_write test. - """ + def ibex_char_flash_write(self, flash_region=3) -> None: + """Starts the ibex.char.flash_write test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharFlashWrite command. time.sleep(0.01) self.target.write(json.dumps("CharFlashWrite").encode("ascii")) + parameters = {"flash_region": flash_region} + self.target.write(json.dumps(parameters).encode("ascii")) def ibex_char_sram_read(self) -> None: - """ Starts the ibex.char.sram_read test. - """ + """Starts the ibex.char.sram_read test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharSramRead command. time.sleep(0.01) self.target.write(json.dumps("CharSramRead").encode("ascii")) + def ibex_char_sram_read_ret(self) -> None: + """Starts the ibex.char.sram_read_ret test.""" + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharSramReadRet command. + time.sleep(0.01) + self.target.write(json.dumps("CharSramReadRet").encode("ascii")) + def ibex_char_sram_write_static_unrolled(self) -> None: - """ Starts the ibex.char.sram_write_static_unrolled test. - """ + """Starts the ibex.char.sram_write_static_unrolled test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharSramWriteStaticUnrolled command. @@ -100,17 +104,23 @@ def ibex_char_sram_write_static_unrolled(self) -> None: self.target.write(json.dumps("CharSramWriteStaticUnrolled").encode("ascii")) def ibex_char_sram_write_read(self) -> None: - """ Starts the ibex.char.sram_write_read test. - """ + """Starts the ibex.char.sram_write_read test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharSramWriteRead command. time.sleep(0.01) self.target.write(json.dumps("CharSramWriteRead").encode("ascii")) + def ibex_char_sram_write_read_alt(self) -> None: + """Starts the ibex.char.sram_write_read test.""" + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharSramWriteRead command. + time.sleep(0.01) + self.target.write(json.dumps("CharSramWriteReadAlt").encode("ascii")) + def ibex_char_sram_write(self) -> None: - """ Starts the ibex.char.sram_write test. - """ + """Starts the ibex.char.sram_write test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharSramWrite command. @@ -118,17 +128,71 @@ def ibex_char_sram_write(self) -> None: self.target.write(json.dumps("CharSramWrite").encode("ascii")) def ibex_char_sram_static(self) -> None: - """ Starts the ibex.char.sram_static test. - """ + """Starts the ibex.char.sram_static test.""" # IbexFi command. self._ujson_ibex_fi_cmd() - # CharSramWrite command. + # CharSramStatic command. time.sleep(0.01) self.target.write(json.dumps("CharSramStatic").encode("ascii")) + def ibex_char_single_beq(self) -> None: + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharSingleBeq command. + time.sleep(0.01) + self.target.write(json.dumps("CharSingleBeq").encode("ascii")) + + def ibex_char_addi_single_beq(self) -> None: + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharAddiSingleBeq command. + time.sleep(0.01) + self.target.write(json.dumps("CharAddiSingleBeq").encode("ascii")) + + def ibex_char_addi_single_beq_neg(self) -> None: + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharAddiSingleBeqNeg command. + time.sleep(0.01) + self.target.write(json.dumps("CharAddiSingleBeqNeg").encode("ascii")) + + def ibex_char_addi_single_beq_cm(self) -> None: + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharAddiSingleBeqCm command. + time.sleep(0.01) + self.target.write(json.dumps("CharAddiSingleBeqCm").encode("ascii")) + + def ibex_char_addi_single_beq_cm2(self) -> None: + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharAddiSingleBeqCm2 command. + time.sleep(0.01) + self.target.write(json.dumps("CharAddiSingleBeqCm2").encode("ascii")) + + def ibex_char_addi_single_bne(self) -> None: + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharAddiSingleBne command. + time.sleep(0.01) + self.target.write(json.dumps("CharAddiSingleBne").encode("ascii")) + + def ibex_char_single_bne(self) -> None: + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharSingleBne command. + time.sleep(0.01) + self.target.write(json.dumps("CharSingleBne").encode("ascii")) + + def ibex_char_addi_single_bne_neg(self) -> None: + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharAddiSingleBneNeg command. + time.sleep(0.01) + self.target.write(json.dumps("CharAddiSingleBneNeg").encode("ascii")) + def ibex_char_conditional_branch_beq(self) -> None: - """ Starts the ibex.char.conditional_branch_beq test. - """ + """Starts the ibex.char.conditional_branch_beq test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharCondBranchBeq command. @@ -136,8 +200,7 @@ def ibex_char_conditional_branch_beq(self) -> None: self.target.write(json.dumps("CharCondBranchBeq").encode("ascii")) def ibex_char_conditional_branch_bne(self) -> None: - """ Starts the ibex.char.conditional_branch_bne test. - """ + """Starts the ibex.char.conditional_branch_bne test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharCondBranchBne command. @@ -145,8 +208,7 @@ def ibex_char_conditional_branch_bne(self) -> None: self.target.write(json.dumps("CharCondBranchBne").encode("ascii")) def ibex_char_conditional_branch_bge(self) -> None: - """ Starts the ibex.char.conditional_branch_bge test. - """ + """Starts the ibex.char.conditional_branch_bge test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharCondBranchBge command. @@ -154,8 +216,7 @@ def ibex_char_conditional_branch_bge(self) -> None: self.target.write(json.dumps("CharCondBranchBge").encode("ascii")) def ibex_char_conditional_branch_bgeu(self) -> None: - """ Starts the ibex.char.conditional_branch_bgeu test. - """ + """Starts the ibex.char.conditional_branch_bgeu test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharCondBranchBgeu command. @@ -163,8 +224,7 @@ def ibex_char_conditional_branch_bgeu(self) -> None: self.target.write(json.dumps("CharCondBranchBgeu").encode("ascii")) def ibex_char_conditional_branch_blt(self) -> None: - """ Starts the ibex.char.conditional_branch_blt test. - """ + """Starts the ibex.char.conditional_branch_blt test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharCondBranchBglt command. @@ -172,17 +232,15 @@ def ibex_char_conditional_branch_blt(self) -> None: self.target.write(json.dumps("CharCondBranchBlt").encode("ascii")) def ibex_char_conditional_branch_bltu(self) -> None: - """ Starts the ibex.char.conditional_branch_bltu test. - """ + """Starts the ibex.char.conditional_branch_bltu test.""" # IbexFi command. self._ujson_ibex_fi_cmd() - # CharCondBranchBltu command. + # CharCondBranchBgltu command. time.sleep(0.01) self.target.write(json.dumps("CharCondBranchBltu").encode("ascii")) def ibex_char_unconditional_branch(self) -> None: - """ Starts the ibex.char.unconditional_branch test. - """ + """Starts the ibex.char.unconditional_branch test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharUncondBranch command. @@ -190,17 +248,25 @@ def ibex_char_unconditional_branch(self) -> None: self.target.write(json.dumps("CharUncondBranch").encode("ascii")) def ibex_char_unconditional_branch_nop(self) -> None: - """ Starts the ibex.char.unconditional_branch_nop test. - """ + """Starts the ibex.char.unconditional_branch_nop test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharUncondBranchNop command. time.sleep(0.01) self.target.write(json.dumps("CharUncondBranchNop").encode("ascii")) + def ibex_char_hardened_check_eq_complement_branch(self) -> None: + """Starts the ibex.char.hardened_check_eq_complement_branch test.""" + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharHardenedCheckComplementBranch command. + time.sleep(0.01) + self.target.write( + json.dumps("CharHardenedCheckComplementBranch").encode("ascii") + ) + def ibex_char_register_file(self) -> None: - """ Starts the ibex.char.register_file test. - """ + """Starts the ibex.char.register_file test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharRegisterFile command. @@ -208,50 +274,61 @@ def ibex_char_register_file(self) -> None: self.target.write(json.dumps("CharRegisterFile").encode("ascii")) def ibex_char_register_file_read(self) -> None: - """ Starts the ibex.char.register_file_read test. - """ + """Starts the ibex.char.register_file_read test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharRegisterFileRead command. time.sleep(0.01) self.target.write(json.dumps("CharRegisterFileRead").encode("ascii")) - def init(self, enable_icache: bool, enable_dummy_instr: bool, - enable_jittery_clock: bool, enable_sram_readback: bool) -> list: - """ Initialize the Ibex FI code on the chip. - Args: - enable_icache: If true, enable the iCache. - enable_dummy_instr: If true, enable the dummy instructions. - enable_jittery_clock: If true, enable the jittery clock. - enable_sram_readback: If true, enable the SRAM readback feature. + def init( + self, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + alert_config: dict = common_library.default_alert_config, + ) -> tuple: + """Initialize the Ibex FI code on the chip. + Returns: - The device ID and countermeasure config of the device. + Device id + The sensor control config + The alert config + The owner page + The boot log + The boot measurements + The testOS version """ + # IbexFi command. self._ujson_ibex_fi_cmd() - # InitTrigger command. + # Init command. time.sleep(0.01) self.target.write(json.dumps("Init").encode("ascii")) - # Configure device and countermeasures. - time.sleep(0.01) - data = {"enable_icache": enable_icache, "enable_dummy_instr": enable_dummy_instr, - "enable_jittery_clock": enable_jittery_clock, - "enable_sram_readback": enable_sram_readback} - self.target.write(json.dumps(data).encode("ascii")) - # Read back device ID and countermeasure configuration from device. - device_config = self.read_response(max_tries=30) - # Read flash owner page. - device_config += self.read_response(max_tries=30) - # Read boot log. - device_config += self.read_response(max_tries=30) - # Read boot measurements. - device_config += self.read_response(max_tries=30) - # Read pentest framework version. - device_config += self.read_response(max_tries=30) - return device_config + + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + self.target.write(json.dumps(alert_config).encode("ascii")) + + device_id = self.target.read_response() + sensors = self.target.read_response() + alerts = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return ( + device_id, + sensors, + alerts, + owner_page, + boot_log, + boot_measurements, + version, + ) def start_test(self, cfg: dict) -> None: - """ Start the selected test. + """Start the selected test. Call the function selected in the config file. Uses the getattr() construct to call the function. @@ -263,8 +340,7 @@ def start_test(self, cfg: dict) -> None: test_function() def ibex_char_csr_write(self) -> None: - """ Starts the ibex.fi.char.csr_write test. - """ + """Starts the ibex.fi.char.csr_write test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharCsrWrite command. @@ -272,26 +348,38 @@ def ibex_char_csr_write(self) -> None: self.target.write(json.dumps("CharCsrWrite").encode("ascii")) def ibex_char_csr_read(self) -> None: - """ Starts the ibex.fi.char.csr_read test. - """ + """Starts the ibex.fi.char.csr_read test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharCsrRead command. time.sleep(0.01) self.target.write(json.dumps("CharCsrRead").encode("ascii")) - def ibex_address_translation_config(self) -> None: - """ Starts the ibex.fi.address_translation_config test. + def ibex_char_csr_combi(self, trigger, ref_values) -> None: + """Starts the ibex.fi.char.csr_combi test. + + Args: + trigger: Which triggers to raise. + ref_values: The values to be written in the CSRs. """ # IbexFi command. self._ujson_ibex_fi_cmd() + # CharCsrCombi command. + time.sleep(0.01) + self.target.write(json.dumps("CharCsrCombi").encode("ascii")) + data = {"trigger": trigger, "ref_values": ref_values} + self.target.write(json.dumps(data).encode("ascii")) + + def ibex_address_translation_config(self) -> None: + """Starts the ibex.fi.address_translation_config test.""" + # IbexFi command. + self._ujson_ibex_fi_cmd() # AddressTranslationCfg command. time.sleep(0.01) self.target.write(json.dumps("AddressTranslationCfg").encode("ascii")) def ibex_address_translation(self) -> None: - """ Starts the ibex.fi.address_translation test. - """ + """Starts the ibex.fi.address_translation test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # AddressTranslation command. @@ -299,8 +387,7 @@ def ibex_address_translation(self) -> None: self.target.write(json.dumps("AddressTranslation").encode("ascii")) def ibex_char_hardened_check_eq_unimp(self) -> None: - """ Starts the ibex.fi.char.hardened_check_eq_unimp test. - """ + """Starts the ibex.fi.char.hardened_check_eq_unimp test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharHardenedCheckUnimp command. @@ -308,8 +395,7 @@ def ibex_char_hardened_check_eq_unimp(self) -> None: self.target.write(json.dumps("CharHardenedCheckUnimp").encode("ascii")) def ibex_char_hardened_check_eq_2_unimps(self) -> None: - """ Starts the ibex.fi.char.hardened_check_eq_2_unimps test. - """ + """Starts the ibex.fi.char.hardened_check_eq_2_unimps test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharHardenedCheck2Unimps command. @@ -317,8 +403,7 @@ def ibex_char_hardened_check_eq_2_unimps(self) -> None: self.target.write(json.dumps("CharHardenedCheck2Unimps").encode("ascii")) def ibex_char_hardened_check_eq_3_unimps(self) -> None: - """ Starts the ibex.fi.char.hardened_check_eq_3_unimps test. - """ + """Starts the ibex.fi.char.hardened_check_eq_3_unimps test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharHardenedCheck3Unimps command. @@ -326,8 +411,7 @@ def ibex_char_hardened_check_eq_3_unimps(self) -> None: self.target.write(json.dumps("CharHardenedCheck3Unimps").encode("ascii")) def ibex_char_hardened_check_eq_4_unimps(self) -> None: - """ Starts the ibex.fi.char.hardened_check_eq_4_unimps test. - """ + """Starts the ibex.fi.char.hardened_check_eq_4_unimps test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharHardenedCheck4Unimps command. @@ -335,35 +419,40 @@ def ibex_char_hardened_check_eq_4_unimps(self) -> None: self.target.write(json.dumps("CharHardenedCheck4Unimps").encode("ascii")) def ibex_char_hardened_check_eq_5_unimps(self) -> None: - """ Starts the ibex.fi.char.hardened_check_eq_5_unimps test. - """ + """Starts the ibex.fi.char.hardened_check_eq_5_unimps test.""" # IbexFi command. self._ujson_ibex_fi_cmd() # CharHardenedCheck5Unimps command. time.sleep(0.01) self.target.write(json.dumps("CharHardenedCheck5Unimps").encode("ascii")) - def ibex_char_hardened_check_eq_complement_branch(self) -> None: - """ Starts the ibex.fi.char.hardened_check_eq_complement_branch test. - """ + def ibex_char_combi(self) -> None: + """Starts the ibex.fi.char.combi test.""" # IbexFi command. self._ujson_ibex_fi_cmd() - # CharHardenedCheckComplementBranch command. + # CharCombi command. time.sleep(0.01) - self.target.write(json.dumps("CharHardenedCheckComplementBranch").encode("ascii")) + self.target.write(json.dumps("CharCombi").encode("ascii")) - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from Ibex FI framework. - Args: - max_tries: Maximum number of attempts to read from UART. + def ibex_char_otp_data_read(self) -> None: + """Starts the ibex.fi.otp.data_read test.""" + # IbexFi command. + self._ujson_ibex_fi_cmd() + # OtpDataRead command. + time.sleep(0.01) + self.target.write(json.dumps("OtpDataRead").encode("ascii")) - Returns: - The JSON response of OpenTitan. - """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" + def ibex_char_otp_read_lock(self) -> None: + """Starts the ibex.fi.otp.read_lock test.""" + # IbexFi command. + self._ujson_ibex_fi_cmd() + # OtpReadLock command. + time.sleep(0.01) + self.target.write(json.dumps("OtpReadLock").encode("ascii")) + + def ibex_characterise(self) -> None: + # IbexFi command. + self._ujson_ibex_fi_cmd() + # CharHardenedCheck3Unimps command. + time.sleep(0.01) + self.target.write(json.dumps("Characterisation").encode("ascii")) diff --git a/target/communication/fi_otbn_commands.py b/target/communication/fi_otbn_commands.py index e46d7639..3abd4311 100644 --- a/target/communication/fi_otbn_commands.py +++ b/target/communication/fi_otbn_commands.py @@ -7,7 +7,8 @@ """ import json import time -from typing import Optional + +from target.communication import common_library class OTFIOtbn: @@ -19,8 +20,7 @@ def _ujson_otbn_fi_cmd(self) -> None: self.target.write(json.dumps("OtbnFi").encode("ascii")) def otbn_char_dmem_access(self) -> None: - """ Starts the otbn.fi.char.dmem.access test. - """ + """Starts the otbn.fi.char.dmem.access test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharDmemAccess command. @@ -28,8 +28,7 @@ def otbn_char_dmem_access(self) -> None: self.target.write(json.dumps("CharDmemAccess").encode("ascii")) def otbn_char_dmem_write(self) -> None: - """ Starts the otbn.fi.char.dmem.write test. - """ + """Starts the otbn.fi.char.dmem.write test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharDmemWrite command. @@ -37,8 +36,7 @@ def otbn_char_dmem_write(self) -> None: self.target.write(json.dumps("CharDmemWrite").encode("ascii")) def otbn_char_rf(self) -> None: - """ Starts the otbn.fi.char.rf test. - """ + """Starts the otbn.fi.char.rf test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharRF command. @@ -46,8 +44,7 @@ def otbn_char_rf(self) -> None: self.target.write(json.dumps("CharRF").encode("ascii")) def otbn_char_beq(self) -> None: - """ Starts the otbn.fi.char.beq test. - """ + """Starts the otbn.fi.char.beq test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharBeq command. @@ -55,44 +52,59 @@ def otbn_char_beq(self) -> None: self.target.write(json.dumps("CharBeq").encode("ascii")) def otbn_char_jal(self) -> None: - """ Starts the otbn.fi.char.jal test. - """ + """Starts the otbn.fi.char.jal test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharJal command. time.sleep(0.01) self.target.write(json.dumps("CharJal").encode("ascii")) - def otbn_char_mem(self) -> None: - """ Starts the otbn.fi.char.mem test. - """ + def otbn_char_mem(self, byte_offset, num_words, imem, dmem, first_call) -> None: + """Starts the otbn.fi.char.mem test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharMem command. time.sleep(0.01) self.target.write(json.dumps("CharMem").encode("ascii")) + if first_call: + parameters = { + "byte_offset": byte_offset, + "num_words": num_words, + "imem": imem, + "dmem": dmem, + } + self.target.write(json.dumps(parameters).encode("ascii")) - def otbn_char_bn_sel(self) -> None: - """ Starts the otbn.fi.char.bn.sel test. - """ + def otbn_char_bn_sel(self, data) -> None: + """Starts the otbn.fi.char.bn.sel test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharBnSel command. time.sleep(0.01) self.target.write(json.dumps("CharBnSel").encode("ascii")) + parameters = {"big_num": data} + self.target.write(json.dumps(parameters).encode("ascii")) - def otbn_char_bn_rshi(self) -> None: - """ Starts the otbn.fi.char.bn.rshi test. - """ + def otbn_char_bne(self) -> None: + """Starts the otbn.fi.char.bne test.""" + # OtbnFi command. + self._ujson_otbn_fi_cmd() + # CharBne command. + time.sleep(0.01) + self.target.write(json.dumps("CharBne").encode("ascii")) + + def otbn_char_bn_rshi(self, data) -> None: + """Starts the otbn.fi.char.bn.rshi test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharBnRshi command. time.sleep(0.01) self.target.write(json.dumps("CharBnRshi").encode("ascii")) + parameters = {"big_num": data} + self.target.write(json.dumps(parameters).encode("ascii")) def otbn_char_bn_wsrr(self) -> None: - """ Starts the otbn.fi.char.bn.wsrr test. - """ + """Starts the otbn.fi.char.bn.wsrr test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharBnWsrr command. @@ -100,8 +112,7 @@ def otbn_char_bn_wsrr(self) -> None: self.target.write(json.dumps("CharBnWsrr").encode("ascii")) def otbn_char_lw(self) -> None: - """ Starts the otbn.fi.char.lw test. - """ + """Starts the otbn.fi.char.lw test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharLw command. @@ -109,8 +120,7 @@ def otbn_char_lw(self) -> None: self.target.write(json.dumps("CharLw").encode("ascii")) def otbn_char_unrolled_reg_op_loop(self) -> None: - """ Starts the otbn.fi.char.unrolled.reg.op.loop test. - """ + """Starts the otbn.fi.char.unrolled.reg.op.loop test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharUnrolledRegOpLoop command. @@ -118,8 +128,7 @@ def otbn_char_unrolled_reg_op_loop(self) -> None: self.target.write(json.dumps("CharUnrolledRegOpLoop").encode("ascii")) def otbn_char_unrolled_dmem_op_loop(self) -> None: - """ Starts the otbn.fi.char.unrolled.dmem.op.loop test. - """ + """Starts the otbn.fi.char.unrolled.dmem.op.loop test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharUnrolledDmemOpLoop command. @@ -127,8 +136,7 @@ def otbn_char_unrolled_dmem_op_loop(self) -> None: self.target.write(json.dumps("CharUnrolledDmemOpLoop").encode("ascii")) def otbn_char_hardware_reg_op_loop(self) -> None: - """ Starts the otbn.fi.char.hardware.reg.op.loop test. - """ + """Starts the otbn.fi.char.hardware.reg.op.loop test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharHardwareRegOpLoop command. @@ -136,8 +144,7 @@ def otbn_char_hardware_reg_op_loop(self) -> None: self.target.write(json.dumps("CharHardwareRegOpLoop").encode("ascii")) def otbn_char_hardware_dmem_op_loop(self) -> None: - """ Starts the otbn.fi.char.hardware.dmem.op.loop test. - """ + """Starts the otbn.fi.char.hardware.dmem.op.loop test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # CharMemOpLoop command. @@ -145,8 +152,7 @@ def otbn_char_hardware_dmem_op_loop(self) -> None: self.target.write(json.dumps("CharHardwareDmemOpLoop").encode("ascii")) def otbn_key_sideload(self) -> None: - """ Starts the otbn.fi.key_sideload test. - """ + """Starts the otbn.fi.key_sideload test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # KeySideload command. @@ -154,25 +160,25 @@ def otbn_key_sideload(self) -> None: self.target.write(json.dumps("KeySideload").encode("ascii")) def otbn_load_integrity(self) -> None: - """ Starts the otbn.fi.load_integrity test. - """ + """Starts the otbn.fi.load_integrity test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # LoadIntegrity command. time.sleep(0.01) self.target.write(json.dumps("LoadIntegrity").encode("ascii")) - def otbn_pc(self) -> None: - """ Starts the otbn.pc test. - """ + def otbn_pc(self, pc) -> None: + """Starts the otbn.pc test.""" # OtbnFi command. self._ujson_otbn_fi_cmd() # PC command. time.sleep(0.01) self.target.write(json.dumps("PC").encode("ascii")) + parameters = {"pc": pc} + self.target.write(json.dumps(parameters).encode("ascii")) def init_keymgr(self, test: str) -> None: - """ Initialize the key manager on the chip. + """Initialize the key manager on the chip. Args: test: Name of the test. Used to determine if key manager init is needed. @@ -185,42 +191,53 @@ def init_keymgr(self, test: str) -> None: self.target.write(json.dumps("InitKeyMgr").encode("ascii")) time.sleep(0.5) - def init(self, enable_icache: bool, enable_dummy_instr: bool, - enable_jittery_clock: bool, enable_sram_readback: bool) -> list: - """ Initialize the OTBN FI code on the chip. - Args: - enable_icache: If true, enable the iCache. - enable_dummy_instr: If true, enable the dummy instructions. - enable_jittery_clock: If true, enable the jittery clock. - enable_sram_readback: If true, enable the SRAM readback feature. + def init( + self, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + alert_config: dict = common_library.default_alert_config, + ) -> tuple: + """Initialize the OTBN FI code on the chip. + Returns: - The device ID and countermeasure config of the device. + Device id + The sensor control config + The alert config + The owner page + The boot log + The boot measurements + The testOS version """ + # OtbnFi command. self._ujson_otbn_fi_cmd() # Init command. - time.sleep(0.01) self.target.write(json.dumps("Init").encode("ascii")) - # Configure device and countermeasures. - time.sleep(0.01) - data = {"enable_icache": enable_icache, "enable_dummy_instr": enable_dummy_instr, - "enable_jittery_clock": enable_jittery_clock, - "enable_sram_readback": enable_sram_readback} - self.target.write(json.dumps(data).encode("ascii")) - # Read back device ID and countermeasure configuration from device. - device_config = self.read_response(max_tries=30) - # Read flash owner page. - device_config += self.read_response(max_tries=30) - # Read boot log. - device_config += self.read_response(max_tries=30) - # Read boot measurements. - device_config += self.read_response(max_tries=30) - # Read pentest framework version. - device_config += self.read_response(max_tries=30) - return device_config + + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + self.target.write(json.dumps(alert_config).encode("ascii")) + + device_id = self.target.read_response() + sensors = self.target.read_response() + alerts = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return ( + device_id, + sensors, + alerts, + owner_page, + boot_log, + boot_measurements, + version, + ) def start_test(self, cfg: dict) -> None: - """ Start the selected test. + """Start the selected test. Call the function selected in the config file. Uses the getattr() construct to call the function. @@ -232,25 +249,9 @@ def start_test(self, cfg: dict) -> None: test_function() def write_payload(self, payload: dict) -> None: - """ Send test payload to OpenTitan. + """Send test payload to OpenTitan. Args: payload: The data to send to the target. """ time.sleep(0.01) self.target.write(json.dumps(payload).encode("ascii")) - - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from Otbn FI framework. - Args: - max_tries: Maximum number of attempts to read from UART. - - Returns: - The JSON response of OpenTitan. - """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" diff --git a/target/communication/fi_otp_commands.py b/target/communication/fi_otp_commands.py index 02c77ad9..2b2348af 100644 --- a/target/communication/fi_otp_commands.py +++ b/target/communication/fi_otp_commands.py @@ -7,7 +7,8 @@ """ import json import time -from typing import Optional + +from target.communication import common_library class OTFIOtp: @@ -19,8 +20,7 @@ def _ujson_otp_fi_cmd(self) -> None: self.target.write(json.dumps("OtpFi").encode("ascii")) def otp_fi_vendor_test(self) -> None: - """ Reads otp VENDOR_TEST partition. - """ + """Reads otp VENDOR_TEST partition.""" # IbexFi command. self._ujson_otp_fi_cmd() # VendorTest command. @@ -28,8 +28,7 @@ def otp_fi_vendor_test(self) -> None: self.target.write(json.dumps("VendorTest").encode("ascii")) def otp_fi_owner_sw_cfg(self) -> None: - """ Reads otp OWNER_SW_CFG partition. - """ + """Reads otp OWNER_SW_CFG partition.""" # IbexFi command. self._ujson_otp_fi_cmd() # OwnerSwCfg command. @@ -37,8 +36,7 @@ def otp_fi_owner_sw_cfg(self) -> None: self.target.write(json.dumps("OwnerSwCfg").encode("ascii")) def otp_fi_hw_cfg(self) -> None: - """ Reads otp HW_CFG partition. - """ + """Reads otp HW_CFG partition.""" # IbexFi command. self._ujson_otp_fi_cmd() # HwCfg command. @@ -46,27 +44,61 @@ def otp_fi_hw_cfg(self) -> None: self.target.write(json.dumps("HwCfg").encode("ascii")) def otp_fi_life_cycle(self) -> None: - """ Reads otp LIFE_CYCLE partition. - """ + """Reads otp LIFE_CYCLE partition.""" # IbexFi command. self._ujson_otp_fi_cmd() # LifeCycle command. time.sleep(0.01) self.target.write(json.dumps("LifeCycle").encode("ascii")) - def init(self) -> None: - """ Initialize the Otp FI code on the chip. + def init( + self, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + alert_config: dict = common_library.default_alert_config, + ) -> tuple: + """Initialize the Otp FI code on the chip. Args: cfg: Config dict containing the selected test. + + Returns: + Device id + The owner info page + The boot log + The boot measurements + The testOS version """ + # OtpFi command. self._ujson_otp_fi_cmd() - # InitTrigger command. + # Init command. time.sleep(0.01) self.target.write(json.dumps("Init").encode("ascii")) + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + self.target.write(json.dumps(alert_config).encode("ascii")) + + device_id = self.target.read_response() + sensors = self.target.read_response() + alerts = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return ( + device_id, + sensors, + alerts, + owner_page, + boot_log, + boot_measurements, + version, + ) + def start_test(self, cfg: dict) -> None: - """ Start the selected test. + """Start the selected test. Call the function selected in the config file. Uses the getattr() construct to call the function. @@ -76,19 +108,3 @@ def start_test(self, cfg: dict) -> None: """ test_function = getattr(self, cfg["test"]["which_test"]) test_function() - - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from Otp FI framework. - Args: - max_tries: Maximum number of attempts to read from UART. - - Returns: - The JSON response of OpenTitan. - """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" diff --git a/target/communication/fi_rng_commands.py b/target/communication/fi_rng_commands.py index 96aff658..61e8a1c1 100644 --- a/target/communication/fi_rng_commands.py +++ b/target/communication/fi_rng_commands.py @@ -9,6 +9,8 @@ import time from typing import Optional +from target.communication import common_library + class OTFIRng: def __init__(self, target) -> None: @@ -19,53 +21,96 @@ def _ujson_rng_cmd(self) -> None: self.target.write(json.dumps("RngFi").encode("ascii")) time.sleep(0.01) - def init(self, enable_icache: bool, enable_dummy_instr: bool, - enable_jittery_clock: bool, enable_sram_readback: bool) -> list: - """ Initialize the RNG FI code on the chip. + def init( + self, + test, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + alert_config: dict = common_library.default_alert_config, + ) -> tuple: + """Initialize the RNG FI code on the chip. Args: - enable_icache: If true, enable the iCache. - enable_dummy_instr: If true, enable the dummy instructions. - enable_jittery_clock: If true, enable the jittery clock. - enable_sram_readback: If true, enable the SRAM readback feature. + test: The selected test. + Returns: - The device ID and countermeasure config of the device. + Device id + The owner info page + The boot log + The boot measurements + The testOS version """ + # RngFi command. self._ujson_rng_cmd() # Init command. time.sleep(0.01) - self.target.write(json.dumps("Init").encode("ascii")) - # Configure device and countermeasures. - time.sleep(0.01) - data = {"enable_icache": enable_icache, "enable_dummy_instr": enable_dummy_instr, - "enable_jittery_clock": enable_jittery_clock, - "enable_sram_readback": enable_sram_readback} - self.target.write(json.dumps(data).encode("ascii")) - # Read back device ID and countermeasure configuration from device. - device_config = self.read_response(max_tries=30) - # Read flash owner page. - device_config += self.read_response(max_tries=30) - # Read boot log. - device_config += self.read_response(max_tries=30) - # Read boot measurements. - device_config += self.read_response(max_tries=30) - # Read pentest framework version. - device_config += self.read_response(max_tries=30) - return device_config - - def rng_csrng_bias(self) -> None: - """ Starts the rng_csrng_bias test. - """ + if "csrng" in test: + self.target.write(json.dumps("CsrngInit").encode("ascii")) + else: + self.target.write(json.dumps("EdnInit").encode("ascii")) + + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + self.target.write(json.dumps(alert_config).encode("ascii")) + + device_id = self.target.read_response() + sensors = self.target.read_response() + alerts = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return ( + device_id, + sensors, + alerts, + owner_page, + boot_log, + boot_measurements, + version, + ) + + def rng_csrng_bias(self, trigger: int) -> None: + """Starts the rng_csrng_bias test.""" # RngFi command. time.sleep(0.05) self._ujson_rng_cmd() # CsrngBias command. time.sleep(0.05) self.target.write(json.dumps("CsrngBias").encode("ascii")) + if trigger == 0: + mode = { + "start_trigger": True, + "valid_trigger": False, + "read_trigger": False, + "all_trigger": False, + } + elif trigger == 1: + mode = { + "start_trigger": False, + "valid_trigger": True, + "read_trigger": False, + "all_trigger": False, + } + elif trigger == 2: + mode = { + "start_trigger": False, + "valid_trigger": False, + "read_trigger": True, + "all_trigger": False, + } + elif trigger == 3: + mode = { + "start_trigger": False, + "valid_trigger": False, + "read_trigger": False, + "all_trigger": True, + } + self.target.write(json.dumps(mode).encode("ascii")) def rng_edn_resp_ack(self) -> None: - """ Starts the rng_edn_resp_ack test. - """ + """Starts the rng_edn_resp_ack test.""" # RngFi command. time.sleep(0.05) self._ujson_rng_cmd() @@ -74,8 +119,7 @@ def rng_edn_resp_ack(self) -> None: self.target.write(json.dumps("EdnRespAck").encode("ascii")) def rng_edn_bias(self) -> None: - """ Starts the rng_edn_bias test. - """ + """Starts the rng_edn_bias test.""" # RngFi command. time.sleep(0.05) self._ujson_rng_cmd() @@ -83,13 +127,19 @@ def rng_edn_bias(self) -> None: time.sleep(0.05) self.target.write(json.dumps("EdnBias").encode("ascii")) - def rng_fw_overwrite(self, init: Optional[bool] = False, - disable_health_check: Optional[bool] = False) -> None: - """ Starts the rng_fw_overwrite test. + def rng_entropy_bias(self) -> None: + """Starts the entropy_src_bias test.""" + # RngFi command. + time.sleep(0.05) + self._ujson_rng_cmd() + # EntropySrcBias command. + time.sleep(0.05) + self.target.write(json.dumps("EntropySrcBias").encode("ascii")) + + def rng_fw_overwrite(self, disable_health_check: Optional[bool] = False) -> None: + """Starts the rng_fw_overwrite test. Args: - init: Using disable_health_check is only possible at the very first - rng_fw_overwrite test. Afterwards this option cannot be switched. disable_health_check: Turn the health check on or off. """ # RngFi command. @@ -98,34 +148,19 @@ def rng_fw_overwrite(self, init: Optional[bool] = False, # FWOverride command. time.sleep(0.05) self.target.write(json.dumps("FWOverride").encode("ascii")) - if init: - data = {"disable_health_check": disable_health_check} - self.target.write(json.dumps(data).encode("ascii")) + data = {"disable_health_check": disable_health_check} + self.target.write(json.dumps(data).encode("ascii")) - def start_test(self, cfg: dict) -> None: - """ Start the selected test. + def start_test(self, cfg: dict, *args, **kwargs) -> None: + """Start the selected test. Call the function selected in the config file. Uses the getattr() construct to call the function. Args: cfg: Config dict containing the selected test. + *args: Variable length argument list to be passed to the test function. + **kwargs: Arbitrary keyword arguments to be passed to the test function. """ test_function = getattr(self, cfg["test"]["which_test"]) - test_function() - - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from RNG FI framework. - Args: - max_tries: Maximum number of attempts to read from UART. - - Returns: - The JSON response of OpenTitan. - """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" + test_function(*args, **kwargs) diff --git a/target/communication/fi_rom_commands.py b/target/communication/fi_rom_commands.py new file mode 100644 index 00000000..bd090217 --- /dev/null +++ b/target/communication/fi_rom_commands.py @@ -0,0 +1,74 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +"""Communication interface for OpenTitan Rom FI framework. + +Communication with OpenTitan happens over the uJSON command interface. +""" +import json +import time + +from target.communication import common_library + + +class OTFIRom: + def __init__(self, target) -> None: + self.target = target + + def _ujson_rom_fi_cmd(self) -> None: + time.sleep(0.01) + self.target.write(json.dumps("RomFi").encode("ascii")) + + def handle_rom_read(self) -> None: + """Reads Rom digest.""" + # RomFi command. + self._ujson_rom_fi_cmd() + # Read command. + time.sleep(0.01) + self.target.write(json.dumps("Read").encode("ascii")) + + def init( + self, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + alert_config: dict = common_library.default_alert_config, + ) -> tuple: + """Initialize the ROM FI code on the chip. + Args: + cfg: Config dict containing the selected test. + + Returns: + Device id + The owner info page + The boot log + The boot measurements + The testOS version + """ + + # RomFi command. + self._ujson_rom_fi_cmd() + # Init command. + time.sleep(0.01) + self.target.write(json.dumps("Init").encode("ascii")) + + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + self.target.write(json.dumps(alert_config).encode("ascii")) + + device_id = self.target.read_response() + sensors = self.target.read_response() + alerts = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return ( + device_id, + sensors, + alerts, + owner_page, + boot_log, + boot_measurements, + version, + ) diff --git a/target/communication/sca_aes_commands.py b/target/communication/sca_aes_commands.py index 00327bea..65887c4e 100644 --- a/target/communication/sca_aes_commands.py +++ b/target/communication/sca_aes_commands.py @@ -3,20 +3,18 @@ # SPDX-License-Identifier: Apache-2.0 """Communication interface for the AES SCA application on OpenTitan. -Communication with OpenTitan either happens over simpleserial or the uJson +Communication with OpenTitan happens over the uJson command interface. """ import json import time -from typing import Optional + +from target.communication import common_library class OTAES: - def __init__(self, target, protocol: str) -> None: + def __init__(self, target) -> None: self.target = target - self.simple_serial = True - if protocol == "ujson": - self.simple_serial = False def _ujson_aes_sca_cmd(self): # TODO: without the delay, the device uJSON command handler program @@ -25,276 +23,140 @@ def _ujson_aes_sca_cmd(self): self.target.write(json.dumps("AesSca").encode("ascii")) time.sleep(0.01) - def init(self, fpga_mode_bit: int, enable_icache: bool, enable_dummy_instr: bool, - enable_jittery_clock: bool, enable_sram_readback: bool) -> list: - """ Initializes AES on the target. + def init( + self, + fpga_mode_bit: int, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + ) -> tuple: + """Initializes AES on the target. Args: fpga_mode_bit: Indicates whether FPGA specific AES test is started. - enable_icache: If true, enable the iCache. - enable_dummy_instr: If true, enable the dummy instructions. - enable_jittery_clock: If true, enable the jittery clock. - enable_sram_readback: If true, enable the SRAM readback feature. + Returns: - The device ID and countermeasure config of the device. + Device id + The owner info page + The boot log + The boot measurements + The testOS version """ - if not self.simple_serial: - # AesSca command. - self._ujson_aes_sca_cmd() - # Init the AES core. - self.target.write(json.dumps("Init").encode("ascii")) - # FPGA mode. - time.sleep(0.01) - fpga_mode = {"fpga_mode": fpga_mode_bit} - self.target.write(json.dumps(fpga_mode).encode("ascii")) - # Configure device and countermeasures. - time.sleep(0.01) - data = {"enable_icache": enable_icache, "enable_dummy_instr": enable_dummy_instr, - "enable_jittery_clock": enable_jittery_clock, - "enable_sram_readback": enable_sram_readback} - self.target.write(json.dumps(data).encode("ascii")) - # Read back device ID and countermeasure configuration from device. - device_config = self.read_response(max_tries=30) - # Read flash owner page. - device_config += self.read_response(max_tries=30) - # Read boot log. - device_config += self.read_response(max_tries=30) - # Read boot measurements. - device_config += self.read_response(max_tries=30) - # Read pentest framework version. - device_config += self.read_response(max_tries=30) - return device_config - def key_set(self, key: list[int], key_length: Optional[int] = 16): - """ Write key to AES. - Args: - key: Bytearray containing the key. - """ - if self.simple_serial: - self.target.write(cmd="k", data=bytearray(key)) - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # KeySet command. - self.target.write(json.dumps("KeySet").encode("ascii")) - # Key payload. - time.sleep(0.01) - key_data = {"key": key, "key_length": key_length} - self.target.write(json.dumps(key_data).encode("ascii")) + # AesSca command. + self._ujson_aes_sca_cmd() + # Init the AES core. + self.target.write(json.dumps("Init").encode("ascii")) + # FPGA mode. + time.sleep(0.01) + fpga_mode = {"fpga_mode": fpga_mode_bit} + self.target.write(json.dumps(fpga_mode).encode("ascii")) - def fvsr_key_set(self, key, key_length: Optional[int] = 16): - """ Write key to AES. - Args: - key: Bytearray containing the key. - """ - if self.simple_serial: - self.target.write(cmd="f", data=bytearray(key)) - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # FvsrKeySet command. - self.target.write(json.dumps("FvsrKeySet").encode("ascii")) - # Key payload. - time.sleep(0.01) - key_data = {"key": key, "key_length": key_length} - self.target.write(json.dumps(key_data).encode("ascii")) + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + + device_id = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return device_id, owner_page, boot_log, boot_measurements, version def seed_lfsr(self, seed): - """ Seed the LFSR. + """Seed the LFSR. Args: seed: The 4-byte seed. """ - if self.simple_serial: - self.target.write(cmd="l", data=seed) - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # SeedLfsr command. - self.target.write(json.dumps("SeedLfsr").encode("ascii")) - # Seed payload. - time.sleep(0.01) - seed_data = {"seed": [x for x in seed]} - self.target.write(json.dumps(seed_data).encode("ascii")) - - def start_fvsr_batch_generate(self, command): - """Set SW PRNG to starting values for FvsR data - generation. - """ - if self.simple_serial: - self.target.write(cmd="d", data=command.to_bytes(4, "little")) - self.target.wait_ack() - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # FvsrKeyStartBatchGenerate command. - self.target.write(json.dumps("FvsrKeyStartBatchGenerate").encode("ascii")) - # Command. - time.sleep(0.01) - cmd = {"cmd": command} - self.target.write(json.dumps(cmd).encode("ascii")) - - def write_fvsr_batch_generate(self, num_segments): - """ Generate random plaintexts for FVSR. - Args: - num_segments: Number of encryptions to perform. - """ - if self.simple_serial: - self.target.write(cmd="g", data=num_segments.to_bytes(4, "little")) - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # FvsrKeyBatchGenerate command. - self.target.write(json.dumps("FvsrKeyBatchGenerate").encode("ascii")) - # Number of encryptions. - time.sleep(0.01) - num_encryption_data = {"num_enc": num_segments} - self.target.write(json.dumps(num_encryption_data).encode("ascii")) + # AesSca command. + self._ujson_aes_sca_cmd() + # SeedLfsr command. + self.target.write(json.dumps("SeedLfsr").encode("ascii")) + # Seed payload. + time.sleep(0.01) + seed_data = {"seed": [x for x in seed]} + self.target.write(json.dumps(seed_data).encode("ascii")) - def batch_alternative_encrypt(self, num_segments): - """ Start encryption for batch (alternative). + def batch_daisy_chain(self, num_segments, key, text): + """Start encryption for batch (alternative). Args: + key: Key to use for all encryptions. + text: First plaintext to use. num_segments: Number of encryptions to perform. """ - if self.simple_serial: - self.target.write(cmd="a", data=num_segments.to_bytes(4, "little")) - self.target.wait_ack() - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # BatchEncrypt command. - self.target.write(json.dumps("BatchAlternativeEncrypt").encode("ascii")) - # Number of encryptions. - time.sleep(0.01) - num_encryption_data = {"num_enc": num_segments} - self.target.write(json.dumps(num_encryption_data).encode("ascii")) - - def batch_encrypt(self, num_segments): - """ Start encryption for batch. + # AesSca command. + self._ujson_aes_sca_cmd() + # BatchAlternativeEncrypt command. + self.target.write(json.dumps("BatchDaisy").encode("ascii")) + time.sleep(0.01) + key_data = {"key": key, "key_length": len(key)} + self.target.write(json.dumps(key_data).encode("ascii")) + text_data = {"text": text, "text_length": len(text)} + self.target.write(json.dumps(text_data).encode("ascii")) + num_encryption_data = {"num_enc": num_segments} + self.target.write(json.dumps(num_encryption_data).encode("ascii")) + + def batch_fvsr_data(self, num_segments, key, text): + """Start encryption for batch fixed vs. random plaintext. Args: + key: Key to use for all encryptions. + text: The fixed plaintext to use. num_segments: Number of encryptions to perform. """ - if self.simple_serial: - self.target.write(cmd="a", data=num_segments.to_bytes(4, "little")) - self.target.wait_ack() - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # BatchEncrypt command. - self.target.write(json.dumps("BatchEncrypt").encode("ascii")) - # Number of encryptions. - time.sleep(0.01) - num_encryption_data = {"num_enc": num_segments} - self.target.write(json.dumps(num_encryption_data).encode("ascii")) - - def fvsr_key_batch_encrypt(self, num_segments): - """ Start batch encryption for FVSR key. + # AesSca command. + self._ujson_aes_sca_cmd() + # BatchFvsrData command. + self.target.write(json.dumps("BatchFvsrData").encode("ascii")) + time.sleep(0.01) + key_data = {"key": key, "key_length": len(key)} + self.target.write(json.dumps(key_data).encode("ascii")) + text_data = {"text": text, "text_length": len(text)} + self.target.write(json.dumps(text_data).encode("ascii")) + num_encryption_data = {"num_enc": num_segments} + self.target.write(json.dumps(num_encryption_data).encode("ascii")) + + def batch_fvsr_key(self, num_segments, key): + """Start batch encryption for FVSR key. Args: + key: Fixed key to use. num_segments: Number of encryptions to perform. """ - if self.simple_serial: - self.target.write(cmd="e", data=num_segments.to_bytes(4, "little")) - self.target.wait_ack() - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # FvsrKeyBatchEncrypt command. - self.target.write(json.dumps("FvsrKeyBatchEncrypt").encode("ascii")) - # Number of encryptions. - time.sleep(0.01) - num_encryption_data = {"num_enc": num_segments} - self.target.write(json.dumps(num_encryption_data).encode("ascii")) + # AesSca command. + self._ujson_aes_sca_cmd() + # BatchFvsrKey command. + self.target.write(json.dumps("BatchFvsrKey").encode("ascii")) + time.sleep(0.01) + key_data = {"key": key, "key_length": len(key)} + self.target.write(json.dumps(key_data).encode("ascii")) + num_encryption_data = {"num_enc": num_segments} + self.target.write(json.dumps(num_encryption_data).encode("ascii")) - def fvsr_data_batch_encrypt(self, num_segments): - """ Start batch encryption for FVSR data. + def batch_random(self, num_segments, key): + """Start batch encryption for FVSR data. Args: + key: Key to use for all encryptions. num_segments: Number of encryptions to perform. """ - if self.simple_serial: - self.target.write(cmd = "h", data = num_segments.to_bytes(4, "little")) - self.target.wait_ack() - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # FvsrKeyBatchEncrypt command. - self.target.write(json.dumps("FvsrDataBatchEncrypt").encode("ascii")) - # Number of encryptions. - time.sleep(0.01) - num_encryption_data = {"num_enc": num_segments} - self.target.write(json.dumps(num_encryption_data).encode("ascii")) - - def batch_plaintext_set(self, text, text_length: Optional[int] = 16): - """ Write plaintext to OpenTitan AES. - - This command is designed to set the initial plaintext for - batch_alternative_encrypt. - - Args: - text: The plaintext bytearray. - """ - if self.simple_serial: - self.target.write(cmd="i", data=bytearray(text)) - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # BatchPlaintextSet command. - self.target.write(json.dumps("BatchPlaintextSet").encode("ascii")) - # Text payload. - time.sleep(0.01) - text_int = [x for x in text] - text_data = {"text": text_int, "text_length": text_length} - self.target.write(json.dumps(text_data).encode("ascii")) - - def single_encrypt(self, text: list[int], text_length: Optional[int] = 16): - """ Write plaintext to OpenTitan AES & start encryption. - Args: - text: The plaintext bytearray. - """ - if self.simple_serial: - self.target.write(cmd="p", data=bytearray(text)) - else: - # AesSca command. - self._ujson_aes_sca_cmd() - # SingleEncrypt command. - self.target.write(json.dumps("SingleEncrypt").encode("ascii")) - # Text payload. - time.sleep(0.01) - text_data = {"text": text, "text_length": text_length} - self.target.write(json.dumps(text_data).encode("ascii")) - - def read_ciphertext(self, len_bytes): - """ Read ciphertext from OpenTitan AES. - Args: - len_bytes: Number of bytes to read. - - Returns: - The received ciphertext. - """ - if self.simple_serial: - response_byte = self.target.read("r", len_bytes, ack=False) - # Convert response into int array. - return [x for x in response_byte] - else: - while True: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - json_string = read_line.split("RESP_OK:")[1].split(" CRC:")[0] - try: - ciphertext = json.loads(json_string)["ciphertext"] - return ciphertext[0:len_bytes] - except Exception: - pass # noqa: E302 + # AesSca command. + self._ujson_aes_sca_cmd() + # BatchRandom command. + self.target.write(json.dumps("BatchRandom").encode("ascii")) + time.sleep(0.01) + key_data = {"key": key, "key_length": len(key)} + self.target.write(json.dumps(key_data).encode("ascii")) + num_encryption_data = {"num_enc": num_segments} + self.target.write(json.dumps(num_encryption_data).encode("ascii")) - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from AES SCA framework. + def single_encrypt(self, key, text): + """Write plaintext to OpenTitan AES & start encryption. Args: - max_tries: Maximum number of attempts to read from UART. - - Returns: - The JSON response of OpenTitan. + key: The key. + text: The plaintext. """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" + # AesSca command. + self._ujson_aes_sca_cmd() + # Single command. + self.target.write(json.dumps("Single").encode("ascii")) + time.sleep(0.01) + key_data = {"key": key, "key_length": len(key)} + self.target.write(json.dumps(key_data).encode("ascii")) + text_data = {"text": text, "text_length": len(text)} + self.target.write(json.dumps(text_data).encode("ascii")) diff --git a/target/communication/sca_hmac_commands.py b/target/communication/sca_hmac_commands.py index 8668db30..6675ce4f 100644 --- a/target/communication/sca_hmac_commands.py +++ b/target/communication/sca_hmac_commands.py @@ -7,14 +7,13 @@ """ import json import time -from typing import Optional + +from target.communication import common_library class OTHMAC: - def __init__(self, target, protocol: str) -> None: + def __init__(self, target) -> None: self.target = target - if protocol == "simpleserial": - raise Exception("Only uJSON protocol is supported for this test.") def _ujson_hmac_sca_cmd(self): # TODO: without the delay, the device uJSON command handler program @@ -23,78 +22,97 @@ def _ujson_hmac_sca_cmd(self): self.target.write(json.dumps("HmacSca").encode("ascii")) time.sleep(0.01) - def init(self, enable_icache: bool, enable_dummy_instr: bool, - enable_jittery_clock: bool, enable_sram_readback: bool) -> list: - """ Initializes HMAC on the target. - Args: - enable_icache: If true, enable the iCache. - enable_dummy_instr: If true, enable the dummy instructions. - enable_jittery_clock: If true, enable the jittery clock. - enable_sram_readback: If true, enable the SRAM readback feature. + def init( + self, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + ) -> tuple: + """Initializes HMAC on the target. + Returns: - The device ID and countermeasure config of the device. + Device id + The owner info page + The boot log + The boot measurements + The testOS version """ + # HmacSca command. self._ujson_hmac_sca_cmd() # Init command. self.target.write(json.dumps("Init").encode("ascii")) - # Configure device and countermeasures. time.sleep(0.01) - data = {"enable_icache": enable_icache, "enable_dummy_instr": enable_dummy_instr, - "enable_jittery_clock": enable_jittery_clock, - "enable_sram_readback": enable_sram_readback} - self.target.write(json.dumps(data).encode("ascii")) - # Read back device ID and countermeasure configuration from device. - device_config = self.read_response(max_tries=30) - # Read flash owner page. - device_config += self.read_response(max_tries=30) - # Read boot log. - device_config += self.read_response(max_tries=30) - # Read boot measurements. - device_config += self.read_response(max_tries=30) - # Read pentest framework version. - device_config += self.read_response(max_tries=30) - return device_config - def single(self, msg: list[int], key: list[int], start_trigger: bool, - msg_trigger: bool, process_trigger: bool, finish_trigger: bool): - """ Start a single HMAC operation using the given message and key. + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + + device_id = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return device_id, owner_page, boot_log, boot_measurements, version + + def single(self, msg: list[int], key: list[int], trigger: int): + """Start a single HMAC operation using the given message and key. Args: msg: The list containing the message. key: The key containing the message. - start_trigger: Set trigger during the start phase. - msg_trigger: Set trigger during the message pushing phase. - process_trigger: Set trigger during the processing phase. - finish_trigger: Set trigger during the finish phase. + trigger: Which trigger to raise. """ # HmacSca command. self._ujson_hmac_sca_cmd() # Single command. self.target.write(json.dumps("Single").encode("ascii")) # Key payload. + # Key payload. time.sleep(0.01) key_data = {"key": key} + key_data = {"key": key} self.target.write(json.dumps(key_data).encode("ascii")) # Message payload. time.sleep(0.01) msg_data = {"message": msg} self.target.write(json.dumps(msg_data).encode("ascii")) - # Trigger configuration. - time.sleep(0.05) - trigger_data = {"start_trigger": start_trigger, "msg_trigger": msg_trigger, - "process_trigger": process_trigger, "finish_trigger": finish_trigger} - self.target.write(json.dumps(trigger_data).encode("ascii")) + # Trigger payload. + time.sleep(0.01) + if trigger == 0: + mode = { + "start_trigger": True, + "msg_trigger": False, + "process_trigger": False, + "finish_trigger": False, + } + elif trigger == 1: + mode = { + "start_trigger": False, + "msg_trigger": True, + "process_trigger": False, + "finish_trigger": False, + } + elif trigger == 2: + mode = { + "start_trigger": False, + "msg_trigger": False, + "process_trigger": True, + "finish_trigger": False, + } + elif trigger == 3: + mode = { + "start_trigger": False, + "msg_trigger": False, + "process_trigger": False, + "finish_trigger": True, + } + self.target.write(json.dumps(mode).encode("ascii")) - def fvsr_batch(self, key: list[int], num_segments: int, start_trigger: bool, - msg_trigger: bool, process_trigger: bool, finish_trigger: bool): - """ Start num_segments HMAC operation in FvsR batch mode. + def fvsr_batch(self, key: list[int], num_segments: int, trigger: int): + """Start num_segments HMAC operation in FvsR batch mode. Args: key: The key containing the message. num_segments: The number of iterations. - start_trigger: Set trigger during the start phase. - msg_trigger: Set trigger during the message pushing phase. - process_trigger: Set trigger during the processing phase. - finish_trigger: Set trigger during the finish phase. + trigger: Which trigger to raise. """ # HmacSca command. self._ujson_hmac_sca_cmd() @@ -108,21 +126,43 @@ def fvsr_batch(self, key: list[int], num_segments: int, start_trigger: bool, time.sleep(0.05) num_it_data = {"num_iterations": num_segments} self.target.write(json.dumps(num_it_data).encode("ascii")) - # Trigger configuration. - time.sleep(0.05) - trigger_data = {"start_trigger": start_trigger, "msg_trigger": msg_trigger, - "process_trigger": process_trigger, "finish_trigger": finish_trigger} - self.target.write(json.dumps(trigger_data).encode("ascii")) + # Trigger payload. + time.sleep(0.01) + if trigger == 0: + mode = { + "start_trigger": True, + "msg_trigger": False, + "process_trigger": False, + "finish_trigger": False, + } + elif trigger == 1: + mode = { + "start_trigger": False, + "msg_trigger": True, + "process_trigger": False, + "finish_trigger": False, + } + elif trigger == 2: + mode = { + "start_trigger": False, + "msg_trigger": False, + "process_trigger": True, + "finish_trigger": False, + } + elif trigger == 3: + mode = { + "start_trigger": False, + "msg_trigger": False, + "process_trigger": False, + "finish_trigger": True, + } + self.target.write(json.dumps(mode).encode("ascii")) - def random_batch(self, num_segments: int, start_trigger: bool, - msg_trigger: bool, process_trigger: bool, finish_trigger: bool): - """ Start num_segments HMAC operations in random batch mode. + def random_batch(self, num_segments: int, trigger: int): + """Start num_segments HMAC operations in random batch mode. Args: num_segments: The number of iterations. - start_trigger: Set trigger during the start phase. - msg_trigger: Set trigger during the message pushing phase. - process_trigger: Set trigger during the processing phase. - finish_trigger: Set trigger during the finish phase. + trigger: Which trigger to raise. """ # HmacSca command. self._ujson_hmac_sca_cmd() @@ -132,40 +172,89 @@ def random_batch(self, num_segments: int, start_trigger: bool, time.sleep(0.01) num_it_data = {"num_iterations": num_segments} self.target.write(json.dumps(num_it_data).encode("ascii")) - # Trigger configuration. - time.sleep(0.05) - trigger_data = {"start_trigger": start_trigger, "msg_trigger": msg_trigger, - "process_trigger": process_trigger, "finish_trigger": finish_trigger} - self.target.write(json.dumps(trigger_data).encode("ascii")) - - def read_tag(self): - """ Read tag from OpenTitan HMAC. - - Returns: - The received tag. - """ - while True: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - json_string = read_line.split("RESP_OK:")[1].split(" CRC:")[0] - try: - tag = json.loads(json_string)["tag"] - return tag - except Exception: - pass # noqa: E302 + # Trigger payload. + time.sleep(0.01) + if trigger == 0: + mode = { + "start_trigger": True, + "msg_trigger": False, + "process_trigger": False, + "finish_trigger": False, + } + elif trigger == 1: + mode = { + "start_trigger": False, + "msg_trigger": True, + "process_trigger": False, + "finish_trigger": False, + } + elif trigger == 2: + mode = { + "start_trigger": False, + "msg_trigger": False, + "process_trigger": True, + "finish_trigger": False, + } + elif trigger == 3: + mode = { + "start_trigger": False, + "msg_trigger": False, + "process_trigger": False, + "finish_trigger": True, + } + self.target.write(json.dumps(mode).encode("ascii")) - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from AES SCA framework. + def daisy_chain( + self, text: list[int], key: list[int], num_segments: int, trigger: int + ): + """Start num_segments HMAC operations in daisy chain mode. Args: - max_tries: Maximum number of attempts to read from UART. - - Returns: - The JSON response of OpenTitan. + text: The input message + key: The HMAC key + num_segments: The number of iterations. + trigger: Which trigger to raise. """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" + # HmacSca command. + self._ujson_hmac_sca_cmd() + # BatchRandom command. + self.target.write(json.dumps("BatchDaisy").encode("ascii")) + # Number of iterations payload. + time.sleep(0.01) + key_data = {"key": key} + self.target.write(json.dumps(key_data).encode("ascii")) + message_data = {"message": text} + self.target.write(json.dumps(message_data).encode("ascii")) + time.sleep(0.05) + num_it_data = {"num_iterations": num_segments} + self.target.write(json.dumps(num_it_data).encode("ascii")) + # Trigger payload. + time.sleep(0.01) + if trigger == 0: + mode = { + "start_trigger": True, + "msg_trigger": False, + "process_trigger": False, + "finish_trigger": False, + } + elif trigger == 1: + mode = { + "start_trigger": False, + "msg_trigger": True, + "process_trigger": False, + "finish_trigger": False, + } + elif trigger == 2: + mode = { + "start_trigger": False, + "msg_trigger": False, + "process_trigger": True, + "finish_trigger": False, + } + elif trigger == 3: + mode = { + "start_trigger": False, + "msg_trigger": False, + "process_trigger": False, + "finish_trigger": True, + } + self.target.write(json.dumps(mode).encode("ascii")) diff --git a/target/communication/sca_ibex_commands.py b/target/communication/sca_ibex_commands.py index eb985c51..6d49ab9d 100644 --- a/target/communication/sca_ibex_commands.py +++ b/target/communication/sca_ibex_commands.py @@ -7,14 +7,13 @@ """ import json import time -from typing import Optional + +from target.communication import common_library class OTIbex: - def __init__(self, target, protocol: str) -> None: + def __init__(self, target) -> None: self.target = target - if protocol == "simpleserial": - raise RuntimeError("Error: Simpleserial not supported!") def _ujson_ibex_sca_cmd(self): # TODO: without the delay, the device uJSON command handler program @@ -22,58 +21,40 @@ def _ujson_ibex_sca_cmd(self): time.sleep(0.01) self.target.write(json.dumps("IbexSca").encode("ascii")) - def ibex_sca_read_response(self, num_attempts: Optional[int] = 100): - """ Reads back the "result" response from the device. - """ - read_counter = 0 - while read_counter < num_attempts: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - json_string = read_line.split("RESP_OK:")[1].split(" CRC:")[0] - try: - if "result" in json_string: - return json.loads(json_string)["result"] - except Exception: - raise Exception("Acknowledge error: Device and host not in sync") - else: - read_counter += 1 - raise Exception("Acknowledge error: Device and host not in sync") + def init( + self, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + ) -> tuple: + """Initializes the Ibex SCA tests on the target. - def init(self, enable_icache: bool, enable_dummy_instr: bool, - enable_jittery_clock: bool, enable_sram_readback: bool) -> list: - """ Initializes the Ibex SCA tests on the target. - Args: - enable_icache: If true, enable the iCache. - enable_dummy_instr: If true, enable the dummy instructions. - enable_jittery_clock: If true, enable the jittery clock. - enable_sram_readback: If true, enable the SRAM readback feature. Returns: - The device ID and countermeasure config of the device. + Device id + The owner info page + The boot log + The boot measurements + The testOS version """ + # IbexSca command. self._ujson_ibex_sca_cmd() - # Init the Ibex SCA tests. - self.target.write(json.dumps("Init").encode("ascii")) - # Configure device and countermeasures. + # Init command. time.sleep(0.01) - data = {"enable_icache": enable_icache, "enable_dummy_instr": enable_dummy_instr, - "enable_jittery_clock": enable_jittery_clock, - "enable_sram_readback": enable_sram_readback} - self.target.write(json.dumps(data).encode("ascii")) - # Read back device ID and countermeasure configuration from device. - device_config = self.read_response(max_tries=30) - # Read flash owner page. - device_config += self.read_response(max_tries=30) - # Read boot log. - device_config += self.read_response(max_tries=30) - # Read boot measurements. - device_config += self.read_response(max_tries=30) - # Read pentest framework version. - device_config += self.read_response(max_tries=30) - return device_config + self.target.write(json.dumps("Init").encode("ascii")) + + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + + device_id = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return device_id, owner_page, boot_log, boot_measurements, version def ibex_sca_register_file_read_batch_random(self, num_segments: int): - """ Start ibex.sca.register_file_read_batch_random test. + """Start ibex.sca.register_file_read_batch_random test. Args: num_segments: The number of iterations. """ @@ -86,8 +67,8 @@ def ibex_sca_register_file_read_batch_random(self, num_segments: int): data = {"num_iterations": num_segments} self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_register_file_read_random(self, data: list[int]): - """ Start ibex.sca.register_file_read_random test. + def ibex_sca_register_file_read(self, data: list[int]): + """Start ibex.sca.register_file_read test. Args: data: The data that is first written into the RF and then read back. """ @@ -101,7 +82,7 @@ def ibex_sca_register_file_read_random(self, data: list[int]): self.target.write(json.dumps(data).encode("ascii")) def ibex_sca_register_file_read_batch_fvsr(self, data: int, num_segments: int): - """ Start ibex.sca.register_file_read_batch_fvsr test. + """Start ibex.sca.register_file_read_batch_fvsr test. Args: data: The data that is first written into the RF and then read back. num_segments: The number of iterations. @@ -115,22 +96,8 @@ def ibex_sca_register_file_read_batch_fvsr(self, data: int, num_segments: int): data = {"num_iterations": num_segments, "fixed_data": data} self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_register_file_read_fvsr(self, data: list[int]): - """ Start ibex.sca.register_file_read_fvsr test. - Args: - data: The data that is first written into the RF and then read back. - """ - # IbexSca command. - self._ujson_ibex_sca_cmd() - # RFRead command. - self.target.write(json.dumps("RFRead").encode("ascii")) - # Data payload. - time.sleep(0.01) - data = {"data": data} - self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_register_file_write_batch_random(self, num_segments: int): - """ Start ibex.sca.register_file_write_batch_random test. + """Start ibex.sca.register_file_write_batch_random test. Args: num_segments: The number of iterations. """ @@ -143,8 +110,8 @@ def ibex_sca_register_file_write_batch_random(self, num_segments: int): data = {"num_iterations": num_segments} self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_register_file_write_random(self, data: list[int]): - """ Start ibex.sca.register_file_write_random test. + def ibex_sca_register_file_write(self, data: list[int]): + """Start ibex.sca.register_file_write test. Args: data: The data that is written into the RF. """ @@ -158,7 +125,7 @@ def ibex_sca_register_file_write_random(self, data: list[int]): self.target.write(json.dumps(data).encode("ascii")) def ibex_sca_register_file_write_batch_fvsr(self, data: int, num_segments: int): - """ Start ibex.sca.register_file_write_batch_fvsr test. + """Start ibex.sca.register_file_write_batch_fvsr test. Args: data: The data that is written into the RF. num_segments: The number of iterations. @@ -172,22 +139,8 @@ def ibex_sca_register_file_write_batch_fvsr(self, data: int, num_segments: int): data = {"num_iterations": num_segments, "fixed_data": data} self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_register_file_write_fvsr(self, data: list[int]): - """ Start ibex.sca.register_file_write_fvsr test. - Args: - data: The data that is written into the RF. - """ - # IbexSca command. - self._ujson_ibex_sca_cmd() - # RFWrite command. - self.target.write(json.dumps("RFWrite").encode("ascii")) - # Data payload. - time.sleep(0.01) - data = {"data": data} - self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_tl_write_batch_random(self, num_segments: int): - """ Start ibex.sca.tl_write_batch_random test. + """Start ibex.sca.tl_write_batch_random test. Args: num_segments: The number of iterations. """ @@ -201,7 +154,7 @@ def ibex_sca_tl_write_batch_random(self, num_segments: int): self.target.write(json.dumps(data).encode("ascii")) def ibex_sca_tl_write_batch_random_fix_address(self, num_segments: int): - """ Start ibex.sca.tl_write_batch_random_fix_address test. + """Start ibex.sca.tl_write_batch_random_fix_address test. Args: num_segments: The number of iterations. """ @@ -214,8 +167,8 @@ def ibex_sca_tl_write_batch_random_fix_address(self, num_segments: int): data = {"num_iterations": num_segments} self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_tl_write_random(self, data: list[int]): - """ Start ibex.sca.tl_write_random test. + def ibex_sca_tl_write(self, data: list[int]): + """Start ibex.sca.tl_write_random test. Args: data: The data that is written into the SRAM over Tl-UL. """ @@ -229,7 +182,7 @@ def ibex_sca_tl_write_random(self, data: list[int]): self.target.write(json.dumps(data).encode("ascii")) def ibex_sca_tl_write_batch_fvsr(self, data: int, num_segments: int): - """ Start ibex.sca.tl_write_batch_fvsr test. + """Start ibex.sca.tl_write_batch_fvsr test. Args: data: The data that is written into the SRAM over Tl-UL. num_segments: The number of iterations. @@ -243,9 +196,8 @@ def ibex_sca_tl_write_batch_fvsr(self, data: int, num_segments: int): data = {"num_iterations": num_segments, "fixed_data": data} self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_tl_write_batch_fvsr_fix_address(self, data: int, - num_segments: int): - """ Start ibex.sca.tl_write_batch_fvsr_fix_address test. + def ibex_sca_tl_write_batch_fvsr_fix_address(self, data: int, num_segments: int): + """Start ibex.sca.tl_write_batch_fvsr_fix_address test. Args: data: The data that is written into the SRAM over Tl-UL. num_segments: The number of iterations. @@ -259,22 +211,8 @@ def ibex_sca_tl_write_batch_fvsr_fix_address(self, data: int, data = {"num_iterations": num_segments, "fixed_data": data} self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_tl_write_fvsr(self, data: list[int]): - """ Start ibex.sca.tl_write_fvsr test. - Args: - data: The data that is written into the SRAM over Tl-UL. - """ - # IbexSca command. - self._ujson_ibex_sca_cmd() - # TLWrite command. - self.target.write(json.dumps("TLWrite").encode("ascii")) - # Data payload. - time.sleep(0.01) - data = {"data": data} - self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_tl_read_batch_random(self, num_segments: int): - """ Start ibex.sca.tl_read_batch_random test. + """Start ibex.sca.tl_read_batch_random test. Args: num_segments: The number of iterations. """ @@ -288,7 +226,7 @@ def ibex_sca_tl_read_batch_random(self, num_segments: int): self.target.write(json.dumps(data).encode("ascii")) def ibex_sca_tl_read_batch_random_fix_address(self, num_segments: int): - """ Start ibex.sca.tl_read_batch_random_fix_address test. + """Start ibex.sca.tl_read_batch_random_fix_address test. Args: num_segments: The number of iterations. """ @@ -301,8 +239,8 @@ def ibex_sca_tl_read_batch_random_fix_address(self, num_segments: int): data = {"num_iterations": num_segments} self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_tl_read_random(self, data: list[int]): - """ Start ibex.sca.tl_read_random test. + def ibex_sca_tl_read(self, data: list[int]): + """Start ibex.sca.tl_read test. Args: num_iterations: The number of iterations the RF is written. data: The data that is written into the SRAM over Tl-UL. @@ -317,7 +255,7 @@ def ibex_sca_tl_read_random(self, data: list[int]): self.target.write(json.dumps(data).encode("ascii")) def ibex_sca_tl_read_batch_fvsr(self, data: int, num_segments: int): - """ Start ibex.sca.tl_read_batch_fvsr test. + """Start ibex.sca.tl_read_batch_fvsr test. Args: data: The data that is written into the SRAM over Tl-UL. num_segments: The number of iterations. @@ -331,9 +269,8 @@ def ibex_sca_tl_read_batch_fvsr(self, data: int, num_segments: int): data = {"num_iterations": num_segments, "fixed_data": data} self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_tl_read_batch_fvsr_fix_address(self, data: int, - num_segments: int): - """ Start ibex.sca.tl_read_batch_fvsr_fix_address test. + def ibex_sca_tl_read_batch_fvsr_fix_address(self, data: int, num_segments: int): + """Start ibex.sca.tl_read_batch_fvsr_fix_address test. Args: data: The data that is written into the SRAM over Tl-UL. num_segments: The number of iterations. @@ -347,23 +284,58 @@ def ibex_sca_tl_read_batch_fvsr_fix_address(self, data: int, data = {"num_iterations": num_segments, "fixed_data": data} self.target.write(json.dumps(data).encode("ascii")) - def ibex_sca_tl_read_fvsr(self, data: list[int]): - """ Start ibex.sca.tl_read_fvsr test. + def ibex_sca_combi_operations_batch_fvsr( + self, num_iterations: int, trigger: int, fixed_data1: int, fixed_data2: int + ): + """Start ibex.sca.combi_operations_batch_fvsr test. Args: - num_iterations: The number of iterations the RF is written. - data: The data that is written into the SRAM over Tl-UL. + num_iterations: The number of iterations the test is repeated. + trigger: 12-bit value, each bit sets the trigger for one of the 12 trigger windows. + fixed_data1: The first fixed value. + fixed_data2: The second fixed value. """ # IbexSca command. self._ujson_ibex_sca_cmd() - # TLRead command. - self.target.write(json.dumps("TLRead").encode("ascii")) - # Data payload. + # CombiOperationsBatchFvsr command. + self.target.write(json.dumps("CombiOperationsBatchFvsr").encode("ascii")) + # Input payload. time.sleep(0.01) - data = {"data": data} + data = { + "num_iterations": num_iterations, + "trigger": trigger, + "fixed_data1": fixed_data1, + "fixed_data2": fixed_data2, + } self.target.write(json.dumps(data).encode("ascii")) - def start_test(self, testname: str, arg1 = None, arg2 = None) -> None: - """ Start the selected test. + def ibex_sca_combi_operations_batch( + self, num_iterations: int, trigger: int, fixed_data1: int, fixed_data2: int + ): + """Start ibex.sca.combi_operations_batch test. + Args: + num_iterations: The number of iterations the test is repeated. + trigger: 12-bit value, each bit sets the trigger for one of the 12 trigger windows. + fixed_data1: The first fixed value. + fixed_data2: The second fixed value. + """ + # IbexSca command. + self._ujson_ibex_sca_cmd() + # CombiOperationsBatchFvsr command. + self.target.write(json.dumps("CombiOperationsBatch").encode("ascii")) + # Input payload. + time.sleep(0.01) + data = { + "num_iterations": num_iterations, + "trigger": trigger, + "fixed_data1": fixed_data1, + "fixed_data2": fixed_data2, + } + self.target.write(json.dumps(data).encode("ascii")) + + def start_test( + self, testname: str, arg1=None, arg2=None, arg3=None, arg4=None + ) -> None: + """Start the selected test. Call the function selected in the config file. Uses the getattr() construct to call the function. @@ -374,25 +346,13 @@ def start_test(self, testname: str, arg1 = None, arg2 = None) -> None: arg2: The second argument passed to the test. """ test_function = getattr(self, testname) - if arg1 is not None and arg2 is None: + if arg1 is not None and arg2 is None and arg3 is None and arg4 is None: test_function(arg1) - elif arg2 is not None: + elif arg2 is not None and arg3 is None and arg4 is None: test_function(arg1, arg2) + elif arg3 is not None and arg4 is None: + test_function(arg1, arg2, arg3) + elif arg4 is not None: + test_function(arg1, arg2, arg3, arg4) else: test_function() - - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from Ibex SCA framework. - Args: - max_tries: Maximum number of attempts to read from UART. - - Returns: - The JSON response of OpenTitan. - """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" diff --git a/target/communication/sca_kmac_commands.py b/target/communication/sca_kmac_commands.py index ce6fed28..c515412a 100644 --- a/target/communication/sca_kmac_commands.py +++ b/target/communication/sca_kmac_commands.py @@ -3,20 +3,19 @@ # SPDX-License-Identifier: Apache-2.0 """Communication interface for the KMAC SCA application on OpenTitan. -Communication with OpenTitan either happens over simpleserial or the uJson +Communication with OpenTitan happens over the uJson command interface. """ import json import time from typing import Optional +from target.communication import common_library + class OTKMAC: - def __init__(self, target, protocol: str) -> None: + def __init__(self, target) -> None: self.target = target - self.simple_serial = True - if protocol == "ujson": - self.simple_serial = False def _ujson_kmac_sca_cmd(self): # TODO: without the delay, the device uJSON command handler program @@ -24,167 +23,132 @@ def _ujson_kmac_sca_cmd(self): time.sleep(0.01) self.target.write(json.dumps("KmacSca").encode("ascii")) - def init(self, fpga_mode_bit: int, enable_icache: bool, enable_dummy_instr: bool, - enable_jittery_clock: bool, enable_sram_readback: bool) -> list: - """ Initializes KMAC on the target. + def init( + self, + fpga_mode_bit: int, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + ) -> tuple: + """Initializes KMAC on the target. Args: fpga_mode_bit: Indicates whether FPGA specific KMAC test is started. - enable_icache: If true, enable the iCache. - enable_dummy_instr: If true, enable the dummy instructions. - enable_jittery_clock: If true, enable the jittery clock. - enable_sram_readback: If true, enable the SRAM readback feature. - Returns: - The device ID and countermeasure config of the device. + + Returns: + Device id + The owner info page + The boot log + The boot measurements + The testOS version """ - if not self.simple_serial: - # KmacSca command. - self._ujson_kmac_sca_cmd() - # Init command. - self.target.write(json.dumps("Init").encode("ascii")) - # FPGA mode. - time.sleep(0.01) - fpga_mode = {"fpga_mode": fpga_mode_bit} - self.target.write(json.dumps(fpga_mode).encode("ascii")) - # Configure device and countermeasures. - time.sleep(0.01) - data = {"enable_icache": enable_icache, "enable_dummy_instr": enable_dummy_instr, - "enable_jittery_clock": enable_jittery_clock, - "enable_sram_readback": enable_sram_readback} - self.target.write(json.dumps(data).encode("ascii")) - # Read back device ID and countermeasure configuration from device. - device_config = self.read_response(max_tries=30) - # Read flash owner page. - device_config += self.read_response(max_tries=30) - # Read boot log. - device_config += self.read_response(max_tries=30) - # Read boot measurements. - device_config += self.read_response(max_tries=30) - # Read pentest framework version. - device_config += self.read_response(max_tries=30) - return device_config + + # KmacSca command. + self._ujson_kmac_sca_cmd() + # Init command. + self.target.write(json.dumps("Init").encode("ascii")) + # FPGA mode. + time.sleep(0.01) + fpga_mode = {"fpga_mode": fpga_mode_bit} + self.target.write(json.dumps(fpga_mode).encode("ascii")) + + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + + device_id = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return device_id, owner_page, boot_log, boot_measurements, version def write_key(self, key: list[int]): - """ Write the key to KMAC. + """Write the key to KMAC. Args: key: Bytearray containing the key. """ - if self.simple_serial: - self.target.write(cmd="k", data=bytearray(key)) - else: - # KmacSca command. - self._ujson_kmac_sca_cmd() - # SetKey command. - self.target.write(json.dumps("SetKey").encode("ascii")) - # Key payload. - time.sleep(0.01) - key_data = {"key": key, "key_length": 16} - self.target.write(json.dumps(key_data).encode("ascii")) + # KmacSca command. + self._ujson_kmac_sca_cmd() + # SetKey command. + self.target.write(json.dumps("SetKey").encode("ascii")) + # Key payload. + time.sleep(0.01) + key_data = {"key": key, "key_length": 16} + self.target.write(json.dumps(key_data).encode("ascii")) def fvsr_key_set(self, key: list[int], key_length: Optional[int] = 16): - """ Write the fixed key to KMAC. + """Write the fixed key to KMAC. Args: key: Bytearray containing the key. """ - if self.simple_serial: - self.target.write(cmd="f", data=bytearray(key)) - else: - # KmacSca command. - self._ujson_kmac_sca_cmd() - # SetKey command. - self.target.write(json.dumps("FixedKeySet").encode("ascii")) - # FixedKeySet payload. - time.sleep(0.01) - key_data = {"key": key, "key_length": key_length} - self.target.write(json.dumps(key_data).encode("ascii")) + # KmacSca command. + self._ujson_kmac_sca_cmd() + # SetKey command. + self.target.write(json.dumps("FixedKeySet").encode("ascii")) + # FixedKeySet payload. + time.sleep(0.01) + key_data = {"key": key, "key_length": key_length} + self.target.write(json.dumps(key_data).encode("ascii")) def write_lfsr_seed(self, seed): - """ Seed the LFSR. + """Seed the LFSR. Args: seed: The 4-byte seed. """ - if self.simple_serial: - self.target.write(cmd="l", data=seed) - else: - # KmacSca command. - self._ujson_kmac_sca_cmd() - # SeedLfsr command. - self.target.write(json.dumps("SeedLfsr").encode("ascii")) - # Seed payload. - time.sleep(0.01) - seed_int = [x for x in seed] - seed_data = {"seed": seed_int} - self.target.write(json.dumps(seed_data).encode("ascii")) + # KmacSca command. + self._ujson_kmac_sca_cmd() + # SeedLfsr command. + self.target.write(json.dumps("SeedLfsr").encode("ascii")) + # Seed payload. + time.sleep(0.01) + seed_int = [x for x in seed] + seed_data = {"seed": seed_int} + self.target.write(json.dumps(seed_data).encode("ascii")) def absorb_batch(self, num_segments): - """ Start absorb for batch. + """Start absorb for batch. Args: num_segments: Number of encryptions to perform. """ - if self.simple_serial: - self.target.write(cmd="b", data=num_segments.to_bytes(4, "little")) - else: - # KmacSca command. - self._ujson_kmac_sca_cmd() - # Batch command. - self.target.write(json.dumps("Batch").encode("ascii")) - # Num_segments payload. - time.sleep(0.01) - num_segments_data = {"num_enc": num_segments} - self.target.write(json.dumps(num_segments_data).encode("ascii")) + # KmacSca command. + self._ujson_kmac_sca_cmd() + # Batch command. + self.target.write(json.dumps("Batch").encode("ascii")) + # Num_segments payload. + time.sleep(0.01) + num_segments_data = {"num_enc": num_segments} + self.target.write(json.dumps(num_segments_data).encode("ascii")) - def absorb(self, text, text_length: Optional[int] = 16): - """ Write plaintext to OpenTitan KMAC & start absorb. + def absorb_daisy_chain(self, text, key, num_segments): + """Start absorb for daisy chain batch. Args: - text: The plaintext bytearray. + num_segments: Number of encryptions to perform. + text: The input message + key: The KMAC128 key """ - if self.simple_serial: - self.target.write(cmd="p", data=text) - else: - # KmacSca command. - self._ujson_kmac_sca_cmd() - # SingleAbsorb command. - self.target.write(json.dumps("SingleAbsorb").encode("ascii")) - # Msg payload. - time.sleep(0.01) - text_int = [x for x in text] - text_data = {"msg": text_int, "msg_length": text_length} - self.target.write(json.dumps(text_data).encode("ascii")) - - def read_ciphertext(self, len_bytes): - """ Read ciphertext from OpenTitan KMAC. - Args: - len_bytes: Number of bytes to read. + # KmacSca command. + self._ujson_kmac_sca_cmd() + # BatchDaisy command. + self.target.write(json.dumps("BatchDaisy").encode("ascii")) + # Num_segments payload. + time.sleep(0.01) + num_it_data = {"num_enc": num_segments} + self.target.write(json.dumps(num_it_data).encode("ascii")) + message_data = {"msg": text, "msg_length": len(text)} + self.target.write(json.dumps(message_data).encode("ascii")) + key_data = {"key": key, "key_length": len(key)} + self.target.write(json.dumps(key_data).encode("ascii")) - Returns: - The received ciphertext. - """ - if self.simple_serial: - response_byte = self.target.read("r", len_bytes, ack=False) - # Convert response into int array. - return [x for x in response_byte] - else: - while True: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - json_string = read_line.split("RESP_OK:")[1].split(" CRC:")[0] - try: - batch_digest = json.loads(json_string)["batch_digest"] - return batch_digest[0:len_bytes] - except Exception: - pass # noqa: E302 - - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from Ibex SCA framework. + def absorb(self, text, text_length: Optional[int] = 16): + """Write plaintext to OpenTitan KMAC & start absorb. Args: - max_tries: Maximum number of attempts to read from UART. - - Returns: - The JSON response of OpenTitan. + text: The plaintext bytearray. """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" + # KmacSca command. + self._ujson_kmac_sca_cmd() + # SingleAbsorb command. + self.target.write(json.dumps("SingleAbsorb").encode("ascii")) + # Msg payload. + time.sleep(0.01) + text_int = [x for x in text] + text_data = {"msg": text_int, "msg_length": text_length} + self.target.write(json.dumps(text_data).encode("ascii")) diff --git a/target/communication/sca_otbn_commands.py b/target/communication/sca_otbn_commands.py index ecb09080..325a8347 100644 --- a/target/communication/sca_otbn_commands.py +++ b/target/communication/sca_otbn_commands.py @@ -3,20 +3,18 @@ # SPDX-License-Identifier: Apache-2.0 """Communication interface for the OTBN SCA application on OpenTitan. -Communication with OpenTitan either happens over simpleserial or the uJson +Communication with OpenTitan happens the uJson command interface. """ import json import time -from typing import Optional + +from target.communication import common_library class OTOTBN: - def __init__(self, target, protocol: str) -> None: + def __init__(self, target) -> None: self.target = target - self.simple_serial = True - if protocol == "ujson": - self.simple_serial = False def _ujson_otbn_sca_cmd(self): # TODO: without the delay, the device uJSON command handler program @@ -24,88 +22,82 @@ def _ujson_otbn_sca_cmd(self): time.sleep(0.01) self.target.write(json.dumps("OtbnSca").encode("ascii")) - def init(self, enable_icache: bool, enable_dummy_instr: bool, - enable_jittery_clock: bool, enable_sram_readback: bool) -> list: - """ Initializes OTBN on the target. - Args: - enable_icache: If true, enable the iCache. - enable_dummy_instr: If true, enable the dummy instructions. - enable_jittery_clock: If true, enable the jittery clock. - enable_sram_readback: If true, enable the SRAM readback feature. + def init( + self, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + ) -> tuple: + """Initializes the Otbn SCA tests on the target. + Returns: - The device ID and countermeasure config of the device. + Device id + The owner info page + The boot log + The boot measurements + The testOS version """ - if not self.simple_serial: - # OtbnSca command. - self._ujson_otbn_sca_cmd() - # Init the OTBN core. - self.target.write(json.dumps("Init").encode("ascii")) - # Configure device and countermeasures. - time.sleep(0.01) - data = {"enable_icache": enable_icache, "enable_dummy_instr": enable_dummy_instr, - "enable_jittery_clock": enable_jittery_clock, - "enable_sram_readback": enable_sram_readback} - self.target.write(json.dumps(data).encode("ascii")) - # Read back device ID and countermeasure configuration from device. - device_config = self.read_response(max_tries=30) - # Read flash owner page. - device_config += self.read_response(max_tries=30) - # Read boot log. - device_config += self.read_response(max_tries=30) - # Read boot measurements. - device_config += self.read_response(max_tries=30) - # Read pentest framework version. - device_config += self.read_response(max_tries=30) - return device_config + + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Init command. + time.sleep(0.01) + self.target.write(json.dumps("Init").encode("ascii")) + + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + + device_id = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return device_id, owner_page, boot_log, boot_measurements, version def init_keymgr(self): - """ Initializes the key manager for OTBN on the target. - """ - if not self.simple_serial: - # OtbnSca command. - self._ujson_otbn_sca_cmd() - # Init the key manager. - self.target.write(json.dumps("InitKeyMgr").encode("ascii")) + """Initializes the key manager for OTBN on the target.""" + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Init the key manager. + self.target.write(json.dumps("InitKeyMgr").encode("ascii")) def key_sideload_fvsr(self, seed: int): - """ Starts the key sidloading FvsR test on OTBN. + """Starts the key sidloading FvsR test on OTBN. Args: seed: The fixed seed used by the key manager. """ - if not self.simple_serial: - # OtbnSca command. - self._ujson_otbn_sca_cmd() - # Start the KeySideloadFvsr test. - self.target.write(json.dumps("KeySideloadFvsr").encode("ascii")) - time.sleep(0.01) - seed_data = {"fixed_seed": seed} - self.target.write(json.dumps(seed_data).encode("ascii")) + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Start the KeySideloadFvsr test. + self.target.write(json.dumps("KeySideloadFvsr").encode("ascii")) + time.sleep(0.01) + seed_data = {"fixed_seed": seed} + self.target.write(json.dumps(seed_data).encode("ascii")) def ecdsa_p256_sign(self, masking_on: bool, msg, d0, k0): - """ Starts the EcdsaP256Sign test on OTBN. + """Starts the EcdsaP256Sign test on OTBN. Args: masking_on: Turn on/off masking. msg: Message array (8xuint32_t) d0: Message array (10xuint32_t) k0: Message array (10xuint32_t) """ - if not self.simple_serial: - # OtbnSca command. - self._ujson_otbn_sca_cmd() - # Start the EcdsaP256Sign test. - self.target.write(json.dumps("EcdsaP256Sign").encode("ascii")) - time.sleep(0.01) - # Configure masking. - masks = {"en_masks": masking_on} - self.target.write(json.dumps(masks).encode("ascii")) - time.sleep(0.01) - # Send msg, d0, and k0. - data = {"msg": msg, "d0": d0, "ko": k0} - self.target.write(json.dumps(data).encode("ascii")) - time.sleep(0.01) + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Start the EcdsaP256Sign test. + self.target.write(json.dumps("EcdsaP256Sign").encode("ascii")) + time.sleep(0.01) + # Configure masking. + masks = {"en_masks": masking_on} + self.target.write(json.dumps(masks).encode("ascii")) + time.sleep(0.01) + # Send msg, d0, and k0. + data = {"msg": msg, "d0": d0, "ko": k0} + self.target.write(json.dumps(data).encode("ascii")) + time.sleep(0.01) def ecdsa_p256_sign_batch(self, num_traces: int, masking_on: bool, msg, d0, k0): - """ Starts the EcdsaP256SignBatch test on OTBN. + """Starts the EcdsaP256SignBatch test on OTBN. Args: num_traces: Number of batch operations. masking_on: Turn on/off masking. @@ -113,27 +105,28 @@ def ecdsa_p256_sign_batch(self, num_traces: int, masking_on: bool, msg, d0, k0): d0: Message array (10xuint32_t) k0: Message array (10xuint32_t) """ - if not self.simple_serial: - # OtbnSca command. - self._ujson_otbn_sca_cmd() - # Start the EcdsaP256SignBatch test. - self.target.write(json.dumps("EcdsaP256Sign").encode("ascii")) - time.sleep(0.01) - # Configure number of traces. - num_traces = {"num_traces": num_traces} - self.target.write(json.dumps(num_traces).encode("ascii")) - time.sleep(0.01) - # Configure masking. - masks = {"en_masks": masking_on} - self.target.write(json.dumps(masks).encode("ascii")) - time.sleep(0.01) - # Send msg, d0, and k0. - data = {"msg": msg, "d0": d0, "ko": k0} - self.target.write(json.dumps(data).encode("ascii")) - time.sleep(0.01) + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Start the EcdsaP256SignBatch test. + self.target.write(json.dumps("EcdsaP256Sign").encode("ascii")) + time.sleep(0.01) + # Configure number of traces. + num_traces = {"num_traces": num_traces} + self.target.write(json.dumps(num_traces).encode("ascii")) + time.sleep(0.01) + # Configure masking. + masks = {"en_masks": masking_on} + self.target.write(json.dumps(masks).encode("ascii")) + time.sleep(0.01) + # Send msg, d0, and k0. + data = {"msg": msg, "d0": d0, "ko": k0} + self.target.write(json.dumps(data).encode("ascii")) + time.sleep(0.01) - def ecdsa_p256_sign_batch_fvsr(self, num_traces: int, masking_on: bool, msg, d0, k0): - """ Starts the EcdsaP256SignFvsrBatch test on OTBN. + def ecdsa_p256_sign_batch_fvsr( + self, num_traces: int, masking_on: bool, msg, d0, k0 + ): + """Starts the EcdsaP256SignFvsrBatch test on OTBN. Args: num_traces: Number of batch operations. masking_on: Turn on/off masking. @@ -141,128 +134,45 @@ def ecdsa_p256_sign_batch_fvsr(self, num_traces: int, masking_on: bool, msg, d0, d0: Message array (10xuint32_t) k0: Message array (10xuint32_t) """ - if not self.simple_serial: - # OtbnSca command. - self._ujson_otbn_sca_cmd() - # Start the EcdsaP256SignBatch test. - self.target.write(json.dumps("EcdsaP256SignFvsrBatch").encode("ascii")) - time.sleep(0.01) - # Configure number of traces. - num_traces = {"num_traces": num_traces} - self.target.write(json.dumps(num_traces).encode("ascii")) - time.sleep(0.01) - # Configure masking. - masks = {"en_masks": masking_on} - self.target.write(json.dumps(masks).encode("ascii")) - time.sleep(0.01) - # Send msg, d0, and k0. - data = {"msg": msg, "d0": d0, "ko": k0} - self.target.write(json.dumps(data).encode("ascii")) - time.sleep(0.01) - - def choose_otbn_app(self, app): - """ Select the OTBN application. - Args: - app: OTBN application - """ - if self.simple_serial: - # Select the otbn app on the device (0 -> keygen, 1 -> modinv). - if app == 'keygen': - self.target.write(cmd="a", data=bytearray([0x00])) - if app == 'modinv': - self.target.write(cmd="a", data=bytearray([0x01])) - - def write_batch_prng_seed(self, seed): - """ Seed the PRNG. - Args: - seed: The 4-byte seed. - """ - if self.simple_serial: - self.target.write(cmd="s", data=seed) - - def write_keygen_seed(self, seed): - """ Write the seed used for the keygen app. - Args: - seed: byte array containing the seed. - """ - if self.simple_serial: - self.target.write(cmd='x', data=seed) - - def write_keygen_key_constant_redundancy(self, const): - """ Write the constant redundancy value for the keygen app. - Args: - seed: byte array containing the redundancy value. - """ - if self.simple_serial: - self.target.write(cmd="c", data=const) - - def config_keygen_masking(self, off): - """ Disable/enable masking. - Args: - off: boolean value. - """ - if self.simple_serial: - # Enable/disable masking. - if off is True: - self.target.write(cmd="m", data=bytearray([0x00])) - else: - self.target.write(cmd="m", data=bytearray([0x01])) - - def start_keygen(self, mask): - """ Write the seed mask and start the keygen app. - Args: - mask: byte array containing the mask value. - """ - if self.simple_serial: - # Send the mask and start the keygen operation. - self.target.write('k', mask) - - def start_modinv(self, scalar_k0, scalar_k1): - """ Write the two scalar shares and start the modinv app. - Args: - scalar_k0: byte array containing the first scalar share. - scalar_k1: byte array containing the second scalar share. - """ - if self.simple_serial: - # Start modinv device computation. - self.target.write('q', scalar_k0 + scalar_k1) - - def start_keygen_batch(self, test_type, num_segments): - """ Start the keygen app in batch mode. - Args: - test_type: string selecting the test type (KEY or SEED). - num_segments: number of keygen executions to perform. - """ - if self.simple_serial: - # Start batch keygen. - if test_type == 'KEY': - self.target.write(cmd="e", data=num_segments) - else: - self.target.write(cmd="b", data=num_segments) - - def read_output(self, len_bytes): - """ Read the output from whichever OTBN app. - Args: - len_bytes: Number of bytes to read. - - Returns: - The received output. - """ - if self.simple_serial: - return self.target.read("r", len_bytes, ack=False) + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Start the EcdsaP256SignBatch test. + self.target.write(json.dumps("EcdsaP256SignFvsrBatch").encode("ascii")) + time.sleep(0.01) + # Configure number of traces. + num_traces = {"num_traces": num_traces} + self.target.write(json.dumps(num_traces).encode("ascii")) + time.sleep(0.01) + # Configure masking. + masks = {"en_masks": masking_on} + self.target.write(json.dumps(masks).encode("ascii")) + time.sleep(0.01) + # Send msg, d0, and k0. + data = {"msg": msg, "d0": d0, "ko": k0} + self.target.write(json.dumps(data).encode("ascii")) + time.sleep(0.01) - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from OTBN SCA framework. + def start_combi_ops_batch( + self, num_iterations, fixed_data1, fixed_data2, print_flag, trigger + ): + """Start the combi ops app in batch mode. Args: - max_tries: Maximum number of attempts to read from UART. - - Returns: - The JSON response of OpenTitan. - """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" + num_iterations: How many traces per batch. + fixed_data1: The first fixed input. + fixed_data2: The second fixed input. + print_flag: Whether to print an output or an empty RESP_OK. + trigger: Which triggers to raise. + """ + # OtbnSca command. + self._ujson_otbn_sca_cmd() + # Start the CombiOps test. + self.target.write(json.dumps("CombiOps").encode("ascii")) + time.sleep(0.01) + data = { + "num_iterations": num_iterations, + "fixed_data1": fixed_data1, + "fixed_data2": fixed_data2, + "print_flag": print_flag, + "trigger": trigger, + } + self.target.write(json.dumps(data).encode("ascii")) diff --git a/target/communication/sca_prng_commands.py b/target/communication/sca_prng_commands.py index a1592992..cc821aa9 100644 --- a/target/communication/sca_prng_commands.py +++ b/target/communication/sca_prng_commands.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 """Communication interface for the PRNG SCA application on OpenTitan. -Communication with OpenTitan either happens over simpleserial or the uJson +Communication with OpenTitan happens over the uJson command interface. """ import json @@ -12,30 +12,24 @@ class OTPRNG: - def __init__(self, target, protocol: str) -> None: + def __init__(self, target) -> None: self.target = target - self.simple_serial = True - if protocol == "ujson": - self.simple_serial = False def _ujson_prng_sca_cmd(self): time.sleep(0.01) self.target.write(json.dumps("PrngSca").encode("ascii")) def seed_prng(self, seed, seed_length: Optional[int] = 4): - """ Seed the PRNG. + """Seed the PRNG. Args: seed: The 4-byte seed. """ - if self.simple_serial: - self.target.write(cmd="s", data=seed) - else: - # PrngSca command. - self._ujson_prng_sca_cmd() - # SingleEncrypt command. - time.sleep(0.01) - self.target.write(json.dumps("SeedPrng").encode("ascii")) - # Text payload. - seed_int = [x for x in seed] - seed_data = {"seed": seed_int, "seed_length": seed_length} - self.target.write(json.dumps(seed_data).encode("ascii")) + # PrngSca command. + self._ujson_prng_sca_cmd() + # SingleEncrypt command. + time.sleep(0.01) + self.target.write(json.dumps("SeedPrng").encode("ascii")) + # Text payload. + seed_int = [x for x in seed] + seed_data = {"seed": seed_int, "seed_length": seed_length} + self.target.write(json.dumps(seed_data).encode("ascii")) diff --git a/target/communication/sca_sha3_commands.py b/target/communication/sca_sha3_commands.py index ee0a0362..442c942e 100644 --- a/target/communication/sca_sha3_commands.py +++ b/target/communication/sca_sha3_commands.py @@ -3,20 +3,19 @@ # SPDX-License-Identifier: Apache-2.0 """Communication interface for the SHA3 SCA application on OpenTitan. -Communication with OpenTitan either happens over simpleserial or the uJson +Communication with OpenTitan happens over the uJson command interface. """ import json import time from typing import Optional +from target.communication import common_library + class OTSHA3: - def __init__(self, target, protocol: str) -> None: + def __init__(self, target) -> None: self.target = target - self.simple_serial = True - if protocol == "ujson": - self.simple_serial = False def _ujson_sha3_sca_cmd(self): # TODO: without the delay, the device uJSON command handler program @@ -24,44 +23,42 @@ def _ujson_sha3_sca_cmd(self): time.sleep(0.01) self.target.write(json.dumps("Sha3Sca").encode("ascii")) - def init(self, fpga_mode_bit: int, enable_icache: bool, enable_dummy_instr: bool, - enable_jittery_clock: bool, enable_sram_readback: bool) -> list: - """ Initializes SHA3 on the target. + def init( + self, + fpga_mode_bit: int, + core_config: dict = common_library.default_core_config, + sensor_config: dict = common_library.default_sensor_config, + ) -> tuple: + """Initializes SHA3 on the target. Args: - fpga_mode_bit: Indicates whether FPGA specific SHA3 test is started. - enable_icache: If true, enable the iCache. - enable_dummy_instr: If true, enable the dummy instructions. - enable_jittery_clock: If true, enable the jittery clock. - enable_sram_readback: If true, enable the SRAM readback feature. + fpga_mode_bit: Indicates whether FPGA specific KMAC test is started. Returns: - The device ID and countermeasure config of the device. + Device id + The owner info page + The boot log + The boot measurements + The testOS version """ - if not self.simple_serial: - # Sha3Sca command. - self._ujson_sha3_sca_cmd() - # Init the SHA3 core. - self.target.write(json.dumps("Init").encode("ascii")) - # FPGA mode. - time.sleep(0.01) - fpga_mode = {"fpga_mode": fpga_mode_bit} - self.target.write(json.dumps(fpga_mode).encode("ascii")) - # Configure device and countermeasures. - time.sleep(0.01) - data = {"enable_icache": enable_icache, "enable_dummy_instr": enable_dummy_instr, - "enable_jittery_clock": enable_jittery_clock, - "enable_sram_readback": enable_sram_readback} - self.target.write(json.dumps(data).encode("ascii")) - # Read back device ID and countermeasure configuration from device. - device_config = self.read_response(max_tries=30) - # Read flash owner page. - device_config += self.read_response(max_tries=30) - # Read boot log. - device_config += self.read_response(max_tries=30) - # Read boot measurements. - device_config += self.read_response(max_tries=30) - # Read pentest framework version. - device_config += self.read_response(max_tries=30) - return device_config + + # Sha3Sca command. + self._ujson_sha3_sca_cmd() + # Init the SHA3 core. + self.target.write(json.dumps("Init").encode("ascii")) + # FPGA mode. + time.sleep(0.01) + fpga_mode = {"fpga_mode": fpga_mode_bit} + self.target.write(json.dumps(fpga_mode).encode("ascii")) + + # Write each configuration block to the target. + self.target.write(json.dumps(core_config).encode("ascii")) + self.target.write(json.dumps(sensor_config).encode("ascii")) + + device_id = self.target.read_response() + owner_page = self.target.read_response() + boot_log = self.target.read_response() + boot_measurements = self.target.read_response() + version = self.target.read_response() + return device_id, owner_page, boot_log, boot_measurements, version def _ujson_sha3_sca_ack(self, num_attempts: Optional[int] = 100): # Wait for ack. @@ -74,7 +71,9 @@ def _ujson_sha3_sca_ack(self, num_attempts: Optional[int] = 100): if "status" in json_string: status = json.loads(json_string)["status"] if status != 0: - raise Exception("Acknowledge error: Device and host not in sync") + raise Exception( + "Acknowledge error: Device and host not in sync" + ) return status except Exception: raise Exception("Acknowledge error: Device and host not in sync") @@ -83,158 +82,86 @@ def _ujson_sha3_sca_ack(self, num_attempts: Optional[int] = 100): raise Exception("Acknowledge error: Device and host not in sync") def set_mask_off(self): - if self.simple_serial: - self.target.write(cmd="m", data=bytearray([0x01])) - ack_ret = self.target.wait_ack(5000) - if ack_ret is None: - raise Exception("Device and host not in sync") - else: - # Sha3Sca command. - self._ujson_sha3_sca_cmd() - # DisableMasking command. - self.target.write(json.dumps("DisableMasking").encode("ascii")) - # masks_off payload. - time.sleep(0.01) - mask = {"masks_off": 1} - self.target.write(json.dumps(mask).encode("ascii")) - # Wait for ack. - self._ujson_sha3_sca_ack() + # Sha3Sca command. + self._ujson_sha3_sca_cmd() + # DisableMasking command. + self.target.write(json.dumps("DisableMasking").encode("ascii")) + # Num_segments payload. + time.sleep(0.01) + mask = {"masks_off": 1} + self.target.write(json.dumps(mask).encode("ascii")) + # Wait for ack. + self._ujson_sha3_sca_ack() def set_mask_on(self): - if self.simple_serial: - self.target.write(cmd="m", data=bytearray([0x00])) - ack_ret = self.target.wait_ack(5000) - if ack_ret is None: - raise Exception("Device and host not in sync") - else: - # Sha3Sca command. - self._ujson_sha3_sca_cmd() - # DisableMasking command. - self.target.write(json.dumps("DisableMasking").encode("ascii")) - # masks_off payload. - time.sleep(0.01) - mask = {"masks_off": 0} - self.target.write(json.dumps(mask).encode("ascii")) - # Wait for ack. - self._ujson_sha3_sca_ack() + # Sha3Sca command. + self._ujson_sha3_sca_cmd() + # DisableMasking command. + self.target.write(json.dumps("DisableMasking").encode("ascii")) + # Num_segments payload. + time.sleep(0.01) + mask = {"masks_off": 0} + self.target.write(json.dumps(mask).encode("ascii")) + # Wait for ack. + self._ujson_sha3_sca_ack() def absorb(self, text, text_length: Optional[int] = 16): - """ Write plaintext to OpenTitan SHA3 & start absorb. + """Write plaintext to OpenTitan SHA3 & start absorb. Args: text: The plaintext bytearray. """ - if self.simple_serial: - self.target.write(cmd="p", data=text) - else: - # Sha3Sca command. - self._ujson_sha3_sca_cmd() - # SingleAbsorb command. - self.target.write(json.dumps("SingleAbsorb").encode("ascii")) - # SingleAbsorb payload. - time.sleep(0.01) - text_int = [x for x in text] - text_data = {"msg": text_int, "msg_length": text_length} - self.target.write(json.dumps(text_data).encode("ascii")) + # Sha3Sca command. + self._ujson_sha3_sca_cmd() + # SingleAbsorb command. + self.target.write(json.dumps("SingleAbsorb").encode("ascii")) + # SingleAbsorb payload. + time.sleep(0.01) + text_int = [x for x in text] + text_data = {"msg": text_int, "msg_length": text_length} + self.target.write(json.dumps(text_data).encode("ascii")) def absorb_batch(self, num_segments): - """ Start absorb for batch. + """Start absorb for batch. Args: num_segments: Number of hashings to perform. """ - if self.simple_serial: - self.target.write(cmd="b", data=num_segments.to_bytes(4, "little")) - ack_ret = self.target.wait_ack(5000) - if ack_ret is None: - raise Exception("Batch mode acknowledge error: Device and host not in sync") - else: - # Sha3Sca command. - self._ujson_sha3_sca_cmd() - # Batch command. - self.target.write(json.dumps("Batch").encode("ascii")) - # Num_segments payload. - time.sleep(0.01) - num_segments_data = {"num_enc": num_segments} - self.target.write(json.dumps(num_segments_data).encode("ascii")) - # Wait for ack. - self._ujson_sha3_sca_ack() + # Sha3Sca command. + self._ujson_sha3_sca_cmd() + # Batch command. + self.target.write(json.dumps("Batch").encode("ascii")) + # Num_segments payload. + time.sleep(0.01) + num_segments_data = {"num_enc": num_segments} + self.target.write(json.dumps(num_segments_data).encode("ascii")) + # Wait for ack. + self._ujson_sha3_sca_ack() def write_lfsr_seed(self, seed): - """ Seed the LFSR. + """Seed the LFSR. Args: seed: The 4-byte seed. """ - if self.simple_serial: - self.target.write(cmd="l", data=seed) - else: - # Sha3Sca command. - self._ujson_sha3_sca_cmd() - # SeedLfsr command. - self.target.write(json.dumps("SeedLfsr").encode("ascii")) - # Seed payload. - time.sleep(0.01) - seed_int = [x for x in seed] - seed_data = {"seed": seed_int} - self.target.write(json.dumps(seed_data).encode("ascii")) + # Sha3Sca command. + self._ujson_sha3_sca_cmd() + # SeedLfsr command. + self.target.write(json.dumps("SeedLfsr").encode("ascii")) + # Seed payload. + time.sleep(0.01) + seed_int = [x for x in seed] + seed_data = {"seed": seed_int} + self.target.write(json.dumps(seed_data).encode("ascii")) def fvsr_fixed_msg_set(self, msg, msg_length: Optional[int] = 16): - """ Write the fixed message to SHA3. + """Write the fixed message to SHA3. Args: msg: Bytearray containing the message. """ - if self.simple_serial: - self.target.write(cmd="f", data=bytearray(msg)) - else: - # Sha3Sca command. - self._ujson_sha3_sca_cmd() - # FixedMessageSet command. - self.target.write(json.dumps("FixedMessageSet").encode("ascii")) - # Msg payload. - time.sleep(0.01) - msg_int = [x for x in msg] - msg_data = {"msg": msg_int, "msg_length": msg_length} - self.target.write(json.dumps(msg_data).encode("ascii")) - - def read_ciphertext(self, len_bytes, num_attempts: Optional[int] = 100): - """ Read ciphertext from OpenTitan SHA3. - Args: - len_bytes: Number of bytes to read. - num_attempts: Number of attempts to read from device. - - Returns: - The received ciphertext and a status flag indicating whether data - was received or not. - """ - if self.simple_serial: - response_byte = self.target.read("r", len_bytes, ack=False) - # Convert response into int array. - return [x for x in response_byte], True - else: - read_counter = 0 - while read_counter < num_attempts: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - json_string = read_line.split("RESP_OK:")[1].split(" CRC:")[0] - try: - batch_digest = json.loads(json_string)["batch_digest"] - return batch_digest[0:len_bytes], True - except Exception: - pass # noqa: E302 - read_counter += 1 - # Reading from device failed. - return None, False - - def read_response(self, max_tries: Optional[int] = 1) -> str: - """ Read response from Ibex SCA framework. - Args: - max_tries: Maximum number of attempts to read from UART. - - Returns: - The JSON response of OpenTitan. - """ - it = 0 - while it != max_tries: - read_line = str(self.target.readline()) - if "RESP_OK" in read_line: - return read_line.split("RESP_OK:")[1].split(" CRC:")[0] - it += 1 - return "" + # Sha3Sca command. + self._ujson_sha3_sca_cmd() + # FixedMessageSet command. + self.target.write(json.dumps("FixedMessageSet").encode("ascii")) + # Msg payload. + time.sleep(0.01) + msg_int = [x for x in msg] + msg_data = {"msg": msg_int, "msg_length": msg_length} + self.target.write(json.dumps(msg_data).encode("ascii")) diff --git a/target/communication/sca_trigger_commands.py b/target/communication/sca_trigger_commands.py index 8e4f04a7..c25bff50 100644 --- a/target/communication/sca_trigger_commands.py +++ b/target/communication/sca_trigger_commands.py @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 """Communication interface for the SHA3 SCA application on OpenTitan. -Communication with OpenTitan either happens over simpleserial or the uJson +Communication with OpenTitan happens over the uJson command interface. """ import json @@ -12,29 +12,23 @@ class OTTRIGGER: - def __init__(self, target, protocol: str) -> None: + def __init__(self, target) -> None: self.target = target - self.simple_serial = True - if protocol == "ujson": - self.simple_serial = False def select_trigger(self, trigger_source: Optional[int] = 0): - """ Select the trigger source for SCA. + """Select the trigger source for SCA. Args: trigger_source: - 0: Precise, hardware-generated trigger - FPGA only. - 1: Fully software-controlled trigger. """ - if self.simple_serial: - self.target.write(cmd="t", data=bytearray([trigger_source])) - else: - # TODO(#256): without the delay, the device uJSON command handler program - # does not recognize the commands. - time.sleep(0.01) - self.target.write(json.dumps("TriggerSca").encode("ascii")) - # SelectTriggerSource command. - self.target.write(json.dumps("SelectTriggerSource").encode("ascii")) - # Source payload. - time.sleep(0.01) - src = {"source": trigger_source} - self.target.write(json.dumps(src).encode("ascii")) + # TODO(#256): without the delay, the device uJSON command handler program + # does not recognize the commands. + time.sleep(0.01) + self.target.write(json.dumps("TriggerSca").encode("ascii")) + # SelectTriggerSource command. + self.target.write(json.dumps("SelectTriggerSource").encode("ascii")) + # Source payload. + time.sleep(0.01) + src = {"source": trigger_source} + self.target.write(json.dumps(src).encode("ascii")) diff --git a/target/cw_fpga.py b/target/cw_fpga.py index 2f417c56..855e1003 100644 --- a/target/cw_fpga.py +++ b/target/cw_fpga.py @@ -49,31 +49,34 @@ class CWFPGA(object): target binary. """ - def __init__(self, bitstream, force_programming, firmware, pll_frequency, - baudrate, output_len, protocol, usb_serial, husky_serial): + def __init__( + self, + bitstream, + force_programming, + firmware, + pll_frequency, + baudrate, + usb_serial, + husky_serial, + ): self.bitstream = bitstream self.firmware = firmware self.pll_frequency = pll_frequency self.baudrate = baudrate - self.output_len = output_len self.usb_serial = usb_serial self.husky_serial = husky_serial # Extract target board type from bitstream name. - m = re.search('cw305|cw310', bitstream) + m = re.search("cw305|cw310", bitstream) if m: - if m.group() == 'cw305': + if m.group() == "cw305": self.fpga_type = cw.capture.targets.CW305() else: - assert m.group() == 'cw310' + assert m.group() == "cw310" self.fpga_type = cw.capture.targets.CW310() programmer = SpiProgrammer(self.fpga_type, self.usb_serial) else: - raise ValueError( - 'Could not infer target board type from bistream name') - self.prot_simple_serial = True - if protocol == "ujson": - self.prot_simple_serial = False + raise ValueError("Could not infer target board type from bistream name") # Initialize ChipWhisperer scope. This is needed to program the binary. # Note that the actual scope config for capturing traces is later # initialized. @@ -82,23 +85,20 @@ def __init__(self, bitstream, force_programming, firmware, pll_frequency, # Initializing the scope twice seems to solve the problem. self.scope = cw.scope(sn=self.husky_serial) - self.fpga = self.initialize_fpga(self.fpga_type, bitstream, - force_programming, pll_frequency) + self.fpga = self.initialize_fpga( + self.fpga_type, bitstream, force_programming, pll_frequency + ) - self.target = self.initialize_target(programmer, firmware, baudrate, - output_len, pll_frequency) + self.target = self.initialize_target( + programmer, firmware, baudrate, pll_frequency + ) - # TODO: add version check also for uJson binary. - if self.prot_simple_serial: - self._test_read_version_from_target() - - def initialize_fpga(self, fpga, bitstream, force_programming, - pll_frequency): + def initialize_fpga(self, fpga, bitstream, force_programming, pll_frequency): """Initializes FPGA bitstream and sets PLL frequency.""" # Do not program the FPGA if it is already programmed. # Note: Set this to True to force programming the FPGA when using a new # bitstream. - print('Connecting and loading FPGA... ', end='', flush = True) + print("Connecting and loading FPGA... ", end="", flush=True) # Runtime patch fpga.fpga.FPGAProgram to detect if it was actually called. # Note: This is fragile and may break but it is easy to miss that the FPGA @@ -111,7 +111,12 @@ def program_callback(): with RuntimePatchFPGAProgram(fpga.fpga, program_callback): # Connect to the FPGA and program it. - fpga.con(bsfile=bitstream, force=force_programming, slurp=False, sn=self.usb_serial) + fpga.con( + bsfile=bitstream, + force=force_programming, + slurp=False, + sn=self.usb_serial, + ) if not programmed: # TODO: Update this message when we have this in the CLI. stack_top = inspect.stack()[0] @@ -121,7 +126,7 @@ def program_callback(): fpga.vccint_set(1.0) - print('Initializing PLL1') + print("Initializing PLL1") fpga.pll.pll_enable_set(True) fpga.pll.pll_outenable_set(False, 0) fpga.pll.pll_outenable_set(True, 1) @@ -139,8 +144,7 @@ def program_callback(): return fpga - def initialize_target(self, programmer, firmware, baudrate, output_len, - pll_frequency): + def initialize_target(self, programmer, firmware, baudrate, pll_frequency): """Loads firmware image and initializes test target.""" # The bootstrapping always runs at 100 MHz. if pll_frequency != PLL_FREQUENCY_DEFAULT: @@ -155,27 +159,13 @@ def initialize_target(self, programmer, firmware, baudrate, output_len, time.sleep(0.5) target = cw.target(self.scope) - target.output_len = output_len - target.baud = int(baudrate * pll_frequency / PLL_FREQUENCY_DEFAULT) + target.baud = int(self.baudrate * pll_frequency / PLL_FREQUENCY_DEFAULT) target.flush() return target - def _test_read_version_from_target(self): - version = None - ping_cnt = 0 - while not version: - if ping_cnt == 3: - raise RuntimeError( - f'No response from the target (attempts: {ping_cnt}).') - self.target.write('v' + '\n') - ping_cnt += 1 - time.sleep(0.5) - version = self.target.read().strip() - print(f'Target simpleserial version: {version} (attempts: {ping_cnt}).') - def program_target(self, fw, pll_frequency=PLL_FREQUENCY_DEFAULT): - """Loads firmware image """ + """Loads firmware image""" programmer1 = SpiProgrammer(self.fpga, self.usb_serial) # To fully capture the long OTBN applications, # we may need to use pll_frequencies other than 100 MHz. @@ -194,7 +184,7 @@ def program_target(self, fw, pll_frequency=PLL_FREQUENCY_DEFAULT): time.sleep(0.5) def reset_target(self): - """Resets the target. """ + """Resets the target.""" # Check if FPGA bitstream is corrupted by reading the state of INITB. if self.fpga.INITB_state() is not True: print("Reprogram the FPGA.") @@ -203,15 +193,16 @@ def reset_target(self): self.scope = cw.scope(sn=self.husky_serial) - self.fpga = self.initialize_fpga(self.fpga_type, self.bitstream, - True, self.pll_frequency) + self.fpga = self.initialize_fpga( + self.fpga_type, self.bitstream, True, self.pll_frequency + ) - self.target = self.initialize_target(programmer, self.firmware, - self.baudrate, self.output_len, - self.pll_frequency) - # TODO: add version check also for uJson binary. - if self.prot_simple_serial: - self._test_read_version_from_target() + self.target = self.initialize_target( + programmer, + self.firmware, + self.baudrate, + self.pll_frequency, + ) else: # Bitstream seems to be OK, reset OpenTitan. print("Reset OpenTitan.") diff --git a/target/targets.py b/target/targets.py index 47fea073..65df5bc4 100644 --- a/target/targets.py +++ b/target/targets.py @@ -7,6 +7,7 @@ from typing import Optional import serial +from serial.tools.list_ports import comports from target.chip import Chip from target.cw_fpga import CWFPGA @@ -14,14 +15,13 @@ @dataclass class TargetConfig: - """ Target configuration. + """Target configuration. Stores information about the target. """ + target_type: str fw_bin: str - protocol: str - pll_frequency: int - output_len: int + pll_frequency: Optional[int] = 100000000 bitstream: Optional[str] = None force_program_bitstream: Optional[bool] = False baudrate: Optional[int] = None @@ -30,104 +30,212 @@ class TargetConfig: interface: Optional[str] = "hyper310" usb_serial: Optional[str] = None husky_serial: Optional[str] = None + opentitantool: Optional[str] = None class Target: - """ Target class. + """Target class. Represents a SCA/FI target. Currently, ChipWhisperer FPGA boards or the discrete OpenTitan chip are supported. """ + + # This is a fixed baudrate. + baudrate = 115200 + # Due to a bug in the UART of the CW340, we need to send each byte separately + # and add a small timeout before sending the next one. + # This contains the calculation of the delay. + pacing = 10 / baudrate + def __init__(self, target_cfg: TargetConfig) -> None: self.target_cfg = target_cfg - self.target = self._init_target() - self.com_interface = self._init_communication() + + if target_cfg.baudrate is None: + target_cfg.baudrate = 115200 + + self.com_interface = self._init_communication( + self.find_target_port(), self.target_cfg.baudrate + ) + + if target_cfg.fw_bin is not None: + self.target = self._init_target() def _init_target(self): - """ Init target. + """Init target. Configure OpenTitan on CW FPGA or the discrete chip. """ target = None - if self.target_cfg.target_type == "cw305" or self.target_cfg.target_type == "cw310": + if ( + self.target_cfg.target_type == "cw305" or + self.target_cfg.target_type == "cw310" + ): target = CWFPGA( - bitstream = self.target_cfg.bitstream, - force_programming = self.target_cfg.force_program_bitstream, - firmware = self.target_cfg.fw_bin, - pll_frequency = self.target_cfg.pll_frequency, - baudrate = self.target_cfg.baudrate, - output_len = self.target_cfg.output_len, - protocol = self.target_cfg.protocol, - usb_serial = self.target_cfg.usb_serial, - husky_serial = self.target_cfg.husky_serial + bitstream=self.target_cfg.bitstream, + force_programming=self.target_cfg.force_program_bitstream, + firmware=self.target_cfg.fw_bin, + pll_frequency=self.target_cfg.pll_frequency, + baudrate=self.target_cfg.baudrate, + usb_serial=self.target_cfg.usb_serial, + husky_serial = self.target_cfg.husky_serial, ) elif self.target_cfg.target_type == "chip": - target = Chip(firmware = self.target_cfg.fw_bin, - opentitantool_path = "../objs/opentitantool", - usb_serial = self.target_cfg.usb_serial, - interface = self.target_cfg.interface) + target = Chip(opentitantool_path=self.target_cfg.opentitantool) + target.flash_target(self.target_cfg.fw_bin) else: raise RuntimeError("Error: Target not supported!") + # Flush the output + self.dump_all() return target - def _init_communication(self): - """ Open the communication interface. + def _init_communication(self, port, baudrate): + """Open the communication interface. Configure OpenTitan on CW FPGA or the discrete chip. """ com_interface = None - if self.target_cfg.protocol == "simpleserial": - com_interface = self.target.target - elif self.target_cfg.protocol == "ujson": - if self.target_cfg.port is None or self.target_cfg.baudrate is None: - raise RuntimeError("Error: Invalid port or baudrate provided!") - com_interface = serial.Serial(self.target_cfg.port) - com_interface.baudrate = self.target_cfg.baudrate - com_interface.timeout = self.target_cfg.read_timeout - else: - raise RuntimeError("Error: Communication protocol not supported!") + com_interface = serial.Serial(port) + com_interface.baudrate = baudrate + com_interface.timeout = 1 return com_interface + def find_target_port(self): + # First go to the manual set port. + if self.target_cfg.port is not None: + return self.target_cfg.port + # Depending on the target find the port automatically. + if self.target_cfg.target_type == "cw310": + return self.find_target_port_cw310() + if self.target_cfg.target_type == "chip": + return self.find_target_port_hyperdebug() + + # Here we failed to find a known target_type. + print("Unknown target_type!") + return None + + def find_target_port_hyperdebug(self): + for port in comports(): + if "UART2" in port.description and "HyperDebug" in port.description: + return port.device + print("Target not found!") + return None + + def find_target_port_cw310(self): + for port in comports(): + # TODO: needs to be tested and specified to take the correct UART + if "c310" in port.product and "11070" in port.vid: + return port.device + print("Target not found!") + return None + def reset_target(self, com_reset: Optional[bool] = False): - """Resets the target. """ + """Resets the target.""" self.target.reset_target() - if com_reset and self.target_cfg.protocol == "ujson": - self.com_interface = self._init_communication() + if com_reset: + self.com_interface = self._init_communication( + self.find_target_port(), self.target_cfg.baudrate + ) def write(self, data, cmd: Optional[str] = ""): - """Write data to the target. """ - if self.target_cfg.protocol == "simpleserial": - self.com_interface.simpleserial_write(cmd, data) - else: - self.com_interface.write(data) + """Write data to the target.""" + self.com_interface.write(data) def readline(self): - """read line. Only for uJSON. """ - if self.target_cfg.protocol == "ujson": - return self.com_interface.readline() - else: - raise RuntimeError("Error: read_line only available for uJSON!") - - def read(self, cmd: str, len_bytes: int, ack: Optional[bool] = False): - """Read. Only for simpleserial. """ - if self.target_cfg.protocol == "simpleserial": - return self.com_interface.simpleserial_read(cmd, len_bytes, ack=ack) - else: - raise RuntimeError("Error: read only available for simpleserial!") - - def wait_ack(self, time: Optional[int] = None): - """Wait_ack. Only for simpleserial. """ - if self.target_cfg.protocol == "simpleserial": - if time is None: - return self.com_interface.simpleserial_wait_ack() - else: - return self.com_interface.simpleserial_wait_ack(time) - else: - raise RuntimeError("Error: wait_ack only available for simpleserial!") + """read line. Only for uJSON.""" + return self.com_interface.readline() def is_done(self): """Check if target is done. Only for CWFPGA.""" - if self.target_cfg.target_type == "cw305" or self.target_cfg.target_type == "cw310": + if ( + self.target_cfg.target_type == "cw305" or + self.target_cfg.target_type == "cw310" + ): return self.target.target.is_done() else: return True + + def print_all(self, max_tries=50): + it = 0 + while it != max_tries: + read_line = str(self.readline().decode().strip()) + if len(read_line) > 0: + print(read_line, flush=True) + else: + break + it += 1 + + def dump_all(self, max_tries=50): + it = 0 + while it != max_tries: + read_line = str(self.readline()) + if len(read_line) <= 5: + break + it += 1 + + def check_fault_or_read_reponse(self, max_tries=50): + """ + Args: + max_tries: Maximum number of attempts to read from UART. + + Returns: + - The JSON response of OpenTitan or the line containing FAULT. + - True if the chip gave a response, False if it ran into a fault. + """ + it = 0 + while it != max_tries: + try: + read_line = str(self.readline()) + if "FAULT" in read_line: + return read_line, False + if "RESP_OK" in read_line: + return read_line.split("RESP_OK:")[1].split(" CRC:")[0], True + it += 1 + except UnicodeDecodeError: + it += 1 + continue + return "", False + + def check_reset_or_read_reponse(self, max_tries=50): + """ + Args: + max_tries: Maximum number of attempts to read from UART. + + Returns: + - The JSON response of OpenTitan or the line containing Chip flashed. + - True if the chip gave a response, False if the chip resetted. + """ + it = 0 + while it != max_tries: + try: + read_line = str(self.readline()) + if "Chip flashed" in read_line: + return read_line, False + if "RESP_OK" in read_line: + return read_line.split("RESP_OK:")[1].split(" CRC:")[0], True + it += 1 + except UnicodeDecodeError: + it += 1 + continue + return "", False + + def read_response(self, max_tries: Optional[int] = 50): + """ + Args: + max_tries: Maximum number of attempts to read from UART. + + Returns: + The JSON response of OpenTitan. + """ + it = 0 + while it < max_tries: + try: + read_line = str(self.readline().decode().strip()) + except UnicodeDecodeError: + break + if len(read_line) > 0: + if "RESP_OK" in read_line: + return read_line.split("RESP_OK:")[1].split(" CRC:")[0] + else: + break + it += 1 + return "" diff --git a/test/cmd.py b/test/cmd.py index 8032dfa7..3b27702f 100644 --- a/test/cmd.py +++ b/test/cmd.py @@ -11,18 +11,18 @@ class Args: """Command-line arguments""" - def __init__(self, cmd: Union[str, 'list[str]']): + def __init__(self, cmd: Union[str, "list[str]"]): """Construct arguments from a string or from a list of strings. If a single string is given, split the string on spaces to form separate arguments. If a list of strings is given, take each string in the list as one argument. """ if isinstance(cmd, str): - self._args = cmd.split(' ') + self._args = cmd.split(" ") else: self._args = cmd - def __add__(self, other: 'Args') -> 'Args': + def __add__(self, other: "Args") -> "Args": """Concatenate two argument lists and return the result.""" return Args(list(self) + list(other)) @@ -56,26 +56,30 @@ def __init__(self, args: Args): def __repr__(self) -> str: return f"Cmd({self._args})" - def run(self) -> 'Cmd': + def run(self) -> "Cmd": """Run the command as subprocess and capture its stdout and stderr. If the expected returncode is not None, assert that it matches the actual returncode. """ - self._proc = subprocess.Popen(self._args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + self._proc = subprocess.Popen( + self._args, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) self._stdout, self._stderr = self._proc.communicate() self._returncode = self._proc.returncode if self._exp_returncode is not None: assert self._returncode == self._exp_returncode, ( f"{self._args} returned {self._returncode} instead of {self._exp_returncode}, " - f"with the following stderr:\n{self.stderr_utf8()}") + f"with the following stderr:\n{self.stderr_utf8()}" + ) return self - def set_exp_returncode(self, exp_returncode) -> 'Cmd': + def set_exp_returncode(self, exp_returncode) -> "Cmd": """Set the expected returncode. - To disable any assertions on the returncode, set the expected returncode to None.""" + To disable any assertions on the returncode, set the expected returncode to None. + """ self._exp_returncode = exp_returncode return self diff --git a/test/repo.py b/test/repo.py index 35f4292d..c5cfcfe8 100644 --- a/test/repo.py +++ b/test/repo.py @@ -30,7 +30,7 @@ def __init__(self, subpath: Union[str, Path]): The subpath argument is a string or a Path object, relative to the test data directory. """ - self._path = REPO_PATH / 'test' / 'data' / subpath + self._path = REPO_PATH / "test" / "data" / subpath def __str__(self) -> str: return str(self._path) diff --git a/test/tvla_test.py b/test/tvla_test.py index c5288e5f..e024e46e 100644 --- a/test/tvla_test.py +++ b/test/tvla_test.py @@ -11,14 +11,14 @@ class TvlaCmd(RepoCmd): def __init__(self, args: Args): # Insert (relative) path to TVLA before the given arguments. - args = Args('analysis/tvla.py') + args + args = Args("analysis/tvla.py") + args super().__init__(args) def test_help(): - tvla = TvlaCmd(Args('--help')).run() + tvla = TvlaCmd(Args("--help")).run() # Assert that a message is printed on stdout or stderr. - assert (len(tvla.stdout()) != 0 or len(tvla.stderr()) != 0) + assert len(tvla.stdout()) != 0 or len(tvla.stderr()) != 0 def ttest_significant(ttest_trace) -> bool: @@ -36,68 +36,137 @@ def ttest_compare_results(expected, received, delta) -> bool: Checks if all numerical values match within precision delta. """ nan_match = np.all(np.isnan(expected) == np.isnan(received)) - numbers_match = np.all(np.logical_or(np.isnan(expected), np.abs(expected - received) < delta)) + numbers_match = np.all( + np.logical_or(np.isnan(expected), np.abs(expected - received) < delta) + ) return nan_match and numbers_match def test_general_kmac_nonleaking_project(): - project_path = TestDataPath('tvla_general/ci_opentitan_simple_kmac.cwp') - tvla = TvlaCmd(Args(['--project-file', str(project_path), - '--mode', 'kmac', '--save-to-disk-ttest', '--test-type', 'GENERAL_KEY', - '--number-of-steps', '10', 'run-tvla'])).run() - expected_path = TestDataPath('tvla_general/ttest-step-golden-kmac.npy.npz') + project_path = TestDataPath("tvla_general/ci_opentitan_simple_kmac.cwp") + tvla = TvlaCmd( + Args( + [ + "--project-file", + str(project_path), + "--mode", + "kmac", + "--save-to-disk-ttest", + "--test-type", + "GENERAL_KEY", + "--number-of-steps", + "10", + "run-tvla", + ] + ) + ).run() + expected_path = TestDataPath("tvla_general/ttest-step-golden-kmac.npy.npz") expected_file = np.load(str(expected_path)) - expected_trace = expected_file['ttest_step'] - received_file = np.load('tmp/ttest-step.npy.npz') - received_trace = received_file['ttest_step'] + expected_trace = expected_file["ttest_step"] + received_file = np.load("tmp/ttest-step.npy.npz") + received_trace = received_file["ttest_step"] # Expected and received traces should be equal within precision delta. # Small mismatch is possible due to the differences in floating point operations # on different machines. delta = 0.001 - assert ttest_compare_results(expected_trace, received_trace, delta), ( - f"{tvla} generated ttest_step values that don't match the expected ones") + assert ttest_compare_results( + expected_trace, received_trace, delta + ), f"{tvla} generated ttest_step values that don't match the expected ones" def test_general_aes_nonleaking_project(): - project_path = TestDataPath('tvla_general/ci_opentitan_simple_aes_fvsr.cwp') - tvla = TvlaCmd(Args(['--project-file', str(project_path), - '--mode', 'aes', '--save-to-disk-ttest', '--test-type', 'GENERAL_KEY', - '--number-of-steps', '10', 'run-tvla'])).run() - expected_path = TestDataPath('tvla_general/ttest-step-golden-aes.npy.npz') + project_path = TestDataPath("tvla_general/ci_opentitan_simple_aes_fvsr.cwp") + tvla = TvlaCmd( + Args( + [ + "--project-file", + str(project_path), + "--mode", + "aes", + "--save-to-disk-ttest", + "--test-type", + "GENERAL_KEY", + "--number-of-steps", + "10", + "run-tvla", + ] + ) + ).run() + expected_path = TestDataPath("tvla_general/ttest-step-golden-aes.npy.npz") expected_file = np.load(str(expected_path)) - expected_trace = expected_file['ttest_step'] - received_file = np.load('tmp/ttest-step.npy.npz') - received_trace = received_file['ttest_step'] + expected_trace = expected_file["ttest_step"] + received_file = np.load("tmp/ttest-step.npy.npz") + received_trace = received_file["ttest_step"] delta = 0.001 - assert ttest_compare_results(expected_trace, received_trace, delta), ( - f"{tvla} generated ttest_step values that don't match the expected ones") + assert ttest_compare_results( + expected_trace, received_trace, delta + ), f"{tvla} generated ttest_step values that don't match the expected ones" def test_general_leaking_histogram(): - hist_path = TestDataPath('tvla_general/kmac_hist_leaking.npz') - tvla = TvlaCmd(Args(['--input-histogram-file', str(hist_path), - '--mode', 'kmac', '--save-to-disk-ttest', '--test-type', 'GENERAL_KEY', - 'run-tvla'])).run() - assert ttest_significant(np.load('tmp/ttest.npy')), ( - f"{tvla} did not find significant leakage, which is unexpected") + hist_path = TestDataPath("tvla_general/kmac_hist_leaking.npz") + tvla = TvlaCmd( + Args( + [ + "--input-histogram-file", + str(hist_path), + "--mode", + "kmac", + "--save-to-disk-ttest", + "--test-type", + "GENERAL_KEY", + "run-tvla", + ] + ) + ).run() + assert ttest_significant( + np.load("tmp/ttest.npy") + ), f"{tvla} did not find significant leakage, which is unexpected" def test_general_nonleaking_histogram(): - hist_path = TestDataPath('tvla_general/kmac_hist_nonleaking.npz') - tvla = TvlaCmd(Args(['--input-histogram-file', str(hist_path), - '--mode', 'kmac', '--save-to-disk-ttest', '--test-type', 'GENERAL_KEY', - 'run-tvla'])).run() - assert not ttest_significant(np.load('tmp/ttest.npy')), ( - f"{tvla} did find significant leakage, which is unexpected") + hist_path = TestDataPath("tvla_general/kmac_hist_nonleaking.npz") + tvla = TvlaCmd( + Args( + [ + "--input-histogram-file", + str(hist_path), + "--mode", + "kmac", + "--save-to-disk-ttest", + "--test-type", + "GENERAL_KEY", + "run-tvla", + ] + ) + ).run() + assert not ttest_significant( + np.load("tmp/ttest.npy") + ), f"{tvla} did find significant leakage, which is unexpected" def test_aes_byte_filtering(): - project_path = TestDataPath('tvla_aes_byte/ci_opentitan_simple_aes.cwp') - tvla = TvlaCmd(Args(['--project-file', str(project_path), - '--mode', 'aes', '--round-select', '0', - '--byte-select', '0', '--save-to-disk', '--test-type', 'SPECIFIC_BYTE', - 'run-tvla'])).run() - received_file = np.load('tmp/traces.npy.npz') - traces_to_use = received_file['traces_to_use'] - assert sum(traces_to_use) <= 100, ( - f"{tvla} filtered less than 90 % of the input traces, which is unexpected.") + project_path = TestDataPath("tvla_aes_byte/ci_opentitan_simple_aes.cwp") + tvla = TvlaCmd( + Args( + [ + "--project-file", + str(project_path), + "--mode", + "aes", + "--round-select", + "0", + "--byte-select", + "0", + "--save-to-disk", + "--test-type", + "SPECIFIC_BYTE", + "run-tvla", + ] + ) + ).run() + received_file = np.load("tmp/traces.npy.npz") + traces_to_use = received_file["traces_to_use"] + assert ( + sum(traces_to_use) <= 100 + ), f"{tvla} filtered less than 90 % of the input traces, which is unexpected." diff --git a/util/check_version.py b/util/check_version.py index b28d5377..c2faea10 100644 --- a/util/check_version.py +++ b/util/check_version.py @@ -8,7 +8,7 @@ def check_cw(cw_version_exp: str) -> None: - """ Check ChipWhisperer API version. + """Check ChipWhisperer API version. Read CW API version and compare against expected version. @@ -18,13 +18,16 @@ def check_cw(cw_version_exp: str) -> None: Returns: Raises a runtime error on a mismatch. """ - cw_version = cw.version.__version__ + cw_version = cw.__version__ if cw_version != cw_version_exp: - raise RuntimeError(f"Please update the Python requirements. CW version: {cw_version}, expected CW version: {cw_version_exp}") # noqa: E501 + raise RuntimeError( + f"Please update the Python requirements. CW version: \ + {cw_version}, expected CW version: {cw_version_exp}" + ) # noqa: E501 def check_husky(husky_fw_exp: str, sn: Optional[str] = None) -> None: - """ Check ChipWhisperer Husky firmware version. + """Check ChipWhisperer Husky firmware version. Read CW Husky FW version and compare against expected version. @@ -39,4 +42,7 @@ def check_husky(husky_fw_exp: str, sn: Optional[str] = None) -> None: else: husky_fw = cw.scope().fw_version_str if husky_fw != husky_fw_exp: - raise RuntimeError(f"Please update the Husky firmware. FW version: {husky_fw}, expected FW version: {husky_fw_exp}") # noqa: E501 + raise RuntimeError( + f"Please update the Husky firmware. FW version: {husky_fw}, \ + expected FW version: {husky_fw_exp}" + ) # noqa: E501 diff --git a/util/cw_to_trs.py b/util/cw_to_trs.py index 196cb168..37510dde 100755 --- a/util/cw_to_trs.py +++ b/util/cw_to_trs.py @@ -29,22 +29,20 @@ def gen_trs_headers(project, export_key): trs file header. """ return { - trsfile.Header.LABEL_X: 's', - trsfile.Header.LABEL_Y: 'V', + trsfile.Header.LABEL_X: "s", + trsfile.Header.LABEL_Y: "V", trsfile.Header.NUMBER_SAMPLES: len(project.waves[0]), - trsfile.Header.TRACE_TITLE: 'title', + trsfile.Header.TRACE_TITLE: "title", trsfile.Header.TRACE_OVERLAP: False, trsfile.Header.GO_LAST_TRACE: False, trsfile.Header.SAMPLE_CODING: trsfile.SampleCoding.FLOAT, - trsfile.Header.LENGTH_DATA: len(gen_trs_data(project.traces[0], - export_key)), - + trsfile.Header.LENGTH_DATA: len(gen_trs_data(project.traces[0], export_key)), # TODO: Hardcoded to 200mV. Consider calculating the range directly from # the traces. trsfile.Header.ACQUISITION_RANGE_OF_SCOPE: 0.200, trsfile.Header.ACQUISITION_COUPLING_OF_SCOPE: 1, trsfile.Header.ACQUISITION_OFFSET_OF_SCOPE: 0.0, - trsfile.Header.ACQUISITION_DEVICE_ID: b'CWHusky', + trsfile.Header.ACQUISITION_DEVICE_ID: b"CWHusky", trsfile.Header.ACQUISITION_TYPE_FILTER: 0, } @@ -65,16 +63,19 @@ def calc_data_offsets(trace, export_key, header): key_offset = output_offset + output_len key_len = len(trace.key) - header.update({ - trsfile.Header.INPUT_OFFSET: input_offset, - trsfile.Header.INPUT_LENGTH: input_len, - trsfile.Header.OUTPUT_OFFSET: output_offset, - trsfile.Header.OUTPUT_LENGTH: output_len, - }) + header.update( + { + trsfile.Header.INPUT_OFFSET: input_offset, + trsfile.Header.INPUT_LENGTH: input_len, + trsfile.Header.OUTPUT_OFFSET: output_offset, + trsfile.Header.OUTPUT_LENGTH: output_len, + } + ) if export_key: - header.update({trsfile.Header.KEY_OFFSET: key_offset, - trsfile.Header.KEY_LENGTH: key_len}) + header.update( + {trsfile.Header.KEY_OFFSET: key_offset, trsfile.Header.KEY_LENGTH: key_len} + ) def gen_trs_data(trace, export_key): @@ -100,43 +101,44 @@ def cw_project_to_trs(project_name, trs_filename, export_keys): trs_filename: Output filename for trs result. export_keys: Set to true to include the keys in the trs output. """ - print(f'input project: {project_name}') + print(f"input project: {project_name}") p = cw.open_project(project_name) - print(f'num_traces: {len(p.traces)}') - print(f'num_samples per trace: {len(p.waves[0])}') - print(f'output file: {trs_filename}') + print(f"num_traces: {len(p.traces)}") + print(f"num_samples per trace: {len(p.waves[0])}") + print(f"output file: {trs_filename}") h = gen_trs_headers(p, export_keys) calc_data_offsets(p.traces[0], export_keys, h) traces = [] - for trace in tqdm(p.traces, desc='Converting', ncols=80): - traces.append(trsfile.Trace(trsfile.SampleCoding.FLOAT, trace.wave, - data=gen_trs_data(trace, export_keys))) - - print('Writing output file, this may take a while.') - with trsfile.trs_open(trs_filename, 'w', engine='TrsEngine', headers=h, - live_update=True) as t: + for trace in tqdm(p.traces, desc="Converting", ncols=80): + traces.append( + trsfile.Trace( + trsfile.SampleCoding.FLOAT, + trace.wave, + data=gen_trs_data(trace, export_keys), + ) + ) + + print("Writing output file, this may take a while.") + with trsfile.trs_open( + trs_filename, "w", engine="TrsEngine", headers=h, live_update=True + ) as t: t.extend(traces) def parse_args(): """Parse command line arguments.""" parser = argparse.ArgumentParser() - parser.add_argument('--input', - '-i', - type=str, - required=True, - help="Input ChipWhisperer project.") - parser.add_argument('--output', - '-o', - type=str, - required=True, - help="Output trs filename.") - parser.add_argument('--export-key', - '-k', - action='store_true', - help="Include keys in data output.") + parser.add_argument( + "--input", "-i", type=str, required=True, help="Input ChipWhisperer project." + ) + parser.add_argument( + "--output", "-o", type=str, required=True, help="Output trs filename." + ) + parser.add_argument( + "--export-key", "-k", action="store_true", help="Include keys in data output." + ) args = parser.parse_args() return args diff --git a/util/db_to_zarr_converter.py b/util/db_to_zarr_converter.py index 647f8298..76768344 100644 --- a/util/db_to_zarr_converter.py +++ b/util/db_to_zarr_converter.py @@ -14,7 +14,7 @@ from tqdm import tqdm ABS_PATH = os.path.dirname(os.path.abspath(__file__)) -sys.path.append(ABS_PATH + '/..') +sys.path.append(ABS_PATH + "/..") from capture.project_library.project import ProjectConfig # noqa: E402 from capture.project_library.project import SCAProject # noqa: E402 @@ -22,7 +22,7 @@ def parse_arguments(argv): - """ Command line argument parsing. + """Command line argument parsing. Args: argv: The command line arguments. @@ -31,30 +31,38 @@ def parse_arguments(argv): The parsed arguments. """ parser = argparse.ArgumentParser(description="Parse") - parser.add_argument("-i", - "--input_db", - dest="input_db", - type=helpers.ap_check_file_exists, - required=True, - help="Path of the input database") - parser.add_argument("-o", - "--output_db", - dest="output_db", - type=helpers.ap_check_dir_exists, - required=True, - help="Path of the output database") - parser.add_argument("-f", - "--db_format", - dest="db_format", - type=str, - required=True, - help="'cw' or 'ot_trace_library'") - parser.add_argument("-m", - "--max_traces_mem", - dest="max_traces_mem", - type=int, - required=True, - help="Maximum number of traces held in memory") + parser.add_argument( + "-i", + "--input_db", + dest="input_db", + type=helpers.ap_check_file_exists, + required=True, + help="Path of the input database", + ) + parser.add_argument( + "-o", + "--output_db", + dest="output_db", + type=helpers.ap_check_dir_exists, + required=True, + help="Path of the output database", + ) + parser.add_argument( + "-f", + "--db_format", + dest="db_format", + type=str, + required=True, + help="'cw' or 'ot_trace_library'", + ) + parser.add_argument( + "-m", + "--max_traces_mem", + dest="max_traces_mem", + type=int, + required=True, + help="Maximum number of traces held in memory", + ) args = parser.parse_args(argv) @@ -71,12 +79,13 @@ def main(argv=None): args = parse_arguments(argv) # Init project. - project_cfg = ProjectConfig(type = args.db_format, - path = args.input_db, - wave_dtype = np.uint16, - overwrite = False, - trace_threshold = args.max_traces_mem - ) + project_cfg = ProjectConfig( + type=args.db_format, + path=args.input_db, + wave_dtype=np.uint16, + overwrite=False, + trace_threshold=args.max_traces_mem, + ) project_in = SCAProject(project_cfg) project_in.open_project() metadata = project_in.get_metadata() @@ -94,7 +103,7 @@ def main(argv=None): shape=(0, len(project_in.get_waves(0))), chunks=(num_traces, len(project_in.get_waves(0))), dtype=np.int16, - compressor=compressor + compressor=compressor, ) zarr_group_tile.zeros( @@ -102,7 +111,7 @@ def main(argv=None): shape=(0, len(project_in.get_plaintexts(0))), chunks=(num_traces, len(project_in.get_plaintexts(0))), dtype=np.uint8, - compressor=compressor_metadata + compressor=compressor_metadata, ) zarr_group_tile.zeros( @@ -110,7 +119,7 @@ def main(argv=None): shape=(0, len(project_in.get_ciphertexts(0))), chunks=(num_traces, len(project_in.get_ciphertexts(0))), dtype=np.uint8, - compressor=compressor_metadata + compressor=compressor_metadata, ) zarr_group_tile.zeros( @@ -118,11 +127,13 @@ def main(argv=None): shape=(0, len(project_in.get_keys(0))), chunks=(num_traces, len(project_in.get_keys(0))), dtype=np.uint8, - compressor=compressor_metadata + compressor=compressor_metadata, ) trace_end = 0 - for trace_it in tqdm(range(0, num_traces, args.max_traces_mem), desc='Converting trace'): + for trace_it in tqdm( + range(0, num_traces, args.max_traces_mem), desc="Converting trace" + ): trace_end += args.max_traces_mem # Fetch trace, plaintext, ciphertext, and key from DB. in_traces = np.array(project_in.get_waves(trace_it, trace_end)) diff --git a/util/helpers.py b/util/helpers.py index 39089c70..13a949d4 100644 --- a/util/helpers.py +++ b/util/helpers.py @@ -83,7 +83,7 @@ def ap_check_dir_exists(path: str) -> Path: def parse_arguments(argv): - """ Command line argument parsing. + """Command line argument parsing. Args: argv: The command line arguments. @@ -92,36 +92,46 @@ def parse_arguments(argv): The parsed arguments. """ parser = argparse.ArgumentParser(description="Parse") - parser.add_argument("-c", - "--capture_config", - dest="cfg", - type=ap_check_file_exists, - required=True, - help="Path of the attack config file") - parser.add_argument("-p", - "--project", - dest="project", - type=ap_check_dir_exists, - required=True, - help="Path of the output project directory") - parser.add_argument("-n", - "--note", - dest="notes", - type=str, - required=False, - help="Notes to be stored in the project database") - parser.add_argument("-b", - "--save_bitstream", - dest="save_bitstream", - type=bool, - required=False, - help="Save bitstream into project database") - parser.add_argument("-f", - "--save_binary", - dest="save_binary", - type=bool, - required=False, - help="Save binary into project database") + parser.add_argument( + "-c", + "--capture_config", + dest="cfg", + type=ap_check_file_exists, + required=True, + help="Path of the attack config file", + ) + parser.add_argument( + "-p", + "--project", + dest="project", + type=ap_check_dir_exists, + required=True, + help="Path of the output project directory", + ) + parser.add_argument( + "-n", + "--note", + dest="notes", + type=str, + required=False, + help="Notes to be stored in the project database", + ) + parser.add_argument( + "-b", + "--save_bitstream", + dest="save_bitstream", + type=bool, + required=False, + help="Save bitstream into project database", + ) + parser.add_argument( + "-f", + "--save_binary", + dest="save_binary", + type=bool, + required=False, + help="Save binary into project database", + ) args = parser.parse_args(argv) diff --git a/util/histograms.py b/util/histograms.py index 0ebfba36..a6f2be70 100644 --- a/util/histograms.py +++ b/util/histograms.py @@ -7,7 +7,7 @@ def compute_histograms_general(trace_resolution, traces, leakage): - """ Building histograms for general fixed-vs-random TVLA. + """Building histograms for general fixed-vs-random TVLA. For each time sample we make two histograms, one for the fixed and one for the random group. Whether a trace belongs to the fixed or random group is indicated in the leakage input @@ -19,19 +19,23 @@ def compute_histograms_general(trace_resolution, traces, leakage): num_rnds = 1 num_bytes = 1 num_samples = traces.shape[1] - histograms = np.zeros((num_rnds, num_bytes, num_leakages, num_samples, trace_resolution), - dtype=np.uint32) + histograms = np.zeros( + (num_rnds, num_bytes, num_leakages, num_samples, trace_resolution), + dtype=np.uint32, + ) for i_sample in range(num_samples): histograms[0, 0, :, i_sample, :] = np.histogram2d( - leakage, traces[:, i_sample], - bins=[range(num_leakages + 1), range(trace_resolution + 1)])[0] + leakage, + traces[:, i_sample], + bins=[range(num_leakages + 1), range(trace_resolution + 1)], + )[0] return histograms def compute_histograms_aes_byte(trace_resolution, rnd_list, byte_list, traces, leakage): - """ Building histograms for AES. + """Building histograms for AES. For each time sample we make two histograms, one for Hamming weight of the sensitive variable = 0 (fixed set) and one for Hamming weight > 0 (random set). The value stored in @@ -42,21 +46,28 @@ def compute_histograms_aes_byte(trace_resolution, rnd_list, byte_list, traces, l num_rnds = len(rnd_list) num_bytes = len(byte_list) num_samples = traces.shape[1] - histograms = np.zeros((num_rnds, num_bytes, num_leakages, num_samples, trace_resolution), - dtype=np.uint32) + histograms = np.zeros( + (num_rnds, num_bytes, num_leakages, num_samples, trace_resolution), + dtype=np.uint32, + ) for i_rnd in range(num_rnds): for i_byte in range(num_bytes): for i_sample in range(num_samples): histograms[i_rnd, i_byte, :, i_sample, :] = np.histogram2d( - leakage[rnd_list[i_rnd], byte_list[i_byte], :], traces[:, i_sample], - bins=[np.append(range(num_leakages), 9), range(trace_resolution + 1)])[0] + leakage[rnd_list[i_rnd], byte_list[i_byte], :], + traces[:, i_sample], + bins=[ + np.append(range(num_leakages), 9), + range(trace_resolution + 1), + ], + )[0] return histograms def compute_histograms_aes_bit(trace_resolution, rnd_list, bit_list, traces, leakage): - """ Building histograms for AES. + """Building histograms for AES. For each time sample we make two histograms, one for selected bit value = 0 (fixed set) and one for selected bit value = 1 (random set). @@ -67,14 +78,18 @@ def compute_histograms_aes_bit(trace_resolution, rnd_list, bit_list, traces, lea num_rnds = len(rnd_list) num_bits = len(bit_list) num_samples = traces.shape[1] - histograms = np.zeros((num_rnds, num_bits, num_leakages, num_samples, trace_resolution), - dtype=np.uint32) + histograms = np.zeros( + (num_rnds, num_bits, num_leakages, num_samples, trace_resolution), + dtype=np.uint32, + ) for i_rnd in range(num_rnds): for i_bit in range(num_bits): for i_sample in range(num_samples): histograms[i_rnd, i_bit, :, i_sample, :] = np.histogram2d( - leakage[rnd_list[i_rnd], bit_list[i_bit], :], traces[:, i_sample], - bins=[range(num_leakages + 1), range(trace_resolution + 1)])[0] + leakage[rnd_list[i_rnd], bit_list[i_bit], :], + traces[:, i_sample], + bins=[range(num_leakages + 1), range(trace_resolution + 1)], + )[0] return histograms diff --git a/util/leakage_models.py b/util/leakage_models.py index 896ecf16..11be8225 100644 --- a/util/leakage_models.py +++ b/util/leakage_models.py @@ -27,7 +27,7 @@ def byte2bits(int_no): return c -def compute_leakage_aes_byte(keys, plaintexts, leakage_model = 'HAMMING_WEIGHT'): +def compute_leakage_aes_byte(keys, plaintexts, leakage_model="HAMMING_WEIGHT"): """ Computes byte-based AES leakage for a given list of plaintexts and keys. @@ -47,16 +47,14 @@ def compute_leakage_aes_byte(keys, plaintexts, leakage_model = 'HAMMING_WEIGHT') if key_fixed: for j in range(11): - subkey[j] = np.asarray( - aes_funcs.key_schedule_rounds(keys[0], 0, j)) + subkey[j] = np.asarray(aes_funcs.key_schedule_rounds(keys[0], 0, j)) subkey = subkey.astype(int) for i in range(num_traces): if not key_fixed: for j in range(11): - subkey[j] = np.asarray( - aes_funcs.key_schedule_rounds(keys[i], 0, j)) + subkey[j] = np.asarray(aes_funcs.key_schedule_rounds(keys[i], 0, j)) subkey = subkey.astype(int) # Init @@ -66,9 +64,8 @@ def compute_leakage_aes_byte(keys, plaintexts, leakage_model = 'HAMMING_WEIGHT') old_state = state state = np.bitwise_xor(state, subkey[0]) for k in range(16): - if leakage_model == 'HAMMING_DISTANCE': - leakage[0][k][i] = bit_count( - np.bitwise_xor(state[k], old_state[k])) + if leakage_model == "HAMMING_DISTANCE": + leakage[0][k][i] = bit_count(np.bitwise_xor(state[k], old_state[k])) else: leakage[0][k][i] = bit_count(state[k]) @@ -77,20 +74,19 @@ def compute_leakage_aes_byte(keys, plaintexts, leakage_model = 'HAMMING_WEIGHT') old_state = state state = aes_funcs.subbytes(state) state = aes_funcs.shiftrows(state) - if (j < 10): + if j < 10: state = aes_funcs.mixcolumns(state) state = np.bitwise_xor(state, subkey[j]) for k in range(16): - if leakage_model == 'HAMMING_DISTANCE': - leakage[j][k][i] = bit_count( - np.bitwise_xor(state[k], old_state[k])) + if leakage_model == "HAMMING_DISTANCE": + leakage[j][k][i] = bit_count(np.bitwise_xor(state[k], old_state[k])) else: leakage[j][k][i] = bit_count(state[k]) return leakage -def compute_leakage_aes_bit(keys, plaintexts, leakage_model = 'HAMMING_WEIGHT'): +def compute_leakage_aes_bit(keys, plaintexts, leakage_model="HAMMING_WEIGHT"): """ Computes bit-based AES leakage for a given list of plaintexts and keys. @@ -110,16 +106,14 @@ def compute_leakage_aes_bit(keys, plaintexts, leakage_model = 'HAMMING_WEIGHT'): if key_fixed: for j in range(11): - subkey[j] = np.asarray( - aes_funcs.key_schedule_rounds(keys[0], 0, j)) + subkey[j] = np.asarray(aes_funcs.key_schedule_rounds(keys[0], 0, j)) subkey = subkey.astype(int) for i in range(num_traces): if not key_fixed: for j in range(11): - subkey[j] = np.asarray( - aes_funcs.key_schedule_rounds(keys[i], 0, j)) + subkey[j] = np.asarray(aes_funcs.key_schedule_rounds(keys[i], 0, j)) subkey = subkey.astype(int) # Init @@ -129,9 +123,8 @@ def compute_leakage_aes_bit(keys, plaintexts, leakage_model = 'HAMMING_WEIGHT'): old_state = state state = np.bitwise_xor(state, subkey[0]) for k in range(16): - if leakage_model == 'HAMMING_DISTANCE': - vec8 = byte2bits( - np.bitwise_xor(state[k], old_state[k])) + if leakage_model == "HAMMING_DISTANCE": + vec8 = byte2bits(np.bitwise_xor(state[k], old_state[k])) else: vec8 = byte2bits(state[k]) leakage[0][8 * k: 8 * k + 8, i] = vec8 @@ -141,11 +134,11 @@ def compute_leakage_aes_bit(keys, plaintexts, leakage_model = 'HAMMING_WEIGHT'): old_state = state state = aes_funcs.subbytes(state) state = aes_funcs.shiftrows(state) - if (j < 10): + if j < 10: state = aes_funcs.mixcolumns(state) state = np.bitwise_xor(state, subkey[j]) for k in range(16): - if leakage_model == 'HAMMING_DISTANCE': + if leakage_model == "HAMMING_DISTANCE": vec8 = byte2bits(np.bitwise_xor(state[k], old_state[k])) else: vec8 = byte2bits(state[k]) diff --git a/util/plot.py b/util/plot.py index 474af338..e6ad3793 100644 --- a/util/plot.py +++ b/util/plot.py @@ -15,8 +15,9 @@ from fault_injection.project_library.project import FISuccess -def save_plot_to_file(traces, set_indices, num_traces, outfile, - add_mean_stddev=False, ref_trace=None): +def save_plot_to_file( + traces, set_indices, num_traces, outfile, add_mean_stddev=False, ref_trace=None +): """Save plot figure to file.""" if set_indices is None: colors = itertools.cycle(palette) @@ -36,14 +37,21 @@ def save_plot_to_file(traces, set_indices, num_traces, outfile, for i in range(min(len(traces), num_traces)): if set_indices is None: if add_mean_stddev or ref_trace is not None: - plot.line(xrange, traces[i], line_color='grey') + plot.line(xrange, traces[i], line_color="grey") else: plot.line(xrange, traces[i], line_color=next(colors)) else: - plot.line(xrange, traces[i], line_color=next(colors), legend_label=str(set_indices[i])) + plot.line( + xrange, + traces[i], + line_color=next(colors), + legend_label=str(set_indices[i]), + ) if ref_trace is not None: - plot.line(xrange, ref_trace, line_color='firebrick', line_width=2, legend_label='mean') + plot.line( + xrange, ref_trace, line_color="firebrick", line_width=2, legend_label="mean" + ) if add_mean_stddev: # Add mean and std dev to figure @@ -55,18 +63,28 @@ def save_plot_to_file(traces, set_indices, num_traces, outfile, std = traces_new.std(axis=0) mean_stddev_upper = mean + std mean_stddev_lower = mean - std - plot.line(xrange, mean_stddev_upper, line_color='firebrick', - line_width=2, legend_label='std') - plot.line(xrange, mean_stddev_lower, line_color='firebrick', - line_width=2, legend_label='std') - plot.line(xrange, mean, line_color='black', line_width=2, legend_label='mean') + plot.line( + xrange, + mean_stddev_upper, + line_color="firebrick", + line_width=2, + legend_label="std", + ) + plot.line( + xrange, + mean_stddev_lower, + line_color="firebrick", + line_width=2, + legend_label="std", + ) + plot.line(xrange, mean, line_color="black", line_width=2, legend_label="mean") output_file(Path(str(outfile) + ".html")) show(plot) def save_fi_plot_to_file(cfg: dict, fi_results: [], outfile: str) -> None: - """ Print FI plot of traces. + """Print FI plot of traces. Printing the plot helps to narrow down the fault injection parameters. @@ -78,11 +96,11 @@ def save_fi_plot_to_file(cfg: dict, fi_results: [], outfile: str) -> None: output_file(Path(str(outfile) + ".html")) x_axis = cfg["fiproject"]["plot_x_axis"] y_axis = cfg["fiproject"]["plot_y_axis"] - plot = figure(plot_width=800, - x_range=(cfg["fisetup"][x_axis + "_min"], - cfg["fisetup"][x_axis + "_max"]), - y_range=(cfg["fisetup"][y_axis + "_min"], - cfg["fisetup"][y_axis + "_max"])) + plot = figure( + plot_width=800, + x_range=(cfg["fisetup"][x_axis + "_min"], cfg["fisetup"][x_axis + "_max"]), + y_range=(cfg["fisetup"][y_axis + "_min"], cfg["fisetup"][y_axis + "_max"]), + ) plot.xaxis.axis_label = x_axis + " " + cfg["fiproject"]["plot_x_axis_legend"] plot.yaxis.axis_label = y_axis + " " + cfg["fiproject"]["plot_y_axis_legend"] @@ -105,13 +123,24 @@ def save_fi_plot_to_file(cfg: dict, fi_results: [], outfile: str) -> None: no_y.append(fi_result_dict[y_axis]) if unexp_x: - plot.scatter(unexp_x, unexp_y, line_color="green", fill_color="green", - legend_label="Unexpected response") + plot.scatter( + unexp_x, + unexp_y, + line_color="green", + fill_color="green", + legend_label="Unexpected response", + ) if exp_x: - plot.scatter(exp_x, exp_y, line_color="orange", fill_color="orange", - legend_label="Expected response") + plot.scatter( + exp_x, + exp_y, + line_color="orange", + fill_color="orange", + legend_label="Expected response", + ) if no_x: - plot.scatter(no_x, no_y, line_color="red", fill_color="red", - legend_label="No response") + plot.scatter( + no_x, no_y, line_color="red", fill_color="red", legend_label="No response" + ) show(plot) diff --git a/util/spiflash.py b/util/spiflash.py index 830ac8ee..b5c44646 100644 --- a/util/spiflash.py +++ b/util/spiflash.py @@ -17,58 +17,64 @@ class SpiProgrammer: Initializes pins, resets OpenTitan, assert strap pins, and programs the flash. """ + # Pin mappings for CW305/CW310 boards. - PinMapping = namedtuple('PinMapping', [ - 'sck', - 'sdi', - 'sdo', - 'cs', - 'trst', - 'srst', - 'sw_strap0', - 'sw_strap1', - 'sw_strap2', - 'tap_strap0', - 'tap_strap1', - ]) + PinMapping = namedtuple( + "PinMapping", + [ + "sck", + "sdi", + "sdo", + "cs", + "trst", + "srst", + "sw_strap0", + "sw_strap1", + "sw_strap2", + "tap_strap0", + "tap_strap1", + ], + ) PIN_MAPPINGS = {} PIN_MAPPINGS[id(CW305)] = PinMapping( - sck='USB_A9', - sdi='USB_A10', - sdo='USB_A11', - cs='USB_A12', - trst='USB_A13', - srst='USB_A14', - sw_strap0='USB_A15', - sw_strap1='USB_A16', - sw_strap2='USB_A17', - tap_strap0='USB_A18', - tap_strap1='USB_A19', + sck="USB_A9", + sdi="USB_A10", + sdo="USB_A11", + cs="USB_A12", + trst="USB_A13", + srst="USB_A14", + sw_strap0="USB_A15", + sw_strap1="USB_A16", + sw_strap2="USB_A17", + tap_strap0="USB_A18", + tap_strap1="USB_A19", ) PIN_MAPPINGS[id(CW310)] = PinMapping( - sck='USB_SPI_SCK', - sdi='USB_SPI_COPI', - sdo='USB_SPI_CIPO', - cs='USB_SPI_CS', - trst='USB_A13', - srst='USB_A14', - sw_strap0='USB_A15', - sw_strap1='USB_A16', - sw_strap2='USB_A17', - tap_strap0='USB_A18', - tap_strap1='USB_A19', + sck="USB_SPI_SCK", + sdi="USB_SPI_COPI", + sdo="USB_SPI_CIPO", + cs="USB_SPI_CS", + trst="USB_A13", + srst="USB_A14", + sw_strap0="USB_A15", + sw_strap1="USB_A16", + sw_strap2="USB_A17", + tap_strap0="USB_A18", + tap_strap1="USB_A19", + ) + INITIAL_VALUES = PinMapping( + sck=0, + sdi=0, + sdo=0, + cs=0, + trst=1, + srst=1, + sw_strap0=0, + sw_strap1=0, + sw_strap2=0, + tap_strap0=0, + tap_strap1=0, ) - INITIAL_VALUES = PinMapping(sck=0, - sdi=0, - sdo=0, - cs=0, - trst=1, - srst=1, - sw_strap0=0, - sw_strap1=0, - sw_strap2=0, - tap_strap0=0, - tap_strap1=0) RESET_DELAY = 0.1 BUSY_POLL_DELAY = 0.01 @@ -90,10 +96,9 @@ def __init__(self, fpga, sn): self.io.pin_set_output(mapped_to) self.io.pin_set_state(mapped_to, getattr(self.INITIAL_VALUES, pin)) # Initialize SPI pins - self.io.spi1_setpins(sck=self.pins.sck, - sdo=self.pins.sdi, - sdi=self.pins.sdo, - cs=self.pins.cs) + self.io.spi1_setpins( + sck=self.pins.sck, sdo=self.pins.sdi, sdi=self.pins.sdo, cs=self.pins.cs + ) self.io.spi1_enable(True) def reset(self): @@ -132,7 +137,7 @@ def transceive(self, data): def read_status(self): """Reads the SPI Flash status register.""" - return self.transceive(bytes([0x05, 0xff]))[1] + return self.transceive(bytes([0x05, 0xFF]))[1] def write_enable(self): """Sends the write enable command.""" @@ -144,7 +149,7 @@ def write_enable_and_chip_erase(self): Also handles enabling writes and busy polling. """ self.write_enable() - self.transceive(bytes([0xc7])) + self.transceive(bytes([0xC7])) self.busy_poll() def write_enable_and_page_program(self, addr, data): @@ -153,8 +158,7 @@ def write_enable_and_page_program(self, addr, data): Also handles enabling writes and busy polling. """ self.write_enable() - packet = bytes([0x02]) + addr.to_bytes( - 3, byteorder="big", signed=False) + data + packet = bytes([0x02]) + addr.to_bytes(3, byteorder="big", signed=False) + data self.transceive(packet) self.busy_poll() @@ -171,16 +175,14 @@ def busy_poll(self): def bootstrap(self, binary): """Bootstraps OpenTitan with the given binary.""" - with open(binary, mode='rb') as f: + with open(binary, mode="rb") as f: with self.bootstrapper() as _: self.write_enable_and_chip_erase() # Read fixed-size blocks from the firmware image. # Note: The second argument ``b''`` to ``iter`` below is the sentinel value that # ends the loop, i.e. the value returned by ``f.read`` at EOF. addr = 0 - for data in iter(partial(f.read, self.PAYLOAD_SIZE), b''): - print( - f'Programming {len(data)} bytes at address 0x{addr:08x}.' - ) + for data in iter(partial(f.read, self.PAYLOAD_SIZE), b""): + print(f"Programming {len(data)} bytes at address 0x{addr:08x}.") self.write_enable_and_page_program(addr, data) addr += len(data) diff --git a/util/trace_util.py b/util/trace_util.py index 27405ae4..ebdc5664 100644 --- a/util/trace_util.py +++ b/util/trace_util.py @@ -6,13 +6,22 @@ def check_range(waves, bits_per_sample): - """ The ADC output is in the interval [0, 2**bits_per_sample-1]. Check that the recorded - traces are within [1, 2**bits_per_sample-2] to ensure the ADC doesn't saturate. """ + """The ADC output is in the interval [0, 2**bits_per_sample-1]. Check that the recorded + traces are within [1, 2**bits_per_sample-2] to ensure the ADC doesn't saturate.""" adc_range = np.array([0, 2**bits_per_sample]) if not (np.all(np.greater(waves[:], adc_range[0])) and np.all(np.less(waves[:], adc_range[1] - 1))): - print('\nWARNING: Some samples are outside the range [' + - str(adc_range[0] + 1) + ', ' + str(adc_range[1] - 2) + '].') - print('The ADC has a max range of [' + - str(adc_range[0]) + ', ' + str(adc_range[1] - 1) + '] and might saturate.') - print('It is recommended to reduce the scope gain.') + print( + "\nWARNING: Some samples are outside the range [" + + str(adc_range[0] + 1) + + ", " + + str(adc_range[1] - 2) + + "]." + ) + print( + "The ADC has a max range of [" + str(adc_range[0]) + + ", " + + str(adc_range[1] - 1) + + "] and might saturate." + ) + print("It is recommended to reduce the scope gain.") diff --git a/util/ttest.py b/util/ttest.py index 9c4599b6..44d45899 100644 --- a/util/ttest.py +++ b/util/ttest.py @@ -54,14 +54,9 @@ def ttest1_hist_xy(x_a, y_a, x_b, y_b): std2 = np.sqrt(var_hist_xy(x_b, y_b, mu2)) N1 = np.sum(y_a, axis=1) N2 = np.sum(y_b, axis=1) - return ttest_ind_from_stats(mu1, - std1, - N1, - mu2, - std2, - N2, - equal_var=False, - alternative='two-sided')[0] + return ttest_ind_from_stats( + mu1, std1, N1, mu2, std2, N2, equal_var=False, alternative="two-sided" + )[0] def ttest_hist_xy(x_a, y_a, x_b, y_b, num_orders): @@ -124,8 +119,8 @@ def ttest_hist_xy(x_a, y_a, x_b, y_b, num_orders): # Take the power and fill in the values. tmp_a = np.power(tmp_a, i_order + 1) tmp_b = np.power(tmp_b, i_order + 1) - x_a_ord[i_order * num_samples:(i_order + 1) * num_samples, :] = tmp_a - x_b_ord[i_order * num_samples:(i_order + 1) * num_samples, :] = tmp_b + x_a_ord[i_order * num_samples: (i_order + 1) * num_samples, :] = tmp_a + x_b_ord[i_order * num_samples: (i_order + 1) * num_samples, :] = tmp_b # Compute Welch's t-test for all requested orders. ttest = ttest1_hist_xy(x_a_ord, y_a_ord, x_b_ord, y_b_ord) diff --git a/util/update_husky_fw.py b/util/update_husky_fw.py index 500ff6d5..fb86a277 100755 --- a/util/update_husky_fw.py +++ b/util/update_husky_fw.py @@ -9,7 +9,7 @@ def parse_arguments(argv): - """ Command line argument parsing. + """Command line argument parsing. Args: argv: The command line arguments. @@ -18,12 +18,14 @@ def parse_arguments(argv): The parsed arguments. """ parser = argparse.ArgumentParser(description="Parse") - parser.add_argument("-s", - "--sn", - dest="sn", - type=int, - required=False, - help="Serial number of CW Husky") + parser.add_argument( + "-s", + "--sn", + dest="sn", + type=int, + required=False, + help="Serial number of CW Husky", + ) args = parser.parse_args(argv) @@ -31,7 +33,7 @@ def parse_arguments(argv): def update_fw(argv=None) -> None: - """ Check ChipWhisperer API version. + """Check ChipWhisperer API version. Read CW API version and compare against expected version.