2

I am trying to implement TR-31 decryption into my test application. Because I don't have TR31 standard from ANSI i relay on free materials :)

I am able to get the clear key using Cryptographics Calculator.

 KBPK:          33333333333333334444444444444444
 TR-31 Key block:   B0080P0TD00S00003A74E0769701C712CC87ECB93E9455CC2BF16C71B30F507E524F535F42B56027
 ----------------------------------------
 TR-31 Header:      B0080P0TD00S0000
 ----------------------------------------
   Version Id:      B
   Block Length:    0080
   Key Usage:       P0
   Algorithm:       T
   Mode of Use:     D
   Key Version No.: 00
   Exportability:   S
   Num. of Opt. blocks: 00
   Reserved:        00
   Optional Blocks: 
 TR-31 Encrypted key:   3A74E0769701C712CC87ECB93E9455CC2BF16C71B30F507E
 TR-31 MAC:     524F535F42B56027
 ----------------------------------------
 Plain Key:     94892FF715E992BC4AC4E56116582AE6

But if I try to do intermediate steps myself I don get the same result.

From the available online sources I have found out that for B version KBEK is made of two components 3DES CMAC of hex "0100000000000080" and "0200000000000080". After result of CMAC is joined we should have KBEK.

Finally we get clear key by using 3DES decryption in CBC mode. KB MAC is used as IV.

Unfortunately following these steps didn't get me to clear key. Any help would be appreciated.

etna
  • 23
  • 4

2 Answers2

1

I cannot reproduce the problem. Here is a Python code that generates a TR-31 key block. From this you can derive the algorithm for decryption, which is the same as the one you described:

  • The two partial keys and the total key are:

    KBEK_1: cee717dc1d467889
    KBEK_2: 92c99160462c9def
    KBEK  : cee717dc1d46788992c99160462c9def
    

    KBEK_1 results when the CMAC/3DES is created for 0x0100000000000080 using the KBPK. Similarly, KBEK_2 results if the CMAC/3DES is created for 0x0200000000000080 using the KBPK. The KBEK is obtained by concatenating both partial keys.

  • The plaintext key block and the plaintext key are:

    Plaintext key block: 008094892ff715e992bc4ac4e56116582ae61a0e90859c76
    Plaintext key:       94892ff715e992bc4ac4e56116582ae6
    

    The plaintext key block is obtained by decrypting the encrypted key using 3DES/CBC with the KBEK. The MAC is applied as IV. The first two bytes 0x0080 indicate the length of the key, so that the plaintext key can be determined from this, which corresponds to the expected value.

Below you will find a Python code that determines the key using the PyCryptodome library:

from Crypto.Hash import CMAC
from Crypto.Cipher import DES3

def generateKey(KBPK):
    KBEK_1 = generateCMAC(bytes.fromhex("0100000000000080"), KBPK)
    KBEK_2 = generateCMAC(bytes.fromhex("0200000000000080"), KBPK)
    KBEK = KBEK_1 + KBEK_2
    print("KBEK_1: " + KBEK_1.hex()) # KBEK_1: cee717dc1d467889
    print("KBEK_2: " + KBEK_2.hex()) # KBEK_2: 92c99160462c9def
    print("KBEK  : " + KBEK.hex())   # KBEK  : cee717dc1d46788992c99160462c9def
    return KBEK

def generateCMAC(data, key):
    cmac = CMAC.new(key, ciphermod=DES3)
    cmac.update(data) 
    return cmac.digest()
  
KBPK = bytes.fromhex('33333333333333334444444444444444')
iv = bytes.fromhex('524F535F42B56027') # iv = MAC
encKey = bytes.fromhex('3A74E0769701C712CC87ECB93E9455CC2BF16C71B30F507E')

KBEK = generateKey(KBPK)
cipher = DES3.new(KBEK, DES3.MODE_CBC, iv)
ptKB = cipher.decrypt(encKey) # plaintext key block

lenKey = int.from_bytes(ptKB[:2], "big") // 8
key = ptKB[2:2+lenKey]

print("Plaintext key block: " + ptKB.hex()) # Plaintext key block: 008094892ff715e992bc4ac4e56116582ae61a0e90859c76
print("Plaintext key:       " + key.hex())  # Plaintext key:       94892ff715e992bc4ac4e56116582ae6
Topaco
  • 40,594
  • 4
  • 35
  • 62
0

Thanks, it has been very helpful.

Support adding the KBAK component and the calculation of the MAC, serves to validate that the key load was successful.

from Crypto.Hash import CMAC
from Crypto.Cipher import DES3

def generateKbek(KBPK):
    KBEK_1 = generateCMAC(bytes.fromhex("0100000000000080"), KBPK)
    KBEK_2 = generateCMAC(bytes.fromhex("0200000000000080"), KBPK)
    KBEK = KBEK_1 + KBEK_2
    print("KBEK_1: " + KBEK_1.hex()) # KBEK_1: cee717dc1d467889
    print("KBEK_2: " + KBEK_2.hex()) # KBEK_2: 92c99160462c9def
    print("KBEK  : " + KBEK.hex())   # KBEK  : cee717dc1d46788992c99160462c9def
    return KBEK

def generateKbak(KBPK):
    KBAK_1 = generateCMAC(bytes.fromhex("0100010000000080"), KBPK)
    KBAK_2 = generateCMAC(bytes.fromhex("0200010000000080"), KBPK)
    KBAK = KBAK_1 + KBAK_2
    print("KBAK_1: " + KBAK_1.hex()) # KBAK_1: 7b2118b913558de1
    print("KBAK_2: " + KBAK_2.hex()) # KBAK_2: 805b4b0496fe66fa
    print("KBAK  : " + KBAK.hex())   # KBAK  : 7b2118b913558de1805b4b0496fe66fa
    return KBAK

def generateCMAC(data, key):
    cmac = CMAC.new(key, ciphermod=DES3)
    cmac.update(data)
    return cmac.digest()


KBPK = bytes.fromhex('33333333333333334444444444444444')
iv = bytes.fromhex('524F535F42B56027')  # iv = MAC
encKey = bytes.fromhex('3A74E0769701C712CC87ECB93E9455CC2BF16C71B30F507E')
header = bytes('B0080P0TD00S0000', 'utf-8')

KBEK = generateKbek(KBPK)
KBAK = generateKbak(KBPK)

cipher = DES3.new(KBEK, DES3.MODE_CBC, iv)
ptKB = cipher.decrypt(encKey)  # plaintext key block

lenKey = int.from_bytes(ptKB[:2], "big") // 8
key = ptKB[2:2 + lenKey]

dataToMac = header + ptKB

mac = generateCMAC(dataToMac, KBAK)


print("Plaintext key block: " + ptKB.hex()) # Plaintext key block: 008094892ff715e992bc4ac4e56116582ae61a0e90859c76
print("Plaintext key:       " + key.hex())  # Plaintext key:       94892ff715e992bc4ac4e56116582ae6

print("TR-31 mac:           " + mac.hex())  # Mac:       524f535f42b56027