cryptographyhardware-security-module

Extract clear key from TR-31 version B key block


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.


Solution

  • 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:

    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