Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: e9be4eb5e9
Fetching contributors…

Cannot retrieve contributors at this time

executable file 492 lines (443 sloc) 15.763 kb
#!/usr/bin/python
# jcoptool.py - JCOP card toolkit
#
# Adam Laurie <adam@algroup.co.uk>
# http://rfidiot.org/
#
# This code is copyright (c) Adam Laurie, 2009, All rights reserved.
# For non-commercial use only, the following terms apply - for all other
# uses, please contact the author:
#
# This code is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This code is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
import rfidiot
import sys
import os
import string
from Crypto.Cipher import DES3
from Crypto.Cipher import DES
from pyasn1.codec.ber import decoder
try:
card= rfidiot.card
except:
print "Couldn't open reader!"
os._exit(True)
args= rfidiot.args
Help= rfidiot.help
# fixed values required by JCOP applet
CLA= '80'
P1= '00'
P2= '00'
templates= {
'66':'Card Data',
'73':'Card Recognition Data',
}
tags= {
'06':'OID',
'60':'Application tag 0 - Card Management Type and Version',
'63':'Application tag 3 - Card Identification Scheme',
'64':'Application tag 4 - Secure Channel Protocol of the Issuer Security Domain and its implementation options',
'65':'Application tag 5 - Card configuration details',
'66':'Application tag 6 - Card / chip details',
'67':'Application tag 7 - Issuer Security Domain\'s Trust Point certificate information',
'68':'Application tag 8 - Issuer Security Domain certificate information',
}
registry_tags= {
'4F':'AID',
'9F70':'Life Cycle State',
'C5':'Privileges',
'C4':'Application\'s Executable Load File AID',
'CE':'Executable Lod File Version Number',
'84':'First or only ExecutableModule AID',
'CC':'Associated Security Domain\'s AID',
}
card_status= {
'80':'Issuer Security Domain',
'40':'Applications and Supplementary Security Domains',
'20':'Executable Load Files',
'10':'Executable Load Files and their Executable Modules',
}
# life cycle state must be masked as bits 4-7 (bit numbering starting at 1) are application specific
application_life_cycle_states= {
'01':'LOADED',
'03':'INSTALLED',
'07':'SELECTABLE',
'83':'LOCKED',
'87':'LOCKED',
}
executable_life_cycle_states= {
'01':'LOADED',
}
security_domain_life_cycle_states= {
'03':'INSTALLED',
'07':'SELECTABLE',
'0F':'PERSONALIZED',
'83':'LOCKED',
'87':'LOCKED',
'8B':'LOCKED',
'8F':'LOCKED',
}
card_life_cycle_states= {
'01':'OP_READY',
'07':'INITIALIZED',
'0F':'SECURED',
'7F':'CARD_LOCKED',
'FF':'TERMINATED',
}
targets= {
'00':'Unknown',
'01':'SmartMX',
'03':'sm412',
}
fuse_state= {
'00':'Not Fused',
'01':'Fused',
}
manufacturers= {
'PH':'Philips Semiconductors',
'NX':'NXP',
}
privilege_byte_1= {
'80':'Security Domain',
'C0':'DAP Verification',
'A0':'Delegated Management',
'10':'Card Lock',
'08':'Card Terminate',
'04':'Card Reset',
'02':'CVM Management',
'C1':'Mandated DAP Verification',
}
def decode_jcop_identify(data, padding):
fabkey= data[0:2]
patch_id= data[2:4]
target= data[4:6]
mask_id= data[6:8]
custom_mask= data[8:16]
mask_name= data[16:28]
fuse= data[28:30]
rom_info= data[30:42]
manufacturer= card.ToBinary(mask_name[0:4])
manufacture_year= card.ToBinary(mask_name[4:6])
manufacture_week= card.ToBinary(mask_name[6:10])
manufacture_mask= ord(card.ToBinary(mask_name[10:12])) - 64
print padding + 'FABKEY ID: %s' % fabkey
print padding + 'PATCH ID: %s' % patch_id
print padding + 'TARGET ID: %s' % target + ' (' + targets[target] + ')'
print padding + 'MASK ID: %s' % mask_id + ' (Mask %s)' % int(mask_id,16)
print padding + 'CUSTOM MASK: %s' % custom_mask + ' (%s)' % card.ReadablePrint(card.ToBinary(custom_mask))
print padding + 'MASK NAME: %s' % card.ToBinary(mask_name)
print padding + 'FUSE STATE: %s' % fuse + ' (' + fuse_state[fuse] + ')'
print padding + 'ROM INFO: %s' % rom_info + ' (Checksum)'
print padding + 'COMBO NAME: %s-m%s.%s.%s-%s' % (targets[target], mask_id, fabkey, patch_id, card.ToBinary(mask_name))
print padding + 'MANUFACTURER: %s' % manufacturers[manufacturer]
print padding + 'PRODUCED: Year %s, Week %s, Build %d' % (manufacture_year, manufacture_week, manufacture_mask)
def decode_jcop_lifecycle(data, padding):
ic_fab= data[0:4]
ic_type= data[4:8]
os_id= data[8:12]
os_release_date= data[12:16]
os_release_level= data[16:20]
ic_fab_date= data[20:24]
ic_serial= data[24:32]
ic_batch= data[32:36]
ic_mod_fab= data[36:40]
ic_mod_pack_date= data[40:44]
icc_man= data[44:48]
ic_embed_date= data[48:52]
ic_pre_perso= data[52:56]
ic_pre_perso_date= data[56:60]
ic_pre_perso_equip= data[60:68]
ic_perso= data[68:72]
ic_perso_date= data[72:76]
ic_perso_equip= data[76:84]
print
print padding + 'IC Fabricator %s' % ic_fab
print padding + 'IC Type %s' % ic_type
print padding + 'OS ID %s' % os_id
print padding + 'OS Release Date %s' % os_release_date
print padding + 'OS Release Level %s' % os_release_level
print padding + 'IC Fabrication Date Year %s Day %s' % (ic_fab_date[0], ic_fab_date[1:4])
print padding + 'IC Serial Number %s' % ic_serial
print padding + 'IC Batch Number %s' % ic_batch
print padding + 'IC Module Fabricator %s' % ic_mod_fab
print padding + 'IC Module Packaging Date Year %s Day %s' % (ic_mod_pack_date[0], ic_mod_pack_date[1:4])
print padding + 'ICC Manufacturer %s' % icc_man
print padding + 'IC Embedding Date Year %s Day %s' % (ic_embed_date[0], ic_embed_date[1:4])
print padding + 'IC Pre-Personalizer %s' % ic_pre_perso
print padding + 'IC Pre-Personalization Date %s' % ic_pre_perso_date
print padding + 'IC Pre-Personalization Equipment %s' % ic_pre_perso_equip
print padding + 'IC Personalizer %s' % ic_perso
print padding + 'IC Personalization Date Year %s Day %s' % (ic_perso_date[0], ic_perso_date[1:4])
print padding + 'IC Personalization Equipment %s' % ic_perso_equip
def decode_privileges(data):
print '(',
multiple= False
try:
for mask in privilege_byte_1.keys():
if (int(data[0:2],16) & int(mask,16)) == int(mask,16):
if multiple:
print '/',
print privilege_byte_1[mask],
multiple= True
except:
print ')',
return
print ')',
# check privilege byte 0 to see if we're a security domain
def check_security_domain(data):
length= int(data[2:4],16) * 2
i= 4
while i < length + 4:
for item in registry_tags.keys():
if data[i:i+len(item)] == item:
itemlength= int(data[i+len(item):i+len(item)+2],16) * 2
if item == card.GP_REG_PRIV:
itemdata= data[i+len(item)+2:i+len(item)+2+itemlength]
if (int(itemdata[0:2],16) & 0x80) == 0x80:
return True
i += itemlength + len(item) + 2
return False
def decode_gp_registry_data(data, padding, filter):
if not data[0:2] == card.GP_REG_DATA:
return False, ''
states= application_life_cycle_states
if filter == card.GP_FILTER_ISD:
states= card_life_cycle_states
if filter == card.GP_FILTER_ASSD:
states= application_life_cycle_states
if filter == card.GP_FILTER_ELF:
states= executable_life_cycle_states
# check if this is a security domain (not set up right, so disabled!)
#if check_security_domain(data):
# states= security_domain_life_cycle_states
length= int(data[2:4],16) * 2
i= 4
while i < length + 4:
decoded= False
for item in registry_tags.keys():
if data[i:i+len(item)] == item:
if not item == card.GP_REG_AID:
print ' ',
itemlength= int(data[i+len(item):i+len(item)+2],16) * 2
itemdata= data[i+len(item)+2:i+len(item)+2+itemlength]
print padding, registry_tags[item]+':', itemdata,
if item == card.GP_REG_LCS:
if filter == card.GP_FILTER_ASSD:
# mask out application specific bits
itemdata= '%02x' % (int(itemdata,16) & 0x87)
print '( '+states[itemdata]+' )',
if item == card.GP_REG_PRIV:
decode_privileges(itemdata)
decoded= True
i += itemlength + len(item) + 2
print
if not decoded:
return False
return True
card.info('jcoptool v0.1d')
if Help or len(args) < 1:
print '\nUsage:\n\n\t%s [OPTIONS] <COMMAND> [ARGS] [ENC Key] [MAC Key] [KEK Key]' % sys.argv[0]
print
print '\tWhere COMMAND/ARGS are one of the following combinations:'
print
print "\tINFO\t\t\tDisplay useful info about the JCOP card and it's contents."
print
print '\tDES keys ENC MAC and KEK are always the final 3 arguments, and should be in HEX.'
print '\tIf not specified, the default \'404142434445464748494A4B4C4D4E4F\' will be used.'
print
os._exit(True)
command= args[0]
if card.select():
print
print ' Card ID: ' + card.uid
if card.readertype == card.READER_PCSC:
print ' ATS: %s (%s)' % (card.pcsc_ats,card.ReadablePrint(card.ToBinary(card.pcsc_ats)))
else:
print ' No RFID card present'
print
#os._exit(True)
#print ' ATR: ' + card.pcsc_atr
#print
# high speed select required for ACG
if not card.hsselect('08'):
print ' Could not select RFID card for APDU processing'
#os._exit(True)
print
print ' JCOP Identity Data:',
# send pseudo file select command for JCOP IDENTIFY
card.iso_7816_select_file(card.AID_JCOP_IDENTIFY,'04','00')
if card.errorcode == '6A82' and len(card.data) > 0:
print card.data
print
decode_jcop_identify(card.data,' ')
else:
print ' Device does not support JCOP IDENTIFY!'
# card life cycle data
# high speed select required for ACG
if not card.hsselect('08'):
print ' Could not select RFID card for APDU processing'
print
print ' Life Cycle data:',
if not card.gp_get_data('9F7F'):
print " Failed - ", card.ISO7816ErrorCodes[card.errorcode]
else:
print card.data
if card.data[0:4] == '9F7F':
decode_jcop_lifecycle(card.data[6:],' ')
# select JCOP Card Manager
# high speed select required for ACG
if not card.hsselect('08'):
print ' Could not select RFID card for APDU processing'
if not card.iso_7816_select_file(card.AID_CARD_MANAGER,'04','00'):
print
print " Can't select Card Manager!",
card.iso_7816_fail(card.errorcode)
if command == 'INFO':
# high speed select required for ACG
if not card.hsselect('08'):
print ' Could not select RFID card for APDU processing'
# get Card Recognition Data
if not card.gp_get_data('0066'):
print
print " Can't get Card Recognition Data!",
card.iso_7816_fail(card.errorcode)
pointer= 0
item= card.data[pointer:pointer+2]
if item != '66':
print 'Unrecognised template:', item
os._exit(True)
pointer += 2
item= card.data[pointer:pointer+2]
length= int(item,16)
print
print ' Card Data length:',length
pointer += 2
item= card.data[pointer:pointer+2]
if item != '73':
print 'Unrecognised template:', item
os._exit(True)
pointer += 2
item= card.data[pointer:pointer+2]
length= int(item,16)
print ' Card Recognition Data length:',length
pointer += 2
while pointer < len(card.data):
item= card.data[pointer:pointer+2]
try:
print ' '+tags[item]+':',
pointer += 2
length= int(card.data[pointer:pointer + 2],16)
pointer += 2
if tags[item] == 'OID':
decodedOID, dummy= decoder.decode(card.ToBinary(item+('%02x' % length)+card.data[pointer:pointer + length * 2]))
print decodedOID.prettyPrint()
else:
if(card.data[pointer:pointer + 2]) == '06':
decodedOID, dummy= decoder.decode(card.ToBinary(card.data[pointer:pointer + length * 2]))
print
print ' OID:', decodedOID.prettyPrint()
else:
print card.data[pointer:pointer + length * 2]
pointer += length * 2
except:
print 'Unrecognised tag', item
os._exit(True)
# set up DES keys for encryption operations
if len(args) > 1:
enc_key= args[1]
if len(args) > 2:
mac_key= args[2]
else:
enc_key= card.GP_ENC_KEY
mac_key= card.GP_MAC_KEY
if command == 'INSTALL':
if len(args) > 2:
enc_key= args[2]
if len(args) > 3:
mac_key= args[3]
else:
enc_key= card.GP_ENC_KEY
mac_key= card.GP_MAC_KEY
if command == 'INFO' or command == 'INSTALL':
# authenticate to card
# initialise secure channel
print
print ' *** Warning'
print ' *** Repeated authentication failures may permanently disable device'
print
x= string.upper(raw_input(' Attempt to authenticate (y/n)? '))
if not x == 'Y':
os._exit(True)
# high speed select required for ACG
if not card.hsselect('08'):
print ' Could not select RFID card for APDU processing'
host_challenge= card.GetRandom(8)
if not card.gp_initialize_update(host_challenge):
print 'Can\'t Initialise Update!'
card.iso_7816_fail(card.errorcode)
card_key_diversification, card_key_info, card_sc_sequence_counter,card_challenge,card_cryptogram= card.gp_initialize_update_response_scp02(card.data)
secure_channel_protocol= card_key_info[2:4]
if secure_channel_protocol == card.GP_SCP02:
# create ENC session key by encrypting derivation data with ENC key
session_pad= '000000000000000000000000'
derivation_data= '0182' + card_sc_sequence_counter + session_pad
# create encryption object with ENC key
e_enc= DES3.new(card.ToBinary(enc_key),DES3.MODE_CBC)
enc_s_key= e_enc.encrypt(card.ToBinary(derivation_data))
# data for cryptograms
card_cryptogram_source= host_challenge + card_sc_sequence_counter + card_challenge
host_cryptogram_source= card_sc_sequence_counter + card_challenge + host_challenge
# check card cryptogram
check_cryptogram= string.upper(card.ToHex(card.DES3MAC(card.ToBinary(card_cryptogram_source), enc_s_key, '')))
if not check_cryptogram == card_cryptogram:
print 'Key mismatch!'
print 'Card Cryptogram: ', card_cryptogram
print 'Calculated Cryptogram:', check_cryptogram
os._exit(True)
# cryptogram checks out, so we can use session key
# create encryption object with ENC Session key
s_enc= DES3.new(enc_s_key,DES3.MODE_CBC)
# authenticate to card
host_cryptogram= card.DES3MAC(card.ToBinary(host_cryptogram_source), enc_s_key, '')
# create encryption object with MAC key
e_enc= DES3.new(card.ToBinary(mac_key),DES3.MODE_CBC)
# create C-MAC session key
derivation_data= '0101' + card_sc_sequence_counter + session_pad
cmac_s_key= e_enc.encrypt(card.ToBinary(derivation_data))
if not card.gp_external_authenticate(host_cryptogram,cmac_s_key):
print 'Card Authentication failed!'
card.iso_7816_fail(card.errorcode)
else:
print 'Unsupported Secure Channel Protocol:', secure_channel_protocol
os._exit(True)
print ' Authentication succeeded'
# get card status (list card contents)
# high speed select required for ACG
#if not card.hsselect('08'):
# print ' Could not select RFID card for APDU processing'
print
print ' Card contents:'
for filter in '80','40','20','10':
if not card.gp_get_status(filter,'02',''):
if not card.errorcode == '6A88':
print
print " Can't get Card Status!",
card.iso_7816_fail(card.errorcode)
print
print ' ', card_status[filter]+':'
if card.errorcode == '6A88':
print ' None!'
else:
if not decode_gp_registry_data(card.data,' ',filter):
print ' Can\'t decode Registry!'
print card.data
os._exit(True)
os._exit(False)
Jump to Line
Something went wrong with that request. Please try again.