Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100755 492 lines (443 sloc) 15.799 kB
447c384 first commit
Adam Laurie authored
1 #!/usr/bin/python
2
3
4 # jcoptool.py - JCOP card toolkit
5 #
6 # Adam Laurie <adam@algroup.co.uk>
7 # http://rfidiot.org/
8 #
9 # This code is copyright (c) Adam Laurie, 2009, All rights reserved.
10 # For non-commercial use only, the following terms apply - for all other
11 # uses, please contact the author:
12 #
13 # This code is free software; you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation; either version 2 of the License, or
16 # (at your option) any later version.
17 #
18 # This code is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
22 #
23
271cf40 @AdamLaurie more package changes - be sure to read INSTALL for small but importan…
authored
24 import rfidiot
447c384 first commit
Adam Laurie authored
25 import sys
26 import os
27 import string
28 from Crypto.Cipher import DES3
29 from Crypto.Cipher import DES
30 from pyasn1.codec.ber import decoder
31
32 try:
271cf40 @AdamLaurie more package changes - be sure to read INSTALL for small but importan…
authored
33 card= rfidiot.card
447c384 first commit
Adam Laurie authored
34 except:
271cf40 @AdamLaurie more package changes - be sure to read INSTALL for small but importan…
authored
35 print "Couldn't open reader!"
447c384 first commit
Adam Laurie authored
36 os._exit(True)
37
271cf40 @AdamLaurie more package changes - be sure to read INSTALL for small but importan…
authored
38 args= rfidiot.args
39 Help= rfidiot.help
447c384 first commit
Adam Laurie authored
40
41 # fixed values required by JCOP applet
42 CLA= '80'
43 P1= '00'
44 P2= '00'
45
46 templates= {
47 '66':'Card Data',
48 '73':'Card Recognition Data',
49 }
50
51 tags= {
52 '06':'OID',
53 '60':'Application tag 0 - Card Management Type and Version',
54 '63':'Application tag 3 - Card Identification Scheme',
55 '64':'Application tag 4 - Secure Channel Protocol of the Issuer Security Domain and its implementation options',
56 '65':'Application tag 5 - Card configuration details',
57 '66':'Application tag 6 - Card / chip details',
58 '67':'Application tag 7 - Issuer Security Domain\'s Trust Point certificate information',
59 '68':'Application tag 8 - Issuer Security Domain certificate information',
60 }
61
62 registry_tags= {
63 '4F':'AID',
64 '9F70':'Life Cycle State',
65 'C5':'Privileges',
66 'C4':'Application\'s Executable Load File AID',
67 'CE':'Executable Lod File Version Number',
68 '84':'First or only ExecutableModule AID',
69 'CC':'Associated Security Domain\'s AID',
70 }
71
72 card_status= {
73 '80':'Issuer Security Domain',
74 '40':'Applications and Supplementary Security Domains',
75 '20':'Executable Load Files',
76 '10':'Executable Load Files and their Executable Modules',
77 }
78
79 # life cycle state must be masked as bits 4-7 (bit numbering starting at 1) are application specific
80 application_life_cycle_states= {
81 '01':'LOADED',
82 '03':'INSTALLED',
83 '07':'SELECTABLE',
84 '83':'LOCKED',
85 '87':'LOCKED',
86 }
87
88 executable_life_cycle_states= {
89 '01':'LOADED',
90 }
91
92 security_domain_life_cycle_states= {
93 '03':'INSTALLED',
94 '07':'SELECTABLE',
95 '0F':'PERSONALIZED',
96 '83':'LOCKED',
97 '87':'LOCKED',
98 '8B':'LOCKED',
99 '8F':'LOCKED',
100 }
101
102
103 card_life_cycle_states= {
104 '01':'OP_READY',
105 '07':'INITIALIZED',
106 '0F':'SECURED',
107 '7F':'CARD_LOCKED',
108 'FF':'TERMINATED',
109 }
110
111 targets= {
112 '00':'Unknown',
113 '01':'SmartMX',
114 '03':'sm412',
115 }
116
117 fuse_state= {
118 '00':'Not Fused',
119 '01':'Fused',
120 }
121
122 manufacturers= {
123 'PH':'Philips Semiconductors',
124 'NX':'NXP',
125 }
126
127 privilege_byte_1= {
128 '80':'Security Domain',
129 'C0':'DAP Verification',
130 'A0':'Delegated Management',
131 '10':'Card Lock',
132 '08':'Card Terminate',
133 '04':'Card Reset',
134 '02':'CVM Management',
135 'C1':'Mandated DAP Verification',
136 }
137
138 def decode_jcop_identify(data, padding):
139 fabkey= data[0:2]
140 patch_id= data[2:4]
141 target= data[4:6]
142 mask_id= data[6:8]
143 custom_mask= data[8:16]
144 mask_name= data[16:28]
145 fuse= data[28:30]
146 rom_info= data[30:42]
147
148 manufacturer= card.ToBinary(mask_name[0:4])
149 manufacture_year= card.ToBinary(mask_name[4:6])
150 manufacture_week= card.ToBinary(mask_name[6:10])
151 manufacture_mask= ord(card.ToBinary(mask_name[10:12])) - 64
152
153
154 print padding + 'FABKEY ID: %s' % fabkey
155 print padding + 'PATCH ID: %s' % patch_id
156 print padding + 'TARGET ID: %s' % target + ' (' + targets[target] + ')'
157 print padding + 'MASK ID: %s' % mask_id + ' (Mask %s)' % int(mask_id,16)
158 print padding + 'CUSTOM MASK: %s' % custom_mask + ' (%s)' % card.ReadablePrint(card.ToBinary(custom_mask))
159 print padding + 'MASK NAME: %s' % card.ToBinary(mask_name)
160 print padding + 'FUSE STATE: %s' % fuse + ' (' + fuse_state[fuse] + ')'
161 print padding + 'ROM INFO: %s' % rom_info + ' (Checksum)'
162 print padding + 'COMBO NAME: %s-m%s.%s.%s-%s' % (targets[target], mask_id, fabkey, patch_id, card.ToBinary(mask_name))
163 print padding + 'MANUFACTURER: %s' % manufacturers[manufacturer]
164 print padding + 'PRODUCED: Year %s, Week %s, Build %d' % (manufacture_year, manufacture_week, manufacture_mask)
165
166 def decode_jcop_lifecycle(data, padding):
167 ic_fab= data[0:4]
168 ic_type= data[4:8]
169 os_id= data[8:12]
170 os_release_date= data[12:16]
171 os_release_level= data[16:20]
172 ic_fab_date= data[20:24]
173 ic_serial= data[24:32]
174 ic_batch= data[32:36]
175 ic_mod_fab= data[36:40]
176 ic_mod_pack_date= data[40:44]
177 icc_man= data[44:48]
178 ic_embed_date= data[48:52]
179 ic_pre_perso= data[52:56]
180 ic_pre_perso_date= data[56:60]
181 ic_pre_perso_equip= data[60:68]
182 ic_perso= data[68:72]
183 ic_perso_date= data[72:76]
184 ic_perso_equip= data[76:84]
185
186 print
187 print padding + 'IC Fabricator %s' % ic_fab
188 print padding + 'IC Type %s' % ic_type
189 print padding + 'OS ID %s' % os_id
190 print padding + 'OS Release Date %s' % os_release_date
191 print padding + 'OS Release Level %s' % os_release_level
192 print padding + 'IC Fabrication Date Year %s Day %s' % (ic_fab_date[0], ic_fab_date[1:4])
193 print padding + 'IC Serial Number %s' % ic_serial
194 print padding + 'IC Batch Number %s' % ic_batch
195 print padding + 'IC Module Fabricator %s' % ic_mod_fab
196 print padding + 'IC Module Packaging Date Year %s Day %s' % (ic_mod_pack_date[0], ic_mod_pack_date[1:4])
197 print padding + 'ICC Manufacturer %s' % icc_man
198 print padding + 'IC Embedding Date Year %s Day %s' % (ic_embed_date[0], ic_embed_date[1:4])
199 print padding + 'IC Pre-Personalizer %s' % ic_pre_perso
200 print padding + 'IC Pre-Personalization Date %s' % ic_pre_perso_date
201 print padding + 'IC Pre-Personalization Equipment %s' % ic_pre_perso_equip
202 print padding + 'IC Personalizer %s' % ic_perso
203 print padding + 'IC Personalization Date Year %s Day %s' % (ic_perso_date[0], ic_perso_date[1:4])
204 print padding + 'IC Personalization Equipment %s' % ic_perso_equip
205
206 def decode_privileges(data):
207 print '(',
208 multiple= False
209 try:
210 for mask in privilege_byte_1.keys():
211 if (int(data[0:2],16) & int(mask,16)) == int(mask,16):
212 if multiple:
213 print '/',
214 print privilege_byte_1[mask],
215 multiple= True
216 except:
217 print ')',
218 return
219 print ')',
220
221 # check privilege byte 0 to see if we're a security domain
222 def check_security_domain(data):
223 length= int(data[2:4],16) * 2
224 i= 4
225 while i < length + 4:
226 for item in registry_tags.keys():
227 if data[i:i+len(item)] == item:
228 itemlength= int(data[i+len(item):i+len(item)+2],16) * 2
229 if item == card.GP_REG_PRIV:
230 itemdata= data[i+len(item)+2:i+len(item)+2+itemlength]
231 if (int(itemdata[0:2],16) & 0x80) == 0x80:
232 return True
233 i += itemlength + len(item) + 2
234 return False
235
236 def decode_gp_registry_data(data, padding, filter):
237 if not data[0:2] == card.GP_REG_DATA:
238 return False, ''
239 states= application_life_cycle_states
240 if filter == card.GP_FILTER_ISD:
241 states= card_life_cycle_states
242 if filter == card.GP_FILTER_ASSD:
243 states= application_life_cycle_states
244 if filter == card.GP_FILTER_ELF:
245 states= executable_life_cycle_states
246 # check if this is a security domain (not set up right, so disabled!)
247 #if check_security_domain(data):
248 # states= security_domain_life_cycle_states
249 length= int(data[2:4],16) * 2
250 i= 4
251 while i < length + 4:
252 decoded= False
253 for item in registry_tags.keys():
254 if data[i:i+len(item)] == item:
255 if not item == card.GP_REG_AID:
256 print ' ',
257 itemlength= int(data[i+len(item):i+len(item)+2],16) * 2
258 itemdata= data[i+len(item)+2:i+len(item)+2+itemlength]
259 print padding, registry_tags[item]+':', itemdata,
260 if item == card.GP_REG_LCS:
261 if filter == card.GP_FILTER_ASSD:
262 # mask out application specific bits
263 itemdata= '%02x' % (int(itemdata,16) & 0x87)
264 print '( '+states[itemdata]+' )',
265 if item == card.GP_REG_PRIV:
266 decode_privileges(itemdata)
267 decoded= True
268 i += itemlength + len(item) + 2
269 print
270 if not decoded:
271 return False
272 return True
273
271cf40 @AdamLaurie more package changes - be sure to read INSTALL for small but importan…
authored
274 card.info('jcoptool v0.1d')
447c384 first commit
Adam Laurie authored
275 if Help or len(args) < 1:
276 print '\nUsage:\n\n\t%s [OPTIONS] <COMMAND> [ARGS] [ENC Key] [MAC Key] [KEK Key]' % sys.argv[0]
277 print
278 print '\tWhere COMMAND/ARGS are one of the following combinations:'
279 print
280 print "\tINFO\t\t\tDisplay useful info about the JCOP card and it's contents."
281 print
282 print '\tDES keys ENC MAC and KEK are always the final 3 arguments, and should be in HEX.'
283 print '\tIf not specified, the default \'404142434445464748494A4B4C4D4E4F\' will be used.'
284 print
285 os._exit(True)
286
287 command= args[0]
288
289 if card.select():
290 print
291 print ' Card ID: ' + card.uid
292 if card.readertype == card.READER_PCSC:
293 print ' ATS: %s (%s)' % (card.pcsc_ats,card.ReadablePrint(card.ToBinary(card.pcsc_ats)))
294 else:
295 print ' No RFID card present'
296 print
297 #os._exit(True)
298
299 #print ' ATR: ' + card.pcsc_atr
300 #print
301
302 # high speed select required for ACG
303 if not card.hsselect('08'):
304 print ' Could not select RFID card for APDU processing'
305 #os._exit(True)
306
307 print
308 print ' JCOP Identity Data:',
309 # send pseudo file select command for JCOP IDENTIFY
310 card.iso_7816_select_file(card.AID_JCOP_IDENTIFY,'04','00')
311 if card.errorcode == '6A82' and len(card.data) > 0:
312 print card.data
313 print
314 decode_jcop_identify(card.data,' ')
315 else:
316 print ' Device does not support JCOP IDENTIFY!'
317
318 # card life cycle data
319 # high speed select required for ACG
320 if not card.hsselect('08'):
321 print ' Could not select RFID card for APDU processing'
322 print
323 print ' Life Cycle data:',
324 if not card.gp_get_data('9F7F'):
325 print " Failed - ", card.ISO7816ErrorCodes[card.errorcode]
326 else:
327 print card.data
328 if card.data[0:4] == '9F7F':
329 decode_jcop_lifecycle(card.data[6:],' ')
330
331 # select JCOP Card Manager
332 # high speed select required for ACG
333 if not card.hsselect('08'):
334 print ' Could not select RFID card for APDU processing'
335 if not card.iso_7816_select_file(card.AID_CARD_MANAGER,'04','00'):
336 print
337 print " Can't select Card Manager!",
338 card.iso_7816_fail(card.errorcode)
339
340 if command == 'INFO':
341 # high speed select required for ACG
342 if not card.hsselect('08'):
343 print ' Could not select RFID card for APDU processing'
344 # get Card Recognition Data
345 if not card.gp_get_data('0066'):
346 print
347 print " Can't get Card Recognition Data!",
348 card.iso_7816_fail(card.errorcode)
349 pointer= 0
350 item= card.data[pointer:pointer+2]
351 if item != '66':
352 print 'Unrecognised template:', item
353 os._exit(True)
354 pointer += 2
355 item= card.data[pointer:pointer+2]
356 length= int(item,16)
357
358 print
359 print ' Card Data length:',length
360 pointer += 2
361 item= card.data[pointer:pointer+2]
362 if item != '73':
363 print 'Unrecognised template:', item
364 os._exit(True)
365 pointer += 2
366 item= card.data[pointer:pointer+2]
367 length= int(item,16)
368 print ' Card Recognition Data length:',length
369 pointer += 2
370 while pointer < len(card.data):
371 item= card.data[pointer:pointer+2]
372 try:
373 print ' '+tags[item]+':',
374 pointer += 2
375 length= int(card.data[pointer:pointer + 2],16)
376 pointer += 2
377 if tags[item] == 'OID':
378 decodedOID, dummy= decoder.decode(card.ToBinary(item+('%02x' % length)+card.data[pointer:pointer + length * 2]))
379 print decodedOID.prettyPrint()
380 else:
381 if(card.data[pointer:pointer + 2]) == '06':
382 decodedOID, dummy= decoder.decode(card.ToBinary(card.data[pointer:pointer + length * 2]))
383 print
384 print ' OID:', decodedOID.prettyPrint()
385 else:
386 print card.data[pointer:pointer + length * 2]
387 pointer += length * 2
388 except:
389 print 'Unrecognised tag', item
390 os._exit(True)
391 # set up DES keys for encryption operations
392 if len(args) > 1:
393 enc_key= args[1]
394 if len(args) > 2:
395 mac_key= args[2]
396 else:
397 enc_key= card.GP_ENC_KEY
398 mac_key= card.GP_MAC_KEY
399
400 if command == 'INSTALL':
401 if len(args) > 2:
402 enc_key= args[2]
403 if len(args) > 3:
404 mac_key= args[3]
405 else:
406 enc_key= card.GP_ENC_KEY
407 mac_key= card.GP_MAC_KEY
408
409 if command == 'INFO' or command == 'INSTALL':
410 # authenticate to card
411 # initialise secure channel
412 print
413 print ' *** Warning'
414 print ' *** Repeated authentication failures may permanently disable device'
415 print
416 x= string.upper(raw_input(' Attempt to authenticate (y/n)? '))
417 if not x == 'Y':
418 os._exit(True)
419
420 # high speed select required for ACG
421 if not card.hsselect('08'):
422 print ' Could not select RFID card for APDU processing'
423 host_challenge= card.GetRandom(8)
424 if not card.gp_initialize_update(host_challenge):
425 print 'Can\'t Initialise Update!'
426 card.iso_7816_fail(card.errorcode)
427 card_key_diversification, card_key_info, card_sc_sequence_counter,card_challenge,card_cryptogram= card.gp_initialize_update_response_scp02(card.data)
428
429
430 secure_channel_protocol= card_key_info[2:4]
431
432 if secure_channel_protocol == card.GP_SCP02:
433 # create ENC session key by encrypting derivation data with ENC key
434 session_pad= '000000000000000000000000'
435 derivation_data= '0182' + card_sc_sequence_counter + session_pad
436 # create encryption object with ENC key
36ec0c6 @doegox jcoptool/mifarekeys: DES needs now an explicit IV value, we can use r…
doegox authored
437 e_enc= DES3.new(card.ToBinary(enc_key),DES3.MODE_CBC,card.DES_IV)
447c384 first commit
Adam Laurie authored
438 enc_s_key= e_enc.encrypt(card.ToBinary(derivation_data))
439 # data for cryptograms
440 card_cryptogram_source= host_challenge + card_sc_sequence_counter + card_challenge
441 host_cryptogram_source= card_sc_sequence_counter + card_challenge + host_challenge
442 # check card cryptogram
443 check_cryptogram= string.upper(card.ToHex(card.DES3MAC(card.ToBinary(card_cryptogram_source), enc_s_key, '')))
444 if not check_cryptogram == card_cryptogram:
445 print 'Key mismatch!'
446 print 'Card Cryptogram: ', card_cryptogram
447 print 'Calculated Cryptogram:', check_cryptogram
448 os._exit(True)
449
450 # cryptogram checks out, so we can use session key
451 # create encryption object with ENC Session key
36ec0c6 @doegox jcoptool/mifarekeys: DES needs now an explicit IV value, we can use r…
doegox authored
452 s_enc= DES3.new(enc_s_key,DES3.MODE_CBC,card.DES_IV)
447c384 first commit
Adam Laurie authored
453
454 # authenticate to card
455 host_cryptogram= card.DES3MAC(card.ToBinary(host_cryptogram_source), enc_s_key, '')
456 # create encryption object with MAC key
36ec0c6 @doegox jcoptool/mifarekeys: DES needs now an explicit IV value, we can use r…
doegox authored
457 e_enc= DES3.new(card.ToBinary(mac_key),DES3.MODE_CBC,card.DES_IV)
447c384 first commit
Adam Laurie authored
458 # create C-MAC session key
459 derivation_data= '0101' + card_sc_sequence_counter + session_pad
460 cmac_s_key= e_enc.encrypt(card.ToBinary(derivation_data))
461 if not card.gp_external_authenticate(host_cryptogram,cmac_s_key):
462 print 'Card Authentication failed!'
463 card.iso_7816_fail(card.errorcode)
464 else:
465 print 'Unsupported Secure Channel Protocol:', secure_channel_protocol
466 os._exit(True)
467
468
469 print ' Authentication succeeded'
470 # get card status (list card contents)
471 # high speed select required for ACG
472 #if not card.hsselect('08'):
473 # print ' Could not select RFID card for APDU processing'
474 print
475 print ' Card contents:'
476 for filter in '80','40','20','10':
477 if not card.gp_get_status(filter,'02',''):
478 if not card.errorcode == '6A88':
479 print
480 print " Can't get Card Status!",
481 card.iso_7816_fail(card.errorcode)
482 print
483 print ' ', card_status[filter]+':'
484 if card.errorcode == '6A88':
485 print ' None!'
486 else:
487 if not decode_gp_registry_data(card.data,' ',filter):
488 print ' Can\'t decode Registry!'
489 print card.data
490 os._exit(True)
491 os._exit(False)
Something went wrong with that request. Please try again.