p68 0x08 practical cracking of white-box implementations by sysk

Upload: atul-tripathi

Post on 14-Apr-2018

223 views

Category:

Documents


0 download

TRANSCRIPT

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    1/51

    ==Phrack Inc.==

    Volume 0x0e, Issue 0x44, Phile #0x08 of 0x13

    |=-----------------------------------------------------------------------=||=--------=[ Practical cracking of white-box implementations ]=---------=||=-----------------------------------------------------------------------=||=---------------=[ by SysK - whiteb0x [o] phrack o org ]=---------------=||=-----------------------------------------------------------------------=|

    -------

    1 - Introduction

    2 - What is a WB implementation?

    3 - The things you should know about white-boxes3.1 - Products available3.2 - Academic state of the art

    4 - Handling the first case: hack.lu's challenge4.1 - The discovery step4.2 - The key recovery

    4.3 - Random thoughts

    5 - White-boxing the DES5.1 - The DES algorithm5.2 - An overview of DES WB primitives

    6 - Breaking the second case: Wyseur's challenge6.1 - Efficient reverse engineering of the binary6.2 - The discovery step6.3 - Recovering the first subkey6.4 - Recovering the original key

    7 - Conclusion

    8 - Gr33tz

    9 - References

    10 - Appendix: Source code

    -------

    --[ 1 - Introduction

    This paper is about WB (white-box) cryptography. You may not have heardtoo much about it but if you're focused on reverse engineering and moreprecisely on software protections, then it may be of interest for you.

    Usually The common way to learn something valuable in cryptography iseither to read academic papers or cryptography books (when they're writtenby true cryptographers). However as cryptography is about maths, it cansometimes seem too theoretical for the average reverser/hacker. I'm willingto take a much more practical approach using a combination of both reverseengineering and elementary maths.

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    2/51

    Obviously such a paper is not written for cryptographers but rather forhackers or crackers unfamiliar with the concept of white-box and willing tolearn about it. Considering the quasi non existence of publicimplementations to play with as well as the 'relatively' small amount ofvaluable information on this subject, I hope this will be of interest. Orat the very least that it will be a pleasant read... O:-)

    --[ 2 - What is a WB implementation?

    So let's begin with a short explanation. A white-box is a particularimplementation of a cryptographic primitive designed to resist to theexamination of its internals. Consider the case of a binary embedding (andusing) a symmetric primitive (such as AES for example). With the commonimplementations, the AES key will always leak in memory at some point ofthe execution of the program. This is the classic case of a reverser usinga debugger. No matter how hard it may be (anti-debug tricks, obfuscation ofthe key, etc.), he will always find a way to intercept the key. White-boxcryptography techniques were designed to solve this problematic which isvery common, especially in the field of DRM (Digital Rights Management).

    So how does it work? The main concept that you should remember is that

    the key is never explicit. Or you could say that it's mathematicallytransformed or 'fused' with the encryption routine. So for one key there isone particular obfuscated primitive which is strictly equivalent to theoriginal one*. For a same input, both implementations will produce anidentical output. The mathematical transformation is designed in such a waythat an attacker with a debugger will not be able to deduce the key fromthe internal state ... at least in a perfect world :-)

    *: It's not 'exactly' true as we will see later with external encodings.

    Confused? Then take a look at this tiny example:

    -> Function1: for x in [0:3] f(x) = (k+x) % 4

    -> Function2: for x in [0:3] g(x) = S[x] with S = [3,0,1,2]

    If k==3, then the two functions f() and g() are equivalent. However thefirst one explicitly uses the key 'k' whereas the second one doesn't, beingimplemented as a lookup table (LUT). You could say that g() is a white-boximplementation of f() (albeit a very weak one) for the key 3. While thisexample is easy to understand, you will soon discover that things are morecomplicated with the obfuscation of a whole real life crypto primitive.

    --[ 3 - The things you should know about white-boxes

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    3/51

    WB cryptography is essentially implemented in commercial securityproducts by a relatively small number of companies (Cloakware -acquired byIrdeto-, Whitecryption, Arxan, Syncrosoft, etc.). Usually they provide asecure API which is then integrated into other security primitives, oftenfor DRM purposes. Amongst other things, they design WB primitives forsymmetric encryption (DES, AES) but also MAC (HMAC, CMAC) and asymmetricprimitives (ECC, RSA, DSA).

    How often do we come across WB in the wild? More than you could thinkof! For example you can see in [R10] that Irdeto has many famous customersincluding TI, Sony, Adobe and NetFLIX. WB cryptography will most likelybecome more and more present in software protections.

    As far as I can tell, there are unfortunately only 2 public (noncommercial) examples of WB implementations, both with undisclosedgenerators:

    - The first historical one is a binary available on Brecht Wyseur'swebsite [R04] and is a WB DES implementation. Brecht challengespeople to find the key:

    "If you like, try to extract the secret key, using all informationyou can find from this implementation (besides brute-force black-box

    attacks of course)."

    Keep in mind that this is a challenge, not some production code.

    - The second one less likely to be known is a challenge proposed by Jbfor the 2009 edition of hack.lu [R02]. This one is a simplistic AESWB but was never labeled officially as such. Part of the challenge isindeed to find out (oops!).

    The cryptanalysis involved is obviously far below the academic state ofthe art but it's nonetheless an interesting one and a first step for whowants to be serious and aims at defeating more robust implementations.

    We'll study both starting with Jb's binary and see how the solution canbe found in each case.

    ,---.,.'-. \

    ( ( ,'"""""-.`,X `./` ` `._

    ( , ,_\| ,---.,'o `.| / o \ )\ ,. ( .____,\| \ \____,' \

    '`'\ \ _,____,'\ ,-- ,-' \

    ( C ,' \`--' .' || | .O |

    __| \ ,-'_/ `L `._ _,' ' `.

    / `--.._ `',. _\ ``-. /\ | `. ( ,\ \

    _/ `-._ / \ |--' ( \

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    4/51

    ' `-. `' \/\`. `. )\ -hrr- \ `. | |

    ----[ 3.2 Academic state of the art

    AFAIK academic publications are limited to symmetric encryption andespecially to DES and AES (though SPN case is somewhat extended in [R08]).Explaining the history of the design and the cryptanalysis techniques whichwere developed would be complicated and is already explained with greatdetails in the thesis of Brecht Wyseur [R04].

    The main question is to know if there exists a secure WB design and ifyou consider the current state of the art in cryptography, well... thereisn't! There is currently no implementation proposal not broken by design.And in this case, broken means a key recovery in a matter of seconds in theworst case. Yes, _that_ broken!

    However, real-life white-box cryptography may be different because:

    - As explained before, proprietary implementations of algorithmsnot mentioned in any paper (MAC algorithms, asymmetric ones)exist. This proves that people were smart enough to design new

    implementations. On the other hand, without any formal analysisof these implementations, nothing can be said regarding theireffective security.

    - Cloakware products were at least partially designed/written bythe cryptographers who designed the first white-box [R7]. On onehand you may suspect that their product is broken by design.Alternatively it can be assumed that it is at least immuneagainst current cryptanalysis techniques. Little can be saidabout other protections (whitecryption, Arxan, Syncrosoft) but wecould speculate that it's not of the same caliber.

    So are WB protections hard to break in practice? Who knows? But

    remember that protecting the key is one thing while protecting a content issomething different. So if you ever audit a white-box solution, beforetrying to retrieve the key, see if you can intercept the plaintexts. Thereare lots of possible attacks, potentially bypassing the WB protections[R06].

    Remark: Obviously in the case of DRM (if no hardware protection isinvolved), you will always find a way to intercept unencrypted data. Thisis because at some point the player will have to send audio/video streamsto the sound/video card drivers and you may want to hook some of theirfunctions to recover the media. This is however a practice to forget if themedia requires the synchronization of several streams (i.e. movies withboth audio and video).

    Now that said, let's begin with the first challenge :)

    --[ 4 - Handling the first case: hack.lu's challenge

    I have to thank Jb for this binary as he was the one who suggested meto solve it a few days ago*. Unfortunately my solution is biased as I knewfrom the very beginning that it was an AES white-box. I may have taken a

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    5/51

    different approach to solve it if I hadn't. This is however a good enoughexample to introduce WB protections.

    *: Phrack being usually late "a few days ago" probably means "a few weeks**ago"**: Phrack being _indeed_ late "a few weeks ago" is now "a few months ago";>

    ----[ 4.1 - The discovery step

    Since the challenge is about breaking an AES white-box, it means thatwe may need to perform several tasks:

    - finding out if the WB is an AES or an AES^-1 and the associated keylength: 16 (AES-128), 24 (AES-192), 32 (AES-256)? We want to discoverexactly *what* was white-boxed.

    - reversing every cryptographic functions involved and discovering howthey are related to the original AES functions. This is aboutunderstanding *how* the implementation was white-boxed.

    - finding a way to recover the original key.

    I won't describe the AES as it's not necessary to understand this part.The necessary details will be provided a bit later. First of all, let's seehow the serial is retrieved. We'll start by a quick reverse engineering ofthe sub_401320() function:

    ---------------------------------------------------------------------------mov eax, [esp+38h+hDlg]push 21h ; cchMaxlea ecx, [esp+3Ch+String]push ecx ; lpStringpush 3ECh ; nIDDlgItempush eax ; hDlg

    call ds:GetDlgItemTextAcmp eax, 20h ; is length == 32?---------------------------------------------------------------------------

    Without too much surprise, GetDlgItemText() is called to retrieve analpha-numeric string. The comparison in the last line implies a length of32 bytes in its ASCII representation (not including the null byte) hence a16 bytes serial. Let's continue:

    ---------------------------------------------------------------------------cmp eax, 20hjz short good_serial ; if len is ok then start the

    ; conversion

    bad_serial:xor eax, eax[...]retn ; return 0

    good_serial:push ebxpush esixor esi, esi ; i=0nop

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    6/51

    build_data_buffer:movzx edx, [esp+esi*2+40h+String]push edxcall sub_4012F0 ; get least significant nibblemov ebx, eaxmovzx eax, [esp+esi*2+44h+var_27]push eaxshl bl, 4call sub_4012F0 ; get most significant nibbleor bl, al ; bl is now a converted bytemov byte ptr [esp+esi+48h+input_converted], bl

    ; input_converted[i] = blinc esi ; i++add esp, 8cmp esi, 10hjl short build_data_buffer

    lea ecx, [esp+40h+input_converted]push ecxmov edx, ecxpush edxcall sub_401250 ; white-box wrapperadd esp, 8

    pop esimov eax, 10hxor ecx, ecxpop ebx

    ; Compare the resulting buffer byte after byte

    compare_buffers:mov edx, [esp+ecx+38h+input_converted]cmp edx, dword ptr ds:aHack_lu2009Ctf[ecx]

    ; "hack.lu-2009-ctf"jnz short bad_serialsub eax, 4

    add ecx, 4cmp eax, 4jnb short compare_buffers[...]retn

    ---------------------------------------------------------------------------

    The alphanumeric string is then converted byte after byte using thesub_4012F0() function in the corresponding plaintext (or ciphertext) blockfor cryptographic manipulations. The function sub_401250() is then calledtaking it as a parameter. When the function returns, the buffer is thencompared to the "hack.lu-2009-ctf" string (16 bytes). If both are equal,the serial is valid (the function returns 1).

    Let's see sub_401250() in more detail:

    ---------------------------------------------------------------------------sub_401250 proc near ; WrapperWhiteBox

    [...]mov eax, [esp+14h+arg_0]push esimov esi, [esp+18h+arg_4]xor ecx, ecx

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    7/51

    add eax, 2lea esp, [esp+0]

    permutation1:; First step is a transposition (special permutation)

    movzx edx, byte ptr [eax-2]mov [esp+ecx+18h+var_14], dlmovzx edx, byte ptr [eax-1]mov [esp+ecx+18h+var_10], dlmovzx edx, byte ptr [eax]mov [esp+ecx+18h+var_C], dlmovzx edx, byte ptr [eax+1]mov [esp+ecx+18h+var_8], dlinc ecxadd eax, 4cmp ecx, 4jl short permutation1

    ; Second step is calling the white-box

    lea eax, [esp+18h+var_14]push eaxcall sub_401050 ; call WhiteBox

    [...]

    permutation2:; Third step is also a transposition; Bytes' position are restored

    movzx edx, [esp+ecx+14h+var_14]mov [eax-2], dlmovzx edx, [esp+ecx+14h+var_10]mov [eax-1], dlmovzx edx, [esp+ecx+14h+var_C]mov [eax], dlmovzx edx, [esp+ecx+14h+var_8]

    mov [eax+1], dlinc ecxadd eax, 4cmp ecx, 4jl short permutation2[...]retn

    ---------------------------------------------------------------------------

    At first sight, sub_401250() is composed of three elements:

    - A first bunch of instructions operating on the buffer which isno more than a (4x4) matrix transposition operating on bytes.

    For example:

    A B C D A E I ME F G H becomes B F J NI J K L C G K OM N O P D H L P

    This is a common step to prepare the plaintext/ciphertext blockinto the so-called "state" as the AES is operating on 4x4 matrix.

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    8/51

    - This function is then calling sub_401050() which is composed ofelementary operations such as XOR, rotations and substitutions.

    - A second transposition. One important thing to know about thetransposition is that the function is its own inverse. The formerbytes' positions are thus restored.

    sub_401050() is the WB. Whether it's an AES or an AES^-1 function andits keylength has yet to be determined. The serial acts as a plaintext ora ciphertext which is (de,en)crypted using a key that we want to retrieve.Since the output buffer is compared with an English sentence, it seems fairto assume that the function is an AES^-1.

    Reverse engineering of sub_401050()-----------------------------------

    Detailing the whole reverse engineering steps is both boring andmeaningless as it doesn't require special skills. It's indeed prettystraightforward. The resulting pseudo C code can be written as such:

    ----------------------------- First version -------------------------------

    void sub_401050(char *arg0){int round,i;

    // 9 first roundsfor(round=0; round

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    9/51

    bl = byte_414000[ 3 + arg0[0+i]*4 ];bl ^= byte_414400[ 3 + arg0[4+i]*4 ];bl ^= byte_414800[ 3 + arg0[8+i]*4 ];bl ^= byte_414C00[ 3 + arg0[12+i]*4 ];

    arg0[0+i] = cl;arg0[4+i] = dl;arg0[8+i] = var_1A;arg0[12+i] = bl;

    }}

    // step-4for(i=0; i

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    10/51

    {if(arg8 != 0){

    (int) tmp = ((int)arg0[4*arg8] > (32-(8*arg8)));

    }return;

    }---------------------------------------------------------------------------

    This is clearly the ShiftRows() elementary function of the AES.For example:

    59 49 90 3F 59 49 90 3F [

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    11/51

    byte_414801 : 0 3 6 5 C F A 9 ... // Coef = 3byte_414C01 : 0 1 2 3 4 5 6 7 ... // Coef = 1

    byte_414002 : 0 1 2 3 4 5 6 7 ... // Coef = 1byte_414402 : 0 1 2 3 4 5 6 7 ... // Coef = 1byte_414802 : 0 2 4 6 8 A C E ... // Coef = 2byte_414C02 : 0 3 6 5 C F A 9 ... // Coef = 3

    byte_414003 : 0 3 6 5 C F A 9 ... // Coef = 3byte_414403 : 0 1 2 3 4 5 6 7 ... // Coef = 1byte_414803 : 0 1 2 3 4 5 6 7 ... // Coef = 1byte_414C03 : 0 2 4 6 8 A C E ... // Coef = 2

    As a result, step-3 can be written as:

    [ arg0(0,i) [ 02 03 01 01 [ arg0(0,i)arg0(4,i) = 01 02 03 01 x arg0(4,i)arg0(8,i) 01 01 02 03 arg0(8,i)arg0(c,i) ] 03 01 01 02 ] arg0(c,i) ]

    And this is exactly the MixColumns of the AES! Everything taken intoaccount gives this new version of sub_401250():

    ---------------------------- Second version -------------------------------

    void sub_401050(char *arg0){int round,i;

    // 9 first roundsfor(round=0; round

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    12/51

    ----[ 4.2 - The key recovery

    The general algorithm (not including the key schedule which generates K)of AES-128 encryption is the following:

    ---------------------------------------------------------------------------ROUNDS=10def AES_128_Encrypt(in):

    out = inAddRoundKey(out, K[0])

    for r in xrange(ROUNDS-1):SubBytes(out)ShiftRows(out)MixColumns(out)AddRoundKey(out,K[r])

    SubBytes(out)ShiftRows(out)AddRoundKey(out, K[10])return out

    ---------------------------------------------------------------------------

    Where K[r] is the subkey (16 bytes) used in round r. From now on, 'o'is the symbol for the composition of functions, this allows us to write:

    SubBytes o AddRoundKey(K[r],IN) = step-1(IN,r) for r in [0..9]

    Exploiting the first round, this immediately gives a system ofequations (with S being located at 0x408138):

    SubBytes(K[0][i] ^ arg0[i]) = S[ i + arg0[i]*16 ] for i in [0..15]

    The equations hold for any arg0[i] and in particular for arg0[i] = 0.

    The resulting simplified system is thus:

    SubByte(K[0][i]) = S[i] for i in [0..15]K[0][i] = SubByte()^-1 o S[i] for i in [0..15]

    Let's try it on the rub^Wpython console:

    --------------------------------------------------------------------------->>> sbox2 = inv_bij(sbox); # We compute SubBytes^-1>>> S = [0xFA, 0xD8, 0x88, 0x91, 0xF1, 0x93, 0x3B, 0x39, 0xAE, 0x69, 0xFF,

    0xCB, 0xAB, 0xCD, 0xCF, 0xF7]; # dumped @ 0x0408138>>> for i in xrange(16):... S2[i] = sbox2[S2[i]];

    ...>>> S2;[20, 45, 151, 172, 43, 34, 73, 91, 190, 228, 125, 89, 14, 128, 95, 38]---------------------------------------------------------------------------

    But remember that a transposition is necessary to retrieve the subkey!

    --------------------------------------------------------------------------->>> P = [0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15] #I'm lazy :)>>> S4 = []

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    13/51

    >>> for i in xrange(16):... S4.insert(i,S2[P[i]])---------------------------------------------------------------------------

    Now S4 holds the subkey K[0]. An interesting property of the AES keyschedule is that the subkey K[0] is equal to the key before derivation.This is why our priority was to exploit the first round.

    --------------------------------------------------------------------------->>> s = 'hack.lu-2009-ctf'>>> key = ''.join(map(lambda x: chr(x), S4))>>> key'\x14+\xbe\x0e-"\xe4\x80\x97I}_\xac[Y&'>>> keyObj=AES.new(key)>>> encPwd=keyObj.decrypt(s)>>> encPwd.encode('hex').upper()'192EF9E61164BD289F773E6C9101B89C'---------------------------------------------------------------------------

    And the solution is the same as baboon's one [R03]. Of course therewere many other ways to proceed but it's useless to even consider them dueto the very weak nature of this 'WB'.

    ----[ 4.3 - Random thoughts

    Jb designed this challenge so that it could be solved in the 2-dayscontext of the hack.lu CTF. It's very likely that any reverser familiarwith the AES would be able to deal with it rather easily and so did baboonat that time when he came up with a smart and quick solution [R03]. If Jbhad used the implementation described in [R07] then it would have been awhole other game though still breakable [R05].

    That being said, this implementation (which is based on what is calledpartial evaluation) may only be a toy cipher but it's perfect to introducemore advanced concepts. Indeed several security measures (amongst others)

    were voluntary missing:

    - ShiftRows() and MixColumns() were not modified. A strongimplementation would have transformed them. Additionally SubBytes()could have been transformed in a less gentle manner to mitigatetrivial attacks.

    - There is a direct correspondence between an obfuscated function andit's unprotected "normal" counterpart. Inputs and outputs of suchfunctions are synchronized or you could say that intermediate statescan be observed. "Internal encoding" removes this property.

    - The first and last rounds should have a special protection. This is

    because the input (respectively the output) of the first(respectively the last) round can be synchronized with the normalimplementation. "External encoding" is used to prevent this but as aside effect alter the compatibility with the original encryption.

    - etc.

    Remark: If you ever come across a WB implementation, let me give you 2 nicetricks to see in the blink of an eye if it's potentially weak or not:

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    14/51

    - Look at the size of the implementation. Remember that the size of anobfuscated primitive is deeply related to the number and size of thelookup tables, the weight of the opcodes being generally negligible.In this case, the binary was 85 kB whereas the state of the artrequires at least 770 kB. It was thus obvious that severalobfuscation layers were missing.

    - The fully obfuscated version of the algorithms described in [R07]only uses XOR and substitutions (lookup tables) as MixColumns andShiftRows are both transformed to make it possible. One may howeverpoint out that the statement holds with T-tables basedimplementations. It's true but such implementations use well knowntables so it's easy to fingerprint them.

    Remember that real-life white-boxes (i.e. used in DRM, embeddeddevices, etc.) are likely to be close to the state of the art (assumingthey are designed by crypto professionals and not by the average engineer;)). Conversely, they may also face practical problematics (size, speed)which have an impact on their security. This is especially true withembedded devices.

    --[ 5 - White-boxing the DES

    If you're still reading (hi there!) then it probably means that youalready have at least a basic knowledge of cryptography. So you know thatDES should not be used because of its short keylength (56 bits), right?Then why the hell should we be focused on it? Well because:

    - There are only 2 public white-box design families: AES and DES- If you can white-box DES, then you can probably white-box 3DES aswell (which is strong)

    - I couldn't find a non commercial sophisticated enough AES WB to playwith and I don't want to be sued by M$, Adobe, etc. :D

    Remark: While AES WB cryptanalysis are essentially algebraic, DES related

    ones are statistical as you will soon find out.

    ----[ 5.1 - The DES algorithm

    DES is a so called Feistel cipher [R01] with a block size of 64 bitsand 16 rounds (r). First a permutation (IP) is applied to the input thenin each round a round-function is applied which splits its input in two 32bits buffers L (Left) and R (Right) and applies the following equationssystem:

    L(r+1) = R(r)

    R(r+1) = L(r) [+] f(R(r),K(r))

    With:0

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    15/51

    * L(r) * * R(r) *********** **********

    | |.------------- || | v .---------------------.| | .-------------. / Linear transformation \| | \ E-Box / ( 32b -> 48b )| | '---------' \ /| | | '---------------------'| | v .------------.| | ..... ********** / XOR operand \| | . + . 48b )| | ..... ********** \ /| | /\ '------------'| | / \| | v v .-------------------------.| | .------. .------. / Non linear transformation \| | \ S1 / ... \ S8 / ( using SBox )| | '--' '--' \ 8x6b -> 8x4b /| | \ / '-------------------------'| | \ /| | v v .---------------------.| | .--------. / Linear transformation \| | | P-Box | ( 32b -> 32b )

    | | '--------' \ /| | | '---------------------'| | ..v.. .------------.| '--------->. + . / XOR operand \| ..... ( 2x32b -> 32b )| | \ /v v '------------'

    ********** *********** L(r+1) * * R(r+1) *********** **********---------------------------------------------------------------------------

    When the 16 rounds are completed, the IP^-1() function is applied and

    the result is called the ciphertext.

    While SBox and XOR are self explanatory, let me give you a few moredetails about the linear transformations (E-Box and P-Box).

    The E-Box---------

    The E-Box is used to extend a 32 bits state into a 48b one so that eachbit can be combined with a round-key bit using a XOR. To transform 32 bitsinto 48 bits, 16 out of the 32 bits are duplicated. This is performed using

    the following table:

    32, 1, 2, 3, 4, 5,4, 5, 6, 7, 8, 9,8, 9, 10, 11, 12, 13,12, 13, 14, 15, 16, 17,16, 17, 18, 19, 20, 21,20, 21, 22, 23, 24, 25,24, 25, 26, 27, 28, 29,28, 29, 30, 31, 32, 1

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    16/51

    For example, the first bit of output will the last bit of input (32)and the second bit of output will be the first bit of input (1). In thisparticular case the bit positions are written from 1 to 32. As you may havenoticed, the 16 bits from columns 3 and 4 are not duplicated. They arecalled the middle bits, we will see later why they are important.

    The P-Box---------

    The P-Box is a bit permutation which means that every bit of input willhave a new position in the output. Such a transformation is linear and canbe represented by a bit matrix. When combined with a XOR operation with aconstant, this is what we call an affine transformation (AT).

    ----[ 5.2 - An overview of DES WB primitives

    The first WB DES implementation was presented in [R09]. Explaining howand why DES white-box were designed is not the most simple of the taskespecially with an ASCII / 75 columns constraint ;> I'll try to focus on

    the main mechanisms so that you can get a global picture with the nextsection. At some point you may however feel lost. In that case, please readthe excellent [R15]

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    17/51

    | | | 48bv v v

    Mem1 Mem2 Mem3

    At this point the internal state is composed of 32 x 2 + 48 = 112bits which is the maximum required size before being shrunken to a64 bits state at the end of the round: L(r+1) || R(r+1). To avoidany information leak, a unique -constant size- state is used to hidethe position of the bits.

    If you remember 5.1 paragraph, the E-Box is duplicating 16 out ofthe 32 bits of R(r). As a result, constructing 'Mem2' can be doneextracting 16 bits out of R(r) and the 16 remaining ones out of'Mem3'. With this property, the internal state is composed of 96bits. Here is a diagram ripped from [R17] to understand how theprimitive is modified to handle this 96 bits state:

    32b 48b 16b************** ********************* ********

    state 1: * L(r) * * X(r) * * r(r) *************** ********************* ********

    | | | |

    | v | || ********* ..... | v| * sK(r) *--> . + . | .-------.| ********* ..... '-->( Merge )| | '-------'| v || .-------------. || \ S / || '---------' || | |

    32b v v 32b 32b v************** *************** ***************

    state 2: * L(r) * * Y(r+1) * * R(r) *

    ************** *************** ***************| | |v | |

    ..... .--------. | |

    . + .

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    18/51

    - Y(r) being the output of the SBox of round r-1- r(r) being the complementary bits so that X(r) and r(r) is aduplication of R(r)

    b) Input and outputs between elementary operations are protected usingwhat is called the "internal encodings". These encodings are appliedto functions implemented as lookup tables.

    Let's take an example. You are chaining f() and g() which means thatyou are calculating the composition g() o f(). Obviously without anyprotection, an attacker can intercept the result of f() at debugtime (e.g. by putting a breakpoint at the entry of g())

    Now if you want to protect it, you can generate a random bijectionh() and replace f() and g() by F() and G() where:

    F() = h() o f()G() = g() o h()^-1

    Note: Again this is a mere example, we do not care about the{co}domain consideration.

    These functions are evaluated and then expressed as lookup tables.Obviously this will not change the output as:

    G() o F() = (g() o h()^-1) o (h() o f())= g() o (h()^-1 o h()) o f() [associativity]= g() o f()

    But the difference is that intercepting the output of F() doesn'tgive the output of f(). Pretty cool trick, right?

    However I've just written that WB DES implementations were alwaysmanipulating 96 bits states. Then does it mean that we need lookuptables of 2^96 entries? No, this would be troublesome ;> We can usethe so called "path splitting" technique.

    Consider the example of a 32 bits buffer. To avoid using a hugelookup table, you can consider that this buffer is an 8 bits array.Each element of the array will then be obfuscated using acorresponding 8 bits lookup table as described below:

    ****************************************** IN[0] || IN[1] || IN[2] || IN[3] ******************************************

    | | | || | | |v v v v

    .-------. .-------. .-------. .-------.| 2^8 B | | 2^8 B | | 2^8 B | | 2^8 B |

    '-------' '-------' '-------' '-------'| | | || | | |v v v v

    ****************************************** OUT[0] || OUT[1] || OUT[2] || OUT[3] ******************************************

    I took the example of an 8 bits array but I could have used anysize. Something really important to understand: the smaller the

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    19/51

    lookup table is, the more it will leak us information. Keep it inmind.

    c) Do you remember when I said that a WB implementation was the exactimplementation of the corresponding crypto primitive? Well it's nottrue. Or you could say that I was simplifying things ^_~

    Most of the time (in real life), WB_DES() is a G() o DES() o F()where F() and G() are encoding functions. So the first input(plaintext) and the last output (ciphertext) may be obfuscated aswell. This is called an "external encoding" and this is used toharden the white-box implementation. Indeed if there were no suchfunctions, first & last rounds would be weaker than other rounds.This 'academic' protection aims at preventing trivial key recoveryattacks. A WB implementation without external encoding is said to be'naked'.

    In the context of real life protections, it may (or may not) beassociated with an additional layer to protect the I/O before &after the encryption. It would be bad to intercept the plaintextonce decrypted, right? Commercial protections almost never usenative implementations for (at least) this reason. Intercepting aplaintext is indeed far easier than recovering the encryption key.

    In the WB DES case, common academic designs use affine functions,encoded or not.

    Transforming DES functions--------------------------

    Now that we've had an overview of how I/O were protected betweenelementary functions, let's see how we can build said functions.

    a) The partial evaluation

    This is probably the most intuitive part of the WB implementation. Thisis about 'fusing' the S-Boxes with the round-keys. This is exactly what wasperformed in the previous AES challenge. If you can remember, this is alsothe first example that I gave at the beginning of the paper to introducethe white-boxing concept.

    Using the previous diagram, it means that we want to convert this step:

    32b 48b 16b************** ********************* ********* L(r) * * X(r) * * r(r) *************** ********************* ********

    | | | |

    | v | || ****** ..... | v| * sK *--> . + . | .-------.| ****** ..... '-->( Merge )| | '-------'| v || .-------------. || \ S / || '---------' || | |

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    20/51

    32b v v 32b 32b v************** *************** *************** L(r) * * Y(r+1) * * R(r) *************** *************** **************

    into this one:

    ********************************************** state 1 (12 x 8 = 96 bits) **********************************************

    | | | |v v v v

    .-----..-----..-----. .-----.| T0 || T1 || T2 | ... | T11 |'-----''-----''-----' '-----'

    | | | |v v v v

    ********************************************** state 2 (96 bits) **********************************************

    A lookup table Ti (mapping a byte to a byte) is called a 'T-Box'. There

    are two types of T-Box because of the heterogeneity of the operationsperformed on the state:

    - The non neutral T-box. They are the 8 T-boxes involved with theSbox and the XOR. Each of them is concealing an Sbox and a subkeymixing.

    input:-> 6 bits from X(r) to be mixed with the subkey-> 1 bit from L(r) or r(r)-> 1 bit from L(r) or r(r)

    output:-> 4 bits from the Sbox

    -> 2 bits from X(r) taken from the input before beingmixed with the subkey-> 1 bit from L(r) or r(r)-> 1 bit from L(r) or r(r)

    - The neutral T-box which are only used to connect bits of state 1to bits of state 2. For example the bits of L(r) are neverinvolved in any operation between state 1 and state 2.

    input:-> 1 bit from L(r) or r(r)-> 1 bit from L(r) or r(r)

    [...]

    -> 1 bit from L(r) or r(r)output:

    -> the input (permuted)

    Keep in mind that in each case, you have a 'nibble view' of both inputsand outputs. Moreover, permutations are used to make harder thelocalization of Sbox upon a simple observation. To have a betterunderstanding of this point as well as associated security explanationsI recommend to read [R09].

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    21/51

    b) The AT transformation

    We now want to transform this:

    ************** *************** ***************state 2: * L(r) * * Y(r+1) * * R(r) *

    ************** *************** ***************| | |v | |

    ..... .--------. | |

    . + .

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    22/51

    '----' '----'----'----'----' '----'

    Vector Y Matrix M Vector X

    Here the Yi and Xi are 2 bits sub-vectors while A,B,C,etc. are 2x2bit-submatrix. Let's focus on Y0, you can write:

    Y0 = A*X0 [+] B*X1 [+] C*X2 [+] D*X3

    Because A,B,C and D are constants it's possible to evaluate themultiplications and build the corresponding lookup tables (Li). This givesthe following diagram:

    ****** ****** ****** ******* X0 * * X1 * * X2 * * X3 ******* ****** ****** ******| | | |v v v v

    .----. .----. .----. .----.| L0 | | L1 | | L3 | | L4 |'----' '----' '----' '----'

    | | | || ..... | | ..... |'->. + .. + .. + .

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    23/51

    '------' '------'

    2b 2b

    \ /\ /| |v v

    2b 2b.---------.\ S2 /'------'

    2b

    |v

    ******* Y0 *******

    This is called an 'encoded network'. The main side effect of thisconstruction is the important number of lookup tables required.

    --[ 6 - Breaking the second case: Wyseur's challenge

    ----[ 6.1 - Reverse engineering of the binary

    As far as I can tell, there is an obvious need to rewrite the binary asC code because:

    - We need to understand exactly what's going on from a mathematicalpoint of view and C is more suitable than ASM for that purpose

    - Rewriting the functions will allow us to manipulate them easilywith our tools. This is not mandatory though because we couldbe using debugging functions on the original binary itself.

    Again I won't detail all the reverse engineering process because thisis neither the main topic nor very hard anyway compared to what you mayfind in the wild (in commercial protections).

    High level overview

    --------------------

    Let's begin by running the executable:

    ---------------------------------------------------------------------------$ ./wbDES.origUsage: ./wbDES.orig Where is an 8-byte hexadecimal representation of the input to beencrypted

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    24/51

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

    OK so we need to provide the 8 bytes of the plaintext as separatearguments in the command line. Hum, weird but OK. When the binary isexecuted, the first thing performed is a conversion of the argumentsbecause obviously a suitable buffer for cryptographic operations isnecessary. The corresponding instructions were rewritten as the followingC function:

    ---------------------------------------------------------------------------// I even emulated a bug, will you find it? ;>inline void convert_args(char **argv){

    int i = 0; // ebp-50h

    while(i

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    25/51

    most likely the initialization function.

    - wb_round(): 0x08048C65 to 0x08049731

    This code takes the 12 bytes buffer generated by wb_init() as inputand modifies it. The function is called 16 times by main(). Because16 is exactly the number of DES rounds, assuming it is the roundfunction seems fair.

    - wb_final(): 0x08049765 to 0x08049E67

    This code takes the last buffer returned by wb_round() as input andreturns an 8 bytes buffer which is printed on the screen. So we canassume that this is the termination function in charge of buildingthe DES ciphertext out of the last internal state.

    *: There is no 'function' in this program, probably because of an inlining,but we can still distinguish logical parts.

    You may argue that attributing roles to wb_init, wb_round and wb_finalis a bit hasty but there is something interesting in the code: symbols! Ineach of these functions, an array of lookup tables is used and named'Initialize', 'RoundAffineNetwork' and 'FinalRoundNetwork' in thecorresponding functions. Convenient isn't it?

    Usually in commercial protections, engineers will take care of littledetails such as this and try to avoid leaking any information. In this casehowever, it can be assumed that the focus is on the cryptography as thereare neither anti-debugs nor anti-disassembling protections so it should besafe to trust our intuition.

    Thanks to this first reverse engineering step, we're able to rewritea similar main function:

    -------------------------------- wb_main.c --------------------------------unsigned char in[8]; // ebp-1Chunsigned char out[12]; // ebp-28h

    unsigned char temp[12]; // ebp-34h

    [...]

    int main(int argc, char **argv){

    if( argc != 9){

    printf(usage, argv[0], argv[0]);return 0;

    }

    /* Fill the in buffer */

    convert_args(argv);

    /* and print it :) */

    printf("\nINPUT: ");for(j=0; j

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    26/51

    for(j=0; j

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    27/51

    Now with this information in mind, let's have a look at the reversedwb_init() function:

    -------------------------------- wb_init.c --------------------------------unsigned char p[8];

    inline void wb_init(int m // ebp-48h

    ){

    unsigned int temp0; // ebp-228hunsigned int temp1; // ebp-224h[...]unsigned int temp23; // ebp-1CCh

    unsigned int eax,ebx,ecx,edx,edi,esi;

    bzero(p,sizeof p);p[0] = iBOX_0[m][in[0]];p[1] = iBOX_1[m][in[1]];p[2] = iBOX_2[m][in[2]];p[3] = iBOX_3[m][in[3]];p[4] = iBOX_4[m][in[4]];p[5] = iBOX_5[m][in[5]];

    p[6] = iBOX_6[m][in[6]];p[7] = iBOX_7[m][in[7]];

    // First nibble

    ecx = (0xF0 & p[0]) ^ ( p[1] >> 4 );temp3 = 0xF0 & iBOX_8[m][ecx];

    ecx = (0xF0 & p[2]) ^ ( p[3] >> 4 );eax = iBOX_9[m][ecx] >> 4;ecx = temp3 ^ eax;temp6 = 0xF0 & iBOX_12[m][ecx];

    ecx = (0xF0 & p[4]) ^ ( p[5] >> 4 );eax = iBOX_10[m][ecx] >> 4;ecx = temp6 ^ eax;edi = 0xF0 & iBOX_13[m][ecx];

    ecx = (0xF0 & p[6]) ^ ( p[7] >> 4 );eax = iBOX_11[m][ecx] >> 4;ecx = edi ^ eax;edx = iBOX_14[m][ecx];esi = edx & 0xFFFFFFF0;

    // Second nibble

    ecx = (0x0F & p[1]) ^ (0xF0 & ( p[0]

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    28/51

    ecx = temp18 ^ eax;temp21 = 0xF0 & (iBOX_13[m][ecx] /

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    29/51

    \ /\ H H /'---------. .---------'

    | |v v

    .---------.\ iBox_14 /'-------'

    \H \ 8 bits

    \ Concatenation '---> ***********of nibbles * OUT_x *

    .---> ***********/

    L //

    .-------./ iBox_14 \'---------'^ ^

    L | | L.--------' '--------.

    / \/ \

    .-------. .-------.

    / iBox_12 \ / iBox_13 \'---------' '---------'

    ^ ^ ^ ^/ \ / \

    L / \ L L / \ L/ \ / \

    .-------. .-------. .-------. .-------./ iBox_8 \ / iBox_9 \ / iBox_10 \ / iBox_11 \'---------' '---------' '---------' '---------'

    ^ ^ ^ ^ ^ ^ ^ ^L / \ L L / \ L L / \ L L / \ L/ \ / \ / \ / \

    .-----. .-----. .-----. .-----. .-----. .-----. .-----. .-----./iBox_0 \/iBox_1 \ /iBox_2 \/iBox_3 \ /iBox_4 \/iBox_5 \ /iBox_6 \/iBox_7 \'-------''-------' '-------''-------' '-------''-------' '-------''-------'

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    30/51

    ^ ^ ^ ^ ^ ^ ^ ^L | L | L | L | L | L | L | L |

    | | | | | | | |

    ******** ******** ******** ******** ******** ******** ******** ********* IN_0 * * IN_1 * * IN_2 * * IN_3 * * IN_4 * * IN_5 * * IN_6 * * IN_7 ********* ******** ******** ******** ******** ******** ******** ********

    In this case, 'H' is used as a suffix to identify the most significant(High) nibble of a particular byte. As you can see, the input (respectivelythe output) is not an 8 (respectively 12) _bytes_ array but rather a 16(respectively 24) _nibbles_ array. Indeed, each byte array (iBox_i) storesexactly 2 lookup tables. We say that such lookup tables are 'compacted',see [R14] for additional details.

    Global description-------------------

    Good news guys, the wb_init(), wb_round() and wb_final() functions are

    composed of the same nibble oriented patterns. So basically wb_round() andwb_final() contain also AT applied to a nibbles array and the end of thereverse engineering is quite straightforward.

    Remark: Manipulating nibbles implies that the internal encoding isperformed using 4 bits to 4 bits bijections.

    Again thanks to asciio, we're able to draw something like that:

    8 x (2x4) = 64 bits

    2x4 = 8 bits

    .----------------------------------. .-----------.| .-----. .-----. .-----. | | INPUT |

    .----| IN0 | | IN1 | ... | IN7 | | '-----------'| | '-----' '-----' '-----' | |v '------------|----------------|----' v| v | .------------.|-------------|-------

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    31/51

    || STG1_0 | | STG1_1 | ... | STG1_11 || ||'--------' '--------' '---------'| |'----------------------------------------------------' |

    |2x4bits |

    12 x (2x4) = 96 bits | |

    v.-------------.

    ... 15x ( wb_round func )'-------------'

    .----------------------------------------------------. ||.---------..---------. .----------.| ||| STG14_0 || STG14_1 | ... | STG14_11 || ||'---------''---------' '----------'| |'-----|--------|-------------------------------|-----' v

    | v | .-------------.| | | ( wb_final func )'----->-----

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    32/51

    not a cryptographer, it's _practical_. If you prefer more _theoretical_solutions, please refer to [R04] for a list of papers dealing with thesubject.

    ----[ 6.2 - The discovery step

    First of all, let's gather some information about this white-box. Thereis a first immediate observation: there is no explicit T-box step whichproves that it is combined with the AT step in a same function. This is anoptimization which was historically proposed in [R14] in order to protectthe output of the T-box and, as a result, to mitigate the so-calledstatistical bucketing attack described in [R09] while compressing theimplementation by merging operations.

    I used this information as well as the size of the binary (which is abit more than the size of the lookup tables) as indicators of how recentthe design could be. I didn't have the time to read all the white-boxrelated papers (although there are not a thousand of them).

    Analyzing the wb_init()-----------------------

    Earlier, I've made assumptions about wb_init() and wb_round() but atthis point little is really known about them. Now is the time to play a bitwith wb_init() and by playing I mean discovering the "link" between theinput (plaintext) and the input of wb_round() which will be called "stage0"from now on.

    Let's begin by a quick observation. As said before, for each outputbyte of wb_init(), there is a corresponding set of 14 (condensed) iBox_i.A simple glance at these boxes is enough to determine that for each set,the 8 first iBox_i have a very low entropy. Conversely, the remaining 5ones have a high entropy:

    ---------------------------------------------------------------------------[...]

    unsigned char iBOX_3[12][256] = {{0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,0xf7,[...]0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,

    0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,0xf1,},

    [...]

    unsigned char iBOX_8[12][256] = {{0x13,0xdf,0xf9,0x38,0x61,0xe2,0x44,0x9e,0xc0,0x2a,0x0b,0xb7,0x7c,0xad,0x56,0x85,0x96,0xbe,0x8b,0x04,0x27,0xcd,0xa8,0x1f,0xec,0x65,0x39,0xd1,0x50,0x42,0x73,0xfa,0x4a,0x52,0x04,0x8b,0xcc,0x2f,0x19,0xad,0x67,0xe3,

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    33/51

    [...]0x8a,0x08,0xbd,0x59,0x36,0xf1,0xef,0x45,0x13,0xd4,0x90,0x67,0xae,0x76,0x3c,0xf7,0xe4,0x65,0x91,0x43,0x2b,0xcd,0x80,0x58,0xd9,0x1a,0xbf,0x02,},

    [...]---------------------------------------------------------------------------

    The example shows us that iBOX_3[0] has only 2 possibles values: 0xf7for any index inferior or equal to 127 and 0xf1 for the remaining ones.Said otherwise, this box is a bit filter:

    - High output nibble: only 1 possible value (0xf) => no bit chosen- Low output nibble: 2 possible values (0x1, 0x7) => the input's

    MSB is chosen

    Let's visualize the effect of the 8 first iBox_i for every outputnibble. To see if the particular bit at position 'i' is involved in the LUT'p' then you can compute:

    - p[0]&0xf0 and p[(1 bit 56

    OUT[0] (low) is composed of:

    -> bit 24-> bit 32-> bit 40-> bit 48

    [...]OUT[11] (high) is composed of:

    -> bit 7-> bit 15-> bit 23-> bit 31

    OUT[11] (low) is composed of:-> bit 14-> bit 22

    -> bit 46-> bit 54

    [+] Total nbr of bits involved = 96[...]---------------------------------------------------------------------------

    So the analysis of the 8 first LUT reveals that each output (OUT[i])nibble is linked to exactly 4 input bits. So the 8 first iBox_i are no morethan an obfuscated linear mapping.

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    34/51

    A good idea is to focus more specifically on the input bits frequency:

    ---------------------------------------------------------------------------$ ./entropy[...][+] Nbr of times a bit is used[b_00] 2 [b_01] 1 [b_02] 2 [b_03] 1 [b_04] 2 [b_05] 1 [b_06] 2 [b_07] 1[b_08] 2 [b_09] 1 [b_10] 2 [b_11] 1 [b_12] 2 [b_13] 1 [b_14] 2 [b_15] 1[b_16] 2 [b_17] 1 [b_18] 2 [b_19] 1 [b_20] 2 [b_21] 1 [b_22] 2 [b_23] 1[b_24] 2 [b_25] 1 [b_26] 2 [b_27] 1 [b_28] 2 [b_29] 1 [b_30] 2 [b_31] 1[b_32] 2 [b_33] 1 [b_34] 2 [b_35] 1 [b_36] 2 [b_37] 1 [b_38] 2 [b_39] 1[b_40] 2 [b_41] 1 [b_42] 2 [b_43] 1 [b_44] 2 [b_45] 1 [b_46] 2 [b_47] 1[b_48] 2 [b_49] 1 [b_50] 2 [b_51] 1 [b_52] 2 [b_53] 1 [b_54] 2 [b_55] 1[b_56] 2 [b_57] 1 [b_58] 2 [b_59] 1 [b_60] 2 [b_61] 1 [b_62] 2 [b_63] 1

    $---------------------------------------------------------------------------

    The even bits are used exactly twice while odd ones are only used once(here odd and even both refer to the position). Or you could say that evenbits are duplicated in the internal state built after this step.

    Anybody familiar with the DES knows that the IP(X) function of the DESgives the internal state L || R where:

    - L is an array composed of the odd bits of X- R is an array composed of the even bits of X

    In an academic WB DES implementation, building the 96 bits state isperformed using the duplication of even bits (R). This is because thesebits are necessary as both input of the E-box and output of the DES roundfunction (see my previous description of DES). So we have an obvious matchand it's a clear indication that there is no external encoding applied tothe input (and as a consequence probably none applied to the output aswell). More precisely there could still be a bit permutation on both L & Rbits but it sounds like a silly hypothesis so let's forget about that.What would be the point?

    ---

    Now let's continue with the differential analysis of the full wb_init().This step is much more intuitive. Think about it: if you want to discoverthe nibbles of stage0 (the output of wb_init) influenced by a specificinput bit then apply wb_init() to two inputs whose only difference is thisbit. Then calculate the XOR of both results and the non null nibbles arethe ones which are affected. This was greatly inspired by [R09].

    ---------------------------------------------------------------------------$ ./entropy[...][+] Differential cryptanalysis on wb_init()

    -> b_00 :: 00 04 20 00 00 00 00 00 00 00 00 00-> b_01 :: 00 00 00 40 00 00 00 00 00 00 00 00-> b_02 :: 00 00 00 09 d0 00 00 00 00 00 00 00-> b_03 :: 00 00 00 00 00 00 00 90 00 00 00 00-> b_04 :: 00 00 00 00 00 0e 60 00 00 00 00 00-> b_05 :: 00 00 00 00 00 00 00 00 00 50 00 00-> b_06 :: 80 00 00 00 00 00 00 05 00 00 00 00-> b_07 :: 00 00 00 00 00 00 00 00 00 00 00 b0-> b_08 :: 00 07 00 00 00 00 00 00 01 00 00 00-> b_09 :: 00 00 00 f0 00 00 00 00 00 00 00 00

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    35/51

    -> b_10 :: 00 00 00 06 00 00 00 00 00 03 00 00[...]---------------------------------------------------------------------------

    So for even bits there are 2 nibbles affected and only one for oddbits. Not only does it confirm our previous hypothesis but it also revealsthe position (the index in the nibble array) of the bits in the WB internalstate (up to 1/2 probability for even bits). This is particularlyinteresting when it comes to locate S-box for example ;-)

    Analyzing the first wb_round()------------------------------

    To analyze this function, one clever trick is to make use of the oddbits (L0) and perform a differential analysis.

    Natively, the DES satisfies the following system of equations:

    L1 = R0R1 = L0 [+] f(R0,K0)

    With

    L0 || R0 being the result of IP(plaintext)K0 being the first subkey

    Let's now consider two plaintexts (A and B). The first one is composedof bits all set to 0 (L0_A || R0_A) whereas the second one ((L0_B || R0_B)has a weight of 1 and more specifically, its sole bit set to 1 is in L0.

    Remark: While there is only one A, there are obviously 32 possible B.We can thus write thanks to the previous equations:

    L1_A = R0_A = 0R1_A = L0_A [+] f(R0_A,K0) = f(0,K0)

    And

    L1_B = R0_B = 0R1_B = L0_B [+] f(R0_B,K0) = L0_B [+] f(0,K0)

    (Again please excuse the lazy notation)

    This finally gives us:

    DELTA(L1||R1)(A,B) = ( L1_A [+] L1_B || R1_A [+] R1_B )= ( 0 [+] 0 || f(0,K0) [+] L0_B [+] f(0,K0) )= ( 0 || L0_B )

    We know that L0_B's weight is 1 so in a native DES the modification ofone bit in L0 induces the modification of a unique bit in the output of theDES round function. In an obfuscated context, this means that only oneoutput nibble is modified and calculating DELTA (the result of the socalled differential analysis if you prefer) is merely a trick to identifyit easily.

    Now that you've grasped the main idea, let's work on the real WB. Againconsider plaintexts A and B which give (L0_A || R0_A) and (L0_B || R0_B)after IP().

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    36/51

    Because wb_round() includes the E-box and produces a 96 bits outputstate, we now have to consider an additional transformation:

    X (64b) ---> [ wb_init + first wb_round ] ----> Y (96b)

    Here Y is the output of wb_round. Following the design in academicpublications we can write:

    Y = RP ( L1 || X1 || r1 ) (RP = Random bit Permutation used to hidethe position of bits in theobfuscated output.)

    With:- L1 being R0 (from DES round equation)- X1 being the result of the E-box applied to R1- r1 being the complementary bits such as the set of X1 and r1 isexactly twice R1

    Now let's apply again the differential analysis. It's important toremark that RP() and E() are both linear operations as this simplifiesthings. Indeed it's well known that:

    LinearFunc(x [+] y) = LinearFunc(x) [+] LinearFunc(y)

    Putting everything together this gives us:

    DELTA(Y)(a,b) = RP(Y_A) [+] RP(Y_B)= RP(Y_A [+] Y_B)= RP(L1_A [+] L1_B || X1_A [+] X1_B

    || r1_A [+] r1_B)= RP(0 [+] 0 || E(f(0,K0)) [+] E(L0_B [+] f(0,K0))

    || r1_a [+] r1_b)= RP(0 || E(f(0,K0) [+] L0_B [+] f(0,K0)z)

    || r1_A [+] r1_B)= RP(0 || E(L0_B) || r1_A [+] r1_B)

    If the bit set in L0 is a middle bit then:- Weight(E(L0_B)) = 1 and Weight(r1_A [+] r1_B)) = 1If the bit set in L0 isn't a middle bit then:

    - Weight(E(L0_B)) = 2 and Weight(r1_A [+] r1_B)) = 0

    In both cases, Weight(RP(0 || E(L0_B) || r1_A [+] r1_B)) = 2, RP havingno effect on the weight since it only permutes bits. This means that 1 bitmodification should have a visible impact on 'at most' 2 nibbles. 'at most'and not 'exactly' because with the effect of RP() the two bits could belocated in the same nibble.

    Let's see if we are right:

    ---------------------------------------------------------------------------b_01 :: 00 05 d0 00 00 00 00 00 00 00 00 00

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    37/51

    b_19 :: 00 00 00 09 00 00 00 00 00 0f 00 00b_21 :: 00 00 00 00 00 08 00 00 00 00 06 00b_23 :: 00 00 00 00 00 00 00 0d 00 00 00 08b_25 :: 08 d0 00 00 00 00 00 00 00 00 00 00b_27 :: 00 00 04 20 00 00 00 00 00 00 00 00b_29 :: 00 00 00 00 05 80 00 00 00 00 00 00b_31 :: 00 00 00 00 00 00 04 20 00 00 00 00b_33 :: 02 70 00 00 00 00 00 00 00 00 00 00b_35 :: 00 00 0c f0 00 00 00 00 00 00 00 00b_37 :: 00 00 00 00 0d b0 00 00 00 00 00 00b_39 :: 00 00 00 00 00 00 0f a0 00 00 00 00b_41 :: 0c 00 00 00 00 00 00 00 0f 00 00 00b_43 :: 00 00 0d 00 00 00 00 00 00 02 00 00b_45 :: 00 00 00 00 09 00 00 00 00 00 05 00b_47 :: 00 00 00 00 00 00 03 00 00 00 00 03b_49 :: 0f 00 00 00 00 00 00 00 0d 00 00 00b_51 :: 00 00 06 00 00 00 00 00 00 03 00 00b_53 :: 00 00 00 00 0b 00 00 00 00 00 0c 00b_55 :: 00 00 00 00 00 00 02 00 00 00 00 01b_57 :: b0 00 00 00 00 00 00 0c 00 00 00 00b_59 :: 00 03 60 00 00 00 00 00 00 00 00 00b_61 :: 00 00 00 0e 40 00 00 00 00 00 00 00b_63 :: 00 00 00 00 00 0b f0 00 00 00 00 00

    ---------------------------------------------------------------------------

    And that's exactly what we were expecting :) Well to be honest, I firstobserved the result of the differential analysis, then remarked a 'strange'behavior related to the odd bits and finally figured out why using maths ;)

    One cool thing with this situation is that we can easily leak theposition of the specific S-Boxes inside the T-Boxes. First let's comparethe differential analysis of even bits 28,36,52,60 and of odd bit 1:

    ---------------------------------------------------------------------------b_01 :: 00 05 d0 00 00 00 00 00 00 00 00 00b_28 :: 0d 75 dd 00 00 00 04 20 0f d2 00 00b_36 :: 0c 05 d0 00 09 00 04 20 cf 00 05 00

    b_52 :: 00 05 d0 09 00 00 00 00 90 0f 00 00b_60 :: 0c 05 d6 09 00 00 02 00 3f 0d 00 01---------------------------------------------------------------------------

    Obviously setting these even bits one by one induces the samemodification (amongst others) as setting the odd bit 1 (nibbles 01L (0x5)and 02H (0xd)) so there must be some kind of mathematical link between thembecause the other bits do not have such property.

    Playing with Sbox------------------

    The reason behind this behavior is very simple to explain. But first,let's take back the example of plaintext 'A' (null vector):

    We know that:

    R1_A = L0_a [+] P(S1[0 [+] k0] || S2[0 [+] k1] || ... || S8[0 [+] k7])R1_A = 0 [+] P(S1[k0] || S2[k0] || ... || S8[k7])R1_A = P( S1[k0] || S2[k1] || ... || S8[k7] )

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    38/51

    Where:The ki being 6 bits vectors (0

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    39/51

    Playing with the witness------------------------

    Now imagine that we're using another plaintext (X) with weight 1 andwhose weight is in one of the 6 possible bits influencing Sbox S. There aretwo possible situations:

    - S still produces b- S now produces b+1

    If we perform a differential analysis between X and A (null vector)this gives us:

    case 1:=======

    ... ??b? ???? ???? ???b ... (from A)

    [+]

    ... ??b? ???? ???? ???b ... (from X)

    =

    ... ??0? ???? ???? ???0 ...

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    40/51

    Let's think. At this point and thanks to our analysis of wb_init()we're almost sure that there is no external encoding applied to the input.So there should be a match between our practical results and thetheoretical relations in the original DES algorithm. To verify my theory, Iwrote a little script to compute the positions of the bits involved witheach Sbox:

    ---------------------------------------------------------------------------$ ./bitmapping.py[6, 56, 48, 40, 32, 24]

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    41/51

    Didn't you notice something particular with bit 02, 28 and 60? Well the'impacted' nibbles were neither 0 nor a witness nibble. For exampleconsider bit 60:

    ---------------------------------------------------------------------------19 :: 00 00 00 09 00 00 00 00 00 0f 00 0060 :: 0c 05 d6 09 00 00 02 00 3f 0d 00 01

    ---------------------------------------------------------------------------

    The first impacted nibble '0x9' is a good one (witness nibble) but thesecond one is neither '0x0' nor '0xf' (witness). How is that possible?

    Well the answer lies in both:- the (non)-middle bits- the P-box

    Indeed if you consider the bits sent to Sbox 5, you have to know that:- bits 02 and 60 are sent to both Sbox 4 & 5- bits 52 and 44 are sent to Sbox 5- bits 36 and 28 are sent to both Sbox 5 & 6

    So when 1 non-middle bit is set, this will impact the output of 2 Sboxand we're unlucky, the P-box will have the unfortunate effect of setting

    them in the same nibble, hence the difference observed.

    ----[ 6.3 - Recovering the first subkey

    If the relations observed are 'key dependent', considering the factthat the S-Boxes are known (which means unmodified otherwise this would becheating :p) then isn't this an indirect leak on the key itself that couldbe transformed in a key recovery? Oh yes it is :-)

    First cryptanalysis

    -------------------

    The main idea is really simple: we know that for a given subkey,several unitary vectors (plaintexts of weight 1) will produce the sameoutput bit.

    Let's take again the previous case. We have:

    .------.------.------.-----.-----.------.| b_02 | b_60 | b_52 |b_44 |b_36 | b_28 |'------'------'------'-----'-----'------'

    .....

    . + .

    ......------.------.------.-----.-----.------.| k24 | k25 | k26 | k27 | k28 | k29 |'------'------'------'-----'-----'------'

    |v

    ********************** Sbox 5 *

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    42/51

    *********************|v

    .------.------.------.-----.| y0 | y1 | y2 | y3 |'------'------'------'-----'

    Let us consider bit 01. We know that it will be XORed to y2 so from thedifferential analysis we can derive the set of relations:

    [ k24 [+] 0, k25 [+] 1, k26 [+] 0, k27 [+] 0, k28 [+] 0, k29 [+] 0 ] => b[ k24 [+] 0, k25 [+] 0, k26 [+] 1, k27 [+] 0, k28 [+] 0, k29 [+] 0 ] => b[ k24 [+] 0, k25 [+] 0, k26 [+] 0, k27 [+] 0, k28 [+] 1, k29 [+] 0 ] => b[ k24 [+] 0, k25 [+] 0, k26 [+] 0, k27 [+] 0, k28 [+] 0, k29 [+] 1 ] => b

    So amongst all possible sets {k24,k25,k26,k27,k28,k29}, only a few ofthem (including the one from the real subkey) will satisfy the relations.Testing all possible sets (there are 2^6 = 64 of them) will give us 2 listsbecause we do not know if b=1 or b=0 so we have to consider both cases.

    Applying this technique to both y0, y1, y2 and y3 will allow to filterefficiently the number of possible candidates as we will only considerthose present in all lists. The success of this cryptanalysis is highly

    dependent on the number of relations that we will be able to create for aparticular S-Box. Practically speaking, this is sufficient to recover thefirst subkey as the complexity should be far below 2^48. Should be? Yes Ididn't test it... I found even better.

    Immediate subkey recovery-------------------------

    As I said above, our success is dependent of the number of equations soimproving the cryptanalysis can be done by finding ways to increase thisnumber. There are two obvious ways to do that:

    - There may exist combinations of input bits other than unitaryvectors (weight > 1) which can produce the witness nibbles in adifferential analysis.

    - If the impacted nibbles are both 0x0 then this gives us a newrelation where expected output bit is b [+] 1

    Practically speaking this gives us the following result for Sbox5 andbit 01:

    ---------------------------------------------------------------------------$ ./exploit[...]

    { 1 0 0 0 0 0 } = { 1 }

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    43/51

    { 1 1 0 1 0 0 } = { 1 }{ 0 0 1 1 0 0 } = { 1 }{ 1 0 1 1 0 0 } = { 0 }{ 0 1 1 1 0 0 } = { 1 }{ 1 1 1 1 0 0 } = { 0 }{ 0 0 0 0 1 0 } = { 0 }{ 1 0 0 0 1 0 } = { 1 }{ 0 1 0 0 1 0 } = { 0 }{ 1 1 0 0 1 0 } = { 0 }{ 0 0 1 0 1 0 } = { 1 }{ 1 0 1 0 1 0 } = { 0 }{ 0 1 1 0 1 0 } = { 0 }{ 1 1 1 0 1 0 } = { 1 }{ 0 0 0 1 1 0 } = { 0 }{ 1 0 0 1 1 0 } = { 0 }{ 0 1 0 1 1 0 } = { 1 }{ 1 1 0 1 1 0 } = { 0 }{ 0 1 0 1 0 1 } = { 1 }

    [...]

    [ key candidate is 31]---------------------------------------------------------------------------

    The cryptanalysts have the habit to always evaluate the complexity oftheir attacks but in this case let's say that it's useless. Only one subkeyappeared to be valid out of the 2^48 possible ones.

    ----[ 6.4 - Recovering the original key

    Now that we've retrieved the first subkey, our goal is almost reached.So how do we retrieve the secret key? Well DES subkeys can be seen astruncated permutations of the original key. This means that we now have 48out of the 56 bits of the original key.

    I could explain the key scheduling mechanism of the DES, but it'suseless as the only important thing is to be able to reverse thepermutation. This is done easily thanks to the following pythonmanipulation applied to the sKMap1 array, itself being shamelessly rippedfrom [13]:

    --------------------------------------------------------------------------->>> InvsKMap1 = [ -1 for i in xrange(64) ]>>> for x in xrange(len(InvsKMap1)):... if 7-x%8 == 0:... InvsKMap1[x] = -2...>>> for x in xrange(64):

    ... if x in sKMap1:

    ... InvsKMap1[x] = sKMap1.index(x)

    ...>>> InvsKMap1[19, 8, 12, 29, 32, -1, -1, -2, 9, 0, -1, -1, 44, 43, 40, -2, 5, 22, 10,41, 37, 24, 34, -2, 15, 14, 21, 25, 35, 31, 47, -2, 6, 2, 13, 20, 28, 38,26, -2, 23, 11, -1, 16, 42, -1, 30, -2, 4, -1, 1, -1, 33, 27, 46, -2, 7,17, 18, 3, 36, 45, 39, -2]>>>---------------------------------------------------------------------------

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    44/51

    Here is the resulting array:

    char InvsKMap1[64] = {19, 8, 12, 29, 32, -1, -1, -2,9, 0, -1, -1, 44, 43, 40, -2,5, 22, 10, 41, 37, 24, 34, -2,15, 14, 21, 25, 35, 31, 47, -2,6, 2, 13, 20, 28, 38, 26, -2,23, 11, -1, 16, 42, -1, 30, -2,4, -1, 1, -1, 33, 27, 46, -2,7, 17, 18, 3, 36, 45, 39, -2};

    My exploit uses this array to build an original key out of both thesubkey bits and an 8 bits vector. '-1' is set for a bit position where thevalue has to be guessed. There are 8 such positions, and for each of them,a bit is taken from the 8 bits vector. '-2' means that the bit can beanything. Indeed the most significant bits (the so-called parity bits) ofthe 8 bytes key array are never taken into account (hence the well known8 x 7 = 56 bits keylength).

    Now the only remaining thing to do is to guess these 8 missing bits.Obviously for each guess you will generate an original key 'K' and test it

    against a known couple of input/output generated by the white-box. Thewhole operation was implemented below:

    ---------------------------------------------------------------------------void RebuildKeyFromSk1(uchar *dst, uchar *src, uchar lastbits){

    int i,j;char *plastbits = (char *)&lastbits;

    memset(dst, 0, DES_KEY_LENGTH);for(i=0,j=0; i

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    45/51

    const_DES_cblock expected = "\xa1\x6b\xd2\xeb\xbf\xe1\xd1\xc2";DES_cblock key;DES_cblock out;DES_key_schedule ks;

    for(missing_bits=0; missing_bits /dev/null # is quite long$ makegcc -c wb_init.c -O3 -Wallgcc -c wb_round.c -O3 -Wallgcc -c wb_final.c -O3 -Wallgcc exploit.c *.o -O3 -Wall -o exploit -lm -lcryptogcc wb_main.c *.o -O3 -Wall -o wbdes.trygcc entropy.c -o entropy -lm

    $ ./exploit

    [+] Number of possible candidates = 256-> Required computation is 2^(8) * DES()

    [+] Key was found!-> Missing bits: 0x3d-> Key: '02424626'

    $---------------------------------------------------------------------------

    And that's it! So the key was bf-able after all ;>

    --[ 7 - Conclusion

    Nowadays there are a lot of white-box protections in the wild (DRM butnot only) using either academic designs or their improvements. Each of themis an interesting challenge which is why you may want to face it one day.This paper is not ground breaking nor even relevant for the averagecryptographer, the cryptanalysis of the naked DES being covered in many

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    46/51

    papers including [R16]. I wrote it however with the hope that it would giveyou an overview of what practical white-box cracking could be. I hope youenjoyed it :)

    Feel free to contact me for any question related to this paper usingthe mail alias provided in the title of the paper.

    --[ 8 - Gr33tz

    Many (randomly ordered) thanks to:

    - the #f4lst4ff crypt0/b33r team for introducing me to the concept ofwhite-box a few years ago.

    - Jb & Brecht for their implementations which gave me a lot of fun :)- X, Y, Z who will remain anonymous but nonetheless helped me toimprove _significantly_ the paper. If you managed to understand a fewthings out of this "blabla" then you must thank them (and especiallyX). I owe you big time man :)

    - asciio authors because without this tool I would never have found thecourage to write the paper

    - The Phrack Staff for publishing it

    --[ 9 - References

    [R01] http://en.wikipedia.org/wiki/Feistel_cipher[R02] http://2009.hack.lu/index.php/ReverseChallenge[R03] http://baboon.rce.free.fr/index.php?post/2009/11/20/

    HackLu-Reverse-Challenge[R04] http://www.whiteboxcrypto.com[R05] "Cryptanalysis of a White Box AES Implementation", Billet et al.

    http://bo.blackowl.org/papers/waes.pdf[R06] "Digital content protection: How to crack DRM and make them more

    resistant", Jean-Baptiste Bedrune

    http://esec-lab.sogeti.com/dotclear/public/publications/10-hitbkl-drm.pdf[R07] "White-Box Cryptography and an AES Implementation", Eisen et al.

    http://www.scs.carleton.ca/%7Epaulv/papers/whiteaes.lncs.ps[R08] "White-Box Cryptography and SPN ciphers", Schelkunov

    http://eprint.iacr.org/2010/419.pdf[R09] "A White-box DES Implementation for DRM Applications", Chow et al.

    http://www.scs.carleton.ca/%7Epaulv/papers/whitedes1.ps[R10] "White-Box Cryptography", James Muir, Irdeto

    http://www.mitacs.ca/events/images/stories/focusperiods/security-presentations/jmuir-mitacs-white-box-cryptography.pdf

    [R11] http://search.cpan.org/dist/App-Asciio/lib/App/Asciio.pm#NAME[R12] http://dhost.info/pasjagor/des/start.php

    [R13] "Cryptography: Theory and Practice", D. Stinson, 1st edition[R14] "Clarifying Obfuscation: Improving the Security of White-Box

    Encoding", Link et al.http://eprint.iacr.org/2004/025.pdf

    [R15] "White-Box Cryptography" (PhD thesis), B. Wyseurhttps://www.cosic.esat.kuleuven.be/publications/thesis-152.pdf

    [R16] "Attacking an obfuscated cipher by injecting faults", Jacob et al.http://www.cs.princeton.edu/~mjacob/papers/drm1.pdf

    [R17] "Cryptanalysis of White-Box DES Implementations with ArbitraryExternal Encodings", B. Wyseur

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    47/51

    http://eprint.iacr.org/2007/104.pdf

    --[ 10 - Appendix

    begin 644 p68-exploit.tgzM'XL(``$N74\``^QW,:Q[+WO_`I)DY9`1G)^P9)H)0?

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    48/51

    M^$$E^-NSL9W'`*]O-M2G(`^B5$M=)B1S@CS*&QW//LH?-ZQM@WW7T5GGIPR"WONSWQYH(T?H?BKP@G3!O3\0OJ;;$BH.RO.5^)`MP\4"2S!R_?CCMC^SP.#UT^1@L9ZLDD&

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    49/51

    M[X%U=WF4.V2OKP,$(.D$"78S7_`?_.\$9B@!MD!X_"O0:IWI&]7NM7H\?I>*DZG\XN^BSLW??B3U^)5B'2>WD]].+_MN7I^]__70B%P_DJ0ZB2EAJMASW?P'DC1%@4M)'T,5)ASI5?0Z[3/K;LZ0QLOK`IO](233]#4IE\)^?"!B"5I",OQJTJGGDL!>///L\K2JM44D8YAV"RM\^U.&@>">A_*J!2+2^X4A:M_!%0Z5DS&&Q2.&.N5.Z_,E8\2$Z/D!]_AORX0V2Q*NMA!WK$OOCX-RFK^4CMM*7(GR[_P+HI396,MSY5+^IYM"-P/V0^2IY;K9N\YI-M986[J5Q@3+[0TW7MAM(CU0YXS#_VSOZIL:N9'^WYY/H2.[P0;#CN;5YN6>>K(O55NU=9=*DN_^J+OU/B,#.4*>RXWJ+HNE'JF[I6EI)/6OUX:R3"XI)!F'[A"AY&R47E`R!M$.%03S`GZ&5+/P*_N[+AI-$P3[SZQ,/8JGPB;SSA/X`,)&VLIFV4*5"VI/3SMU[#-+GOR%X%G0S9ZI?PA>^W)7P3D7V6PO2I2M5P/E/:VT(WL1/]12KY(]:+1=SHMXM?"M9ML3OG2$+WB@"]OMMOOR%UEH[(1-M^&K+%;;FGB*RU8IHM>=>%?Y$5``.C#"79A9Q>2A1W5LU_[Z=GJYN*#&Q3=>FK"J9,/BOEF2(^?[1+ESR/P$*+F@[X9CT1RVF9#5=9MX9GU\;HY4CMB6R(G7D>(SO@VA5D?P#]/*X7W!8>'T^NCNF8WT]E%13=^Z')C

    M_VAO+U-^SX[K-%;;7Y^NLRW&X\%NRU,]^5B#8?#?:^/WWV3WQWU2T/U9Q29F@Z=^.M3/A#"'`T9(V./.EC"=SI&4-G]

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    50/51

    M/\0E$:HC5>$@5,B)3`;MR*R`!2JH"@1UD:%+5-`6+@,BR']U`!A.`%:1_)=4M/);834)8^2^A5J6D):&.*%&X6`4I`/4OVI7_HL(1,1_Y!KD.3ZAC0=\C`[T%MW0"509QGS!4BP#WJ>O[IM["*EA#,@``(CPIZ:.+ZXP4@3XAO#[;!@"TL%*W7^W'4^X(^(K`FMN685JM^S"$7+H`I)6-,OJI84B,\>(+'(F&QQ(JG9YKYXF0V@#3Q!0F)5Y*7;MQ_]"(PA#4,]/]]?7)6^@4X"A@(\^H-K![T;X=-X7PQ-^R4=$0^OOY^NJ^#D;MH8>N10&\K!^LP]+:9*P]/QZN"6KIOE)O[O.[JI@,UZ/(K@(W4D@UE$L2DCO?M#MQH3/`K5H^;A="\CL$ABN1X*3)]VUPPNCEA/[#]=9DA-:6?PGWB'=G+WQMIZE06Y)(C3\F)LR#6]%%$+S1;NWMU_T?!HT6U>.#79?Z71PD/=A)$SH`?X>?M[W:VQ>4[U&R-)Q#O8O56#"@/-+9(9"8"P?=4Z^\!!XXA/OL/?__F]2L:_#H/M_(PD+`_5@4/ZX*'EUTW;"0Q[\A4T4GP6J`OP#=6G\

    M=1#\8&01Q2'$`&Z(7F4(`Q#=Z4X^K*Y;7=5?#"6PT$+>M*`7_13C5)/?&R\E!/0>/1E7(=2&7A=P4)KHPD86)*4QU82H+4U.8Z%N2S,36&A"PM96)C"4A>6LK"'?WZL\$E%5&>U$1@F8$VHOQL5B&]_*`$6?;RKZMZZP^/9/`M2T1@Q&DW^XZ84#\,`M.8\H9M!\!3X06`$.@QPL"*GWV^MU

  • 7/27/2019 p68 0x08 Practical Cracking of White-box Implementations by Sysk

    51/51

    M$%I6O1=\FWU_-@7W3(HR?T'.-K/JYJ>JFF/FV[^A^^G?__$=C:'K__$T^JZ>M?]!/-*B;BG0#G8$WK#!+H@,QA(/XMXR;>6I9]:B+B/L?$@-M[=U