All my life I thought crypto is hard. Well, it is, but it is not that bad if you only focus on existing attacks. I realized this after watching HackerOne video lessons at https://www.hacker101.com/videos. After that i dived into coding solutions for cryptopals challenges and naturally used an approach as universal as possible. The result of my (still incomplete) work is now accessible on Github and is known as Langdon framework (which is a reference to famous symbologist Robert Langdon). Let’s see how Langdon works.

Basic usage

You can run Langdon interactively or from the command line with limited set of the most useful commands. Let’s use Langdon in interactive mode first – that happens when no argument is provided. You can then use help command to show implicit documentation.

Variable definition

Naturally you will want to define some data to use crypto on. This is quite straightforward:

a1 = Hello

Now new variable a1 is created and holds 5 bytes of data. We can print it just by specifying variable name:

*** a1
Bin:    0100100001100101011011000110110001101111
Int:    310939249775
Hex:    0x48656c6c6f
Raw:    b'Hello'
Base64: SGVsbG8=

As you can see, Langdon happily shows multiple representations of the same, which is useful. Of course, you can define data with different formats:

a2 = 'Hello'
a3 = 310939249775
a4 = 0x48656c6c6f
a5 = base64:SGVsbG8=
a6 = 0100100001100101011011000110110001101111
a7 = He\x6clo

and all variables are equal. Use quotes as with a2 to ensure variable is given as unescaped string.

You can also load files directly. Let’s assume you have /tmp/hello file with ‘Hello’ string in it. Then you can run:

a8 = file:/tmp/hello

Printing

Print all variables using vars command. This will show the best form, but you can override it by specifying desired type, e.g. vars hex.

*** vars
a1  Hello
a2  Hello
a3  310939249775
a4  0x48656c6c6f
a5  Hello
a6  Hello
a7  Hello
a8  Hello
*** vars hex
a1  0x48656c6c6f
a2  0x48656c6c6f
a3  0x48656c6c6f
a4  0x48656c6c6f
a5  0x48656c6c6f
a6  0x48656c6c6f
a7  0x48656c6c6f
a8  0x48656c6c6f

Currently valid types are int, bin, hex, raw, base64 and escaped.

To see just specify type of one variable, use ~ which works like grep.

*** a1~Hex
Hex:    0x48656c6c6f

You can use grep on all commands that yield some output. Note that one tilde character looks for exact match, but you can use ~~ to search for regular expressions as well:

*** a1~~(Hex|Int)
Int:    310939249775
Hex:    0x48656c6c6f

Finally you can print your variables as hexdump using hexdump or hd command:

*** hd a1
00000000  4865 6c6c 6f                            |Hello|

Exporting

You can export variables into files like this:

export a1 /tmp/a1 

or force datatype:

export a1 /tmp/a1 int

or export all variables:

export all /tmp/variables

which will create files /tmp/variables_a1, /tmp/variables_a2 etc. Again, you can force desired datatype.

Sequences

Sometimes you do not want to specify variables manually, for example when you need random data or long boring sequences. A number of commands exist solely for this purpose:

b1 = random 0x30 0x39 10
b2 = zeros 10
b3 = prime 80
b4 = timestamp
b5 = debruijn 10

I should explain this. The b1 variable will hold 10 random bytes from interval <0x30; 0x39> – these are ASCII codes for numbers. Next we create a simple stream of NULL (0x00) bytes. The b3 will hold a 80-bit prime number. The b4 will hold current timestamp, you can also optionally specify datetime to convert. Finally we generate something called DeBruijn pattern. This is a stream of bytes in where any sequence of x bytes (4 in this case) will appear in the pattern once or not at all. That means, given a 4B substring, you can easily find its offset. This is useful when looking for stack overflows (you use the pattern as payload and when program crashes and spits out the bad instruction pointer value you can easily get the correct offset). But this is a different topic. In the end we can expect results like this:

*** vars~b
b1  1831257872
b2  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
b3  894066956381389645393937
b4  1577966984
b5  AAABAACAAD   

Useful functions

There are few generally useful functions worth mentioning. You can assign them into new variable, like c1 = len a1. The functions are:

  • len a1 or length a1 returns 5 – the number of bytes a variable is holding,
  • rev a1 reverses data (olleH), you can also use rev a1 16 to reverse by 2B (16b) chunks (ollHe),
  • concat a1 b1 concatenates data, this will result in Hello1831257872 here,
  • substring a1 1 2 returns 2 bytes at offset 1 of variable a1, ‘el‘ in this case,
  • gray a1 converts data into 8b Gray code (lW\xdaZX),
  • ungray c1 would convert it back,
  • sleep 2 will just sleep for 2 seconds
  • entropy a1 will get a1’s entropy (as <0; 1>), 0.24024 in this case,
  • histogram a1 shows simple byte histogram, like the one below.
Byte histogram of bytestring ‘Hello’.

CLI mode

If you run Langdon with --help argument, you will get list of available console commands. There are basic functions mentioned above, plus a few functions for transition between different forms, such as --hex and --unhex (they are also available in interactive Langdon, but they are not so useful there). For CLI approach you can use files or stdin as input.

But wait! There’s more! But we will deal with the other Langdon perks later in appropriate chapters. In the next chapter I will show how to solve first few cryptopals challenges with the Langdon’s aid. In the meantime you can watch today’s topic as asciinema cast.

Leave a Reply

Your email address will not be published. Required fields are marked *