White-Box Cryptography: Tracer demonstration

The goal of the White-Box Cryptography is to obfuscate a sensitive cryptographic key and store it in a program. In that way, the program can be executed in an untrusted environment, and keeps using the sensitive key without fearing to reveal its secret value. This protection is used for instance with the Digital Rights Management (DRM) especially on mobile platform. Most of the time, sensitive keys are stored obfuscated in native libraries as this is the most efficient way.

We are going to analyze a white-box binary, and demonstrate how to extract its secret key.

In order to analyze a binary, a dynamic binary instrumentation (DBI) tool must be used to instrument the code and capture interesting data, for instance Intel PIN, Valgrind or Panda. Our white-box solution, the Tracer, is based on a different tool : Qemu. Its main advantages are to support a lot of different architecture (i386, ARM, x86-32, x86-64) and be able to launch them on an unique platform. For each executed instruction, our tool record a piece of or all the context register.

Tracer demonstration

The target : the Wyseur DES

We use the classical Wyseur challenge available at http://www.whiteboxcrypto.com/challenges.php in 2007. It implements a DES white-box with a i386 architecture. We use the GNU/Linux implementation.

In [1]:
!file ./wbDES
./wbDES: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.0, not stripped

Let's see how to use it.

In [2]:
!./wbDES
Usage: ./wbDES <INPUT>

Where <INPUT> is an 8-byte hexadecimal representation of the input to be encrypted

Example: ./wbDES 12 32 e7 d3 0f f1 29 b3

In [3]:
!./wbDES 00 11 22 33 44 55 66 77

INPUT:    00 11 22 33 44 55 66 77 

OUTPUT:   0a df b4 a0 ec 7a 60 69 

We need to provide an 8-byte hexadecimal input, and then get the ciphered message.

In [4]:
!./wbDES 0011223344556677
Usage: ./wbDES <INPUT>

Where <INPUT> is an 8-byte hexadecimal representation of the input to be encrypted

Example: ./wbDES 12 32 e7 d3 0f f1 29 b3

The input format must be carefully respected in order to get the ciphered message.

In [5]:
!./wbDES 00 11 22 33 44 55 66 77

INPUT:    00 11 22 33 44 55 66 77 

OUTPUT:   0a df b4 a0 ec 7a 60 69 

As we understood how to use the binary, we are goint to see how to use the tracer.

First step with the tracer

To start, we clean the current directory.

Using the eshard Whitebox module

We indicate:

  • the target binary
  • the Tracer command
  • the algorithm
  • the architecture

... and instantiate our tool.

Or you can use the API and customize it yourself as shown in the cell below

We are going to trace the program scanning only the PC register.

In [ ]:
from estoolkit.white_box import WhiteBox

archi = "i386"
algo  = "DES"
cmd   = "./wbDES"

wb = white_box(config)
wb.set_options_binary_handler(archi, algo, cmd)

pc_range = "0x8000000:0x8100000"
registers = "PC"
file_out_ext  = "DES_I386"
directory_out = "./traces"
information = True

wb.set_options_tracer(pc_range, registers, directory_out, file_out_ext, information)

# We build the configuration and generate one trace.
wb.tracer_build_configuration()
wb.tracer_generate_traces(1)

We can get a graphical representation of this trace.

To do so, we simply double-click on the gui_trace_pc.ths file.

We clearly see the DES rounds. Its demontraste we are looking at the correct area. We are now ready to start the acquisition campaign.

Trace acquisition campaign

We have all the required parameters to generate an acquisition campaign. We indicate we want to get all the registers, and then acquire 100 traces.

Or use the API again as shown in the next cell

In [5]:
wb.tracer_generate_traces(100)
Check binary configuration...
[ OK] : algorithm DES
[ OK] : architecture i386
[ OK] : executable ./wbDES
Check tracer configuration...
[ OK] : pc range format correct
[ OK] : ins range format correct
[ OK] : information : True

Generating 100 trace(s). Please wait...

Once again, we can have a graphical view of the captured register of a trace.

The graphical representation of the register can give tips about obfuscated code. For instance, in the image below, the EDX register seems to act as a state register.

Resynchronisation step

We acquire a lot of traces, however they could contain useless point, meaning giving no interested information on the key.

This is why we execute two steps:

  • First step. Remove all variant PC : addresses accessed only on some traces),
  • Second step. Remove all constant register values : most registers migth be unused and will not serve for the attack.
In [ ]:
wb.tracer_resynchro()

Now we're all set to perform the attack...

Let's use these traces to perform a Correlation Power Analysis (CPA) attack and retrieve the key.

CPA attack

The CPA module of esdynamic is used to perform the attack with the synchronized traces.

First, we create the CPA campaign with the following options:

  • its name,
  • the point size. As we have a 32 bits i386 architecture, we use uint32 point,
  • the folder containg the traces,
  • the trace extenstion to use,
  • the filename where the graphical view of the curve can be displayed.
In [16]:
wb.cpa_campaign_create(name = "DES i386 32-bits",
                       type = "uint32",
                       folder = "traces", 
                       filter = "*.bin.p2.ne2",
                       target_data = "plaintext",
                       save_result_filename="gui_traces")
Warning: 0 traces declared but 100 found with filter '*.bin.p2.ne2'.
Setting nb_trace to 100.
Loading traces....................
done.
Generating trace set....................
done.

Right click on the file gui_traces.ths, and choose Open With > Visualization. Then, click on "Data" button, and select the trace you want to see and click on apply.

We are now ready to perform the CPA attack using the esDynamic Side-Channel Module as already presented in www.eshard.com/product/esdynamic-framework.

As usual, you can either use the graphical interface or write down your own cell content as depicted below.

In [17]:
wb.cpa_campaign_run(attack_method    = cpa_constants.DES_ATTACK_HW,
                    selection_fn     = cpa_constants.DES_SELECT_R,
                    start_offset     = 20150,
                    end_offset       = 50151,
                    target_data      = "plaintext",
                    step_convergence = 10)
Performing attack 'DES i386 32-bits'...
	Start offset.......: 20150
	End offset.........: 50151
	Convergence step...: 10
	Attack mode........: attacking HW(data) (0)
	Selection function.: Get K1 or K15 with extract R1 or R15 (2)
	Data_type..........: 5
	Number of traces...: 100
	Target data........: plaintext
Done.

We display the result.

In [18]:
wb.cpa_campaign_show_result(expected_key=config.expected_key_round_0, save_result_filename = "cpa_results")
*** Byte ***	key_guess@point
*** B00  ***	14 @7994
*** B01  ***	02 @12750 
*** B02  ***	32 @27694 
*** B03  ***	2c @19513 
*** B04  ***	31 @29475 
*** B05  ***	20 @7332 
*** B06  ***	0f @17814 
*** B07  ***	07 @24516 

Scanned range [20150:50151]. Found DES key:
[0x14, 0x2, 0x32, 0x2c, 0x31, 0x20, 0xf, 0x7]
	 Correct bytes : 8 [14 02 32 2C 31 20 0F 07 ] 

Conclusion

We demonstrate how our tool based on qemu was able to trace all the registers of an i386 DES whitebox, and successfully execute a CPA attack to retrieve the correct key.