Search code examples
pythonauthenticationsmartcardapduglobalplatform

Why Smart Card answers 6982 to EXTERNAL AUTHENTICATE while all calculations are correct?


I am trying to establish a secure channel SCP02 with a smart card using python. My smartcard is connected to the terminal using a serial port and I use pySerial to send APDUs.

I send commands SELECT ISD, INITIALIZE UPDATE correctly, and next I try to do EXTERNAL AUTHENTICATE as the python code below:

import serial
from serial.serialutil import EIGHTBITS, PARITY_NONE, STOPBITS_ONE, XON
import exchangeApdu
import numpy as np
from Crypto.Cipher import DES, DES3

CARD_KEY = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F]
ZERO_IV_8 = [0X00, 0X00, 0x00, 0x00, 0X00, 0X00, 0x00, 0x00]

serialObj = serial.Serial(  port = 'COM3', \
                            baudrate = 115200, \
                            parity = PARITY_NONE, \
                            bytesize = EIGHTBITS, \
                            stopbits = STOPBITS_ONE, \
                            timeout = 0.1, \
                            xonxoff = True, \
                            rtscts = True, \
                            inter_byte_timeout = None, \
                            dsrdtr = True   )
if(serialObj.is_open):
    serialObj.close()
serialObj.open()

# Select ISD
select_apdu = [0x00, 0xA4, 0x04, 0x00, 0x00]
response = exchangeApdu.exchange(serialObj, select_apdu)
print('Select ISD: ' + response.hex())

# Initialize Update
host_challenge = np.random.bytes(8)
initialize_update_apdu = [0x80, 0x50, 0x00, 0x00, 0x08] + list(host_challenge)
response = exchangeApdu.exchange(serialObj, initialize_update_apdu)
print('Initialize Update: ' + response.hex())

key_derivation_data = list(response[:10])
key_information = list(response[10:12])
sequence_counter = list(response[12:14])
card_challenge = list(response[14:20])
card_cryptogram = list(response[20:28])

derivation_data = [0X01, 0X82] + sequence_counter + \
    [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
encryptor = DES3.new(bytes(CARD_KEY), DES3.MODE_CBC, bytes(ZERO_IV_8))
S_ENC = encryptor.encrypt(bytes(derivation_data))
derivation_data = [0X01, 0X01] + sequence_counter + \
    [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
encryptor = DES3.new(bytes(CARD_KEY), DES3.MODE_CBC, bytes(ZERO_IV_8))
S_MAC = encryptor.encrypt(bytes(derivation_data))

# External Authenticate
PADDING_DES = [0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
host_auth_data = sequence_counter + card_challenge + list(host_challenge) + PADDING_DES
card_auth_data = list(host_challenge) + sequence_counter + card_challenge + PADDING_DES
encryptor = DES3.new(bytes(S_ENC), DES3.MODE_CBC, bytes(ZERO_IV_8))
host_cryptogram = list(bytes((encryptor.encrypt(bytes(host_auth_data)))[-8:]))
encryptor = DES3.new(bytes(S_ENC), DES3.MODE_CBC, bytes(ZERO_IV_8))
card_cryptogram = list(bytes((encryptor.encrypt(bytes(card_auth_data)))[-8:]))

external_auth_apdu = [0x84, 0x82, 0x00, 0x00, 0x10] + list(host_cryptogram)
external_auth_apdu_padded = external_auth_apdu + [0x80, 0x00, 0x00]
cipher = DES.new(bytes(list(S_MAC[:8])), DES3.MODE_CBC, bytes(ZERO_IV_8))
step1 = cipher.encrypt(bytes(external_auth_apdu_padded))
cipher = DES.new(bytes(list(S_MAC[8:16])), DES3.MODE_ECB)
step2 = cipher.decrypt(step1[-8:])
cipher = DES.new(bytes(list(S_MAC[:8])), DES3.MODE_ECB)
apdu_mac = list(bytes(cipher.encrypt(step2[-8:])))
external_auth_apdu = external_auth_apdu + apdu_mac
response = exchangeApdu.exchange(serialObj, external_auth_apdu)
print('External Authenticate: ' + response.hex())

serialObj.close()

The "exchangeApdu" is a class in which I have handled APDUs like 61xx and 6Cxx. This is the output for this code:

Select ISD: 6f108408a000000151000000a5049f6501ff9000
Initialize Update: 000081210103b49d856dff02004eecc2acd14944a54f9790521d203b9000
External Authenticate: 6982

Smartcard rejects the channel sending back 6982 on the serial port. I have checked whole the procedure uwing online cryptography tools and I am quite sure the cryptographic part is completely doing right. I have also checked this procedure using a usb smartcard reader and again correctly working and I get 9000. Again I checked this on a smartcard simulator, namely JCIDE, and again 9000. Thus I'm sure about the procedure correctness. I have used a serial port monitoring application on Win10 to check the correctness of APDUs on the serial port and there is no error. I think there must be a problem with the smartcard itself but I cannot guess what it is!

Does anyone have any idea where the problem rises?


Solution

  • I found the roblem. Byte array is not delivered to the card correctly, hence the error 6982. This refers to ISO7816 standard which needs bytes sent to the card by a specific delay. I put delays between bytes and now everything is working correctly.