more apdu methods added
This commit is contained in:
parent
2fbfa5ce07
commit
238fa1025e
163
src/lib/apdu.rb
163
src/lib/apdu.rb
|
@ -17,6 +17,8 @@ along with SAP. If not, see <http://www.gnu.org/licenses/>.
|
|||
Copyright (C) 2011 Kevin "tsaitgaist" Redon kevredon@mail.tsaitgaist.info
|
||||
=end
|
||||
# this librarie is to centralise the APDU related work
|
||||
$KCODE = 'UTF8'
|
||||
require 'jcode'
|
||||
|
||||
# transform binary string into readable hex string
|
||||
class String
|
||||
|
@ -82,6 +84,10 @@ end
|
|||
|
||||
module APDU
|
||||
|
||||
#===============
|
||||
#== constants ==
|
||||
#===============
|
||||
|
||||
# APDU constants (TS 102.221 10.1.2)
|
||||
# SIM Class code (TS 51.011 9.2)
|
||||
CLASS = 0xA0
|
||||
|
@ -103,8 +109,54 @@ module APDU
|
|||
EF_ICCID = [0x2F,0xE2]
|
||||
DF_GSM = [0x7F,0x20]
|
||||
EF_IMSI = [0x6F,0x07] # TS 51.011 10.3.2
|
||||
EF_KC = [0x6F,0x20] # TS 51.011 10.3.3
|
||||
EF_PLMNSEL = [0x6F,0x30] # TS 51.011 10.3.4
|
||||
EF_HPPLMN = [0x6F,0x31] # TS 51.011 10.3.5
|
||||
EF_FPLMN = [0x6F,0x7B] # TS 51.011 10.3.16
|
||||
EF_PLMNWACT = [0x6F,0x60] # TS 51.011 10.3.35
|
||||
EF_OPLMNWACT = [0x6F,0x61] # TS 51.011 10.3.36
|
||||
EF_PHASE = [0x6F,0xAE] # TS 51.011 10.3.19
|
||||
EF_SST = [0x6F,0x38] # TS 51.011 10.3.7
|
||||
EF_AD = [0x6F,0xAD] # TS 51.011 10.3.18
|
||||
EF_LOCI = [0x6F,0x7E] # TS 51.011 10.3.17
|
||||
EF_SPN = [0x6F,0x46] # TS 51.011 10.3.11
|
||||
EF_ACC = [0x6F,0x78] # TS 51.011 10.3.15
|
||||
DF_TELECOM = [0x7F,0x10]
|
||||
EF_SMS = [0x6F,0x3C] # TS 51.011 10.5.3
|
||||
EF_SMSS = [0x6F,0x43] # TS 51.011 10.5.7
|
||||
EF_MSISDN = [0x6F,0x40] # TS 51.011 10.5.5
|
||||
|
||||
# File IF (from ETSI TS 151 011 V4.9.0, figure 8)
|
||||
FILE_ID = {
|
||||
0x3f00 => "MF",
|
||||
0x7f20=>"DF_GSM",0x7f10=>"DF_TELECOM",0x7f22=>"DF_IS-41",0x7f23=>"DF_FR-CTS",0x2fe2=>"EF_ICCID",0x2f05=>"EF_ELP",
|
||||
0x6f3a=>"EF_ADN",0x6f3b=>"EF_FDN",0x6f3c=>"EF_SMS",0x6f3d=>"EF_CCP",0x6f40=>"EF_MSISDN",
|
||||
0x6f42=>"EF_SMSP",0x6f43=>"EF_SMSS",0x6f44=>"EF_LND",0x6f47=>"EF_SMSR",0x6f49=>"EF_SDN",
|
||||
0x6f4a=>"EF_EXT1",0x6f4b=>"EF_EXT2",0x6f4c=>"EF_EXT3",0x6f4d=>"EF_BDN",0x6f4d=>"EF_EXT4",
|
||||
0x5f50=>"DF_GRAPHICS",0x4f20=>"EF_IMG",0x6f4f=>"EF_ECCP",
|
||||
0x5f30=>"DF_IRIDIUM",0x5f31=>"DF_GLOBST",0x5f32=>"DF_ICO",0x5f33=>"DF_ACeS",
|
||||
0x5f40=>"DF_EIA/TIA-553",0x5f60=>"DF_CTS",0x5f70=>"DF_SoLSA",0x4f30=>"EF_SAI",0x4F31=>"EF_SLL",
|
||||
0x5f3c=>"DF_MExE",0x4f40=>"EF_MExE-ST",0x4f41=>"EF_ORPK",0x4f42=>"EF_ARPK",0x4f43=>"EF_TPRPK",
|
||||
0x6f05=>"EF_LP",0x6f07=>"EF_IMSI",0x6f20=>"EF_Kc",0x6f2c=>"ED_DCK",0x6f30=>"EF_PLMNsel",0x6f31=>"EF_HPPLMN",
|
||||
0x6f32=>"EF_CNL",0x6f37=>"EF_ACMmax",0x6f38=>"EF_SST",0x6f39=>"EF_ACM",0x6f3e=>"GID1",0x6f3f=>"GID2",
|
||||
0x6f41=>"EF_PUCT",0x6f45=>"EF_CBMI",0x6f46=>"EF_SPN",0x6f48=>"EF_CBMID",0x6f74=>"EF_BCCH",0x6f78=>"EF_ACC",
|
||||
0x6f7b=>"EF_FPLMN",0x6f7e=>"EF_LOCI",0x6fad=>"EF_AD",0x6fae=>"EF-PHASE",0x6fb1=>"EF_VGCS",0x6fba=>"EF_VGCSS",
|
||||
0x6fb3=>"EF_VBS",0x6fb4=>"EF_VBSS",0x6fb5=>"EF_eMLPP",0x6fb6=>"EF_AAeM",0x6fb7=>"EF_ECC",0x6f50=>"EF_CBMIR",
|
||||
0x6f51=>"EF_NIA",0x6f52=>"EF_KcGPRS",0x6f53=>"EF_LOCIGPRS",0x6f54=>"EF_SUME",0x6f58=>"EF_CMI",0x6f60=>"EF_PLMNwEAcT",
|
||||
0x6f61=>"EF_OPLMNwAcT",0x6f62=>"EF_HPLMNAcT",0x6f63=>"EF_CPBCCH",0x6f64=>"EF_INVSCAN",0x6fc5=>"EF_PNN",0x6fc6=>"EF_OPL",
|
||||
0x6fc7=>"EF_MBDN",0x6fc8=>"EF_EXT6",0x6fc9=>"EF_MBI",0x6fca=>"EF_MWIS",0x6fcb=>"EF_CFIS",0x6fcc=>"EF_EXT7",
|
||||
0x6fcd=>"EF_SPDI",0x6fce=>"EF_MMSN",0x6fcf=>"EF_EXT8",0x6fd0=>"EF_MMSIFP",0x6fd1=>"EF_MMSUP",0x6fd2=>"EF_MMSUCP"
|
||||
}
|
||||
|
||||
# GSM alphabet (7 bits)
|
||||
# 0x1b escape caharacter is now space
|
||||
GSM_ALPHABET = "@£$¥èéùìòÇ\rØø\nÅåΔ_ΦΓΛΩΠΨΣΘΞ ÆæßÉ !\"#¤%&'()*=,-./0123456789:;<=>?¡ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà"
|
||||
# not defined is a space
|
||||
EXTENDED_ALPHABET = " ^ {} \\ [~] | € "
|
||||
|
||||
#=============
|
||||
#== methods ==
|
||||
#=============
|
||||
|
||||
# send APDU byte array
|
||||
# return : APDU response
|
||||
|
@ -181,4 +233,115 @@ module APDU
|
|||
|
||||
return response
|
||||
end
|
||||
|
||||
# get the status (current directory)
|
||||
def status
|
||||
begin
|
||||
response, sw1, sw2 = transmit(STATUS+[0x00])
|
||||
rescue
|
||||
return nil
|
||||
end
|
||||
response, sw1, sw2 = transmit(GET_RESPONSE+[sw2])
|
||||
return response
|
||||
end
|
||||
|
||||
# RUN GSM ALGORITHM
|
||||
def a38(rand)
|
||||
# am I in DF_GSM ?
|
||||
pwd = status()
|
||||
cd [MF,DF_GSM] unless pwd and pwd[4,2]==DF_GSM
|
||||
|
||||
# run algo
|
||||
response, sw1, sw2 = transmit(A38+rand)
|
||||
response, sw1, sw2 = transmit(GET_RESPONSE+[sw2])
|
||||
|
||||
return response
|
||||
end
|
||||
|
||||
# change directory
|
||||
# - path : array of files (EF/DF) to browse
|
||||
def cd(path)
|
||||
# change each folder
|
||||
path.each do |folder|
|
||||
# select folder
|
||||
response = select(folder)
|
||||
# verify it's a folder (MF or DF)
|
||||
raise "#{folder.to_hex_disp} is not a folder" unless response[6]==1 or response[6]==2
|
||||
end
|
||||
end
|
||||
|
||||
# read an elementary file
|
||||
# - path : array of files (directory+ef) to browse
|
||||
# returns the content (binary or record)
|
||||
def read_ef(path)
|
||||
|
||||
# browse the path
|
||||
cd path[0..-2]
|
||||
# select file
|
||||
response = select(path[-1])
|
||||
size = (response[2]<<8)+response[3]
|
||||
# verify it's really and EF (TS 51.011 9.3)
|
||||
if response[6]==0x04 then
|
||||
# read ef (depending on the type of file)
|
||||
if response[13]==0x00 then # transparent file (TS 51.011 9.3)
|
||||
response, sw1, sw2 = transmit(READ_BINARY+[0x00,0x00]+[size&0xFF])
|
||||
to_return = response
|
||||
if size>0xFF then
|
||||
response, sw1, sw2 = transmit(READ_BINARY+[0x01, 0x00]+[(size>>8)&0xFF])
|
||||
to_return += response
|
||||
end
|
||||
else # linear fixed or cyclic
|
||||
record_size = response[14]
|
||||
to_return = []
|
||||
# read all records
|
||||
(1..size/record_size).each do |i|
|
||||
response = transmit(READ_RECORD+[i,0x04,record_size])[0]
|
||||
to_return << response
|
||||
end
|
||||
end
|
||||
else
|
||||
raise "selection is not an EF"
|
||||
# TODO : implement the MF/DF reading
|
||||
end
|
||||
|
||||
return to_return
|
||||
end
|
||||
|
||||
# is the CHV1/PIN required
|
||||
def chv_enabled?
|
||||
# goto DF_GSM and verify if CHV is required
|
||||
cd [MF]
|
||||
response = select(DF_GSM)
|
||||
# check if enabled
|
||||
chv_enabled = (response[13]>>7)&0x01==0
|
||||
chv_tries = response[18]&0x0f
|
||||
if chv_enabled and chv_tries==0 then
|
||||
puts "no CHV1 try left. enter PUK1 on your phone"
|
||||
exit 0
|
||||
elsif chv_enabled
|
||||
puts "#{chv_tries} CHV1 tries left"
|
||||
end
|
||||
|
||||
return chv_enabled
|
||||
end
|
||||
|
||||
# convert a 7-bit GSM alphabet text into UTF8
|
||||
def alphabet(text)
|
||||
converted = ""
|
||||
escape = false
|
||||
text.each do |c|
|
||||
if escape then # extended table
|
||||
converted += EXTENDED_ALPHABET.char_at(c)
|
||||
escape = false
|
||||
else # gsm 7 bit alphabet
|
||||
if c==0x1b then
|
||||
escape = true
|
||||
else
|
||||
converted += GSM_ALPHABET.char_at(c)
|
||||
end
|
||||
end
|
||||
end
|
||||
return converted
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue