Obfuscating VHDL Code
Semantic Designs can construct custom obfuscators for virtually any source language as a part of the corresponding Source Formatter. This page contains VHDL sample code, its obfuscated version, and the generated obfuscation map.
VHDL Sample Code before Obfuscation
(This is the same formatted code shown on the VHDL Formatter example page)
USE work.multiplier_types.all; USE work.bv_arithmetic.all; USE std.textio.all; ENTITY multiplier IS PORT ( clk : in bit; load : in bit; multiplicand : in word; multiply_by : in word; ready : out bit; product_low : inout word; product_high : inout word ); END multiplier; ARCHITECTURE mixed OF multiplier IS COMPONENT reg_1 PORT ( clk : in bit; load : in bit; d : in bit; q : out bit ); END COMPONENT; COMPONENT shift_reg_word PORT ( clk : in bit; load : in bit; shift : in bit; clr : in bit; d : in word; d_s : in bit; q : out word; q_s : out bit ); END COMPONENT; COMPONENT reg_word PORT ( clk : in bit; load : in bit; d : in word; q : out word); END COMPONENT; COMPONENT adder PORT ( a : in word; b : in word; c_in : in bit; s : out word; c_out : out bit); END COMPONENT; COMPONENT and_word PORT ( a : in bit; b : in word; z : out word); END COMPONENT; SIGNAL b : word; SIGNAL b_or_0 : word; SIGNAL partial_product : word; SIGNAL c_in : bit; SIGNAL c_out : bit; SIGNAL c_to_p : bit; SIGNAL p_to_a : bit; SIGNAL p_and_c_load : bit; SIGNAL shift : bit; SIGNAL tied_0 : bit := '0'; ALIAS a_0 : bit IS product_low(0); BEGIN -- mixed a_reg : shift_reg_word port map ( clk => clk, load => load, shift => shift, clr => tied_0, d => multiplicand, d_s => p_to_a, q => product_low, q_s => open ); b_reg : reg_word port map ( clk => clk, load => load, d => multiply_by, q => b ); p_reg : shift_reg_word port map ( clk => clk, load => p_and_c_load, shift => shift, clr => load, d => partial_product, d_s => c_in, q => product_high, q_s => p_to_a ); carry_reg : reg_1 port map (clk => clk, load => p_and_c_load, d => c_out, q => c_in ); b_gate : and_word port map ( a => a_0, b => b, z => b_or_0 ); the_adder : adder port map ( a => product_high, b => b_or_0, c_in => c_in, s => partial_product, c_out => c_out ); ----------------------------------------------------------------------------- -- Process: controller -- Purpose: sequences register loading and shifting -- Inputs: clk, load -- Outputs: p_and_c_load, shift, ready ----------------------------------------------------------------------------- controller : PROCESS CONSTANT Tpd_clk_load : Time := 5 ns; CONSTANT Tpd_clk_shift : Time := 5 ns; CONSTANT Tpd_clk_ready : Time := 5 ns; BEGIN -- PROCESS controller p_and_c_load <= '0' after Tpd_Clk_Load; shift <= '0' after Tpd_clk_shift; ready <= '1' after Tpd_clk_ready; WAIT on clk until clk = '1' and load = '1'; ready <= '0' after Tpd_clk_ready; FOR cycle IN 1 to word_size LOOP p_and_c_load <= '1' after Tpd_clk_load; WAIT until clk = '1'; p_and_c_load <= '0' after Tpd_clk_load; shift <= '1' after Tpd_clk_shift; WAIT until clk = '1'; shift <= '0' after Tpd_clk_shift; END LOOP; -- cycle ready <= '1' after Tpd_clk_ready; END PROCESS controller; END mixed;
VHDL Code after Obfuscation
Notice that comments are gone, names have been scrambled. The obfuscator uses a special list provided by the user to define names that should be preserved, ensuring that public interfaces and accesses to public libraries remain valid. If you obfuscate a set of VHDL source files simultaneously, only the public symbols they collectively offer will be sensibly named in the source files.
use l.O.all; use l.l1.all; use std.textio.all; entity multiplier is port (clk: in bit; load: in bit; multiplicand: in word; multiply_by: in word; ready: out bit; product_low: inout word; product_high: inout word); end multiplier; architecture O0 of multiplier is component ll1 port (clk: in bit; load: in bit; OO0: in bit; l11: out bit); end component; component O00 port (clk: in bit; load: in bit; lll1: in bit; OOO0: in bit; OO0: in word; l1l1: in bit; l11: out word; O0O0: out bit); end component; component ll11 port (clk: in bit; load: in bit; OO0: in word; l11: out word); end component; component OO00 port (l111: in word; O000: in word; llll1: in bit; OOOO0: out word; l1ll1: out bit); end component; component O0OO0 port (l111: in bit; O000: in word; ll1l1: out word); end component; signal O000: word; signal OO0O0: word; signal l11l1: word; signal llll1: bit; signal l1ll1: bit; signal O00O0: bit; signal lll11: bit; signal OOO00: bit; signal lll1: bit; signal l1l11: bit := '0'; alias O0O00: bit is product_low(0); begin ll111: O00 port map (clk => clk,load => load,lll1 => lll1,OOO0 => l1l11,OO0 => multiplicand,l1l1 => lll11,l11 => product_low,O0O0 => open ); OO000: ll11 port map (clk => clk,load => load,OO0 => multiply_by,l11 => O000); l1111: O00 port map (clk => clk,load => OOO00,lll1 => lll1,OOO0 => load,OO0 => l11l1,l1l1 => llll1,l11 => product_high,O0O0 => lll11); O0000: ll1 port map (clk => clk,load => OOO00,OO0 => l1ll1,l11 => llll1); lllll1: O0OO0 port map (l111 => O0O00,O000 => O000,ll1l1 => OO0O0); OOOOO0: OO00 port map (l111 => product_high,O000 => OO0O0,llll1 => llll1,OOOO0 => l11l1,l1ll1 => l1ll1); l1lll1: process is constant O0OOO0: ll1ll1 := 5 OO0OO0; constant l11ll1: ll1ll1 := 5 OO0OO0; constant O00OO0: ll1ll1 := 5 OO0OO0; begin OOO00 <= '0' after O0OOO0; lll1 <= '0' after l11ll1; ready <= '1' after O00OO0; wait on clk until clk = '1' and load = '1'; ready <= '0' after O00OO0; for lll1l1 in 1 to OOO0O0 loop OOO00 <= '1' after O0OOO0; wait until clk = '1'; OOO00 <= '0' after O0OOO0; lll1 <= '1' after l11ll1; wait until clk = '1'; lll1 <= '0' after l11ll1; end loop; ready <= '1' after O00OO0; end process l1lll1; end O0;
Obfuscated Symbol Cross Reference
The obfuscator produces a cross reference mapping obfuscated symbols to the orginal symbols, so that obfuscated code in the field can still be decoded if necessary. In fact, by reversing this map, the obfuscator can unobfuscate the code (of course, it cannot restore the comments).
### Obfuscated Identifiers ### a -> l111 a_0 -> O0O00 a_reg -> ll111 adder -> OO00 and_word -> O0OO0 b -> O000 b_gate -> lllll1 b_or_0 -> OO0O0 b_reg -> OO000 bv_arithmetic -> l1 c_in -> llll1 c_out -> l1ll1 c_to_p -> O00O0 carry_reg -> O0000 clr -> OOO0 controller -> l1lll1 cycle -> lll1l1 d -> OO0 d_s -> l1l1 mixed -> O0 multiplier_types -> O ns -> OO0OO0 p_and_c_load -> OOO00 p_reg -> l1111 p_to_a -> lll11 partial_product -> l11l1 q -> l11 q_s -> O0O0 reg_1 -> ll1 reg_word -> ll11 s -> OOOO0 shift -> lll1 shift_reg_word -> O00 the_adder -> OOOOO0 tied_0 -> l1l11 time -> ll1ll1 tpd_clk_load -> O0OOO0 tpd_clk_ready -> O00OO0 tpd_clk_shift -> l11ll1 word_size -> OOO0O0 work -> l z -> ll1l1 ### Preserved Identifiers ### bit -> bit clk -> clk load -> load multiplicand -> multiplicand multiplier -> multiplier multiply_by -> multiply_by product_high -> product_high product_low -> product_low ready -> ready std -> std textio -> textio word -> word