From 4c3aa07711209b158a23b3703b263c078e14d637 Mon Sep 17 00:00:00 2001 From: tmeissner Date: Mon, 30 Nov 2020 19:09:45 +0100 Subject: [PATCH] Update CTR-AES testbench to use openSSL as reference, unpolished --- ctraes/sim/vhdl/Makefile | 5 +- ctraes/sim/vhdl/tb_ctraes.c | 164 ++++++++++++++++++++++++++++++++++ ctraes/sim/vhdl/tb_ctraes.vhd | 65 +++++++++----- 3 files changed, 211 insertions(+), 23 deletions(-) create mode 100644 ctraes/sim/vhdl/tb_ctraes.c diff --git a/ctraes/sim/vhdl/Makefile b/ctraes/sim/vhdl/Makefile index c2ef051..1a0bb84 100644 --- a/ctraes/sim/vhdl/Makefile +++ b/ctraes/sim/vhdl/Makefile @@ -29,6 +29,7 @@ RTL_SRC := \ SIM_SRC := tb_$(DESIGN_NAME).vhd +C_SRC := tb_ctraes.c OSVVM_DIR := ../../../lib/osvvm @@ -72,11 +73,11 @@ osvvm/OsvvmContext.o: $(OSVVM_SRC) | osvvm ghdl -a --std=$(VHD_STD) -Wno-hide --work=osvvm --workdir=osvvm $(OSVVM_SRC) -tb_$(DESIGN_NAME): ${RTL_SRC} ${SIM_SRC} osvvm/OsvvmContext.o | work +tb_$(DESIGN_NAME): ${RTL_SRC} ${SIM_SRC} ${C_SRC} osvvm/OsvvmContext.o | work @echo "Analyze testbench & design ..." ghdl -a --std=$(VHD_STD) -fpsl --workdir=work -P=osvvm ${RTL_SRC} ${SIM_SRC} @echo "Elaborate testbench & design ..." - ghdl -e --std=$(VHD_STD) -fpsl --workdir=work -P=osvvm $@ + ghdl -e --std=$(VHD_STD) -fpsl --workdir=work -P=osvvm -Wl,$@.c -Wl,-lcrypto -Wl,-lssl $@ tb_$(DESIGN_NAME).ghw: tb_$(DESIGN_NAME) diff --git a/ctraes/sim/vhdl/tb_ctraes.c b/ctraes/sim/vhdl/tb_ctraes.c new file mode 100644 index 0000000..8702e6b --- /dev/null +++ b/ctraes/sim/vhdl/tb_ctraes.c @@ -0,0 +1,164 @@ +#include +#include +#include +#include +#include + +static const char HDL_LOGIC_CHAR[] = { 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'}; + +enum HDL_LOGIC_STATES { +HDL_U = 0, +HDL_X = 1, +HDL_0 = 2, +HDL_1 = 3, +HDL_Z = 4, +HDL_W = 5, +HDL_L = 6, +HDL_H = 7, +HDL_D = 8, +}; + +EVP_CIPHER_CTX *ctx; + +void slv_to_uchar(char* datain, unsigned char* dataout, int bytelen) { + + for (int i = 0; i < bytelen; i++) { + for (int y = 0; y < 8; y++) { + if (*datain == HDL_1) { + *dataout |= 1 << y; + } else if (*datain == HDL_0) { + *dataout &= ~(1 << y); + } + datain++; + } + dataout++; + } + + return; + +} + + +void slv_to_string(char* datain, char* dataout, int bytelen) { + + for (int i = 0; i < bytelen; i++) { + *dataout = HDL_LOGIC_CHAR[*datain]; + datain++; + dataout++; + } + + return; + +} + + +void uchar_to_slv(unsigned char* datain, char* dataout, int bytelen) { + + for (int i = 0; i < bytelen; i++) { + for (int y = 0; y < 8; y++) { + if ((*datain >> y) & 1 == 1) { + *dataout = HDL_1 ; + } else { + *dataout = HDL_0; + } + dataout++; + } + datain++; + } + + return; + +} + + +void handleErrors(void) { + + ERR_print_errors_fp(stderr); + abort(); + +} + + +void init(unsigned char *key, unsigned char *iv) { + + // Create and initialise the context + if(!(ctx = EVP_CIPHER_CTX_new())) + handleErrors(); + + // Initialise the encryption operation, no IV needed in CTR mode + if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv)) + handleErrors(); + + // We don't want padding + if(1 != EVP_CIPHER_CTX_set_padding(ctx, 0)) + handleErrors(); + +} + + +int encrypt(unsigned char *plaintext, + int plaintext_len, + unsigned char *ciphertext) { + + int len = 0; + + // Provide the message to be encrypted, and obtain the encrypted output + if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) + handleErrors(); + + return len; + +} + + +int finalize(void) { + + int len = 0; + unsigned char data[16]; + + // Finalise the encryption. No further bytes are written as padding is switched off + if (1 != EVP_EncryptFinal_ex(ctx, data, &len)) + handleErrors(); + + // Clean up + EVP_CIPHER_CTX_free(ctx); + + return len; + +} + + +void cryptData(char* datain, char* key, char* iv, char start, char final, char* dataout, int bytelen) { + + int crypt_len; + unsigned char c_din[bytelen]; + unsigned char c_key[bytelen]; + unsigned char c_iv[bytelen]; + unsigned char c_dout[bytelen]; + + slv_to_uchar(datain, c_din, bytelen); + slv_to_uchar(key, c_key, bytelen); + slv_to_uchar(iv, c_iv, bytelen); + + if (start) { + init(c_key, c_iv); + } + + crypt_len = encrypt(c_din, bytelen, c_dout); + + if (crypt_len != bytelen) { + printf("Warning: encrypt() returned with unexpected length %d\n", crypt_len); + } + + if (final) { + crypt_len = finalize(); + if (crypt_len != 0) { + printf("Warning: finalize() returned with unexpected length %d\n", crypt_len); + } + } + + uchar_to_slv(c_dout, dataout, bytelen); + + return; + +} diff --git a/ctraes/sim/vhdl/tb_ctraes.vhd b/ctraes/sim/vhdl/tb_ctraes.vhd index 1b788be..07f2fe4 100644 --- a/ctraes/sim/vhdl/tb_ctraes.vhd +++ b/ctraes/sim/vhdl/tb_ctraes.vhd @@ -52,6 +52,29 @@ architecture sim of tb_ctraes is signal s_validout : std_logic := '0'; signal s_acceptout : std_logic := '0'; + procedure cryptData(datain : in std_logic_vector(0 to 127); + key : in std_logic_vector(0 to 127); + iv : in std_logic_vector(0 to 127); + start : in boolean; + final : in boolean; + dataout : out std_logic_vector(0 to 127); + bytelen : in integer) is + begin + report "VHPIDIRECT cryptData" severity failure; + end procedure; + + attribute foreign of cryptData: procedure is "VHPIDIRECT cryptData"; + + function swap (datain : std_logic_vector(0 to 127)) return std_logic_vector is + variable v_data : std_logic_vector(0 to 127); + begin + for i in 0 to 15 loop + for y in 0 to 7 loop + v_data((i*8)+y) := datain((i*8)+7-y); + end loop; + end loop; + return v_data; + end function; begin @@ -80,43 +103,43 @@ begin process is + variable v_start : std_logic; + variable v_key : std_logic_vector(0 to 127); + variable v_nonce : std_logic_vector(0 to C_NONCE_WIDTH-1); + variable v_datain : std_logic_vector(0 to 127); + variable v_dataout : std_logic_vector(0 to 127); variable v_random : RandomPType; begin v_random.InitSeed(v_random'instance_name); wait until s_reset = '1' and rising_edge(s_clk); -- ENCRYPTION TESTs - report "Test encryption"; + report "Test CTR-AES encryption"; for i in 0 to 31 loop if (i = 0) then - s_start <= '1'; - s_nonce <= v_random.RandSlv(s_nonce'length); + v_start := '1'; + v_nonce := v_random.RandSlv(s_nonce'length); else - s_start <= '0'; + v_start := '0'; end if; + v_key := v_random.RandSlv(128); + v_datain := v_random.RandSlv(128); + s_key <= v_key; s_validin <= '1'; - s_key <= v_random.RandSlv(128); - s_datain <= v_random.RandSlv(128); - report "Test #" & to_string(i); + s_start <= v_start; + s_nonce <= v_nonce; + s_datain <= v_datain; + cryptData(swap(v_datain), swap(v_key), swap(v_nonce & 32x"0"), i = 0, i = 31, v_dataout, v_datain'length/8); wait until s_acceptin = '1' and rising_edge(s_clk); s_validin <= '0'; - end loop; - -- Watchdog - wait for 1 us; - report "Watchdog error" - severity failure; - end process; - - - process is - begin - s_acceptout <= '0'; - for i in 0 to 31 loop - wait until s_validout = '1' and rising_edge(s_clk); + wait until s_validout = '1' and rising_edge(s_clk); s_acceptout <= '1'; + assert s_dataout = swap(v_dataout) + report "Encryption error: Expected 0x" & to_hstring(swap(v_dataout)) & ", got 0x" & to_hstring(s_dataout) + severity failure; wait until rising_edge(s_clk); s_acceptout <= '0'; end loop; - report "Tests finished"; + -- Watchdog wait for 100 ns; finish(0); end process;