Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
ors-utils
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
ors-utils
Commits
f363bd12
Commit
f363bd12
authored
Mar 07, 2024
by
Thomas Gambier
🚴🏼
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Upgrade uicc to version 3.3
parent
80893308
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
1835 additions
and
1680 deletions
+1835
-1680
uicc/Makefile
uicc/Makefile
+5
-0
uicc/REAME.txt
uicc/REAME.txt
+37
-0
uicc/program_uicc.c
uicc/program_uicc.c
+765
-749
uicc/uicc.h
uicc/uicc.h
+1028
-931
No files found.
uicc/Makefile
View file @
f363bd12
program_uicc
:
program_uicc.c uicc.h milenage.h
g++
--std
=
c++11
-g3
-I
.
-Wall
program_uicc.c
-o
program_uicc
program_uicc_pcsc
:
program_uicc.c uicc.h milenage.h
g++
--std
=
c++11
-g3
-DPCSC
-I
.
-I
/usr/include/PCSC
-Wall
program_uicc.c
-L
/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Linux
-lccid
-o
program_uicc_pcsc
clean
:
rm
program_uicc program_uicc_pcsc
uicc/REAME.txt
0 → 100644
View file @
f363bd12
To compile
================
# make
For raw protocol reader
or
# make program_uicc_pcsc
For raw and pc/sc readers support
You may have to adapt Makefile to your directories for the libccid.so file and the PCSC include directory
The package, on debian style can be installed with
#apt install libccid
To use
===============
*** With raw reader, full options (set all values in the card)
# sudo program_uicc --port /dev/ttyUSB0 --adm 12345678 --iccid 89860061100000000123 --imsi 208920100001123 --isdn 00000$i --acc 0001 --key 6874736969202073796d4b2079650a73 --opc 504f20634f6320504f50206363500a4f -spn OpenCells --authenticate
*** If you use PC/SC reader
# apt install libpcsclite-dev
# LD_LIBRARY_PATH=/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Linux ./program_uicc_pcsc --port usb:08e6/3437 --adm 12345678 --iccid 89860061100000000123 --imsi 208920100001123 --isdn 00000$i --acc 0001 --key 6874736969202073796d4b2079650a73 --opc 504f20634f6320504f50206363500a4f -spn OpenCells --authenticate
The library path may change on your linux distrbution
*** The port value setting is:
For raw readers
If you have no other serial, it should be /dev/ttyUSB0 (default). Else, the tty number will be in "dmesg" command result for example
For PC/SC readers
#lsusb
You will recognize your reader like:
Bus 001 Device 011: ID 08e6:3437 Gemalto (was Gemplus) GemPC Twin SmartCard Reader
The --port value for this example is usb:08e6/3437 (note the ":" is replaced by "/" in libccid)
uicc/program_uicc.c
View file @
f363bd12
...
...
@@ -21,816 +21,832 @@
#include <sys/time.h>
struct
uicc_vals
{
bool
setIt
=
false
;
string
adm
=
""
;
string
iccid
=
""
;
string
imsi
=
""
;
string
opc
=
""
;
string
op
=
""
;
string
isdn
=
""
;
string
acc
=
""
;
string
key
=
""
;
string
spn
=
"open cells"
;
string
ust
=
"866F1F1C231E0000400050"
;
int
mncLen
=
2
;
bool
authenticate
=
false
;
string
sqn
=
""
;
string
rand
=
""
;
bool
setIt
=
false
;
string
adm
=
""
;
string
iccid
=
""
;
string
imsi
=
""
;
string
opc
=
""
;
string
op
=
""
;
string
isdn
=
""
;
string
acc
=
""
;
string
key
=
""
;
string
spn
=
"open cells"
;
string
act
=
"7c00"
;
string
ust
=
"866F1F1C231E0000400050"
;
int
mncLen
=
2
;
bool
authenticate
=
false
;
string
sqn
=
""
;
string
rand
=
""
;
};
#define sc(in, out) \
USIMcard.send_check( string( (char*)in +37 ,sizeof(in) -37), \
string( (char*)out+37 ,sizeof(out)-37) )
bool
readSIMvalues
(
char
*
port
)
{
SIM
SIMcard
;
string
ATR
;
Assert
((
ATR
=
SIMcard
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
//dump_hex("ATR", ATR);
vector
<
string
>
res
;
cout
<<
"GSM IMSI: "
<<
SIMcard
.
decodeIMSI
(
SIMcard
.
readFile
(
"IMSI"
)[
0
])
<<
endl
;
// Show only the first isdn (might be several)
cout
<<
"GSM MSISDN: "
<<
SIMcard
.
decodeISDN
(
SIMcard
.
readFile
(
"MSISDN"
)[
0
])
<<
endl
;
SIMcard
.
close
();
return
true
;
SIM
SIMcard
;
string
ATR
;
Assert
((
ATR
=
SIMcard
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
//dump_hex("ATR", ATR);
vector
<
string
>
res
;
cout
<<
"GSM IMSI: "
<<
SIMcard
.
decodeIMSI
(
SIMcard
.
readFile
(
"IMSI"
)[
0
])
<<
endl
;
// Show only the first isdn (might be several)
cout
<<
"GSM MSISDN: "
<<
SIMcard
.
decodeISDN
(
SIMcard
.
readFile
(
"MSISDN"
)[
0
])
<<
endl
;
SIMcard
.
close
();
return
true
;
}
int
readUSIMvalues
(
char
*
port
)
{
vector
<
string
>
res
;
USIM
USIMcard
;
string
ATR
;
Assert
((
ATR
=
USIMcard
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
//dump_hex("ATR", ATR);
res
=
USIMcard
.
readFile
(
"ICCID"
);
string
iccid
=
to_hex
(
res
[
0
],
true
);
cout
<<
"ICCID: "
<<
iccid
<<
endl
;
if
(
!
luhn
(
iccid
))
printf
(
"WARNING: iccid luhn encoding of last digit not done
\n
"
);
USIMcard
.
openUSIM
();
string
imsi
=
USIMcard
.
readFile
(
"IMSI"
)[
0
];
cout
<<
"USIM IMSI: "
<<
USIMcard
.
decodeIMSI
(
imsi
)
<<
endl
;
res
=
USIMcard
.
readFile
(
"PLMN selector with Access Technology"
);
//cout << "USIM PLMN selector: " << bcdToAscii(res[0]) <<endl;
// Show only the first isdn (might be several)
string
msisdn
=
USIMcard
.
readFile
(
"MSISDN"
)[
0
];
cout
<<
"USIM MSISDN: "
<<
USIMcard
.
decodeISDN
(
msisdn
)
<<
endl
;
string
spn
=
USIMcard
.
readFile
(
"Service Provider Name"
)[
0
];
cout
<<
"USIM Service Provider Name: "
<<
printable
(
spn
.
substr
(
1
))
<<
endl
;
if
(
USIMcard
.
debug
)
{
string
stt
=
USIMcard
.
readFile
(
"USIM service table"
)[
0
];
decodeServiceTable
(
stt
);
}
return
USIMcard
.
GRver
;
vector
<
string
>
res
;
USIM
USIMcard
;
string
ATR
;
Assert
((
ATR
=
USIMcard
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
//dump_hex("ATR", ATR);
res
=
USIMcard
.
readFile
(
"ICCID"
);
string
iccid
=
"No iccid readable"
;
if
(
res
.
size
()
)
iccid
=
to_hex
(
res
[
0
],
true
);
cout
<<
"ICCID: "
<<
iccid
<<
endl
;
if
(
!
luhn
(
iccid
))
printf
(
"WARNING: iccid luhn encoding of last digit not done
\n
"
);
USIMcard
.
openUSIM
();
string
imsi
=
USIMcard
.
readFile
(
"IMSI"
)[
0
];
cout
<<
"USIM IMSI: "
<<
USIMcard
.
decodeIMSI
(
imsi
)
<<
endl
;
res
=
USIMcard
.
readFile
(
"PLMN selector with Access Technology"
);
auto
last
=
res
[
0
].
find_last_not_of
(
string
(
u8"
\xff
"
,
1
));
if
(
last
!=
std
::
string
::
npos
)
dump_hex
(
"PLMN selector: "
,
res
[
0
].
substr
(
0
,
last
));
res
=
USIMcard
.
readFile
(
"Operator controlled PLMN selector with Access Technology"
);
last
=
res
[
0
].
find_last_not_of
(
string
(
u8"
\xff
"
,
1
));
if
(
last
!=
std
::
string
::
npos
)
dump_hex
(
"Operator Control PLMN selector: "
,
res
[
0
].
substr
(
0
,
last
));
res
=
USIMcard
.
readFile
(
"Home PLMN selector with Access Technology"
);
last
=
res
[
0
].
find_last_not_of
(
string
(
u8"
\xff
"
,
1
));
if
(
last
!=
std
::
string
::
npos
)
dump_hex
(
"Home PLMN selector: "
,
res
[
0
].
substr
(
0
,
last
));
string
msisdn
=
USIMcard
.
readFile
(
"MSISDN"
)[
0
];
cout
<<
"USIM MSISDN: "
<<
USIMcard
.
decodeISDN
(
msisdn
)
<<
endl
;
string
spn
=
USIMcard
.
readFile
(
"Service Provider Name"
)[
0
];
cout
<<
"USIM Service Provider Name: "
<<
printable
(
spn
.
substr
(
1
))
<<
endl
;
if
(
USIMcard
.
debug
)
{
string
stt
=
USIMcard
.
readFile
(
"USIM service table"
)[
0
];
decodeServiceTable
(
stt
);
}
return
USIMcard
.
GRver
;
}
bool
testATR
(
char
*
port
)
{
SIM
card
;
string
ATR
;
Assert
((
ATR
=
card
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
// Proprietary handcheck to open card flashing
return
ATR
[
ATR
.
size
()
-
1
]
==
'\xac'
||
ATR
[
ATR
.
size
()
-
1
]
==
'\xf3'
;
SIM
card
;
string
ATR
;
Assert
((
ATR
=
card
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
// Proprietary handcheck to open card flashing
return
ATR
[
ATR
.
size
()
-
1
]
==
'\xac'
||
ATR
[
ATR
.
size
()
-
1
]
==
'\xf3'
;
}
bool
writeSIMv2values
(
char
*
port
,
struct
uicc_vals
&
values
)
{
SIM
card
;
string
ATR
;
bool
ATRpersonalized
=
testATR
(
port
);
Assert
((
ATR
=
card
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
SIM
card
;
string
ATR
;
bool
ATRpersonalized
=
testATR
(
port
);
Assert
((
ATR
=
card
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
// Proprietary handcheck to open card flashing
if
(
ATRpersonalized
)
// if already flashed
card
.
send_check
(
hexa
(
"A0580000083132333431323334"
),
hexa
(
"9000"
),
10
);
// Proprietary handcheck to open card flashing
if
(
ATRpersonalized
)
// if already flashed
card
.
send_check
(
hexa
(
"A0580000083132333431323334"
),
hexa
(
"9000"
),
10
);
card
.
send_check
(
hexa
(
"A0580000083132333431323334"
),
hexa
(
"9000"
),
10
);
if
(
card
.
debug
)
{
// Check the card available AIDs
vector
<
string
>
EFdir
=
card
.
readFile
(
"EFDIR"
);
card
.
decodeEFdir
(
EFdir
);
}
// Proprietary PIN1, PUK1
card
.
send_check
(
hexa
(
"A0A40000020100"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D6000017000000 31323334FFFFFFFF 8383 3838383838383838 8A8A"
),
hexa
(
"9000"
));
// Proprietary PIN2, PUK2
card
.
send_check
(
hexa
(
"A0A40000020200"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D6000017010000 31323334FFFFFFFF 8383 3838383838383838 8A8A"
),
hexa
(
"9000"
));
// Proprietary ADM
card
.
send_check
(
hexa
(
"A0A40000020B00"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D600000D010000"
)
+
values
.
adm
+
hexa
(
"8A8A"
),
hexa
(
"9000"
));
//Write ALG Type 1910:Millenage 1920:XOR
card
.
send_check
(
hexa
(
"A0A40000022FD0"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D6000002 1910"
),
hexa
(
"9000"
));
//Write Ki
if
(
values
.
key
.
size
()
==
32
)
{
card
.
send_check
(
hexa
(
"A0A40000020001"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D6000010"
)
+
hexa
(
values
.
key
),
hexa
(
"9000"
));
}
else
printf
(
"No Key or not 32 char length key
\n
"
);
// Write OPc
if
(
values
.
opc
.
size
()
==
32
)
{
card
.
send_check
(
hexa
(
"A0A40000026002"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D600001101"
)
+
hexa
(
values
.
opc
),
hexa
(
"9000"
),
10
);
}
else
printf
(
"No OPc or not 32 char length key
\n
"
);
// Set milenage R and C
card
.
send_check
(
hexa
(
"A0A40000022FE6"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0DC0104114000000000000000000000000000000000"
),
hexa
(
"9000"
));
card
.
send_check
(
hexa
(
"A0DC0204110000000000000000000000000000000001"
),
hexa
(
"9000"
));
card
.
send_check
(
hexa
(
"A0DC0304112000000000000000000000000000000002"
),
hexa
(
"9000"
));
card
.
send_check
(
hexa
(
"A0DC0404114000000000000000000000000000000004"
),
hexa
(
"9000"
));
card
.
send_check
(
hexa
(
"A0DC0504116000000000000000000000000000000008"
),
hexa
(
"9000"
));
card
.
send_check
(
hexa
(
"A0A40000022FE5"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D6000005081C2A0001"
),
hexa
(
"9000"
));
//
// We enter regular files, defined in the 3GPP documents
//
if
(
values
.
iccid
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"ICCID"
,
card
.
encodeICCID
(
values
.
iccid
)),
"can't set iccid %s"
,
values
.
iccid
.
c_str
());
vector
<
string
>
li
;
li
.
push_back
(
"en"
);
Assert
(
card
.
writeFile
(
"Extended language preference"
,
li
),
"can't set language"
);
Assert
(
card
.
writeFile
(
"language preference"
,
makeBcdVect
(
"01"
,
false
)),
"can't set language"
);
vector
<
string
>
ad
;
ad
.
push_back
(
makeBcd
(
"810000"
,
false
));
ad
[
0
]
+=
(
char
)
values
.
mncLen
;
Assert
(
card
.
writeFile
(
"Administrative data"
,
ad
),
"can't set Administrative data"
);
if
(
values
.
imsi
.
size
()
>
0
)
{
Assert
(
card
.
writeFile
(
"IMSI"
,
card
.
encodeIMSI
(
values
.
imsi
)),
"can't set imsi %s"
,
values
.
imsi
.
c_str
());
string
MccMnc
=
card
.
encodeMccMnc
(
values
.
imsi
.
substr
(
0
,
3
),
values
.
imsi
.
substr
(
3
,
values
.
mncLen
));
vector
<
string
>
VectMccMnc
;
VectMccMnc
.
push_back
(
MccMnc
);
Assert
(
card
.
writeFile
(
"PLMN selector"
,
VectMccMnc
,
true
),
"Can't write PLMN Selector"
);
vector
<
string
>
loci
;
loci
.
push_back
(
makeBcd
(
""
,
true
,
4
));
loci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
loci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
loci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"Location information"
,
loci
),
"location information"
);
}
if
(
values
.
acc
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"Access control class"
,
card
.
encodeACC
(
values
.
acc
)),
"can't set acc %s"
,
values
.
acc
.
c_str
());
vector
<
string
>
spn
;
spn
.
push_back
(
string
(
u8"
\x01
"
,
1
));
spn
[
0
]
+=
values
.
spn
;
Assert
(
card
.
writeFile
(
"Service Provider Name"
,
spn
,
true
),
"can't set spn"
);
Assert
(
card
.
writeFile
(
"Higher Priority PLMN search period"
,
makeBcdVect
(
"02"
,
false
)),
"can't set plmn search period"
);
Assert
(
card
.
writeFile
(
"Forbidden PLMN"
,
makeBcdVect
(
""
),
true
),
"can't set forbidden plmn"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 1"
,
makeBcdVect
(
""
),
true
),
"can't set GID1"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 2"
,
makeBcdVect
(
""
),
true
),
"can't set GID2"
);
// Typical service list, a bit complex to define (see 3GPP TS 51.011)
Assert
(
card
.
writeFile
(
"SIM service table"
,
makeBcdVect
(
"ff33ffff00003f033000"
,
false
)),
"can't set GSM service table"
);
if
(
values
.
isdn
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"MSISDN"
,
card
.
encodeISDN
(
"9"
+
values
.
isdn
,
card
.
fileRecordSize
(
"MSISDN"
))),
"can't set msisdn %s"
,
values
.
isdn
.
c_str
());
Assert
(
card
.
writeFile
(
"SMSC"
,
makeBcdVect
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFFF0191"
),
true
),
"can't set SMS center"
);
//
// Set USIM values, from GSM APDU CLA, proprietary method but regular file names
//
Assert
(
card
.
writeFile
(
"USIM Extended language preference"
,
li
),
"can't set language"
);
Assert
(
card
.
writeFile
(
"USIM Administrative data"
,
ad
),
"can't set Administrative data"
);
Assert
(
card
.
writeFile
(
"USIM Short Message Service Parameters"
,
makeBcdVect
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFFF 0191"
,
true
,
40
)),
"can't set SMSC"
);
if
(
values
.
isdn
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"USIM MSISDN"
,
card
.
encodeISDN
(
values
.
isdn
,
card
.
fileRecordSize
(
"MSISDN"
))),
"can't set msisdn %s"
,
values
.
isdn
.
c_str
());
if
(
values
.
acc
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"USIM Access control class"
,
card
.
encodeACC
(
values
.
acc
)),
"can't set acc %s"
,
values
.
acc
.
c_str
());
if
(
values
.
imsi
.
size
()
>
0
)
{
Assert
(
card
.
writeFile
(
"USIM IMSI"
,
card
.
encodeIMSI
(
values
.
imsi
)),
"can't set imsi %s"
,
values
.
imsi
.
c_str
());
string
MccMnc
=
card
.
encodeMccMnc
(
values
.
imsi
.
substr
(
0
,
3
),
values
.
imsi
.
substr
(
3
,
values
.
mncLen
));
vector
<
string
>
VectMccMnc
;
VectMccMnc
.
push_back
(
MccMnc
);
vector
<
string
>
MccMncWithAct
=
VectMccMnc
;
// Add EUTRAN access techno only
MccMncWithAct
[
0
]
+=
string
(
u8"
\x40\x00
"
,
2
);
Assert
(
card
.
writeFile
(
"USIM PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write PLMN Selector"
);
Assert
(
card
.
writeFile
(
"USIM Operator controlled PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write Operator PLMN Selector"
);
Assert
(
card
.
writeFile
(
"USIM Home PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write home PLMN Selector"
);
vector
<
string
>
psloci
;
psloci
.
push_back
(
makeBcd
(
""
,
true
,
7
));
psloci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
psloci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
psloci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"USIM PS Location information"
,
psloci
,
false
),
"PS location information"
);
vector
<
string
>
csloci
;
csloci
.
push_back
(
makeBcd
(
""
,
true
,
4
));
csloci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
csloci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
csloci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"USIM CS Location information"
,
csloci
,
false
),
"CS location information"
);
}
Assert
(
card
.
writeFile
(
"USIM Service Provider Name"
,
spn
,
true
),
"can't set spn"
);
Assert
(
card
.
writeFile
(
"USIM Higher Priority PLMN search period"
,
makeBcdVect
(
"02"
,
false
)),
"can't set plmn search period"
);
Assert
(
card
.
writeFile
(
"USIM Forbidden PLMNs"
,
makeBcdVect
(
""
,
true
,
12
)),
"can't set forbidden plmn"
);
Assert
(
card
.
writeFile
(
"USIM Group Identifier Level 1"
,
makeBcdVect
(
""
,
true
,
4
)),
"can't set GID1"
);
Assert
(
card
.
writeFile
(
"USIM Group Identifier Level 2"
,
makeBcdVect
(
""
,
true
,
4
)),
"can't set GID2"
);
vector
<
string
>
ecc
;
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
Assert
(
card
.
writeFile
(
"USIM emergency call codes"
,
ecc
),
"can't set emergency call codes"
);
// Typical service list, a bit complex to define (see 3GPP TS 51.011)
Assert
(
card
.
writeFile
(
"USIM service table"
,
makeBcdVect
(
values
.
ust
,
false
)),
"can't set USIM service table"
);
return
true
;
if
(
card
.
debug
)
{
// Check the card available AIDs
vector
<
string
>
EFdir
=
card
.
readFile
(
"EFDIR"
);
card
.
decodeEFdir
(
EFdir
);
}
// Proprietary PIN1, PUK1
card
.
send_check
(
hexa
(
"A0A40000020100"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D6000017000000 31323334FFFFFFFF 8383 3838383838383838 8A8A"
),
hexa
(
"9000"
));
// Proprietary PIN2, PUK2
card
.
send_check
(
hexa
(
"A0A40000020200"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D6000017010000 31323334FFFFFFFF 8383 3838383838383838 8A8A"
),
hexa
(
"9000"
));
// Proprietary ADM
card
.
send_check
(
hexa
(
"A0A40000020B00"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D600000D010000"
)
+
values
.
adm
+
hexa
(
"8A8A"
),
hexa
(
"9000"
));
//Write ALG Type 1910:Millenage 1920:XOR
card
.
send_check
(
hexa
(
"A0A40000022FD0"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D6000002 1910"
),
hexa
(
"9000"
));
//Write Ki
if
(
values
.
key
.
size
()
==
32
)
{
card
.
send_check
(
hexa
(
"A0A40000020001"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D6000010"
)
+
hexa
(
values
.
key
),
hexa
(
"9000"
));
}
else
printf
(
"No Key or not 32 char length key
\n
"
);
// Write OPc
if
(
values
.
opc
.
size
()
==
32
)
{
card
.
send_check
(
hexa
(
"A0A40000026002"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D600001101"
)
+
hexa
(
values
.
opc
),
hexa
(
"9000"
),
10
);
}
else
printf
(
"No OPc or not 32 char length key
\n
"
);
// Set milenage R and C
card
.
send_check
(
hexa
(
"A0A40000022FE6"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0DC0104114000000000000000000000000000000000"
),
hexa
(
"9000"
));
card
.
send_check
(
hexa
(
"A0DC0204110000000000000000000000000000000001"
),
hexa
(
"9000"
));
card
.
send_check
(
hexa
(
"A0DC0304112000000000000000000000000000000002"
),
hexa
(
"9000"
));
card
.
send_check
(
hexa
(
"A0DC0404114000000000000000000000000000000004"
),
hexa
(
"9000"
));
card
.
send_check
(
hexa
(
"A0DC0504116000000000000000000000000000000008"
),
hexa
(
"9000"
));
card
.
send_check
(
hexa
(
"A0A40000022FE5"
),
hexa
(
"9F10"
));
card
.
send_check
(
hexa
(
"A0D6000005081C2A0001"
),
hexa
(
"9000"
));
//
// We enter regular files, defined in the 3GPP documents
//
if
(
values
.
iccid
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"ICCID"
,
card
.
encodeICCID
(
values
.
iccid
)),
"can't set iccid %s"
,
values
.
iccid
.
c_str
());
vector
<
string
>
li
;
li
.
push_back
(
"en"
);
Assert
(
card
.
writeFile
(
"Extended language preference"
,
li
),
"can't set language"
);
Assert
(
card
.
writeFile
(
"language preference"
,
makeBcdVect
(
"01"
,
false
)),
"can't set language"
);
vector
<
string
>
ad
;
ad
.
push_back
(
makeBcd
(
"810000"
,
false
));
ad
[
0
]
+=
(
char
)
values
.
mncLen
;
Assert
(
card
.
writeFile
(
"Administrative data"
,
ad
),
"can't set Administrative data"
);
if
(
values
.
imsi
.
size
()
>
0
)
{
Assert
(
card
.
writeFile
(
"IMSI"
,
card
.
encodeIMSI
(
values
.
imsi
)),
"can't set imsi %s"
,
values
.
imsi
.
c_str
());
string
MccMnc
=
card
.
encodeMccMnc
(
values
.
imsi
.
substr
(
0
,
3
),
values
.
imsi
.
substr
(
3
,
values
.
mncLen
));
vector
<
string
>
VectMccMnc
;
VectMccMnc
.
push_back
(
MccMnc
);
Assert
(
card
.
writeFile
(
"PLMN selector"
,
VectMccMnc
,
true
),
"Can't write PLMN Selector"
);
vector
<
string
>
loci
;
loci
.
push_back
(
makeBcd
(
""
,
true
,
4
));
loci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
loci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
loci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"Location information"
,
loci
),
"location information"
);
}
if
(
values
.
acc
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"Access control class"
,
card
.
encodeACC
(
values
.
acc
)),
"can't set acc %s"
,
values
.
acc
.
c_str
());
vector
<
string
>
spn
;
spn
.
push_back
(
string
(
u8"
\x01
"
,
1
));
spn
[
0
]
+=
values
.
spn
;
Assert
(
card
.
writeFile
(
"Service Provider Name"
,
spn
,
true
),
"can't set spn"
);
Assert
(
card
.
writeFile
(
"Higher Priority PLMN search period"
,
makeBcdVect
(
"02"
,
false
)),
"can't set plmn search period"
);
Assert
(
card
.
writeFile
(
"Forbidden PLMN"
,
makeBcdVect
(
""
),
true
),
"can't set forbidden plmn"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 1"
,
makeBcdVect
(
""
),
true
),
"can't set GID1"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 2"
,
makeBcdVect
(
""
),
true
),
"can't set GID2"
);
// Typical service list, a bit complex to define (see 3GPP TS 51.011)
Assert
(
card
.
writeFile
(
"SIM service table"
,
makeBcdVect
(
"ff33ffff00003f033000"
,
false
)),
"can't set GSM service table"
);
if
(
values
.
isdn
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"MSISDN"
,
card
.
encodeISDN
(
"9"
+
values
.
isdn
,
card
.
fileRecordSize
(
"MSISDN"
))),
"can't set msisdn %s"
,
values
.
isdn
.
c_str
());
//
// Set USIM values, from GSM APDU CLA, proprietary method but regular file names
//
Assert
(
card
.
writeFile
(
"USIM Extended language preference"
,
li
),
"can't set language"
);
Assert
(
card
.
writeFile
(
"USIM Administrative data"
,
ad
),
"can't set Administrative data"
);
Assert
(
card
.
writeFile
(
"USIM Short Message Service Parameters"
,
makeBcdVect
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFFF 0191"
,
true
,
40
)),
"can't set SMSC"
);
if
(
values
.
isdn
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"USIM MSISDN"
,
card
.
encodeISDN
(
values
.
isdn
,
card
.
fileRecordSize
(
"MSISDN"
))),
"can't set msisdn %s"
,
values
.
isdn
.
c_str
());
if
(
values
.
acc
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"USIM Access control class"
,
card
.
encodeACC
(
values
.
acc
)),
"can't set acc %s"
,
values
.
acc
.
c_str
());
if
(
values
.
imsi
.
size
()
>
0
)
{
Assert
(
card
.
writeFile
(
"USIM IMSI"
,
card
.
encodeIMSI
(
values
.
imsi
)),
"can't set imsi %s"
,
values
.
imsi
.
c_str
());
string
MccMnc
=
card
.
encodeMccMnc
(
values
.
imsi
.
substr
(
0
,
3
),
values
.
imsi
.
substr
(
3
,
values
.
mncLen
));
vector
<
string
>
VectMccMnc
;
VectMccMnc
.
push_back
(
MccMnc
);
vector
<
string
>
MccMncWithAct
=
VectMccMnc
;
MccMncWithAct
[
0
]
+=
makeBcd
(
values
.
act
,
false
,
2
);
Assert
(
card
.
writeFile
(
"USIM PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write PLMN Selector"
);
Assert
(
card
.
writeFile
(
"USIM Operator controlled PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write Operator PLMN Selector"
);
Assert
(
card
.
writeFile
(
"USIM Home PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write home PLMN Selector"
);
vector
<
string
>
psloci
;
psloci
.
push_back
(
makeBcd
(
""
,
true
,
7
));
psloci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
psloci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
psloci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"USIM PS Location information"
,
psloci
,
false
),
"PS location information"
);
vector
<
string
>
csloci
;
csloci
.
push_back
(
makeBcd
(
""
,
true
,
4
));
csloci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
csloci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
csloci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"USIM CS Location information"
,
csloci
,
false
),
"CS location information"
);
}
Assert
(
card
.
writeFile
(
"USIM Service Provider Name"
,
spn
,
true
),
"can't set spn"
);
Assert
(
card
.
writeFile
(
"USIM Higher Priority PLMN search period"
,
makeBcdVect
(
"02"
,
false
)),
"can't set plmn search period"
);
Assert
(
card
.
writeFile
(
"USIM Forbidden PLMNs"
,
makeBcdVect
(
""
,
true
,
12
)),
"can't set forbidden plmn"
);
Assert
(
card
.
writeFile
(
"USIM Group Identifier Level 1"
,
makeBcdVect
(
""
,
true
,
4
)),
"can't set GID1"
);
Assert
(
card
.
writeFile
(
"USIM Group Identifier Level 2"
,
makeBcdVect
(
""
,
true
,
4
)),
"can't set GID2"
);
vector
<
string
>
ecc
;
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
Assert
(
card
.
writeFile
(
"USIM emergency call codes"
,
ecc
),
"can't set emergency call codes"
);
// Typical service list, a bit complex to define (see 3GPP TS 51.011)
Assert
(
card
.
writeFile
(
"USIM service table"
,
makeBcdVect
(
values
.
ust
,
false
)),
"can't set USIM service table"
);
return
true
;
}
bool
writeSIMvalues
(
char
*
port
,
struct
uicc_vals
&
values
)
{
vector
<
string
>
res
;
SIM
card
;
string
ATR
;
Assert
((
ATR
=
card
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
if
(
!
card
.
verifyChv
(
'\x0a'
,
values
.
adm
))
{
printf
(
"chv 0a Nok
\n
"
);
return
false
;
}
if
(
card
.
debug
)
{
// Check the card available AIDs
vector
<
string
>
EFdir
=
card
.
readFile
(
"EFDIR"
);
card
.
decodeEFdir
(
EFdir
);
}
if
(
values
.
iccid
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"ICCID"
,
card
.
encodeICCID
(
values
.
iccid
)),
"can't set iccid %s"
,
values
.
iccid
.
c_str
());
vector
<
string
>
li
;
li
.
push_back
(
"en"
);
Assert
(
card
.
writeFile
(
"Extended language preference"
,
li
),
"can't set language"
);
Assert
(
card
.
writeFile
(
"language preference"
,
makeBcdVect
(
"01"
,
false
)),
"can't set language"
);
vector
<
string
>
ad
;
ad
.
push_back
(
makeBcd
(
"810000"
,
false
));
ad
[
0
]
+=
(
char
)
values
.
mncLen
;
Assert
(
card
.
writeFile
(
"Administrative data"
,
ad
),
"can't set Administrative data"
);
if
(
values
.
imsi
.
size
()
>
0
)
{
Assert
(
card
.
writeFile
(
"IMSI"
,
card
.
encodeIMSI
(
values
.
imsi
)),
"can't set imsi %s"
,
values
.
imsi
.
c_str
());
string
MccMnc
=
card
.
encodeMccMnc
(
values
.
imsi
.
substr
(
0
,
3
),
values
.
imsi
.
substr
(
3
,
values
.
mncLen
));
vector
<
string
>
VectMccMnc
;
VectMccMnc
.
push_back
(
MccMnc
);
Assert
(
card
.
writeFile
(
"PLMN selector"
,
VectMccMnc
,
true
),
"Can't write PLMN Selector"
);
Assert
(
card
.
writeFile
(
"Equivalent home PLMN"
,
VectMccMnc
),
"Can't write Equivalent PLMN"
);
vector
<
string
>
loci
;
loci
.
push_back
(
makeBcd
(
""
,
true
,
4
));
loci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
loci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
loci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"Location information"
,
loci
),
"location information"
);
}
if
(
values
.
acc
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"Access control class"
,
card
.
encodeACC
(
values
.
acc
)),
"can't set acc %s"
,
values
.
acc
.
c_str
());
vector
<
string
>
spn
;
spn
.
push_back
(
string
(
u8"
\x01
"
,
1
));
spn
[
0
]
+=
values
.
spn
;
Assert
(
card
.
writeFile
(
"Service Provider Name"
,
spn
,
true
),
"can't set spn"
);
Assert
(
card
.
writeFile
(
"Higher Priority PLMN search period"
,
makeBcdVect
(
"02"
,
false
)),
"can't set plmn search period"
);
Assert
(
card
.
writeFile
(
"Forbidden PLMN"
,
makeBcdVect
(
""
),
true
),
"can't set forbidden plmn"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 1"
,
makeBcdVect
(
""
),
true
),
"can't set GID1"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 2"
,
makeBcdVect
(
""
),
true
),
"can't set GID2"
);
Assert
(
card
.
writeFile
(
"emergency call codes"
,
makeBcdVect
(
""
),
true
),
"can't set emergency call codes"
);
// Typical service list, a bit complex to define (see 3GPP TS 51.011)
Assert
(
card
.
writeFile
(
"SIM service table"
,
makeBcdVect
(
"ff33ffff00003f033000f0c3"
,
false
)),
"can't set GSM service table"
);
if
(
values
.
isdn
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"MSISDN"
,
card
.
encodeISDN
(
values
.
isdn
,
card
.
fileRecordSize
(
"MSISDN"
))),
"can't set msisdn %s"
,
values
.
isdn
.
c_str
());
Assert
(
card
.
writeFile
(
"SMSC"
,
makeBcdVect
(
""
),
true
),
"can't set SMS center"
);
return
true
;
vector
<
string
>
res
;
SIM
card
;
string
ATR
;
Assert
((
ATR
=
card
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
if
(
!
card
.
verifyChv
(
'\x0a'
,
values
.
adm
))
{
printf
(
"chv 0a Nok
\n
"
);
return
false
;
}
if
(
card
.
debug
)
{
// Check the card available AIDs
vector
<
string
>
EFdir
=
card
.
readFile
(
"EFDIR"
);
card
.
decodeEFdir
(
EFdir
);
}
if
(
values
.
iccid
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"ICCID"
,
card
.
encodeICCID
(
values
.
iccid
)),
"can't set iccid %s"
,
values
.
iccid
.
c_str
());
vector
<
string
>
li
;
li
.
push_back
(
"en"
);
Assert
(
card
.
writeFile
(
"Extended language preference"
,
li
),
"can't set language"
);
Assert
(
card
.
writeFile
(
"language preference"
,
makeBcdVect
(
"01"
,
false
)),
"can't set language"
);
vector
<
string
>
ad
;
ad
.
push_back
(
makeBcd
(
"810000"
,
false
));
ad
[
0
]
+=
(
char
)
values
.
mncLen
;
Assert
(
card
.
writeFile
(
"Administrative data"
,
ad
),
"can't set Administrative data"
);
if
(
values
.
imsi
.
size
()
>
0
)
{
Assert
(
card
.
writeFile
(
"IMSI"
,
card
.
encodeIMSI
(
values
.
imsi
)),
"can't set imsi %s"
,
values
.
imsi
.
c_str
());
string
MccMnc
=
card
.
encodeMccMnc
(
values
.
imsi
.
substr
(
0
,
3
),
values
.
imsi
.
substr
(
3
,
values
.
mncLen
));
vector
<
string
>
VectMccMnc
;
VectMccMnc
.
push_back
(
MccMnc
);
Assert
(
card
.
writeFile
(
"PLMN selector"
,
VectMccMnc
,
true
),
"Can't write PLMN Selector"
);
Assert
(
card
.
writeFile
(
"Equivalent home PLMN"
,
VectMccMnc
),
"Can't write Equivalent PLMN"
);
vector
<
string
>
loci
;
loci
.
push_back
(
makeBcd
(
""
,
true
,
4
));
loci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
loci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
loci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"Location information"
,
loci
),
"location information"
);
}
if
(
values
.
acc
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"Access control class"
,
card
.
encodeACC
(
values
.
acc
)),
"can't set acc %s"
,
values
.
acc
.
c_str
());
vector
<
string
>
spn
;
spn
.
push_back
(
string
(
u8"
\x01
"
,
1
));
spn
[
0
]
+=
values
.
spn
;
Assert
(
card
.
writeFile
(
"Service Provider Name"
,
spn
,
true
),
"can't set spn"
);
Assert
(
card
.
writeFile
(
"Higher Priority PLMN search period"
,
makeBcdVect
(
"02"
,
false
)),
"can't set plmn search period"
);
Assert
(
card
.
writeFile
(
"Forbidden PLMN"
,
makeBcdVect
(
""
),
true
),
"can't set forbidden plmn"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 1"
,
makeBcdVect
(
""
),
true
),
"can't set GID1"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 2"
,
makeBcdVect
(
""
),
true
),
"can't set GID2"
);
Assert
(
card
.
writeFile
(
"emergency call codes"
,
makeBcdVect
(
""
),
true
),
"can't set emergency call codes"
);
// Typical service list, a bit complex to define (see 3GPP TS 51.011)
Assert
(
card
.
writeFile
(
"SIM service table"
,
makeBcdVect
(
"ff33ffff00003f033000f0c3"
,
false
)),
"can't set GSM service table"
);
if
(
values
.
isdn
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"MSISDN"
,
card
.
encodeISDN
(
values
.
isdn
,
card
.
fileRecordSize
(
"MSISDN"
))),
"can't set msisdn %s"
,
values
.
isdn
.
c_str
());
Assert
(
card
.
writeFile
(
"Short Message Service Parameters"
,
makeBcdVect
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFFF 0191"
,
true
,
40
)),
"can't set SMSC"
);
return
true
;
}
void
writeUSIMproprietary
(
USIM
&
card
,
struct
uicc_vals
&
values
)
{
if
(
values
.
key
.
size
()
>
0
)
// Ki files and Milenage algo parameters are specific to the card manufacturer
Assert
(
card
.
writeFile
(
"GR Ki"
,
card
.
encodeKi
(
values
.
key
)),
"can't set Ki %s"
,
values
.
key
.
c_str
());
if
(
values
.
opc
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"GR OPc"
,
card
.
encodeOPC
(
values
.
opc
)),
"can't set OPc %s"
,
values
.
opc
.
c_str
());
//Milenage internal paramters
card
.
writeFile
(
"GR R"
,
makeBcdVect
(
"4000204060"
,
false
));
vector
<
string
>
C
;
C
.
push_back
(
makeBcd
(
"00000000000000000000000000000000"
,
false
));
C
.
push_back
(
makeBcd
(
"00000000000000000000000000000001"
,
false
));
C
.
push_back
(
makeBcd
(
"00000000000000000000000000000002"
,
false
));
C
.
push_back
(
makeBcd
(
"00000000000000000000000000000004"
,
false
));
C
.
push_back
(
makeBcd
(
"00000000000000000000000000000008"
,
false
));
card
.
writeFile
(
"GR C"
,
C
);
if
(
values
.
key
.
size
()
>
0
)
// Ki files and Milenage algo parameters are specific to the card manufacturer
Assert
(
card
.
writeFile
(
"GR Ki"
,
card
.
encodeKi
(
values
.
key
)),
"can't set Ki %s"
,
values
.
key
.
c_str
());
if
(
values
.
opc
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"GR OPc"
,
card
.
encodeOPC
(
values
.
opc
)),
"can't set OPc %s"
,
values
.
opc
.
c_str
());
//Milenage internal paramters
card
.
writeFile
(
"GR R"
,
makeBcdVect
(
"4000204060"
,
false
));
vector
<
string
>
C
;
C
.
push_back
(
makeBcd
(
"00000000000000000000000000000000"
,
false
));
C
.
push_back
(
makeBcd
(
"00000000000000000000000000000001"
,
false
));
C
.
push_back
(
makeBcd
(
"00000000000000000000000000000002"
,
false
));
C
.
push_back
(
makeBcd
(
"00000000000000000000000000000004"
,
false
));
C
.
push_back
(
makeBcd
(
"00000000000000000000000000000008"
,
false
));
card
.
writeFile
(
"GR C"
,
C
);
}
bool
writeUSIMvalues
(
char
*
port
,
struct
uicc_vals
&
values
)
{
vector
<
string
>
res
;
USIM
card
;
string
ATR
;
Assert
((
ATR
=
card
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
if
(
!
card
.
verifyChv
(
'\x0a'
,
values
.
adm
))
{
printf
(
"chv 0a Nok
\n
"
);
return
false
;
}
writeUSIMproprietary
(
card
,
values
);
vector
<
string
>
li
;
li
.
push_back
(
"en"
);
Assert
(
card
.
writeFile
(
"language preference"
,
li
),
"can't set language"
);
vector
<
string
>
ad
;
ad
.
push_back
(
makeBcd
(
"810000"
,
false
));
ad
[
0
]
+=
(
char
)
values
.
mncLen
;
Assert
(
card
.
writeFile
(
"Administrative data"
,
ad
),
"can't set Administrative data"
);
Assert
(
card
.
writeFile
(
"SMSC"
,
makeBcdVect
(
""
,
true
,
40
)),
"can't set SMSC"
);
if
(
values
.
isdn
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"MSISDN"
,
card
.
encodeISDN
(
values
.
isdn
,
card
.
fileRecordSize
(
"MSISDN"
))),
"can't set msisdn %s"
,
values
.
isdn
.
c_str
());
if
(
values
.
acc
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"Access control class"
,
card
.
encodeACC
(
values
.
acc
)),
"can't set acc %s"
,
values
.
acc
.
c_str
());
if
(
values
.
imsi
.
size
()
>
0
)
{
Assert
(
card
.
writeFile
(
"IMSI"
,
card
.
encodeIMSI
(
values
.
imsi
)),
"can't set imsi %s"
,
values
.
imsi
.
c_str
());
string
MccMnc
=
card
.
encodeMccMnc
(
values
.
imsi
.
substr
(
0
,
3
),
values
.
imsi
.
substr
(
3
,
values
.
mncLen
));
vector
<
string
>
VectMccMnc
;
VectMccMnc
.
push_back
(
MccMnc
);
vector
<
string
>
MccMncWithAct
=
VectMccMnc
;
// Add EUTRAN access techno only
MccMncWithAct
[
0
]
+=
string
(
u8"
\x40\x00
"
,
2
);
Assert
(
card
.
writeFile
(
"PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write PLMN Selector"
);
Assert
(
card
.
writeFile
(
"Operator controlled PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write Operator PLMN Selector"
);
Assert
(
card
.
writeFile
(
"Home PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write home PLMN Selector"
);
Assert
(
card
.
writeFile
(
"Equivalent Home PLMN"
,
VectMccMnc
),
"Can't write Equivalent PLMN"
);
vector
<
string
>
psloci
;
psloci
.
push_back
(
makeBcd
(
""
,
true
,
7
));
psloci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
psloci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
psloci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"PS Location information"
,
psloci
,
false
),
"PS location information"
);
vector
<
string
>
csloci
;
csloci
.
push_back
(
makeBcd
(
""
,
true
,
4
));
csloci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
csloci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
csloci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"CS Location information"
,
csloci
,
false
),
"CS location information"
);
}
vector
<
string
>
spn
;
spn
.
push_back
(
string
(
u8"
\x01
"
,
1
));
spn
[
0
]
+=
values
.
spn
;
Assert
(
card
.
writeFile
(
"Service Provider Name"
,
spn
,
true
),
"can't set spn"
);
Assert
(
card
.
writeFile
(
"Higher Priority PLMN search period"
,
makeBcdVect
(
"02"
,
false
)),
"can't set plmn search period"
);
Assert
(
card
.
writeFile
(
"Forbidden PLMNs"
,
makeBcdVect
(
""
,
true
,
12
)),
"can't set forbidden plmn"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 1"
,
makeBcdVect
(
""
,
true
,
4
)),
"can't set GID1"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 2"
,
makeBcdVect
(
""
,
true
,
4
)),
"can't set GID2"
);
vector
<
string
>
ecc
;
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
Assert
(
card
.
writeFile
(
"emergency call codes"
,
ecc
),
"can't set emergency call codes"
);
// Typical service list, a bit complex to define (see 3GPP TS 51.011)
Assert
(
card
.
writeFile
(
"USIM service table"
,
makeBcdVect
(
values
.
ust
,
false
)),
"can't set USIM service table"
);
return
true
;
vector
<
string
>
res
;
USIM
card
;
string
ATR
;
Assert
((
ATR
=
card
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
if
(
!
card
.
verifyChv
(
'\x0a'
,
values
.
adm
))
{
printf
(
"chv 0a Nok
\n
"
);
return
false
;
}
writeUSIMproprietary
(
card
,
values
);
vector
<
string
>
li
;
li
.
push_back
(
"en"
);
Assert
(
card
.
writeFile
(
"language preference"
,
li
),
"can't set language"
);
vector
<
string
>
ad
;
ad
.
push_back
(
makeBcd
(
"810000"
,
false
));
ad
[
0
]
+=
(
char
)
values
.
mncLen
;
Assert
(
card
.
writeFile
(
"Administrative data"
,
ad
),
"can't set Administrative data"
);
Assert
(
card
.
writeFile
(
"Short Message Service Parameters"
,
makeBcdVect
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFFF 0191"
,
true
,
40
)),
"can't set SMSC"
);
if
(
values
.
isdn
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"MSISDN"
,
card
.
encodeISDN
(
values
.
isdn
,
card
.
fileRecordSize
(
"MSISDN"
))),
"can't set msisdn %s"
,
values
.
isdn
.
c_str
());
if
(
values
.
acc
.
size
()
>
0
)
Assert
(
card
.
writeFile
(
"Access control class"
,
card
.
encodeACC
(
values
.
acc
)),
"can't set acc %s"
,
values
.
acc
.
c_str
());
if
(
values
.
imsi
.
size
()
>
0
)
{
Assert
(
card
.
writeFile
(
"IMSI"
,
card
.
encodeIMSI
(
values
.
imsi
)),
"can't set imsi %s"
,
values
.
imsi
.
c_str
());
string
MccMnc
=
card
.
encodeMccMnc
(
values
.
imsi
.
substr
(
0
,
3
),
values
.
imsi
.
substr
(
3
,
values
.
mncLen
));
vector
<
string
>
VectMccMnc
;
VectMccMnc
.
push_back
(
MccMnc
);
vector
<
string
>
MccMncWithAct
=
VectMccMnc
;
MccMncWithAct
[
0
]
+=
makeBcd
(
values
.
act
,
false
,
2
);
Assert
(
card
.
writeFile
(
"PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write PLMN Selector"
);
Assert
(
card
.
writeFile
(
"Operator controlled PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write Operator PLMN Selector"
);
Assert
(
card
.
writeFile
(
"Home PLMN selector with Access Technology"
,
MccMncWithAct
,
true
),
"Can't write home PLMN Selector"
);
Assert
(
card
.
writeFile
(
"Equivalent Home PLMN"
,
VectMccMnc
),
"Can't write Equivalent PLMN"
);
vector
<
string
>
psloci
;
psloci
.
push_back
(
makeBcd
(
""
,
true
,
7
));
psloci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
psloci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
psloci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"PS Location information"
,
psloci
,
false
),
"PS location information"
);
vector
<
string
>
csloci
;
csloci
.
push_back
(
makeBcd
(
""
,
true
,
4
));
csloci
[
0
]
+=
MccMnc
;
if
(
values
.
mncLen
==
3
)
csloci
[
0
]
+=
makeBcd
(
"00ff01"
,
false
);
else
csloci
[
0
]
+=
makeBcd
(
"0000ff01"
,
false
);
Assert
(
card
.
writeFile
(
"CS Location information"
,
csloci
,
false
),
"CS location information"
);
}
vector
<
string
>
spn
;
spn
.
push_back
(
string
(
u8"
\x01
"
,
1
));
spn
[
0
]
+=
values
.
spn
;
Assert
(
card
.
writeFile
(
"Service Provider Name"
,
spn
,
true
),
"can't set spn"
);
Assert
(
card
.
writeFile
(
"Higher Priority PLMN search period"
,
makeBcdVect
(
"02"
,
false
)),
"can't set plmn search period"
);
Assert
(
card
.
writeFile
(
"Forbidden PLMNs"
,
makeBcdVect
(
""
,
true
,
12
)),
"can't set forbidden plmn"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 1"
,
makeBcdVect
(
""
,
true
,
4
)),
"can't set GID1"
);
Assert
(
card
.
writeFile
(
"Group Identifier Level 2"
,
makeBcdVect
(
""
,
true
,
4
)),
"can't set GID2"
);
vector
<
string
>
ecc
;
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
ecc
.
push_back
(
makeBcd
(
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
,
false
));
Assert
(
card
.
writeFile
(
"emergency call codes"
,
ecc
),
"can't set emergency call codes"
);
// Typical service list, a bit complex to define (see 3GPP TS 51.011)
Assert
(
card
.
writeFile
(
"USIM service table"
,
makeBcdVect
(
values
.
ust
,
false
)),
"can't set USIM service table"
);
return
true
;
}
void
setOPc
(
struct
uicc_vals
&
values
)
{
string
key
=
hexa
(
values
.
key
);
Assert
(
key
.
size
()
==
16
,
"can't read a correct key: 16 hexa figures
\n
"
);
string
op
=
hexa
(
values
.
op
);
Assert
(
op
.
size
()
==
16
,
"can't read a correct op: 16 hexa figures
\n
"
);
uint8_t
opc
[
16
];
milenage_opc_gen
((
const
uint8_t
*
)
key
.
c_str
(),
(
const
uint8_t
*
)
op
.
c_str
(),
opc
);
for
(
int
i
=
0
;
i
<
16
;
i
++
)
{
char
tmp
[
8
];
sprintf
(
tmp
,
"%02hhx"
,
opc
[
i
]);
values
.
opc
+=
tmp
;
}
string
key
=
hexa
(
values
.
key
);
Assert
(
key
.
size
()
==
16
,
"can't read a correct key: 16 hexa figures
\n
"
);
string
op
=
hexa
(
values
.
op
);
Assert
(
op
.
size
()
==
16
,
"can't read a correct op: 16 hexa figures
\n
"
);
uint8_t
opc
[
16
];
milenage_opc_gen
((
const
uint8_t
*
)
key
.
c_str
(),
(
const
uint8_t
*
)
op
.
c_str
(),
opc
);
for
(
int
i
=
0
;
i
<
16
;
i
++
)
{
char
tmp
[
8
];
sprintf
(
tmp
,
"%02hhx"
,
opc
[
i
]);
values
.
opc
+=
tmp
;
}
}
vector
<
string
>
oneAuthentication
(
USIM
&
USIMcard
,
string
&
opc
,
string
&
key
,
uint64_t
intSqn
,
u8
*
rand
,
u8
*
amf
,
u8
*
autn
,
u8
*
ik
,
u8
*
ck
,
u8
*
res
)
{
union
{
u8
bytes
[
8
];
uint64_t
ll
;
}
simSqn
=
{
0
};
simSqn
.
ll
=
htobe64
(
intSqn
);
Assert
(
milenage_generate
((
const
uint8_t
*
)
opc
.
c_str
(),
amf
,
(
const
uint8_t
*
)
key
.
c_str
(),
&
simSqn
.
bytes
[
2
],
rand
,
autn
,
ik
,
ck
,
res
),
"Milenage internal failure
\n
"
);
return
USIMcard
.
authenticate
(
string
((
char
*
)
rand
,
16
),
string
((
char
*
)
autn
,
16
));
union
{
u8
bytes
[
8
];
uint64_t
ll
;
}
simSqn
=
{
0
};
simSqn
.
ll
=
htobe64
(
intSqn
);
Assert
(
milenage_generate
((
const
uint8_t
*
)
opc
.
c_str
(),
amf
,
(
const
uint8_t
*
)
key
.
c_str
(),
&
simSqn
.
bytes
[
2
],
rand
,
autn
,
ik
,
ck
,
res
),
"Milenage internal failure
\n
"
);
return
USIMcard
.
authenticate
(
string
((
char
*
)
rand
,
16
),
string
((
char
*
)
autn
,
16
));
}
void
fillRand
(
u8
*
out
,
int
size
)
{
struct
timeval
tv
;
gettimeofday
(
&
tv
,
NULL
);
srand
(
tv
.
tv_usec
);
struct
timeval
tv
;
gettimeofday
(
&
tv
,
NULL
);
srand
(
tv
.
tv_usec
);
for
(
int
i
=
0
;
i
<
size
;
i
++
)
out
[
i
]
=
(
u8
)(
rand
()
&
0xFF
);
for
(
int
i
=
0
;
i
<
size
;
i
++
)
out
[
i
]
=
(
u8
)(
rand
()
&
0xFF
);
}
void
testAUTN
(
struct
uicc_vals
&
values
)
{
string
key
=
hexa
(
values
.
key
);
string
opc
=
hexa
(
values
.
opc
);
if
(
key
.
size
()
!=
16
||
opc
.
size
()
!=
16
)
{
printf
(
"Authenticate test require to have key (Ki) and OP or OPc
\n
"
);
return
;
}
u8
amf
[
2
]
=
{
0x80
,
0x00
};
u8
rand
[
16
]
=
{
0
};
memcpy
(
rand
,
hexa
(
values
.
rand
).
c_str
(),
sizeof
(
rand
));
u8
autn
[
16
]
=
{
0
};
u8
ik
[
16
]
=
{
0
};
u8
ck
[
16
]
=
{
0
};
u8
res
[
8
]
=
{
0
};
uint64_t
intSqn
=
atoi
(
values
.
sqn
.
c_str
());
union
{
u8
bytes
[
8
];
uint64_t
ll
;
}
simSqn
=
{
0
};
simSqn
.
ll
=
htobe64
(
intSqn
);
Assert
(
milenage_generate
((
const
uint8_t
*
)
opc
.
c_str
(),
amf
,
(
const
uint8_t
*
)
key
.
c_str
(),
&
simSqn
.
bytes
[
2
],
rand
,
autn
,
ik
,
ck
,
res
),
"Milenage internal failure
\n
"
);
cout
<<
"AUTN:"
;
for
(
size_t
i
=
0
;
i
<
sizeof
(
autn
)
;
i
++
)
printf
(
"%02x"
,
autn
[
i
]);
cout
<<
endl
;
string
key
=
hexa
(
values
.
key
);
string
opc
=
hexa
(
values
.
opc
);
if
(
key
.
size
()
!=
16
||
opc
.
size
()
!=
16
)
{
printf
(
"Authenticate test require to have key (Ki) and OP or OPc
\n
"
);
return
;
}
u8
amf
[
2
]
=
{
0x80
,
0x00
};
u8
rand
[
16
]
=
{
0
};
memcpy
(
rand
,
hexa
(
values
.
rand
).
c_str
(),
sizeof
(
rand
));
u8
autn
[
16
]
=
{
0
};
u8
ik
[
16
]
=
{
0
};
u8
ck
[
16
]
=
{
0
};
u8
res
[
8
]
=
{
0
};
uint64_t
intSqn
=
atoi
(
values
.
sqn
.
c_str
());
union
{
u8
bytes
[
8
];
uint64_t
ll
;
}
simSqn
=
{
0
};
simSqn
.
ll
=
htobe64
(
intSqn
);
Assert
(
milenage_generate
((
const
uint8_t
*
)
opc
.
c_str
(),
amf
,
(
const
uint8_t
*
)
key
.
c_str
(),
&
simSqn
.
bytes
[
2
],
rand
,
autn
,
ik
,
ck
,
res
),
"Milenage internal failure
\n
"
);
cout
<<
"AUTN:"
;
for
(
size_t
i
=
0
;
i
<
sizeof
(
autn
)
;
i
++
)
printf
(
"%02x"
,
autn
[
i
]);
cout
<<
endl
;
}
void
authenticate
(
char
*
port
,
struct
uicc_vals
&
values
)
{
string
key
=
hexa
(
values
.
key
);
string
opc
=
hexa
(
values
.
opc
);
if
(
key
.
size
()
!=
16
||
opc
.
size
()
!=
16
)
{
printf
(
"Authenticate test require to have key (Ki) and OP or OPc
\n
"
);
return
;
}
USIM
USIMcard
;
string
ATR
;
Assert
((
ATR
=
USIMcard
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
//dump_hex("ATR", ATR);
USIMcard
.
openUSIM
();
//USIMcard.debug=false;
// We don't make proper values for rand, sqn,
// we perform first authentication only to get the AUTS from the USIM
u8
amf
[
2
]
=
{
0x80
,
0x00
};
u8
rand
[
16
]
=
{
0
};
u8
autn
[
16
]
=
{
0
};
u8
ik
[
16
]
=
{
0
};
u8
ck
[
16
]
=
{
0
};
u8
res
[
8
]
=
{
0
};
uint64_t
intSqn
=
0
;
u8
autsSQN
[
8
]
=
{
0
};
fillRand
(
rand
,
sizeof
(
rand
));
//memset(rand, 0x11, sizeof(rand));
vector
<
string
>
firstCall
=
oneAuthentication
(
USIMcard
,
opc
,
key
,
intSqn
,
rand
,
amf
,
autn
,
ik
,
ck
,
res
);
// We should have one LV value returned, the AUTS (or AUTN)
if
(
firstCall
.
size
()
!=
1
)
{
printf
(
"The card didn't accept our challenge: OPc or Ki is wrong
\n
"
);
return
;
}
if
(
!
milenage_auts
((
const
uint8_t
*
)
opc
.
c_str
(),
(
const
uint8_t
*
)
key
.
c_str
(),
rand
,
(
const
uint8_t
*
)
firstCall
[
0
].
c_str
(),
&
autsSQN
[
2
])
)
printf
(
"Warning in AUTS (card serial OC004000 to OC004110, call support), let's check the SQN anyway
\n
"
);
intSqn
=
be64toh
(
*
(
uint64_t
*
)
autsSQN
);
// here we should have the current sqn in the UICC
intSqn
+=
32
;
// according to 3GPP TS 33.102 version 11, annex C. 3.2
// To make better validation, let's generate a random value in milenage "rand"
fillRand
(
rand
,
sizeof
(
rand
));
vector
<
string
>
returned_newSQN
=
oneAuthentication
(
USIMcard
,
opc
,
key
,
intSqn
,
rand
,
amf
,
autn
,
ik
,
ck
,
res
);
if
(
returned_newSQN
.
size
()
!=
4
)
printf
(
"We tried SQN %"
PRId64
", but the card refused!
\n
"
,
intSqn
);
else
{
string
s_ik
((
char
*
)
ik
,
sizeof
(
ik
));
string
s_ck
((
char
*
)
ck
,
sizeof
(
ck
));
string
s_res
((
char
*
)
res
,
sizeof
(
res
));
if
(
s_res
!=
returned_newSQN
[
0
]
||
s_ck
!=
returned_newSQN
[
1
]
||
s_ik
!=
returned_newSQN
[
2
]
)
printf
(
"The card sent back vectors, but they are not our milenage computation
\n
"
);
string
key
=
hexa
(
values
.
key
);
string
opc
=
hexa
(
values
.
opc
);
if
(
key
.
size
()
!=
16
||
opc
.
size
()
!=
16
)
{
printf
(
"Authenticate test require to have key (Ki) and OP or OPc
\n
"
);
return
;
}
USIM
USIMcard
;
string
ATR
;
Assert
((
ATR
=
USIMcard
.
open
(
port
))
!=
""
,
"Failed to open %s"
,
port
);
//dump_hex("ATR", ATR);
USIMcard
.
openUSIM
();
//USIMcard.debug=false;
// We don't make proper values for rand, sqn,
// we perform first authentication only to get the AUTS from the USIM
u8
amf
[
2
]
=
{
0x80
,
0x00
};
u8
rand
[
16
]
=
{
0
};
u8
autn
[
16
]
=
{
0
};
u8
ik
[
16
]
=
{
0
};
u8
ck
[
16
]
=
{
0
};
u8
res
[
8
]
=
{
0
};
uint64_t
intSqn
=
0
;
u8
autsSQN
[
8
]
=
{
0
};
fillRand
(
rand
,
sizeof
(
rand
));
//memset(rand, 0x11, sizeof(rand));
vector
<
string
>
firstCall
=
oneAuthentication
(
USIMcard
,
opc
,
key
,
intSqn
,
rand
,
amf
,
autn
,
ik
,
ck
,
res
);
// We should have one LV value returned, the AUTS (or AUTN)
if
(
firstCall
.
size
()
!=
1
)
{
printf
(
"The card didn't accept our challenge: OPc or Ki is wrong
\n
"
);
return
;
}
if
(
!
milenage_auts
((
const
uint8_t
*
)
opc
.
c_str
(),
(
const
uint8_t
*
)
key
.
c_str
(),
rand
,
(
const
uint8_t
*
)
firstCall
[
0
].
c_str
(),
&
autsSQN
[
2
])
)
printf
(
"Warning in AUTS (card serial OC004000 to OC004110, call support), let's check the SQN anyway
\n
"
);
intSqn
=
be64toh
(
*
(
uint64_t
*
)
autsSQN
);
// here we should have the current sqn in the UICC
intSqn
+=
32
;
// according to 3GPP TS 33.102 version 11, annex C. 3.2
// To make better validation, let's generate a random value in milenage "rand"
fillRand
(
rand
,
sizeof
(
rand
));
vector
<
string
>
returned_newSQN
=
oneAuthentication
(
USIMcard
,
opc
,
key
,
intSqn
,
rand
,
amf
,
autn
,
ik
,
ck
,
res
);
if
(
returned_newSQN
.
size
()
!=
4
)
printf
(
"We tried SQN %"
PRId64
", but the card refused!
\n
"
,
intSqn
);
else
{
printf
(
"Succeeded to authentify with SQN: %"
PRId64
"
\n
"
,
intSqn
);
printf
(
"set HSS SQN value as: %"
PRId64
"
\n
"
,
intSqn
+
32
);
string
s_ik
((
char
*
)
ik
,
sizeof
(
ik
));
string
s_ck
((
char
*
)
ck
,
sizeof
(
ck
));
string
s_res
((
char
*
)
res
,
sizeof
(
res
));
if
(
s_res
!=
returned_newSQN
[
0
]
||
s_ck
!=
returned_newSQN
[
1
]
||
s_ik
!=
returned_newSQN
[
2
]
)
printf
(
"The card sent back vectors, but they are not our milenage computation
\n
"
);
else
{
printf
(
"Succeeded to authentify with SQN: %"
PRId64
"
\n
"
,
intSqn
);
printf
(
"set HSS SQN value as: %"
PRId64
"
\n
"
,
intSqn
+
32
);
}
}
}
}
int
main
(
int
argc
,
char
**
argv
)
{
char
portName
[
FILENAME_MAX
+
1
]
=
"/dev/ttyUSB0"
;
struct
uicc_vals
new_vals
;
bool
readAfter
=
true
;
static
struct
option
long_options
[]
=
{
{
"port"
,
required_argument
,
0
,
0
},
{
"adm"
,
required_argument
,
0
,
1
},
{
"iccid"
,
required_argument
,
0
,
2
},
{
"imsi"
,
required_argument
,
0
,
3
},
{
"opc"
,
required_argument
,
0
,
4
},
{
"isdn"
,
required_argument
,
0
,
5
},
{
"acc"
,
required_argument
,
0
,
6
},
{
"key"
,
required_argument
,
0
,
7
},
{
"MNCsize"
,
required_argument
,
0
,
8
},
{
"xx"
,
required_argument
,
0
,
9
},
{
"authenticate"
,
no_argument
,
0
,
10
},
{
"spn"
,
required_argument
,
0
,
11
},
{
"noreadafter"
,
no_argument
,
0
,
12
},
{
"ust"
,
required_argument
,
0
,
13
},
{
"sqn"
,
required_argument
,
0
,
14
},
{
"rand"
,
required_argument
,
0
,
15
},
{
0
,
0
,
0
,
0
}
};
static
map
<
string
,
string
>
help_text
=
{
{
"port"
,
"Linux port to access the card reader (/dev/ttyUSB0)"
},
{
"adm"
,
"The ADM code of the card (the master password)"
},
{
"iccid"
,
"the UICC id to set"
},
{
"imsi"
,
"The imsi to set, we automatically set complementary files such as
\"
home PLMN
\"
"
},
{
"opc"
,
"OPc field: OPerator code: must be also set in HSS (exlusive with OP)"
},
{
"isdn"
,
"The mobile phone number (not used in simple 4G)"
},
{
"acc"
,
"One of the defined security codes"
},
{
"key"
,
"The authentication key (called Ki in 3G/4G, Kc in GSM), must be the same in HSS"
},
{
"MNCsize"
,
"Mobile network code size in digits (default to 2)"
},
{
"xx"
,
"OP field: OPerator code: must be also set in HSS (exclusive with OPc)"
},
{
"spn"
,
"service provider name: the name that the UE will show as 'network'"
},
{
"authenticate"
,
"Test the milenage authentication and discover the current sequence number"
},
{
"noreadafter"
,
"no read after write"
},
{
"ust"
,
"usim service table in hexa decimal (first byte is services 1-8, so 81 enable service 1 and service 8 ...)"
},
{
"sqn"
,
"only for test, no UICC dialog, prints the generated AUTN for debugging"
},
{
"rand"
,
"only for test, no UICC dialog, prints the generated AUTN for debugging"
},
};
setbuf
(
stdout
,
NULL
);
int
c
;
bool
correctOpt
=
true
;
while
(
correctOpt
)
{
int
option_index
=
0
;
c
=
getopt_long_only
(
argc
,
argv
,
""
,
long_options
,
&
option_index
);
if
(
c
==
-
1
)
break
;
switch
(
c
)
{
case
0
:
strncpy
(
portName
,
optarg
,
FILENAME_MAX
);
break
;
case
1
:
new_vals
.
adm
=
optarg
;
new_vals
.
setIt
=
true
;
break
;
case
2
:
new_vals
.
iccid
=
optarg
;
break
;
case
3
:
new_vals
.
imsi
=
optarg
;
break
;
case
4
:
new_vals
.
opc
=
optarg
;
break
;
case
5
:
new_vals
.
isdn
=
optarg
;
break
;
case
6
:
new_vals
.
acc
=
optarg
;
break
;
case
7
:
new_vals
.
key
=
optarg
;
break
;
case
8
:
new_vals
.
mncLen
=
atoi
(
optarg
);
break
;
case
9
:
new_vals
.
op
=
optarg
;
break
;
case
10
:
new_vals
.
authenticate
=
true
;
break
;
case
11
:
new_vals
.
spn
=
optarg
;
break
;
case
12
:
readAfter
=
false
;
break
;
case
13
:
new_vals
.
ust
=
optarg
;
break
;
case
14
:
new_vals
.
sqn
=
optarg
;
break
;
case
15
:
new_vals
.
rand
=
optarg
;
break
;
default:
printf
(
"unrecognized option: %d
\n
"
,
c
);
correctOpt
=
false
;
char
portName
[
FILENAME_MAX
+
1
]
=
"/dev/ttyUSB0"
;
struct
uicc_vals
new_vals
;
bool
readAfter
=
true
;
static
struct
option
long_options
[]
=
{
{
"port"
,
required_argument
,
0
,
0
},
{
"adm"
,
required_argument
,
0
,
1
},
{
"iccid"
,
required_argument
,
0
,
2
},
{
"imsi"
,
required_argument
,
0
,
3
},
{
"opc"
,
required_argument
,
0
,
4
},
{
"isdn"
,
required_argument
,
0
,
5
},
{
"acc"
,
required_argument
,
0
,
6
},
{
"key"
,
required_argument
,
0
,
7
},
{
"MNCsize"
,
required_argument
,
0
,
8
},
{
"xx"
,
required_argument
,
0
,
9
},
{
"authenticate"
,
no_argument
,
0
,
10
},
{
"spn"
,
required_argument
,
0
,
11
},
{
"act"
,
required_argument
,
0
,
12
},
{
"noreadafter"
,
no_argument
,
0
,
13
},
{
"ust"
,
required_argument
,
0
,
14
},
{
"sqn"
,
required_argument
,
0
,
15
},
{
"rand"
,
required_argument
,
0
,
16
},
{
0
,
0
,
0
,
0
}
};
}
if
(
optind
<
argc
||
correctOpt
==
false
)
{
printf
(
"non-option ARGV-elements: "
);
while
(
optind
<
argc
)
printf
(
"%s "
,
argv
[
optind
++
]);
printf
(
"Possible options are:
\n
"
);
static
map
<
string
,
string
>
help_text
=
{
{
"port"
,
"Linux port to access the card reader (/dev/ttyUSB0)"
},
{
"adm"
,
"The ADM code of the card (the master password)"
},
{
"iccid"
,
"the UICC id to set"
},
{
"imsi"
,
"The imsi to set, we automatically set complementary files such as
\"
home PLMN
\"
"
},
{
"opc"
,
"OPc field: OPerator code: must be also set in HSS (exlusive with OP)"
},
{
"isdn"
,
"The mobile phone number (not used in simple 4G)"
},
{
"acc"
,
"One of the defined security codes"
},
{
"key"
,
"The authentication key (called Ki in 3G/4G, Kc in GSM), must be the same in HSS"
},
{
"MNCsize"
,
"Mobile network code size in digits (default 2)"
},
{
"xx"
,
"OP field: OPerator code: must be also set in HSS (exclusive with OPc)"
},
{
"spn"
,
"service provider name: the name that the UE will show as 'network' (default
\"
open cells
\"
)"
},
{
"act"
,
"bitmap describing supported RAN technologies (default
\"
7c00
\"
see TS31.102 chap 4.2.5)"
},
{
"authenticate"
,
"Test the milenage authentication and discover the current sequence number"
},
{
"noreadafter"
,
"no read after write"
},
{
"ust"
,
"usim service table in hexa decimal (first byte is services 1-8,
\n
so 81 enable service 1 and service 8 ...)"
},
{
"sqn"
,
"only for test, no UICC dialog, prints the generated AUTN for debugging"
},
{
"rand"
,
"only for test, no UICC dialog, prints the generated AUTN for debugging"
},
};
setbuf
(
stdout
,
NULL
);
int
c
;
bool
correctOpt
=
true
;
while
(
correctOpt
)
{
int
option_index
=
0
;
c
=
getopt_long_only
(
argc
,
argv
,
""
,
long_options
,
&
option_index
);
if
(
c
==
-
1
)
break
;
switch
(
c
)
{
case
0
:
strncpy
(
portName
,
optarg
,
FILENAME_MAX
);
break
;
case
1
:
new_vals
.
adm
=
optarg
;
new_vals
.
setIt
=
true
;
break
;
case
2
:
new_vals
.
iccid
=
optarg
;
break
;
case
3
:
new_vals
.
imsi
=
optarg
;
break
;
case
4
:
new_vals
.
opc
=
optarg
;
break
;
case
5
:
new_vals
.
isdn
=
optarg
;
break
;
case
6
:
new_vals
.
acc
=
optarg
;
break
;
case
7
:
new_vals
.
key
=
optarg
;
break
;
case
8
:
new_vals
.
mncLen
=
atoi
(
optarg
);
break
;
case
9
:
new_vals
.
op
=
optarg
;
break
;
case
10
:
new_vals
.
authenticate
=
true
;
break
;
case
11
:
new_vals
.
spn
=
optarg
;
break
;
case
12
:
new_vals
.
act
=
optarg
;
break
;
case
13
:
readAfter
=
false
;
break
;
case
14
:
new_vals
.
ust
=
optarg
;
break
;
case
15
:
new_vals
.
sqn
=
optarg
;
break
;
case
16
:
new_vals
.
rand
=
optarg
;
break
;
default:
printf
(
"unrecognized option: %d
\n
"
,
c
);
correctOpt
=
false
;
};
}
for
(
int
i
=
0
;
long_options
[
i
].
name
!=
NULL
;
i
++
)
printf
(
" --%-10s %s
\n
"
,
long_options
[
i
].
name
,
help_text
[
long_options
[
i
].
name
].
c_str
()
);
if
(
optind
<
argc
||
correctOpt
==
false
)
{
printf
(
"non-option ARGV-elements: "
);
printf
(
"
\n
"
);
exit
(
1
);
}
while
(
optind
<
argc
)
printf
(
"%s "
,
argv
[
optind
++
]);
if
(
new_vals
.
op
!=
""
)
{
setOPc
(
new_vals
);
printf
(
"Computed OPc from OP and Ki as: %s
\n
"
,
new_vals
.
opc
.
c_str
());
}
printf
(
"Possible options are:
\n
"
);
if
(
new_vals
.
sqn
.
size
()
&&
new_vals
.
rand
.
size
()
)
{
testAUTN
(
new_vals
);
exit
(
0
);
}
for
(
int
i
=
0
;
long_options
[
i
].
name
!=
NULL
;
i
++
)
printf
(
" --%-10s %s
\n
"
,
long_options
[
i
].
name
,
help_text
[
long_options
[
i
].
name
].
c_str
());
int
cardVersion
=
0
;
printf
(
"
\n
Existing values in USIM
\n
"
);
Assert
(
cardVersion
=
readUSIMvalues
(
portName
),
"failed to read UICC"
);
printf
(
"
\n
"
)
;
exit
(
1
);
}
if
(
new_vals
.
adm
.
size
()
==
16
)
// adm in hexa, convert it to bytes
new_vals
.
adm
=
makeBcd
(
new_vals
.
adm
);
if
(
new_vals
.
op
!=
""
)
{
setOPc
(
new_vals
);
printf
(
"Computed OPc from OP and Ki as: %s
\n
"
,
new_vals
.
opc
.
c_str
());
}
if
(
new_vals
.
adm
.
size
()
!=
8
)
{
// must be 8 bytes
printf
(
"
\n
No ADM code of 8 figures, can't program the UICC
\n
"
);
readAfter
=
false
;
}
else
{
printf
(
"
\n
Setting new values
\n
"
);
if
(
new_vals
.
sqn
.
size
()
&&
new_vals
.
rand
.
size
()
)
{
testAUTN
(
new_vals
);
exit
(
0
);
}
switch
(
cardVersion
)
{
case
1
:
writeSIMvalues
(
portName
,
new_vals
);
writeUSIMvalues
(
portName
,
new_vals
);
break
;
int
cardVersion
=
0
;
printf
(
"
\n
Existing values in USIM
\n
"
);
Assert
(
cardVersion
=
readUSIMvalues
(
portName
),
"failed to read UICC"
);
case
2
:
writeSIMv2values
(
portName
,
new_vals
);
break
;
if
(
new_vals
.
adm
.
size
()
==
16
)
// adm in hexa, convert it to bytes
new_vals
.
adm
=
makeBcd
(
new_vals
.
adm
);
default:
printf
(
"
\n
Unknown UICC type
\n
"
);
exit
(
1
);
if
(
new_vals
.
adm
.
size
()
!=
8
)
{
// must be 8 bytes
printf
(
"
\n
No ADM code of 8 figures, can't program the UICC
\n
"
);
readAfter
=
false
;
}
else
{
printf
(
"
\n
Setting new values
\n
"
);
switch
(
cardVersion
)
{
case
1
:
writeSIMvalues
(
portName
,
new_vals
);
writeUSIMvalues
(
portName
,
new_vals
);
break
;
case
2
:
writeSIMv2values
(
portName
,
new_vals
);
break
;
default:
printf
(
"
\n
Unknown UICC type
\n
"
);
exit
(
1
);
}
}
}
if
(
readAfter
)
{
printf
(
"
\n
Reading UICC values after uploading new values
\n
"
);
readUSIMvalues
(
portName
);
}
if
(
readAfter
)
{
printf
(
"
\n
Reading UICC values after uploading new values
\n
"
);
readUSIMvalues
(
portName
);
}
if
(
new_vals
.
authenticate
)
{
if
(
new_vals
.
opc
.
size
()
==
0
||
new_vals
.
key
.
size
()
==
0
)
printf
(
"
\n
Need the key (Ki) and the OPc to test Milenage and dispal
y the SQN
\n
"
);
else
authenticate
(
portName
,
new_vals
);
}
if
(
new_vals
.
authenticate
)
{
if
(
new_vals
.
opc
.
size
()
==
0
||
new_vals
.
key
.
size
()
==
0
)
printf
(
"
\n
Need the key (Ki) and the OPc to test Milenage and displa
y the SQN
\n
"
);
else
authenticate
(
portName
,
new_vals
);
}
return
0
;
return
0
;
}
uicc/uicc.h
View file @
f363bd12
...
...
@@ -39,7 +39,24 @@
#include <numeric>
#include <string>
#include <sstream>
#ifdef PCSC
extern
"C"
{
#include "PCSC/ifdhandler.h"
void
log_msg
(
const
int
priority
,
const
char
*
fmt
,
...)
{
(
void
)
priority
;
(
void
)
fmt
;
}
void
log_xxd
(
const
int
priority
,
const
char
*
msg
,
const
unsigned
char
*
buffer
,
const
int
len
)
{
(
void
)
priority
;
(
void
)
msg
;
(
void
)
buffer
;
(
void
)
len
;
}
}
#endif
using
namespace
std
;
/*
Copyright: Open cells company
...
...
@@ -91,770 +108,860 @@ using namespace std;
__FUNCTION__, __FILE__, __LINE__, strerror(errno), ##aRGS); \
fflush(stdout); \
fflush(stderr); \
exit(EXIT_FAILURE);
\
abort();
\
} \
} while(0)
static
inline
string
extractTLV
(
string
in
,
string
TLVname
)
{
static
const
map
<
string
,
char
>
Tags
=
{
{
"Application Template"
,
'\x61'
},
{
"FCP Template"
,
'\x62'
},
{
"AID"
,
'\x4f'
},
{
"Card"
,
'\x50'
},
{
"File Size - Data"
,
'\x80'
},
{
"File Size - Total"
,
'\x81'
},
{
"File Descriptor"
,
'\x82'
},
{
"File Identifier"
,
'\x83'
},
{
"DF Name (AID)"
,
'\x85'
},
{
"Life Cycle Status"
,
'\x8a'
},
{
"Security attribute data"
,
'\x8b'
},
{
"SFI"
,
'\x88'
},
};
auto
it
=
Tags
.
find
(
TLVname
);
if
(
it
!=
Tags
.
end
())
{
char
tag
=
it
->
second
;
size_t
index
=
0
;
while
(
index
<
in
.
size
())
{
if
(
in
[
index
]
==
tag
)
return
in
.
substr
(
index
+
2
,
(
unsigned
)
in
[
index
+
1
]);
index
+=
in
[
index
+
1
]
+
2
;
static
const
map
<
string
,
char
>
Tags
=
{
{
"Application Template"
,
'\x61'
},
{
"FCP Template"
,
'\x62'
},
{
"AID"
,
'\x4f'
},
{
"Card"
,
'\x50'
},
{
"File Size - Data"
,
'\x80'
},
{
"File Size - Total"
,
'\x81'
},
{
"File Descriptor"
,
'\x82'
},
{
"File Identifier"
,
'\x83'
},
{
"DF Name (AID)"
,
'\x85'
},
{
"Life Cycle Status"
,
'\x8a'
},
{
"Security attribute data"
,
'\x8b'
},
{
"SFI"
,
'\x88'
},
};
auto
it
=
Tags
.
find
(
TLVname
);
if
(
it
!=
Tags
.
end
())
{
char
tag
=
it
->
second
;
size_t
index
=
0
;
while
(
index
<
in
.
size
())
{
if
(
in
[
index
]
==
tag
)
return
in
.
substr
(
index
+
2
,
(
unsigned
)
in
[
index
+
1
]);
index
+=
in
[
index
+
1
]
+
2
;
}
}
}
return
""
;
return
""
;
}
const
string
hexTable
(
"0123456789abcdef"
);
static
inline
string
to_hex
(
const
string
&
data
,
bool
swap
=
false
)
{
string
out
=
""
;
if
(
swap
)
for
(
size_t
i
=
0
;
i
<
data
.
size
();
i
++
)
{
out
+=
hexTable
[
data
[
i
]
&
0xf
];
out
+=
hexTable
[
data
[
i
]
>>
4
&
0xf
];
}
else
{
for
(
size_t
i
=
0
;
i
<
data
.
size
();
i
++
)
{
out
+=
hexTable
[
data
[
i
]
>>
4
&
0xf
];
out
+=
hexTable
[
data
[
i
]
&
0xf
];
string
out
=
""
;
if
(
swap
)
for
(
size_t
i
=
0
;
i
<
data
.
size
();
i
++
)
{
out
+=
hexTable
[
data
[
i
]
&
0xf
];
out
+=
hexTable
[
data
[
i
]
>>
4
&
0xf
];
}
else
{
for
(
size_t
i
=
0
;
i
<
data
.
size
();
i
++
)
{
out
+=
hexTable
[
data
[
i
]
>>
4
&
0xf
];
out
+=
hexTable
[
data
[
i
]
&
0xf
];
}
}
}
return
out
;
return
out
;
}
static
inline
void
dump_hex
(
const
string
&
name
,
const
string
&
data
)
{
printf
(
"%s: 0x%s
\n
"
,
name
.
c_str
(),
to_hex
(
data
).
c_str
());
printf
(
"%s: 0x%s
\n
"
,
name
.
c_str
(),
to_hex
(
data
).
c_str
());
}
static
inline
unsigned
char
mkDigit
(
unsigned
char
in
)
{
size_t
pos
=
hexTable
.
find
(
tolower
(
in
));
size_t
pos
=
hexTable
.
find
(
tolower
(
in
));
if
(
pos
!=
string
::
npos
)
return
(
unsigned
char
)
pos
;
else
printf
(
"Invalid hexa value: %x
\n
"
,
(
int
)
in
);
if
(
pos
!=
string
::
npos
)
return
(
unsigned
char
)
pos
;
else
printf
(
"Invalid hexa value: %x
\n
"
,
(
int
)
in
);
return
0
;
return
0
;
}
static
inline
string
makeBcd
(
string
in
,
bool
swap
=
true
,
int
outputLength
=
0
)
{
// ingnore white chars
string
tmp
=
""
;
// ingnore white chars
string
tmp
=
""
;
for
(
size_t
i
=
0
;
i
<
in
.
size
();
i
++
)
if
(
in
[
i
]
!=
' '
)
tmp
+=
in
[
i
];
for
(
size_t
i
=
0
;
i
<
in
.
size
();
i
++
)
if
(
in
[
i
]
!=
' '
)
tmp
+=
in
[
i
];
string
output
;
string
output
;
// must have pairs of characters to make bytes
if
(
tmp
.
size
()
%
2
==
1
)
tmp
+=
'f'
;
// must have pairs of characters to make bytes
if
(
tmp
.
size
()
%
2
==
1
)
tmp
+=
'f'
;
if
(
swap
)
for
(
size_t
i
=
0
;
i
<
tmp
.
size
();
i
+=
2
)
output
+=
(
char
)(
(
mkDigit
(
tmp
[
i
+
1
])
<<
4
)
+
(
mkDigit
(
tmp
[
i
]))
);
else
for
(
size_t
i
=
0
;
i
<
tmp
.
size
();
i
+=
2
)
output
+=
(
char
)(
(
mkDigit
(
tmp
[
i
])
<<
4
)
+
(
mkDigit
(
tmp
[
i
+
1
]))
);
if
(
swap
)
for
(
size_t
i
=
0
;
i
<
tmp
.
size
();
i
+=
2
)
output
+=
(
char
)(
(
mkDigit
(
tmp
[
i
+
1
])
<<
4
)
+
(
mkDigit
(
tmp
[
i
]))
);
else
for
(
size_t
i
=
0
;
i
<
tmp
.
size
();
i
+=
2
)
output
+=
(
char
)(
(
mkDigit
(
tmp
[
i
])
<<
4
)
+
(
mkDigit
(
tmp
[
i
+
1
]))
);
for
(
int
i
=
tmp
.
size
()
/
2
;
i
<
outputLength
;
i
++
)
output
+=
'\xff'
;
for
(
int
i
=
tmp
.
size
()
/
2
;
i
<
outputLength
;
i
++
)
output
+=
'\xff'
;
return
output
;
return
output
;
}
static
inline
string
hexa
(
string
data
)
{
return
makeBcd
(
data
,
false
,
0
);
return
makeBcd
(
data
,
false
,
0
);
}
static
inline
vector
<
string
>
makeBcdVect
(
string
data
,
bool
swap
=
true
,
int
outputLength
=
0
)
{
vector
<
string
>
out
;
out
.
push_back
(
makeBcd
(
data
,
swap
,
outputLength
));
return
out
;
vector
<
string
>
out
;
out
.
push_back
(
makeBcd
(
data
,
swap
,
outputLength
));
return
out
;
}
static
inline
vector
<
string
>
hexaVect
(
string
data
)
{
return
makeBcdVect
(
data
,
false
,
0
);
return
makeBcdVect
(
data
,
false
,
0
);
}
static
inline
string
printable
(
string
in
)
{
string
ret
=
""
;
string
ret
=
""
;
for
(
auto
c
:
in
)
if
(
isprint
(
c
))
ret
+=
c
;
for
(
auto
c
:
in
)
if
(
isprint
(
c
))
ret
+=
c
;
return
ret
;
return
ret
;
}
static
inline
bool
luhn
(
const
string
&
id
)
{
static
const
int
m
[
10
]
=
{
0
,
2
,
4
,
6
,
8
,
1
,
3
,
5
,
7
,
9
};
// mapping for rule 3
bool
is_odd_dgt
=
false
;
auto
lambda
=
[
&
](
int
a
,
char
c
)
{
return
a
+
((
is_odd_dgt
=
!
is_odd_dgt
)
?
c
-
'0'
:
m
[
c
-
'0'
]);
};
int
s
=
std
::
accumulate
(
id
.
rbegin
(),
id
.
rend
(),
0
,
lambda
);
return
0
==
s
%
10
;
static
const
int
m
[
10
]
=
{
0
,
2
,
4
,
6
,
8
,
1
,
3
,
5
,
7
,
9
};
// mapping for rule 3
bool
is_odd_dgt
=
false
;
auto
lambda
=
[
&
](
int
a
,
char
c
)
{
return
a
+
((
is_odd_dgt
=
!
is_odd_dgt
)
?
c
-
'0'
:
m
[
c
-
'0'
]);
};
int
s
=
std
::
accumulate
(
id
.
rbegin
(),
id
.
rend
(),
0
,
lambda
);
return
0
==
s
%
10
;
}
bool
pcscOpen
=
false
;
class
UICC
{
public:
UICC
()
{
char
*
debug_env
=
getenv
(
"DEBUG"
);
if
(
debug_env
!=
NULL
&&
(
debug_env
[
0
]
==
'Y'
||
debug_env
[
0
]
==
'y'
))
debug
=
true
;
};
~
UICC
()
{
close
();
};
bool
isOpen
()
{
return
fd
>=
0
;
}
string
read
(
size_t
s
=
1024
,
int
timeoutTensSec
=
10
)
{
if
(
timeoutTensSec
!=
lastTimeout
)
{
struct
termios
tty
;
Assert
(
tcgetattr
(
fd
,
&
tty
)
>=
0
,
""
);
tty
.
c_cc
[
VTIME
]
=
timeoutTensSec
;
Assert
(
tcsetattr
(
fd
,
TCSANOW
,
&
tty
)
==
0
,
""
);
lastTimeout
=
timeoutTensSec
;
}
public:
UICC
()
{
char
*
debug_env
=
getenv
(
"DEBUG"
);
size_t
got
=
0
;
string
data
=
""
;
if
(
debug_env
!=
NULL
&&
(
debug_env
[
0
]
==
'Y'
||
debug_env
[
0
]
==
'y'
))
debug
=
true
;
};
~
UICC
()
{
close
();
};
bool
isOpen
()
{
return
fd
>=
0
;
}
while
(
got
<
s
)
{
int
ret
;
char
buf
;
Assert
(
(
ret
=::
read
(
fd
,
&
buf
,
1
))
>=
0
,
"Error from read"
);
string
read
(
size_t
s
=
1024
,
int
timeoutTensSec
=
10
)
{
if
(
timeoutTensSec
!=
lastTimeout
)
{
struct
termios
tty
;
Assert
(
tcgetattr
(
fd
,
&
tty
)
>=
0
,
""
);
tty
.
c_cc
[
VTIME
]
=
timeoutTensSec
;
Assert
(
tcsetattr
(
fd
,
TCSANOW
,
&
tty
)
==
0
,
""
);
lastTimeout
=
timeoutTensSec
;
}
switch
(
ret
)
{
case
1
:
got
++
;
data
+=
buf
;
break
;
size_t
got
=
0
;
string
data
=
""
;
case
0
:
// for time out: no more data
if
(
debug
)
dump_hex
(
"Received and timeout"
,
data
);
while
(
got
<
s
)
{
int
ret
;
char
buf
;
Assert
(
(
ret
=::
read
(
fd
,
&
buf
,
1
))
>=
0
,
"Error from read"
);
return
data
;
break
;
switch
(
ret
)
{
case
1
:
got
++
;
data
+=
buf
;
break
;
default:
fprintf
(
stderr
,
"Error from read > 1 char
\n
"
);
}
}
case
0
:
// for time out: no more data
if
(
debug
)
dump_hex
(
"Received and timeout"
,
data
);
if
(
debug
)
dump_hex
(
"Received"
,
data
)
;
return
data
;
break
;
return
data
;
}
default:
fprintf
(
stderr
,
"Error from read > 1 char
\n
"
);
}
}
int
writeBin
(
string
buf
)
{
for
(
size_t
i
=
0
;
i
<
buf
.
size
();
i
++
)
{
printf
(
"sending: %x
\n
"
,
buf
[
i
]);
Assert
(
1
==
::
write
(
fd
,
&
buf
[
i
],
1
),
""
);
char
c
;
int
ret
;
if
(
debug
)
dump_hex
(
"Received"
,
data
);
if
(
(
ret
==::
read
(
fd
,
&
c
,
1
))
>
0
)
{
printf
(
"rcv: %x
\n
"
,
c
);
}
return
data
;
}
}
int
write
(
string
buf
)
{
if
(
debug
)
dump_hex
(
"Sending"
,
buf
);
size_t
size
=
buf
.
size
();
Assert
(
size
>=
5
,
""
);
for
(
int
i
=
0
;
i
<
5
;
i
++
)
{
Assert
(
1
==
::
write
(
fd
,
&
buf
[
i
],
1
),
""
);
// UICC have only one wire for Tx and Rx,
// so over a RS232 we always receive back what we send
char
c
;
Assert
(
::
read
(
fd
,
&
c
,
1
)
==
1
,
"All data sent must echo back"
);
int
writeBin
(
string
buf
)
{
for
(
size_t
i
=
0
;
i
<
buf
.
size
();
i
++
)
{
printf
(
"sending: %x
\n
"
,
buf
[
i
]);
Assert
(
1
==
::
write
(
fd
,
&
buf
[
i
],
1
),
""
);
char
c
;
int
ret
;
if
(
(
ret
==::
read
(
fd
,
&
c
,
1
))
>
0
)
{
printf
(
"rcv: %x
\n
"
,
c
);
}
}
}
// Read UICC acknowledge the order
if
(
buf
[
0
]
==
(
int8_t
)
'\xa0'
||
buf
[
0
]
==
(
int8_t
)
'\x00'
)
{
char
c
;
size_t
ret
=::
read
(
fd
,
&
c
,
1
);
int
write
(
string
buf
)
{
if
(
debug
)
dump_hex
(
"Sending"
,
buf
);
if
(
ret
!=
1
)
{
printf
(
"UICC should answer the command but no answer
\n
"
);
//abort();
return
size
;
}
size_t
size
=
buf
.
size
();
Assert
(
size
>=
5
,
""
);
// see TS31.101, procedure byte
if
(
c
!=
buf
[
1
]
)
{
char
c2
=-
1
;
int
ret
__attribute__
((
unused
))
=::
read
(
fd
,
&
c2
,
1
);
for
(
int
i
=
0
;
i
<
5
;
i
++
)
{
Assert
(
1
==
::
write
(
fd
,
&
buf
[
i
],
1
),
""
);
// UICC have only one wire for Tx and Rx,
// so over a RS232 we always receive back what we send
char
c
;
Assert
(
::
read
(
fd
,
&
c
,
1
)
==
1
,
"All data sent must echo back"
);
}
if
(
c
==
'\x60'
)
{
if
(
debug
)
printf
(
"UICC got correct wait code, wait done (%02hhx,%02hhx)
\n
"
,
c
,
c2
);
}
else
{
// full implementation of uicc transport layer to do
printf
(
"UICC should answer the command but (%02hhx,%02hhx)
\n
"
,
c
,
c2
);
return
size
;
// Read UICC acknowledge the order
if
(
buf
[
0
]
==
(
int8_t
)
'\xa0'
||
buf
[
0
]
==
(
int8_t
)
'\x00'
)
{
char
c
;
size_t
ret
=::
read
(
fd
,
&
c
,
1
);
if
(
ret
!=
1
)
{
printf
(
"UICC should answer the command but no answer
\n
"
);
//abort();
return
size
;
}
// see TS31.101, procedure byte
if
(
c
!=
buf
[
1
]
)
{
char
c2
=-
1
;
int
ret
__attribute__
((
unused
))
=::
read
(
fd
,
&
c2
,
1
);
if
(
c
==
'\x60'
)
{
if
(
debug
)
printf
(
"UICC got correct wait code, wait done (%02hhx,%02hhx)
\n
"
,
c
,
c2
);
}
else
{
// full implementation of uicc transport layer to do
printf
(
"UICC should answer the command but (%02hhx,%02hhx)
\n
"
,
c
,
c2
);
return
size
;
}
}
}
else
printf
(
"WARNING: Non standard packet sent
\n
"
);
for
(
size_t
i
=
5
;
i
<
size
;
i
++
)
{
Assert
(
1
==
::
write
(
fd
,
&
buf
[
i
],
1
),
""
);
char
c
;
// to carefully test, adding a sleep decompose the exchange
// so, interleaved communication is avoided
// usleep(10000);
Assert
(
::
read
(
fd
,
&
c
,
1
)
==
1
,
"All data sent must echo back"
);
Assert
(
buf
[
i
]
==
c
,
"sent %02hhx, echoed %02hhx
\n
"
,
buf
[
i
],
c
);
}
}
}
else
printf
(
"WARNING: Non standard packet sent
\n
"
);
for
(
size_t
i
=
5
;
i
<
size
;
i
++
)
{
Assert
(
1
==
::
write
(
fd
,
&
buf
[
i
],
1
),
""
);
char
c
;
// to carefully test, adding a sleep decompose the exchange
// so, interleaved communication is avoided
// usleep(10000);
Assert
(
::
read
(
fd
,
&
c
,
1
)
==
1
,
"All data sent must echo back"
);
Assert
(
buf
[
i
]
==
c
,
"sent %02hhx, echoed %02hhx
\n
"
,
buf
[
i
],
c
);
}
return
size
;
}
// Returns the ATR (answer to reset) string
string
open
(
char
*
portname
)
{
Assert
(
(
fd
=::
open
(
portname
,
O_RDWR
|
O_NOCTTY
|
O_SYNC
))
>=
0
,
"Failed to open %s"
,
portname
);
struct
termios
tty
;
Assert
(
tcgetattr
(
fd
,
&
tty
)
>=
0
,
""
);
tty
.
c_cflag
&=
~
(
CSIZE
);
tty
.
c_cflag
|=
CLOCAL
|
CREAD
|
CS8
|
PARENB
|
CSTOPB
|
HUPCL
;
/* setup for non-canonical mode */
tty
.
c_iflag
&=
~
(
IGNBRK
|
PARMRK
|
ISTRIP
|
INLCR
|
IGNCR
|
ICRNL
|
IXON
);
tty
.
c_lflag
&=
~
(
ECHO
|
ECHONL
|
ICANON
|
ISIG
|
IEXTEN
);
tty
.
c_oflag
&=
~
OPOST
;
/* fetch bytes as they become available */
tty
.
c_cc
[
VMIN
]
=
0
;
tty
.
c_cc
[
VTIME
]
=
10
;
cfsetispeed
(
&
tty
,
(
speed_t
)
B9600
);
cfsetospeed
(
&
tty
,
(
speed_t
)
B9600
);
Assert
(
tcsetattr
(
fd
,
TCSANOW
,
&
tty
)
==
0
,
""
);
// reset the UICC
int
iFlags
;
iFlags
=
0
;
// turn off DTR
ioctl
(
fd
,
TIOCMSET
,
&
iFlags
);
struct
timespec
t
=
{
0
,
1000
*
1000
*
1000
};
nanosleep
(
&
t
,
NULL
);
iFlags
=
0xFFFF
;
// turn on DTR
//iFlags = TIOCM_CTS ;
//ioctl(fd, TIOCMSET, &iFlags);
ATR
=
this
->
read
(
200
,
3
);
this
->
init
();
return
ATR
;
}
void
init
()
{
string
v2ATR
=
hexa
(
"3b9f94801fc38031a073b6a10067cf3210df0ef520ec"
);
if
(
0
==
ATR
.
compare
(
0
,
21
,
v2ATR
,
0
,
21
)
)
GRver
=
2
;
v2ATR
=
hexa
(
"3b9f95801fc78031a073b6a10067cf3211b252c679b3"
);
if
(
0
==
ATR
.
compare
(
0
,
21
,
v2ATR
,
0
,
21
)
)
GRver
=
2
;
v2ATR
=
hexa
(
"3b9f95801fc78031a073b6a10067cf3211b252c679f3"
);
if
(
0
==
ATR
.
compare
(
0
,
21
,
v2ATR
,
0
,
21
)
)
GRver
=
2
;
v2ATR
=
hexa
(
"3b9f94801fc38031a073b6a10067cf3250df0e723d76"
);
if
(
0
==
ATR
.
compare
(
0
,
21
,
v2ATR
,
0
,
21
)
)
GRver
=
2
;
v2ATR
=
hexa
(
"3b9f94801fc38031a073b6a10067cf3250df0e723d36"
);
if
(
0
==
ATR
.
compare
(
0
,
21
,
v2ATR
,
0
,
21
)
)
GRver
=
2
;
}
void
close
()
{
if
(
fd
!=-
1
)
::
close
(
fd
);
fd
=-
1
;
}
bool
send_check
(
string
in
,
string
out
,
int
timeout
=
1
)
{
Assert
(
write
(
in
)
==
(
int
)
in
.
size
(),
""
);
string
answer
=
read
(
out
.
size
(),
timeout
);
if
(
answer
.
size
()
!=
out
.
size
())
{
printf
(
"ret is not right size
\n
"
);
dump_hex
(
"expect"
,
out
);
dump_hex
(
"answer"
,
answer
);
return
false
;
return
size
;
}
if
(
answer
!=
out
)
{
if
(
answer
==
hexa
(
"9404"
)
||
answer
==
hexa
(
"9804"
)
||
answer
==
hexa
(
"9400"
)
)
{
printf
(
"Known error, cmd:%s res:%s
\n
"
,
to_hex
(
in
).
c_str
(),
to_hex
(
answer
).
c_str
());
return
false
;
}
string
answer2
=
read
(
255
);
dump_hex
(
"Expected: "
,
out
);
dump_hex
(
"got answer: "
,
answer
+
answer2
);
printf
(
"BAD return code %s%s
\n
"
,
to_hex
(
answer
).
c_str
(),
to_hex
(
answer2
).
c_str
());
return
false
;
// Returns the ATR (answer to reset) string
string
open
(
char
*
portname
)
{
#ifdef PCSC
RESPONSECODE
res
;
if
(
strncmp
(
portname
,
"usb:"
,
4
)
==
0
)
{
if
(
!
pcscOpen
)
{
res
=
IFDHCreateChannelByName
(
0
,
portname
);
if
(
res
!=
0
)
{
printf
(
"reader not detected
\n
"
);
return
""
;
}
pcscOpen
=
true
;
}
res
=
IFDHICCPresence
(
0
);
switch
(
res
)
{
case
IFD_ICC_PRESENT
:
printf
(
"found card in the reader
\n
"
);
break
;
case
IFD_ICC_NOT_PRESENT
:
printf
(
"no card found card in the reader
\n
"
);
break
;
default:
printf
(
"bad answer from detect card in the reader
\n
"
);
break
;
}
unsigned
char
atr
[
MAX_ATR_SIZE
];
size_t
atrSz
=
0
;
res
=
IFDHPowerICC
(
0
,
IFD_RESET
,
atr
,
&
atrSz
);
if
(
res
!=
0
)
{
printf
(
"error powering up the card
\n
"
);
return
""
;
}
ATR
.
assign
((
const
char
*
)
atr
,
atrSz
);
}
else
#endif
{
Assert
(
(
fd
=::
open
(
portname
,
O_RDWR
|
O_NOCTTY
|
O_SYNC
))
>=
0
,
"Failed to open %s"
,
portname
);
struct
termios
tty
;
Assert
(
tcgetattr
(
fd
,
&
tty
)
>=
0
,
""
);
tty
.
c_cflag
&=
~
(
CSIZE
);
tty
.
c_cflag
|=
CLOCAL
|
CREAD
|
CS8
|
PARENB
|
CSTOPB
|
HUPCL
;
/* setup for non-canonical mode */
tty
.
c_iflag
&=
~
(
IGNBRK
|
PARMRK
|
ISTRIP
|
INLCR
|
IGNCR
|
ICRNL
|
IXON
);
tty
.
c_lflag
&=
~
(
ECHO
|
ECHONL
|
ICANON
|
ISIG
|
IEXTEN
);
tty
.
c_oflag
&=
~
OPOST
;
/* fetch bytes as they become available */
tty
.
c_cc
[
VMIN
]
=
0
;
tty
.
c_cc
[
VTIME
]
=
10
;
cfsetispeed
(
&
tty
,
(
speed_t
)
B9600
);
cfsetospeed
(
&
tty
,
(
speed_t
)
B9600
);
Assert
(
tcsetattr
(
fd
,
TCSANOW
,
&
tty
)
==
0
,
""
);
// reset the UICC
int
iFlags
;
iFlags
=
0
;
// turn off DTR
ioctl
(
fd
,
TIOCMSET
,
&
iFlags
);
struct
timespec
t
=
{
0
,
1000
*
1000
*
1000
};
nanosleep
(
&
t
,
NULL
);
iFlags
=
0xFFFF
;
// turn on DTR
//iFlags = TIOCM_CTS ;
//ioctl(fd, TIOCMSET, &iFlags);
ATR
=
this
->
read
(
200
,
3
);
}
this
->
init
();
return
ATR
;
}
return
true
;
}
bool
verifyChv
(
char
cla
,
char
chv
,
string
pwd
)
{
if
(
GRver
==
2
)
{
//GR card version 2 is not compliant
string
order
=
cla
+
hexa
(
"580000083132333431323334"
);
string
answer
=
hexa
(
"9000"
);
return
send_check
(
order
,
answer
,
10
);
}
else
{
string
order
;
order
+=
cla
;
order
+=
string
(
u8"
\x20\x00
"
,
2
);
order
+=
chv
;
order
+=
(
char
)
8
;
order
+=
pwd
;
for
(
int
i
=
pwd
.
size
();
i
<
8
;
i
++
)
order
+=
'\xff'
;
string
answer
(
u8"
\x90\x00
"
,
2
);
return
send_check
(
order
,
answer
);
void
init
()
{
string
v2ATR
=
hexa
(
"3b9f94801fc38031a073b6a10067cf3210df0ef520ec"
);
if
(
0
==
ATR
.
compare
(
0
,
21
,
v2ATR
,
0
,
21
)
)
GRver
=
2
;
v2ATR
=
hexa
(
"3b9f95801fc78031a073b6a10067cf3211b252c679b3"
);
if
(
0
==
ATR
.
compare
(
0
,
21
,
v2ATR
,
0
,
21
)
)
GRver
=
2
;
v2ATR
=
hexa
(
"3b9f95801fc78031a073b6a10067cf3211b252c679f3"
);
if
(
0
==
ATR
.
compare
(
0
,
21
,
v2ATR
,
0
,
21
)
)
GRver
=
2
;
v2ATR
=
hexa
(
"3b9f94801fc38031a073b6a10067cf3250df0e723d76"
);
if
(
0
==
ATR
.
compare
(
0
,
21
,
v2ATR
,
0
,
21
)
)
GRver
=
2
;
v2ATR
=
hexa
(
"3b9f94801fc38031a073b6a10067cf3250df0e723d36"
);
if
(
0
==
ATR
.
compare
(
0
,
21
,
v2ATR
,
0
,
21
)
)
GRver
=
2
;
}
}
bool
unblockChv
(
char
cla
,
char
chv
,
string
pwd
)
{
string
order
;
order
+=
cla
;
order
+=
string
(
u8"
\x2C\x00
"
,
2
);
order
+=
chv
;
order
+=
(
char
)
16
;
order
+=
pwd
;
for
(
int
i
=
pwd
.
size
();
i
<
16
;
i
++
)
order
+=
'\xff'
;
string
answer
(
u8"
\x90\x00
"
,
2
);
return
send_check
(
order
,
answer
);
}
bool
updateChv
(
char
cla
,
char
chv
,
string
oldpwd
,
string
newpwd
)
{
string
order
;
order
+=
cla
;
order
+=
string
(
u8"
\x24\x00
"
,
2
);
order
+=
chv
;
order
+=
(
char
)
16
;
order
+=
oldpwd
;
for
(
int
i
=
oldpwd
.
size
();
i
<
8
;
i
++
)
order
+=
'\xff'
;
order
+=
newpwd
;
for
(
int
i
=
newpwd
.
size
();
i
<
8
;
i
++
)
order
+=
'\xff'
;
string
answer
(
u8"
\x90\x00
"
,
2
);
return
send_check
(
order
,
answer
);
}
string
decodeISDN
(
string
raw
)
{
// ISDN is in last 14 bytes
string
isdn
=
raw
.
substr
(
raw
.
size
()
-
14
);
char
isdnLength
=
isdn
[
0
]
-
1
;
//char TON=isdn[1]; // should be 0x81
// two last bytes should be FF (capability , extensions)
return
to_hex
(
isdn
.
substr
(
2
,
isdnLength
),
true
);
}
vector
<
string
>
encodeISDN
(
string
isdn
,
int
recordLenght
)
{
vector
<
string
>
encoded
;
encoded
.
push_back
(
""
);
for
(
int
i
=
0
;
i
<
recordLenght
-
14
;
i
++
)
encoded
[
0
]
+=
'\xff'
;
encoded
[
0
]
+=
makeBcd
(
isdn
).
size
()
+
1
;
encoded
[
0
]
+=
'\x81'
;
//add TON field
encoded
[
0
]
+=
makeBcd
(
isdn
);
for
(
int
i
=
encoded
[
0
].
size
();
i
<
recordLenght
;
i
++
)
encoded
[
0
]
+=
'\xff'
;
return
encoded
;
}
string
decodeIMSI
(
string
raw
)
{
//int l=raw.c_str()[0];
string
imsi
=
to_hex
(
raw
.
substr
(
1
),
true
);
// First byte is length
//IMSI length bytes, then parity is second byte
return
imsi
.
substr
(
1
);
}
string
encodeMccMnc
(
string
Mcc
,
string
Mnc
,
int
len
=
0
)
{
string
out
;
out
=
makeBcd
(
Mcc
);
out
+=
makeBcd
(
Mnc
,
true
,
len
>
2
?
len
-
2
:
0
);
return
out
;
}
vector
<
string
>
encodeIMSI
(
string
imsi
)
{
vector
<
string
>
encoded
;
encoded
.
push_back
(
""
);
if
(
imsi
.
size
()
%
2
==
1
)
{
encoded
[
0
]
+=
(
char
)(
imsi
.
size
()
/
2
+
1
);
encoded
[
0
]
+=
(
char
)(
9
|
(
imsi
[
0
]
-
'0'
)
<<
4
);
}
else
{
encoded
[
0
]
+=
(
char
)(
imsi
.
size
()
/
2
);
encoded
[
0
]
+=
(
char
)(
1
|
(
imsi
[
0
]
-
'0'
)
<<
4
);
void
close
()
{
if
(
fd
!=-
1
)
::
close
(
fd
);
fd
=-
1
;
}
encoded
[
0
]
+=
makeBcd
(
imsi
.
substr
(
1
));
return
encoded
;
}
vector
<
string
>
encodeOPC
(
string
in
)
{
return
makeBcdVect
(
in
,
false
);
}
vector
<
string
>
encodeACC
(
string
in
)
{
return
makeBcdVect
(
in
,
false
);
}
vector
<
string
>
encodeKi
(
string
in
)
{
return
makeBcdVect
(
in
,
false
);
}
vector
<
string
>
encodeICCID
(
string
in
)
{
return
makeBcdVect
(
in
,
true
,
10
);
}
void
decodeEFdir
(
vector
<
string
>
EFdir
)
{
printf
(
"should be: a000000087 (3GPP) 1002 (USIM)
\n
"
);
for
(
size_t
i
=
0
;
i
<
EFdir
.
size
()
;
i
++
)
{
string
Appli
=
extractTLV
(
EFdir
[
i
],
"Application Template"
);
string
AID
=
extractTLV
(
Appli
,
"AID"
);
if
(
AID
.
size
()
>
0
)
{
dump_hex
(
"AID"
,
AID
);
printf
(
"card supplier id: %s
\n
"
,
extractTLV
(
Appli
,
"Card"
).
c_str
());
}
string
send_noCheck
(
string
in
,
int
responseSize
,
int
timeout
=
1
)
{
string
answer
=
""
;
#ifdef PCSC
if
(
fd
==
-
1
)
{
unsigned
char
rx
[
1024
];
size_t
rxSz
=
sizeof
(
rx
);
SCARD_IO_HEADER
recv
=
{
0
};
RESPONSECODE
res
=
IFDHTransmitToICC
(
0
,
recv
,
(
unsigned
char
*
)
in
.
c_str
(),
in
.
size
(),
rx
,
&
rxSz
,
&
recv
);
if
(
res
!=
0
)
{
printf
(
"send with iccid driver error
\n
"
);
return
answer
;
}
answer
.
assign
((
const
char
*
)
rx
,
rxSz
);
}
else
#endif
{
Assert
(
write
(
in
)
==
(
int
)
in
.
size
(),
""
);
answer
=
read
(
responseSize
,
timeout
);
}
return
answer
;
}
}
bool
debug
=
false
;
int
GRver
=
1
;
protected:
string
ATR
=
""
;
int
fd
=-
1
;
private:
int
lastTimeout
=
0
;
};
class
SIM
:
public
UICC
{
public:
typedef
struct
fileChar_s
{
uint16_t
rfu
;
uint16_t
size
;
// total size
uint16_t
id
;
// file name
uint8_t
type
;
// 01=MF, 02=DF, 04=EF
uint8_t
cyclic_variant
;
//
uint8_t
access
[
3
];
//
uint8_t
status
;
// usage when invalidated
uint8_t
length_following
;
//
uint8_t
structure
;
// 00=binary, 01=linear, 03=cyclic
uint8_t
record_length
;
// provided only for linear and cyclic files
}
__attribute__
((
packed
))
GSMfileChar_t
;
GSMfileChar_t
curFile
;
string
UICCFile
(
string
name
,
bool
reverse
=
false
)
{
static
const
map
<
string
,
string
>
UICCFiles
=
{
{
"EFDIR"
,
string
(
u8"
\x2f\x00
"
,
2
)},
{
"ICCID"
,
string
(
u8"
\x2f\xe2
"
,
2
)},
{
"GR type"
,
string
(
u8"
\xa0\x00
"
,
2
)},
{
"Extended language preference"
,
string
(
u8"
\x2f\x05
"
,
2
)},
{
"language preference"
,
string
(
u8"
\x7f\x20\x6f\x05
"
,
4
)},
{
"IMSI"
,
string
(
u8"
\x7f\x20\x6f\x07
"
,
4
)},
{
"Access control class"
,
string
(
u8"
\x7f\x20\x6f\x78
"
,
4
)},
{
"Location information"
,
string
(
u8"
\x7f\x20\x6f\x7e
"
,
4
)},
{
"Administrative data"
,
string
(
u8"
\x7f\x20\x6f\xad
"
,
4
)},
{
"Service Provider Name"
,
string
(
u8"
\x7f\x20\x6f\x46
"
,
4
)},
{
"PLMN selector"
,
string
(
u8"
\x7f\x20\x6f\x30
"
,
4
)},
{
"Higher Priority PLMN search period"
,
string
(
u8"
\x7f\x20\x6f\x31
"
,
4
)},
{
"Forbidden PLMN"
,
string
(
u8"
\x7f\x20\x6f\x7b
"
,
4
)},
{
"Equivalent home PLMN"
,
string
(
u8"
\x7f\x20\x6f\xd9
"
,
4
)},
{
"Group Identifier Level 1"
,
string
(
u8"
\x7f\x20\x6f\x3e
"
,
4
)},
{
"Group Identifier Level 2"
,
string
(
u8"
\x7f\x20\x6f\x3f
"
,
4
)},
{
"emergency call codes"
,
string
(
u8"
\x7f\x20\x6f\xb7
"
,
4
)},
{
"SIM service table"
,
string
(
u8"
\x7f\x20\x6f\x38
"
,
4
)},
{
"ACM maximum value"
,
string
(
u8"
\x7f\x20\x6f\x37
"
,
4
)},
{
"Accumulated call meter"
,
string
(
u8"
\x7f\x20\x6f\x39
"
,
4
)},
{
"Phase identification"
,
string
(
u8"
\x7f\x20\x6f\xae
"
,
4
)},
{
"HPLMN Selector with Access Technology"
,
string
(
u8"
\x7f\x20\x6f\x62
"
,
4
)},
{
"MSISDN"
,
string
(
u8"
\x7f\x10\x6f\x40
"
,
4
)},
{
"SMSC"
,
string
(
u8"
\x7f\x10\x6f\x42
"
,
4
)},
{
"GR OPc"
,
string
(
u8"
\x7f\xf0\xff\x01
"
,
4
)},
{
"GR Ki"
,
string
(
u8"
\x7f\xf0\xff\x02
"
,
4
)},
{
"GR R"
,
string
(
u8"
\x7f\xf0\xff\x03
"
,
4
)},
{
"GR C"
,
string
(
u8"
\x7f\xf0\xff\x04
"
,
4
)},
{
"GR secret"
,
string
(
u8"
\x7f\x20\x00\x01
"
,
4
)},
{
"GRv2 AlgType"
,
string
(
u8"
\x2f\xd0
"
,
2
)},
{
"GRv2 RC"
,
string
(
u8"
\x2f\xe6
"
,
2
)},
{
"GRv2 Milenage Param"
,
string
(
u8"
\x2f\xe5
"
,
2
)},
{
"GRv2 OPc"
,
string
(
u8"
\x60\x02
"
,
2
)},
{
"GRv2 Ki"
,
string
(
u8"
\x00\x01
"
,
2
)},
{
"GRv2 ADM"
,
string
(
u8"
\x0b\x00
"
,
2
)},
// prefix \x01\x00\x00, add \x8a\x8a end of apdu
{
"USIM Extended language preference"
,
string
(
u8"
\x7f\xf0\x6f\x05
"
,
4
)},
{
"USIM IMSI"
,
string
(
u8"
\x7f\xf0\x6f\x07
"
,
4
)},
{
"USIM Access control class"
,
string
(
u8"
\x7f\xf0\x6f\x78
"
,
4
)},
{
"USIM PS Location information"
,
string
(
u8"
\x7f\xf0\x6f\x73
"
,
4
)},
{
"USIM CS Location information"
,
string
(
u8"
\x7f\xf0\x6f\x7e
"
,
4
)},
{
"USIM Administrative data"
,
string
(
u8"
\x7f\xf0\x6f\xad
"
,
4
)},
{
"USIM PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x60
"
,
4
)},
{
"USIM Operator controlled PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x61
"
,
4
)},
{
"USIM Home PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x62
"
,
4
)},
{
"USIM Forbidden PLMNs"
,
string
(
u8"
\x7f\xf0\x6f\x7b
"
,
4
)},
{
"USIM Higher Priority PLMN search period"
,
string
(
u8"
\x7f\xf0\x6f\x31
"
,
4
)},
{
"USIM Equivalent Home PLMN"
,
string
(
u8"
\x7f\xf0\x6f\xd9
"
,
4
)},
{
"USIM Group Identifier Level 1"
,
string
(
u8"
\x7f\xf0\x6f\x3e
"
,
4
)},
{
"USIM Group Identifier Level 2"
,
string
(
u8"
\x7f\xf0\x6f\x3f
"
,
4
)},
{
"USIM emergency call codes"
,
string
(
u8"
\x7f\xf0\x6f\xb7
"
,
4
)},
{
"USIM Short Message Service Parameters"
,
string
(
u8"
\x7f\xf0\x6f\x42
"
,
4
)},
{
"USIM Service Provider Name"
,
string
(
u8"
\x7f\xf0\x6f\x46
"
,
4
)},
{
"USIM EPS LOCation Information"
,
string
(
u8"
\x7f\xf0\x6f\xe3
"
,
4
)},
{
"USIM EPS NAS Security Contex"
,
string
(
u8"
\x7f\xf0\x6f\xe4
"
,
4
)},
{
"USIM MSISDN"
,
string
(
u8"
\x7f\xf0\x6f\x40
"
,
4
)},
{
"USIM service table"
,
string
(
u8"
\x7f\xf0\x6f\x38
"
,
4
)},
};
bool
send_check
(
string
in
,
string
out
,
int
timeout
=
1
)
{
string
answer
=
send_noCheck
(
in
,
out
.
size
(),
timeout
);
if
(
!
reverse
)
{
auto
it
=
UICCFiles
.
find
(
name
);
Assert
(
it
!=
UICCFiles
.
end
(),
"try to access not defined file: %s"
,
name
.
c_str
());
return
(
it
->
second
);
}
else
{
for
(
auto
it
=
UICCFiles
.
begin
();
it
!=
UICCFiles
.
end
();
++
it
)
if
(
it
->
second
.
substr
(
it
->
second
.
size
()
-
2
)
==
name
)
return
it
->
first
;
if
(
answer
.
size
()
!=
out
.
size
())
{
printf
(
"ret is not right size
\n
"
);
dump_hex
(
"expect"
,
out
);
dump_hex
(
"answer"
,
answer
);
return
false
;
}
return
"Not existing"
;
}
}
public:
bool
readFileInfo
()
{
string
order
(
u8"
\xa0\xc0\x00\x00\x0f
"
,
5
);
string
good
(
u8"
\x90\x00
"
,
2
);
write
(
order
);
string
values
=
read
(
17
);
memcpy
(
&
curFile
,
values
.
c_str
(),
min
(
values
.
size
(),
sizeof
(
curFile
))
);
if
(
debug
)
{
static
map
<
char
,
string
>
FileType
=
{{
'\x01'
,
"Master dir"
},
{
'\x02'
,
"Sub dir"
},{
'\x04'
,
"Element File"
},};
string
fName
=
UICCFile
(
string
((
char
*
)
&
curFile
.
id
,
2
),
true
);
printf
(
"File: %s, type: %s "
,
fName
.
c_str
(),
FileType
[
curFile
.
type
].
c_str
());
if
(
curFile
.
type
==
4
)
{
static
map
<
char
,
string
>
FileAccess
=
{{
'\x00'
,
"Always"
},{
'\x01'
,
"Pin1"
},{
'\x02'
,
"Pin2"
},{
'\x03'
,
"RFU"
},{
'\x04'
,
"ADM"
},{
'\x0e'
,
"ADM"
},{
'\x0F'
,
"Never"
},
{
'\x0a'
,
"GR"
}};
static
map
<
char
,
string
>
FileType
=
{{
'\x00'
,
"Transparent"
},{
'\x01'
,
"Linear Fixed"
},{
'\x03'
,
"Cyclic"
}};
printf
(
"Type: %s, Access: read=%x (%s), update=%x (%s), size %hu
\n
"
,
FileType
[
curFile
.
structure
].
c_str
(),
curFile
.
access
[
0
]
>>
4
,
FileAccess
[
curFile
.
access
[
0
]
>>
4
].
c_str
(),
curFile
.
access
[
0
]
&
0xf
,
FileAccess
[
curFile
.
access
[
0
]
&
0xf
].
c_str
(),
ntohs
(
curFile
.
size
)
);
}
else
printf
(
"
\n
"
);
if
(
answer
!=
out
)
{
if
(
answer
==
hexa
(
"9404"
)
||
answer
==
hexa
(
"9804"
)
||
answer
==
hexa
(
"9400"
)
)
{
printf
(
"Known error, cmd:%s res:%s
\n
"
,
to_hex
(
in
).
c_str
(),
to_hex
(
answer
).
c_str
());
return
false
;
}
string
answer2
=
read
(
255
);
dump_hex
(
"Expected: "
,
out
);
dump_hex
(
"got answer: "
,
answer
+
answer2
);
printf
(
"BAD return code %s%s
\n
"
,
to_hex
(
answer
).
c_str
(),
to_hex
(
answer2
).
c_str
());
return
false
;
}
return
true
;
}
return
values
.
substr
(
values
.
size
()
-
2
)
==
good
;
}
bool
openFile
(
string
filename
)
{
string
order
(
u8"
\xa0\xa4\x00\x00\x02
"
,
5
);
// go to root directory (MF)
string
goToRoot
(
u8"
\x3f\x00
"
,
2
);
string
answerChangeDir
,
answerOpenFile
;
if
(
GRver
==
2
)
{
answerChangeDir
=
hexa
(
"9F16"
);
answerOpenFile
=
hexa
(
"9F10"
);
}
else
{
answerChangeDir
=
hexa
(
"9F17"
);
answerOpenFile
=
hexa
(
"9F0F"
);
bool
verifyChv
(
char
cla
,
char
chv
,
string
pwd
)
{
if
(
GRver
==
2
)
{
//GR card version 2 is not compliant
string
order
=
cla
+
hexa
(
"580000083132333431323334"
);
string
answer
=
hexa
(
"9000"
);
return
send_check
(
order
,
answer
,
10
);
}
else
{
string
order
;
order
+=
cla
;
order
+=
string
(
u8"
\x20\x00
"
,
2
);
order
+=
chv
;
order
+=
(
char
)
8
;
order
+=
pwd
;
for
(
int
i
=
pwd
.
size
();
i
<
8
;
i
++
)
order
+=
'\xff'
;
string
answer
(
u8"
\x90\x00
"
,
2
);
return
send_check
(
order
,
answer
);
}
}
bool
unblockChv
(
char
cla
,
char
chv
,
string
pwd
)
{
string
order
;
order
+=
cla
;
order
+=
string
(
u8"
\x2C\x00
"
,
2
);
order
+=
chv
;
order
+=
(
char
)
16
;
order
+=
pwd
;
for
(
int
i
=
pwd
.
size
();
i
<
16
;
i
++
)
order
+=
'\xff'
;
string
answer
(
u8"
\x90\x00
"
,
2
);
return
send_check
(
order
,
answer
);
}
bool
updateChv
(
char
cla
,
char
chv
,
string
oldpwd
,
string
newpwd
)
{
string
order
;
order
+=
cla
;
order
+=
string
(
u8"
\x24\x00
"
,
2
);
order
+=
chv
;
order
+=
(
char
)
16
;
order
+=
oldpwd
;
if
(
!
send_check
(
order
+
goToRoot
,
answerChangeDir
)
)
return
false
;
for
(
int
i
=
oldpwd
.
size
();
i
<
8
;
i
++
)
order
+=
'\xff'
;
string
filenameBin
=
UICCFile
(
filename
)
;
order
+=
newpwd
;
for
(
size_t
i
=
0
;
i
<
filenameBin
.
size
()
-
2
;
i
+=
2
)
if
(
!
send_check
(
order
+
filenameBin
.
substr
(
i
,
2
),
answerChangeDir
))
return
false
;
for
(
int
i
=
newpwd
.
size
();
i
<
8
;
i
++
)
order
+=
'\xff'
;
if
(
!
send_check
(
order
+
filenameBin
.
substr
(
filenameBin
.
size
()
-
2
),
answerOpenFile
))
return
false
;
string
answer
(
u8"
\x90\x00
"
,
2
);
return
send_check
(
order
,
answer
);
}
string
decodeISDN
(
string
raw
)
{
// ISDN is in last 14 bytes
if
(
raw
.
size
()
<
14
)
return
"Invalid ISDN"
;
string
isdn
=
raw
.
substr
(
raw
.
size
()
-
14
);
char
isdnLength
=
isdn
[
0
]
-
1
;
//char TON=isdn[1]; // should be 0x81
// two last bytes should be FF (capability , extensions)
return
to_hex
(
isdn
.
substr
(
2
,
isdnLength
),
true
);
}
vector
<
string
>
encodeISDN
(
string
isdn
,
int
recordLenght
)
{
vector
<
string
>
encoded
;
encoded
.
push_back
(
""
);
return
readFileInfo
();
}
for
(
int
i
=
0
;
i
<
recordLenght
-
14
;
i
++
)
encoded
[
0
]
+=
'\xff'
;
vector
<
string
>
readFile
(
string
filename
)
{
vector
<
string
>
content
;
encoded
[
0
]
+=
makeBcd
(
isdn
).
size
()
+
1
;
encoded
[
0
]
+=
'\x81'
;
//add TON field
encoded
[
0
]
+=
makeBcd
(
isdn
);
if
(
!
openFile
(
filename
)
)
return
content
;
for
(
int
i
=
encoded
[
0
].
size
();
i
<
recordLenght
;
i
++
)
encoded
[
0
]
+=
'\xff'
;
uint16_t
size
=
ntohs
(
curFile
.
size
);
return
encoded
;
}
string
decodeIMSI
(
string
raw
)
{
//int l=raw.c_str()[0];
string
imsi
;
if
(
raw
.
size
()
>
1
)
imsi
=
to_hex
(
raw
.
substr
(
1
),
true
);
// First byte is length
else
return
"Invalid read"
;
//IMSI length bytes, then parity is second byte
return
imsi
.
substr
(
1
);
}
if
(
ntohs
(
curFile
.
structure
)
==
0
)
{
// binary (flat)
Assert
(
size
<=
256
,
"Not developped: read binary files > 256 bytes (%hu)"
,
size
);
string
command
=
hexa
(
"a0b00000"
);
string
good
=
hexa
(
"9000"
);
char
s
=
size
&
0xFF
;
command
+=
string
(
&
s
,
1
);
write
(
command
);
string
answ
=
read
(
size
+
good
.
size
());
string
encodeMccMnc
(
string
Mcc
,
string
Mnc
)
{
string
plmn
;
if
(
answ
.
size
()
==
(
size_t
)
size
+
2
&&
answ
.
substr
(
answ
.
size
()
-
2
)
==
good
)
content
.
push_back
(
answ
.
substr
(
0
,
answ
.
size
()
-
2
));
if
(
Mnc
.
size
()
==
2
)
{
plmn
.
insert
(
0
,
1
,
Mcc
[
1
]);
plmn
.
insert
(
1
,
1
,
Mcc
[
0
]);
plmn
.
insert
(
2
,
1
,
'f'
);
plmn
.
insert
(
3
,
1
,
Mcc
[
2
]);
plmn
.
insert
(
4
,
1
,
Mnc
[
1
]);
plmn
.
insert
(
5
,
1
,
Mnc
[
0
]);
}
else
{
plmn
.
insert
(
0
,
1
,
Mcc
[
1
]);
plmn
.
insert
(
1
,
1
,
Mcc
[
0
]);
plmn
.
insert
(
2
,
1
,
Mnc
[
2
]);
plmn
.
insert
(
3
,
1
,
Mcc
[
2
]);
plmn
.
insert
(
4
,
1
,
Mnc
[
1
]);
plmn
.
insert
(
5
,
1
,
Mnc
[
0
]);
}
return
makeBcd
(
plmn
,
false
,
2
);
}
return
content
;
}
else
{
// records
for
(
int
i
=
0
;
i
<
size
/
curFile
.
record_length
;
i
++
)
{
string
command
(
u8"
\xa0\xb2\x00\x02
"
,
4
);
string
good
(
u8"
\x90\x00
"
,
2
);
command
+=
string
((
char
*
)
&
curFile
.
record_length
,
1
);
write
(
command
);
string
answ
=
read
(
size
+
good
.
size
());
vector
<
string
>
encodeIMSI
(
string
imsi
)
{
vector
<
string
>
encoded
;
encoded
.
push_back
(
""
);
if
(
answ
.
size
()
==
(
size_t
)
curFile
.
record_length
+
good
.
size
()
&&
answ
.
substr
(
answ
.
size
()
-
2
)
==
good
)
content
.
push_back
(
answ
.
substr
(
0
,
answ
.
size
()
-
good
.
size
()));
}
if
(
imsi
.
size
()
%
2
==
1
)
{
encoded
[
0
]
+=
(
char
)(
imsi
.
size
()
/
2
+
1
);
encoded
[
0
]
+=
(
char
)(
9
|
(
imsi
[
0
]
-
'0'
)
<<
4
);
}
else
{
encoded
[
0
]
+=
(
char
)(
imsi
.
size
()
/
2
);
encoded
[
0
]
+=
(
char
)(
1
|
(
imsi
[
0
]
-
'0'
)
<<
4
);
}
return
content
;
encoded
[
0
]
+=
makeBcd
(
imsi
.
substr
(
1
));
return
encoded
;
}
}
bool
writeFile
(
string
filename
,
vector
<
string
>
content
,
bool
fillIt
=
false
,
bool
records
=
false
)
{
if
(
!
openFile
(
filename
))
{
printf
(
"Can't open file: %s
\n
"
,
filename
.
c_str
());
return
false
;
vector
<
string
>
encodeOPC
(
string
in
)
{
return
makeBcdVect
(
in
,
false
);
}
vector
<
string
>
encodeACC
(
string
in
)
{
return
makeBcdVect
(
in
,
false
);
}
vector
<
string
>
encodeKi
(
string
in
)
{
return
makeBcdVect
(
in
,
false
);
}
vector
<
string
>
encodeICCID
(
string
in
)
{
return
makeBcdVect
(
in
,
true
,
10
);
}
void
decodeEFdir
(
vector
<
string
>
EFdir
)
{
printf
(
"should be: a000000087 (3GPP) 1002 (USIM)
\n
"
);
unsigned
char
size
=
(
unsigned
char
)
content
[
0
].
size
();
uint16_t
fileSize
=
ntohs
(
curFile
.
size
);
for
(
size_t
i
=
0
;
i
<
EFdir
.
size
()
;
i
++
)
{
string
Appli
=
extractTLV
(
EFdir
[
i
],
"Application Template"
);
string
AID
=
extractTLV
(
Appli
,
"AID"
);
if
(
curFile
.
structure
==
0
&&
records
==
false
)
{
// binary (flat)
string
fileContent
=
content
[
0
];
if
(
AID
.
size
()
>
0
)
{
dump_hex
(
"AID"
,
AID
);
printf
(
"card supplier id: %s
\n
"
,
extractTLV
(
Appli
,
"Card"
).
c_str
());
}
}
}
bool
debug
=
false
;
int
GRver
=
1
;
protected:
string
ATR
=
""
;
int
fd
=-
1
;
private:
int
lastTimeout
=
0
;
};
if
(
fillIt
)
for
(
int
j
=
size
;
j
<
fileSize
;
j
++
)
fileContent
+=
u8"
\xff
"
;
class
SIM
:
public
UICC
{
public:
typedef
struct
fileChar_s
{
uint16_t
rfu
;
uint16_t
size
;
// total size
uint16_t
id
;
// file name
uint8_t
type
;
// 01=MF, 02=DF, 04=EF
uint8_t
cyclic_variant
;
//
uint8_t
access
[
3
];
//
uint8_t
status
;
// usage when invalidated
uint8_t
length_following
;
//
uint8_t
structure
;
// 00=binary, 01=linear, 03=cyclic
uint8_t
record_length
;
// provided only for linear and cyclic files
}
__attribute__
((
packed
))
GSMfileChar_t
;
GSMfileChar_t
curFile
;
string
UICCFile
(
string
name
,
bool
reverse
=
false
)
{
static
const
map
<
string
,
string
>
UICCFiles
=
{
{
"EFDIR"
,
string
(
u8"
\x2f\x00
"
,
2
)},
{
"ICCID"
,
string
(
u8"
\x2f\xe2
"
,
2
)},
{
"GR type"
,
string
(
u8"
\xa0\x00
"
,
2
)},
{
"Extended language preference"
,
string
(
u8"
\x2f\x05
"
,
2
)},
{
"language preference"
,
string
(
u8"
\x7f\x20\x6f\x05
"
,
4
)},
{
"IMSI"
,
string
(
u8"
\x7f\x20\x6f\x07
"
,
4
)},
{
"Access control class"
,
string
(
u8"
\x7f\x20\x6f\x78
"
,
4
)},
{
"Location information"
,
string
(
u8"
\x7f\x20\x6f\x7e
"
,
4
)},
{
"Administrative data"
,
string
(
u8"
\x7f\x20\x6f\xad
"
,
4
)},
{
"Service Provider Name"
,
string
(
u8"
\x7f\x20\x6f\x46
"
,
4
)},
{
"PLMN selector"
,
string
(
u8"
\x7f\x20\x6f\x30
"
,
4
)},
{
"Higher Priority PLMN search period"
,
string
(
u8"
\x7f\x20\x6f\x31
"
,
4
)},
{
"Forbidden PLMN"
,
string
(
u8"
\x7f\x20\x6f\x7b
"
,
4
)},
{
"Equivalent home PLMN"
,
string
(
u8"
\x7f\x20\x6f\xd9
"
,
4
)},
{
"Group Identifier Level 1"
,
string
(
u8"
\x7f\x20\x6f\x3e
"
,
4
)},
{
"Group Identifier Level 2"
,
string
(
u8"
\x7f\x20\x6f\x3f
"
,
4
)},
{
"emergency call codes"
,
string
(
u8"
\x7f\x20\x6f\xb7
"
,
4
)},
{
"SIM service table"
,
string
(
u8"
\x7f\x20\x6f\x38
"
,
4
)},
{
"ACM maximum value"
,
string
(
u8"
\x7f\x20\x6f\x37
"
,
4
)},
{
"Accumulated call meter"
,
string
(
u8"
\x7f\x20\x6f\x39
"
,
4
)},
{
"Phase identification"
,
string
(
u8"
\x7f\x20\x6f\xae
"
,
4
)},
{
"HPLMN Selector with Access Technology"
,
string
(
u8"
\x7f\x20\x6f\x62
"
,
4
)},
{
"MSISDN"
,
string
(
u8"
\x7f\x10\x6f\x40
"
,
4
)},
{
"Short Message Service Parameters"
,
string
(
u8"
\x7f\x10\x6f\x42
"
,
4
)},
{
"GR OPc"
,
string
(
u8"
\x7f\xf0\xff\x01
"
,
4
)},
{
"GR Ki"
,
string
(
u8"
\x7f\xf0\xff\x02
"
,
4
)},
{
"GR R"
,
string
(
u8"
\x7f\xf0\xff\x03
"
,
4
)},
{
"GR C"
,
string
(
u8"
\x7f\xf0\xff\x04
"
,
4
)},
{
"GR secret"
,
string
(
u8"
\x7f\x20\x00\x01
"
,
4
)},
{
"GRv2 AlgType"
,
string
(
u8"
\x2f\xd0
"
,
2
)},
{
"GRv2 RC"
,
string
(
u8"
\x2f\xe6
"
,
2
)},
{
"GRv2 Milenage Param"
,
string
(
u8"
\x2f\xe5
"
,
2
)},
{
"GRv2 OPc"
,
string
(
u8"
\x60\x02
"
,
2
)},
{
"GRv2 Ki"
,
string
(
u8"
\x00\x01
"
,
2
)},
{
"GRv2 ADM"
,
string
(
u8"
\x0b\x00
"
,
2
)},
// prefix \x01\x00\x00, add \x8a\x8a end of apdu
{
"USIM Extended language preference"
,
string
(
u8"
\x7f\xf0\x6f\x05
"
,
4
)},
{
"USIM IMSI"
,
string
(
u8"
\x7f\xf0\x6f\x07
"
,
4
)},
{
"USIM Access control class"
,
string
(
u8"
\x7f\xf0\x6f\x78
"
,
4
)},
{
"USIM PS Location information"
,
string
(
u8"
\x7f\xf0\x6f\x73
"
,
4
)},
{
"USIM CS Location information"
,
string
(
u8"
\x7f\xf0\x6f\x7e
"
,
4
)},
{
"USIM Administrative data"
,
string
(
u8"
\x7f\xf0\x6f\xad
"
,
4
)},
{
"USIM PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x60
"
,
4
)},
{
"USIM Operator controlled PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x61
"
,
4
)},
{
"USIM Home PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x62
"
,
4
)},
{
"USIM Forbidden PLMNs"
,
string
(
u8"
\x7f\xf0\x6f\x7b
"
,
4
)},
{
"USIM Higher Priority PLMN search period"
,
string
(
u8"
\x7f\xf0\x6f\x31
"
,
4
)},
{
"USIM Equivalent Home PLMN"
,
string
(
u8"
\x7f\xf0\x6f\xd9
"
,
4
)},
{
"USIM Group Identifier Level 1"
,
string
(
u8"
\x7f\xf0\x6f\x3e
"
,
4
)},
{
"USIM Group Identifier Level 2"
,
string
(
u8"
\x7f\xf0\x6f\x3f
"
,
4
)},
{
"USIM emergency call codes"
,
string
(
u8"
\x7f\xf0\x6f\xb7
"
,
4
)},
{
"USIM Short Message Service Parameters"
,
string
(
u8"
\x7f\xf0\x6f\x42
"
,
4
)},
{
"USIM Service Provider Name"
,
string
(
u8"
\x7f\xf0\x6f\x46
"
,
4
)},
{
"USIM EPS LOCation Information"
,
string
(
u8"
\x7f\xf0\x6f\xe3
"
,
4
)},
{
"USIM EPS NAS Security Contex"
,
string
(
u8"
\x7f\xf0\x6f\xe4
"
,
4
)},
{
"USIM MSISDN"
,
string
(
u8"
\x7f\xf0\x6f\x40
"
,
4
)},
{
"USIM service table"
,
string
(
u8"
\x7f\xf0\x6f\x38
"
,
4
)},
};
if
(
!
reverse
)
{
auto
it
=
UICCFiles
.
find
(
name
);
Assert
(
it
!=
UICCFiles
.
end
(),
"try to access not defined file: %s"
,
name
.
c_str
());
return
(
it
->
second
);
}
else
{
for
(
auto
it
=
UICCFiles
.
begin
();
it
!=
UICCFiles
.
end
();
++
it
)
if
(
it
->
second
.
substr
(
it
->
second
.
size
()
-
2
)
==
name
)
return
it
->
first
;
uint16_t
wroteBytes
=
0
;
return
"Not existing"
;
}
}
while
(
wroteBytes
<
fileContent
.
size
())
{
uint8_t
sizeToWrite
=
fileContent
.
size
()
-
wroteBytes
>
255
?
255
:
fileContent
.
size
()
-
wroteBytes
;
int16_t
offset
=
htons
(
wroteBytes
);
string
command
(
u8"
\xa0\xd6
"
,
2
);
command
+=
((
uint8_t
*
)
&
offset
)[
0
];
command
+=
((
uint8_t
*
)
&
offset
)[
1
];
command
+=
sizeToWrite
;
command
+=
fileContent
.
substr
(
wroteBytes
,
sizeToWrite
);
public:
bool
readFileInfo
()
{
string
order
(
u8"
\xa0\xc0\x00\x00\x0f
"
,
5
);
string
good
(
u8"
\x90\x00
"
,
2
);
write
(
command
);
string
answ
=
read
(
good
.
size
());
string
values
=
send_noCheck
(
order
,
17
);
memcpy
(
&
curFile
,
values
.
c_str
(),
min
(
values
.
size
(),
sizeof
(
curFile
))
);
if
(
debug
)
{
static
map
<
char
,
string
>
FileType
=
{{
'\x01'
,
"Master dir"
},
{
'\x02'
,
"Sub dir"
},{
'\x04'
,
"Element File"
},};
string
fName
=
UICCFile
(
string
((
char
*
)
&
curFile
.
id
,
2
),
true
);
printf
(
"File: %s, type: %s "
,
fName
.
c_str
(),
FileType
[
curFile
.
type
].
c_str
());
if
(
curFile
.
type
==
4
)
{
static
map
<
char
,
string
>
FileAccess
=
{{
'\x00'
,
"Always"
},{
'\x01'
,
"Pin1"
},{
'\x02'
,
"Pin2"
},{
'\x03'
,
"RFU"
},{
'\x04'
,
"ADM"
},{
'\x0e'
,
"ADM"
},{
'\x0F'
,
"Never"
},
{
'\x0a'
,
"GR"
}};
static
map
<
char
,
string
>
FileType
=
{{
'\x00'
,
"Transparent"
},{
'\x01'
,
"Linear Fixed"
},{
'\x03'
,
"Cyclic"
}};
printf
(
"Type: %s, Access: read=%x (%s), update=%x (%s), size %hu
\n
"
,
FileType
[
curFile
.
structure
].
c_str
(),
curFile
.
access
[
0
]
>>
4
,
FileAccess
[
curFile
.
access
[
0
]
>>
4
].
c_str
(),
curFile
.
access
[
0
]
&
0xf
,
FileAccess
[
curFile
.
access
[
0
]
&
0xf
].
c_str
(),
ntohs
(
curFile
.
size
)
);
}
else
printf
(
"
\n
"
);
}
if
(
answ
!=
good
)
{
printf
(
"Write in file: %s failed
\n
"
,
filename
.
c_str
());
return
false
;
return
values
.
substr
(
values
.
size
()
-
2
)
==
good
;
}
bool
openFile
(
string
filename
)
{
string
order
(
u8"
\xa0\xa4\x00\x00\x02
"
,
5
);
// go to root directory (MF)
string
goToRoot
(
u8"
\x3f\x00
"
,
2
);
string
answerChangeDir
,
answerOpenFile
;
if
(
GRver
==
2
)
{
answerChangeDir
=
hexa
(
"9F16"
);
answerOpenFile
=
hexa
(
"9F10"
);
}
else
{
answerChangeDir
=
hexa
(
"9F17"
);
answerOpenFile
=
hexa
(
"9F0F"
);
}
wroteBytes
+=
sizeToWrite
;
}
if
(
!
send_check
(
order
+
goToRoot
,
answerChangeDir
))
return
false
;
return
true
;
}
else
{
// records
for
(
size_t
i
=
0
;
i
<
content
.
size
();
i
++
)
{
string
command
(
u8"
\xa0\xdc
"
,
2
);
string
good
(
u8"
\x90\x00
"
,
2
);
command
+=
(
unsigned
char
)
i
+
1
;
command
+=
'\x04'
;
command
+=
curFile
.
record_length
;
//record lenght;
command
+=
content
[
i
];
string
filenameBin
=
UICCFile
(
filename
);
for
(
int
j
=
content
[
i
].
size
();
j
<
curFile
.
record_length
;
j
++
)
command
+=
u8"
\xff
"
;
for
(
size_t
i
=
0
;
i
<
filenameBin
.
size
()
-
2
;
i
+=
2
)
if
(
!
send_check
(
order
+
filenameBin
.
substr
(
i
,
2
),
answerChangeDir
))
return
false
;
write
(
command
);
string
answ
=
read
(
good
.
size
())
;
if
(
!
send_check
(
order
+
filenameBin
.
substr
(
filenameBin
.
size
()
-
2
),
answerOpenFile
))
return
false
;
if
(
answ
!=
good
)
return
false
;
}
return
readFileInfo
();
}
return
true
;
}
vector
<
string
>
readFile
(
string
filename
)
{
vector
<
string
>
content
;
if
(
!
openFile
(
filename
))
return
content
;
uint16_t
size
=
ntohs
(
curFile
.
size
);
if
(
ntohs
(
curFile
.
structure
)
==
0
)
{
// binary (flat)
Assert
(
size
<=
256
,
"Not developped: read binary files > 256 bytes (%hu)"
,
size
);
string
command
=
hexa
(
"a0b00000"
);
string
good
=
hexa
(
"9000"
);
char
s
=
size
&
0xFF
;
command
+=
string
(
&
s
,
1
);
string
answ
=
send_noCheck
(
command
,
size
+
good
.
size
());
if
(
answ
.
size
()
==
(
size_t
)
size
+
2
&&
answ
.
substr
(
answ
.
size
()
-
2
)
==
good
)
content
.
push_back
(
answ
.
substr
(
0
,
answ
.
size
()
-
2
));
return
content
;
}
else
{
// records
for
(
int
i
=
0
;
i
<
size
/
curFile
.
record_length
;
i
++
)
{
string
command
(
u8"
\xa0\xb2\x00\x02
"
,
4
);
string
good
(
u8"
\x90\x00
"
,
2
);
command
+=
string
((
char
*
)
&
curFile
.
record_length
,
1
);
string
answ
=
send_noCheck
(
command
,
size
+
good
.
size
());
if
(
answ
.
size
()
==
(
size_t
)
curFile
.
record_length
+
good
.
size
()
&&
answ
.
substr
(
answ
.
size
()
-
2
)
==
good
)
content
.
push_back
(
answ
.
substr
(
0
,
answ
.
size
()
-
good
.
size
()));
}
if
(
content
.
size
()
==
0
)
content
.
push_back
(
"Error"
);
return
content
;
}
}
bool
writeFile
(
string
filename
,
vector
<
string
>
content
,
bool
fillIt
=
false
,
bool
records
=
false
)
{
if
(
!
openFile
(
filename
))
{
printf
(
"Can't open file: %s
\n
"
,
filename
.
c_str
());
return
false
;
}
unsigned
char
size
=
(
unsigned
char
)
content
[
0
].
size
();
uint16_t
fileSize
=
ntohs
(
curFile
.
size
);
if
(
curFile
.
structure
==
0
&&
records
==
false
)
{
// binary (flat)
string
fileContent
=
content
[
0
];
if
(
fillIt
)
for
(
int
j
=
size
;
j
<
fileSize
;
j
++
)
fileContent
+=
u8"
\xff
"
;
uint16_t
wroteBytes
=
0
;
while
(
wroteBytes
<
fileContent
.
size
())
{
uint8_t
sizeToWrite
=
fileContent
.
size
()
-
wroteBytes
>
255
?
255
:
fileContent
.
size
()
-
wroteBytes
;
int16_t
offset
=
htons
(
wroteBytes
);
string
command
(
u8"
\xa0\xd6
"
,
2
);
command
+=
((
uint8_t
*
)
&
offset
)[
0
];
command
+=
((
uint8_t
*
)
&
offset
)[
1
];
command
+=
sizeToWrite
;
command
+=
fileContent
.
substr
(
wroteBytes
,
sizeToWrite
);
string
good
(
u8"
\x90\x00
"
,
2
);
string
answ
=
send_noCheck
(
command
,
good
.
size
());
if
(
answ
!=
good
)
{
printf
(
"Write in file: %s failed
\n
"
,
filename
.
c_str
());
return
false
;
}
wroteBytes
+=
sizeToWrite
;
}
return
true
;
}
else
{
// records
for
(
size_t
i
=
0
;
i
<
content
.
size
();
i
++
)
{
string
command
(
u8"
\xa0\xdc
"
,
2
);
string
good
(
u8"
\x90\x00
"
,
2
);
command
+=
(
unsigned
char
)
i
+
1
;
command
+=
'\x04'
;
command
+=
curFile
.
record_length
;
//record lenght;
command
+=
content
[
i
];
for
(
int
j
=
content
[
i
].
size
();
j
<
curFile
.
record_length
;
j
++
)
command
+=
u8"
\xff
"
;
string
answ
=
send_noCheck
(
command
,
good
.
size
());
if
(
answ
!=
good
)
return
false
;
}
}
return
true
;
}
int
fileRecordSize
(
string
filename
)
{
openFile
(
filename
);
return
curFile
.
record_length
;
}
int
fileRecordSize
(
string
filename
)
{
openFile
(
filename
);
return
curFile
.
record_length
;
}
bool
verifyChv
(
char
chv
,
string
pwd
)
{
return
UICC
::
verifyChv
(
'\xa0'
,
chv
,
pwd
);
}
bool
verifyChv
(
char
chv
,
string
pwd
)
{
return
UICC
::
verifyChv
(
'\xa0'
,
chv
,
pwd
);
}
bool
unblockChv
(
char
chv
,
string
pwd
)
{
return
UICC
::
unblockChv
(
'\xa0'
,
chv
,
pwd
);
}
bool
unblockChv
(
char
chv
,
string
pwd
)
{
return
UICC
::
unblockChv
(
'\xa0'
,
chv
,
pwd
);
}
bool
updateChv
(
char
chv
,
string
oldpwd
,
string
newpwd
)
{
return
UICC
::
updateChv
(
'\xa0'
,
chv
,
oldpwd
,
newpwd
);
}
bool
updateChv
(
char
chv
,
string
oldpwd
,
string
newpwd
)
{
return
UICC
::
updateChv
(
'\xa0'
,
chv
,
oldpwd
,
newpwd
);
}
};
...
...
@@ -995,324 +1102,314 @@ class SIM: public UICC {
#define SERVICE_STRING(SeRvice) #SeRvice,
/* Map task id to printable name. */
static
const
string
service_info
[]
=
{
FOREACH_SERVICE
(
SERVICE_STRING
)
FOREACH_SERVICE
(
SERVICE_STRING
)
};
#define SERVICE_ENUM(SeRvice) SeRvice,
//! Tasks id of each task
typedef
enum
{
FOREACH_SERVICE
(
SERVICE_ENUM
)
FOREACH_SERVICE
(
SERVICE_ENUM
)
}
service_id_t
;
void
decodeServiceTable
(
string
ST
)
{
dump_hex
(
"usst"
,
ST
);
dump_hex
(
"usst"
,
ST
);
for
(
size_t
i
=
0
;
i
<
ST
.
size
()
;
i
++
)
for
(
int
b
=
0
;
b
<
8
;
b
++
)
if
(
(
ST
[
i
]
>>
b
)
&
1
)
printf
(
"(%d) %s
\n
"
,
(
int
)
i
*
8
+
b
+
1
,
service_info
[
i
*
8
+
b
].
c_str
());
for
(
size_t
i
=
0
;
i
<
ST
.
size
()
;
i
++
)
for
(
int
b
=
0
;
b
<
8
;
b
++
)
if
(
(
ST
[
i
]
>>
b
)
&
1
)
printf
(
"(%d) %s
\n
"
,
(
int
)
i
*
8
+
b
+
1
,
service_info
[
i
*
8
+
b
].
c_str
());
}
class
USIM
:
public
UICC
{
private:
string
UICCFile
(
string
name
)
{
static
const
map
<
string
,
string
>
UICCFiles
=
{
{
"EFDIR"
,
string
(
u8"
\x2f\x00
"
,
2
)},
{
"ICCID"
,
string
(
u8"
\x2f\xe2
"
,
2
)},
{
"Extended language preference"
,
string
(
u8"
\x2f\x05
"
,
2
)},
{
"language preference"
,
string
(
u8"
\x7f\x20\x6f\x05
"
,
4
)},
{
"SMSC"
,
string
(
u8"
\x7f\x10\x6f\x42
"
,
4
)},
{
"IMSI"
,
string
(
u8"
\x7f\xf0\x6f\x07
"
,
4
)},
{
"Access control class"
,
string
(
u8"
\x7f\xf0\x6f\x78
"
,
4
)},
{
"PS Location information"
,
string
(
u8"
\x7f\xf0\x6f\x73
"
,
4
)},
{
"CS Location information"
,
string
(
u8"
\x7f\xf0\x6f\x7e
"
,
4
)},
{
"Administrative data"
,
string
(
u8"
\x7f\xf0\x6f\xad
"
,
4
)},
{
"PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x60
"
,
4
)},
{
"Operator controlled PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x61
"
,
4
)},
{
"Home PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x62
"
,
4
)},
{
"Forbidden PLMNs"
,
string
(
u8"
\x7f\xf0\x6f\x7b
"
,
4
)},
{
"Higher Priority PLMN search period"
,
string
(
u8"
\x7f\xf0\x6f\x31
"
,
4
)},
{
"Equivalent Home PLMN"
,
string
(
u8"
\x7f\xf0\x6f\xd9
"
,
4
)},
{
"Group Identifier Level 1"
,
string
(
u8"
\x7f\xf0\x6f\x3e
"
,
4
)},
{
"Group Identifier Level 2"
,
string
(
u8"
\x7f\xf0\x6f\x3f
"
,
4
)},
{
"emergency call codes"
,
string
(
u8"
\x7f\xf0\x6f\xb7
"
,
4
)},
{
"Short Message Service Parameters"
,
string
(
u8"
\x7f\xf0\x6f\x42
"
,
4
)},
{
"Service Provider Name"
,
string
(
u8"
\x7f\xf0\x6f\x46
"
,
4
)},
{
"EPS LOCation Information"
,
string
(
u8"
\x7f\xf0\x6f\xe3
"
,
4
)},
{
"EPS NAS Security Contex"
,
string
(
u8"
\x7f\xf0\x6f\xe4
"
,
4
)},
{
"MSISDN"
,
string
(
u8"
\x7f\xf0\x6f\x40
"
,
4
)},
{
"USIM service table"
,
string
(
u8"
\x7f\xf0\x6f\x38
"
,
4
)},
{
"GR OPc"
,
string
(
u8"
\x7f\xf0\xff\x01
"
,
4
)},
{
"GR Ki"
,
string
(
u8"
\x7f\xf0\xff\x02
"
,
4
)},
{
"GR R"
,
string
(
u8"
\x7f\xf0\xff\x03
"
,
4
)},
{
"GR C"
,
string
(
u8"
\x7f\xf0\xff\x04
"
,
4
)},
{
"GR secret"
,
string
(
u8"
\x7f\x20\x00\x01
"
,
4
)},
{
"GRv2 AlgType"
,
string
(
u8"
\x2f\xd0
"
,
2
)},
{
"GRv2 RC"
,
string
(
u8"
\x2f\xe6
"
,
2
)},
{
"GRv2 OPc"
,
string
(
u8"
\x60\x02
"
,
2
)},
{
"GRv2 Ki"
,
string
(
u8"
\x00\x01
"
,
2
)},
{
"GRv2 ADM"
,
string
(
u8"
\x0b\x00
"
,
2
)},
// prefix \x01\x00\x00, add \x8a\x8a end of apdu
{
"GRv2 Pin1Puk1"
,
string
(
u8"
\x01\x00
"
,
2
)},
{
"GRv2 Pin2Puk2"
,
string
(
u8"
\x02\x00
"
,
2
)},
};
auto
it
=
UICCFiles
.
find
(
name
);
Assert
(
it
!=
UICCFiles
.
end
(),
"try to access not defined file: %s"
,
name
.
c_str
());
return
(
it
->
second
);
}
string
fileInfo
;
string
fileDesc
;
int
fileSize
;
public:
bool
readFileInfo
(
string
size
)
{
string
order
(
u8"
\x00\xc0\x00\x00
"
,
4
);
order
+=
size
;
string
good
(
u8"
\x90\x00
"
,
2
);
write
(
order
);
string
values
=
read
(
size
[
0
]
+
good
.
size
());
if
(
values
[
0
]
!=
'\x62'
||
values
.
substr
(
values
.
size
()
-
2
)
!=
good
)
return
false
;
fileInfo
=
extractTLV
(
values
,
"FCP Template"
);
fileDesc
=
extractTLV
(
fileInfo
,
"File Descriptor"
);
string
fileSizeString
=
extractTLV
(
fileInfo
,
"File Size - Data"
);
fileSize
=
0
;
for
(
size_t
i
=
0
;
i
<
fileSizeString
.
size
();
i
++
)
fileSize
=
fileSize
*
256
+
(
unsigned
char
)
fileSizeString
[
i
];
return
true
;
}
bool
openFile
(
string
filename
)
{
string
order
(
u8"
\x00\xa4\x08\x04
"
,
4
);
string
answer
(
u8"
\x61
"
,
1
);
string
filenameBin
=
UICCFile
(
filename
);
if
(
!
send_check
(
order
+
(
char
)(
filenameBin
.
size
())
+
filenameBin
,
answer
))
return
false
;
string
size
=
read
(
1
);
if
(
size
.
size
()
!=
1
)
return
false
;
return
readFileInfo
(
size
);
}
vector
<
string
>
readFile
(
string
filename
)
{
vector
<
string
>
content
;
if
(
!
openFile
(
filename
))
return
content
;
if
(
fileDesc
.
size
()
<=
2
)
{
// this is a plain file
long
size
=
fileSize
;
string
fullanswr
=
""
;
Assert
(
size
<
32767
,
"Not developped"
);
long
alreadyRead
=
0
;
while
(
size
>
0
)
{
string
command
(
u8"
\x00\xb0
"
,
2
);
string
good
(
u8"
\x90\x00
"
,
2
);
unsigned
char
s
;
if
(
size
>
255
)
s
=
255
;
else
s
=
size
;
unsigned
char
P1
=
alreadyRead
>>
8
;
unsigned
char
P2
=
alreadyRead
&
0xFF
;
command
+=
string
((
char
*
)
&
P1
,
1
);
command
+=
string
((
char
*
)
&
P2
,
1
);
command
+=
string
((
char
*
)
&
s
,
1
);
write
(
command
);
string
answ
=
read
(
s
+
2
);
if
(
answ
.
size
()
==
(
size_t
)
s
+
good
.
size
()
&&
answ
.
substr
(
answ
.
size
()
-
good
.
size
())
==
good
)
fullanswr
+=
answ
.
substr
(
0
,
answ
.
size
()
-
good
.
size
());
size
-=
s
;
alreadyRead
+=
s
;
}
content
.
push_back
(
fullanswr
);
return
content
;
}
else
{
// This is a records set file
// records
// string len must be 5 bytes
// file type is byte 0
// byte 1 is useless: always 0x21
// bytes 3 and 4: record length
// (byte 3 should be 00 according to ETSI 102 221)
// byte 5: number of records
for
(
int
i
=
1
;
i
<=
(
unsigned
char
)
fileDesc
[
4
]
;
i
++
)
{
string
command
(
u8"
\x00\xb2
"
,
2
);
command
+=
(
unsigned
char
)
i
;
command
+=
(
unsigned
char
)
4
;
private:
string
UICCFile
(
string
name
)
{
static
const
map
<
string
,
string
>
UICCFiles
=
{
{
"EFDIR"
,
string
(
u8"
\x2f\x00
"
,
2
)},
{
"ICCID"
,
string
(
u8"
\x2f\xe2
"
,
2
)},
{
"Maximum Power Consumption"
,
string
(
u8"
\x2f\x08
"
,
2
)},
//Not available in present cards
{
"Extended language preference"
,
string
(
u8"
\x2f\x05
"
,
2
)},
{
"language preference"
,
string
(
u8"
\x7f\x20\x6f\x05
"
,
4
)},
{
"IMSI"
,
string
(
u8"
\x7f\xf0\x6f\x07
"
,
4
)},
{
"Access control class"
,
string
(
u8"
\x7f\xf0\x6f\x78
"
,
4
)},
{
"PS Location information"
,
string
(
u8"
\x7f\xf0\x6f\x73
"
,
4
)},
{
"CS Location information"
,
string
(
u8"
\x7f\xf0\x6f\x7e
"
,
4
)},
{
"Administrative data"
,
string
(
u8"
\x7f\xf0\x6f\xad
"
,
4
)},
{
"PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x60
"
,
4
)},
{
"Operator controlled PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x61
"
,
4
)},
{
"Home PLMN selector with Access Technology"
,
string
(
u8"
\x7f\xf0\x6f\x62
"
,
4
)},
{
"Forbidden PLMNs"
,
string
(
u8"
\x7f\xf0\x6f\x7b
"
,
4
)},
{
"Higher Priority PLMN search period"
,
string
(
u8"
\x7f\xf0\x6f\x31
"
,
4
)},
{
"Equivalent Home PLMN"
,
string
(
u8"
\x7f\xf0\x6f\xd9
"
,
4
)},
{
"Group Identifier Level 1"
,
string
(
u8"
\x7f\xf0\x6f\x3e
"
,
4
)},
{
"Group Identifier Level 2"
,
string
(
u8"
\x7f\xf0\x6f\x3f
"
,
4
)},
{
"emergency call codes"
,
string
(
u8"
\x7f\xf0\x6f\xb7
"
,
4
)},
{
"Short Message Service Parameters"
,
string
(
u8"
\x7f\xf0\x6f\x42
"
,
4
)},
{
"Service Provider Name"
,
string
(
u8"
\x7f\xf0\x6f\x46
"
,
4
)},
{
"EPS LOCation Information"
,
string
(
u8"
\x7f\xf0\x6f\xe3
"
,
4
)},
{
"EPS NAS Security Contex"
,
string
(
u8"
\x7f\xf0\x6f\xe4
"
,
4
)},
{
"MSISDN"
,
string
(
u8"
\x7f\xf0\x6f\x40
"
,
4
)},
{
"USIM service table"
,
string
(
u8"
\x7f\xf0\x6f\x38
"
,
4
)},
{
"GR OPc"
,
string
(
u8"
\x7f\xf0\xff\x01
"
,
4
)},
{
"GR Ki"
,
string
(
u8"
\x7f\xf0\xff\x02
"
,
4
)},
{
"GR R"
,
string
(
u8"
\x7f\xf0\xff\x03
"
,
4
)},
{
"GR C"
,
string
(
u8"
\x7f\xf0\xff\x04
"
,
4
)},
{
"GR secret"
,
string
(
u8"
\x7f\x20\x00\x01
"
,
4
)},
{
"GRv2 AlgType"
,
string
(
u8"
\x2f\xd0
"
,
2
)},
{
"GRv2 RC"
,
string
(
u8"
\x2f\xe6
"
,
2
)},
{
"GRv2 OPc"
,
string
(
u8"
\x60\x02
"
,
2
)},
{
"GRv2 Ki"
,
string
(
u8"
\x00\x01
"
,
2
)},
{
"GRv2 ADM"
,
string
(
u8"
\x0b\x00
"
,
2
)},
// prefix \x01\x00\x00, add \x8a\x8a end of apdu
{
"GRv2 Pin1Puk1"
,
string
(
u8"
\x01\x00
"
,
2
)},
{
"GRv2 Pin2Puk2"
,
string
(
u8"
\x02\x00
"
,
2
)},
};
auto
it
=
UICCFiles
.
find
(
name
);
Assert
(
it
!=
UICCFiles
.
end
(),
"try to access not defined file: %s"
,
name
.
c_str
());
return
(
it
->
second
);
}
string
fileInfo
;
string
fileDesc
;
int
fileSize
;
public:
bool
readFileInfo
(
string
size
)
{
string
order
(
u8"
\x00\xc0\x00\x00
"
,
4
);
order
+=
size
;
string
good
(
u8"
\x90\x00
"
,
2
);
command
+=
fileDesc
.
substr
(
3
,
1
);
write
(
command
);
string
answ
=
read
(
(
unsigned
char
)
fileDesc
[
3
]
+
2
);
string
values
=
send_noCheck
(
order
,
size
[
0
]
+
good
.
size
());
if
(
answ
.
size
()
==
((
unsigned
char
)
fileDesc
[
3
]
+
good
.
size
())
&&
answ
.
substr
(
answ
.
size
()
-
good
.
size
())
==
good
)
content
.
push_back
(
answ
.
substr
(
0
,
answ
.
size
()
-
good
.
size
()));
}
if
(
values
[
0
]
!=
'\x62'
||
values
.
substr
(
values
.
size
()
-
2
)
!=
good
)
return
false
;
return
content
;
}
}
fileInfo
=
extractTLV
(
values
,
"FCP Template"
);
fileDesc
=
extractTLV
(
fileInfo
,
"File Descriptor"
);
string
fileSizeString
=
extractTLV
(
fileInfo
,
"File Size - Data"
);
fileSize
=
0
;
bool
writeFile
(
string
filename
,
vector
<
string
>
content
,
bool
fillIt
=
false
,
bool
records
=
false
)
{
if
(
!
openFile
(
filename
))
return
false
;
for
(
size_t
i
=
0
;
i
<
fileSizeString
.
size
();
i
++
)
fileSize
=
fileSize
*
256
+
(
unsigned
char
)
fileSizeString
[
i
];
int
size
=
content
[
0
].
size
();
return
true
;
}
if
(
fileDesc
.
size
()
<=
2
)
{
// binary (flat)
Assert
(
size
<=
256
,
"Not developped: write binary files > 256 bytes"
);
string
command
(
u8"
\x00\xd6\x00\x00
"
,
4
);
string
good
(
u8"
\x90\x00
"
,
2
);
unsigned
char
x
=
(
char
)
size
;
bool
openFile
(
string
filename
)
{
string
order
(
u8"
\x00\xa4\x08\x04
"
,
4
);
string
filenameBin
=
UICCFile
(
filename
);
string
answer
=
send_noCheck
(
order
+
(
char
)(
filenameBin
.
size
())
+
filenameBin
,
2
,
1
);
if
(
fillIt
)
command
+=
(
unsigned
char
)
fileSize
;
else
command
+=
x
;
if
(
answer
.
size
()
!=
2
||
answer
[
0
]
!=
'\x61'
)
return
false
;
command
+=
content
[
0
];
string
size
=
answer
.
substr
(
1
,
1
);
return
readFileInfo
(
size
);
}
if
(
fillIt
)
for
(
int
j
=
content
[
0
].
size
();
j
<
(
unsigned
char
)
fileSize
;
j
++
)
command
+=
u8"
\xff
"
;
vector
<
string
>
readFile
(
string
filename
)
{
vector
<
string
>
content
;
if
(
!
openFile
(
filename
))
return
content
;
if
(
fileDesc
.
size
()
<=
2
)
{
// this is a plain file
long
size
=
fileSize
;
string
fullanswr
=
""
;
Assert
(
size
<
32767
,
"Not developped"
);
long
alreadyRead
=
0
;
while
(
size
>
0
)
{
string
command
(
u8"
\x00\xb0
"
,
2
);
string
good
(
u8"
\x90\x00
"
,
2
);
unsigned
char
s
;
if
(
size
>
255
)
s
=
255
;
else
s
=
size
;
unsigned
char
P1
=
alreadyRead
>>
8
;
unsigned
char
P2
=
alreadyRead
&
0xFF
;
command
+=
string
((
char
*
)
&
P1
,
1
);
command
+=
string
((
char
*
)
&
P2
,
1
);
command
+=
string
((
char
*
)
&
s
,
1
);
string
answ
=
send_noCheck
(
command
,
s
+
2
);
if
(
answ
.
size
()
==
(
size_t
)
s
+
good
.
size
()
&&
answ
.
substr
(
answ
.
size
()
-
good
.
size
())
==
good
)
fullanswr
+=
answ
.
substr
(
0
,
answ
.
size
()
-
good
.
size
());
size
-=
s
;
alreadyRead
+=
s
;
}
content
.
push_back
(
fullanswr
);
return
content
;
}
else
{
// This is a records set file
// records
// string len must be 5 bytes
// file type is byte 0
// byte 1 is useless: always 0x21
// bytes 3 and 4: record length
// (byte 3 should be 00 according to ETSI 102 221)
// byte 5: number of records
for
(
int
i
=
1
;
i
<=
(
unsigned
char
)
fileDesc
[
4
]
;
i
++
)
{
string
command
(
u8"
\x00\xb2
"
,
2
);
command
+=
(
unsigned
char
)
i
;
command
+=
(
unsigned
char
)
4
;
string
good
(
u8"
\x90\x00
"
,
2
);
command
+=
fileDesc
.
substr
(
3
,
1
);
string
answ
=
send_noCheck
(
command
,(
unsigned
char
)
fileDesc
[
3
]
+
2
);
if
(
answ
.
size
()
==
((
unsigned
char
)
fileDesc
[
3
]
+
good
.
size
())
&&
answ
.
substr
(
answ
.
size
()
-
good
.
size
())
==
good
)
content
.
push_back
(
answ
.
substr
(
0
,
answ
.
size
()
-
good
.
size
()));
}
return
content
;
}
}
write
(
command
);
string
answ
=
read
(
good
.
size
());
bool
writeFile
(
string
filename
,
vector
<
string
>
content
,
bool
fillIt
=
false
,
bool
records
=
false
)
{
if
(
!
openFile
(
filename
))
return
false
;
int
size
=
content
[
0
].
size
();
if
(
fileDesc
.
size
()
<=
2
)
{
// binary (flat)
Assert
(
size
<=
256
,
"Not developped: write binary files > 256 bytes"
);
string
command
(
u8"
\x00\xd6\x00\x00
"
,
4
);
string
good
(
u8"
\x90\x00
"
,
2
);
unsigned
char
x
=
(
char
)
size
;
if
(
fillIt
)
command
+=
(
unsigned
char
)
fileSize
;
else
command
+=
x
;
command
+=
content
[
0
];
if
(
fillIt
)
for
(
int
j
=
content
[
0
].
size
();
j
<
(
unsigned
char
)
fileSize
;
j
++
)
command
+=
u8"
\xff
"
;
string
answ
=
send_noCheck
(
command
,
good
.
size
());
if
(
answ
==
good
)
return
true
;
else
return
false
;
}
else
{
// records
for
(
size_t
i
=
0
;
i
<
content
.
size
();
i
++
)
{
string
command
(
u8"
\x00\xdc
"
,
2
);
string
good
(
u8"
\x90\x00
"
,
2
);
command
+=
(
unsigned
char
)
i
+
1
;
command
+=
'\x04'
;
command
+=
fileDesc
.
substr
(
3
,
1
);
//record lenght;
command
+=
content
[
i
];
for
(
int
j
=
content
[
i
].
size
();
j
<
(
unsigned
char
)
fileDesc
[
3
]
;
j
++
)
command
+=
u8"
\xff
"
;
string
answ
=
send_noCheck
(
command
,
good
.
size
());
if
(
answ
!=
good
)
return
false
;
}
}
if
(
answ
==
good
)
return
true
;
else
return
false
;
}
else
{
// records
for
(
size_t
i
=
0
;
i
<
content
.
size
();
i
++
)
{
string
command
(
u8"
\x00\xdc
"
,
2
);
string
good
(
u8"
\x90\x00
"
,
2
);
command
+=
(
unsigned
char
)
i
+
1
;
command
+=
'\x04'
;
command
+=
fileDesc
.
substr
(
3
,
1
);
//record lenght;
command
+=
content
[
i
];
for
(
int
j
=
content
[
i
].
size
();
j
<
(
unsigned
char
)
fileDesc
[
3
]
;
j
++
)
command
+=
u8"
\xff
"
;
write
(
command
);
string
answ
=
read
(
good
.
size
());
if
(
answ
!=
good
)
return
false
;
}
}
return
true
;
}
bool
verifyChv
(
char
chv
,
string
pwd
)
{
return
UICC
::
verifyChv
(
'\x00'
,
chv
,
pwd
);
}
bool
unblockChv
(
char
chv
,
string
pwd
)
{
return
UICC
::
unblockChv
(
'\x00'
,
chv
,
pwd
);
}
bool
updateChv
(
char
chv
,
string
oldpwd
,
string
newpwd
)
{
return
UICC
::
updateChv
(
'\x00'
,
chv
,
oldpwd
,
newpwd
);
}
bool
openUSIM
()
{
vector
<
string
>
res
;
// Read card description
res
=
readFile
(
"EFDIR"
);
if
(
debug
)
decodeEFdir
(
res
);
string
AID
=
hexa
(
"a0000000871002"
);
//3GPP + USIM PIX (see ETSI TS 101 220 annex E)
string
order
(
u8"
\x00\xa4\x04\x0c
"
,
4
);
order
+=
(
char
)
AID
.
size
();
order
+=
AID
;
string
answer
(
u8"
\x90\x00
"
,
2
);
return
send_check
(
order
,
answer
);
}
int
fileRecordSize
(
string
filename
)
{
openFile
(
filename
);
if
(
fileDesc
.
size
()
<=
2
)
return
-
1
;
return
fileDesc
[
3
];
}
vector
<
string
>
authenticate
(
string
rand
,
string
autn
)
{
vector
<
string
>
ret
;
string
order
(
u8"
\x00\x88\x00\x81
"
,
4
);
order
+=
(
unsigned
char
)
(
rand
.
size
()
+
autn
.
size
()
+
2
);
order
+=
(
unsigned
char
)
rand
.
size
();
order
+=
rand
;
order
+=
(
unsigned
char
)
autn
.
size
();
order
+=
autn
;
string
answerKeys
(
u8"
\x61
"
,
1
);
string
answerAUTS
(
u8"
\x9f
"
,
1
);
Assert
(
write
(
order
)
==
(
int
)
order
.
size
(),
""
);
// Cards need CPU procesing, so delay to check Milenage
usleep
(
100
);
string
answer
=
read
(
1
);
string
size
=
read
(
1
);
if
(
answer
!=
answerKeys
&&
answer
!=
answerAUTS
)
{
printf
(
"Not possible answer to milenage challenge: %x, %02x
\n
"
,
answer
[
0
],
size
[
0
]);
//return ret;
bool
verifyChv
(
char
chv
,
string
pwd
)
{
return
UICC
::
verifyChv
(
'\x00'
,
chv
,
pwd
);
}
bool
unblockChv
(
char
chv
,
string
pwd
)
{
return
UICC
::
unblockChv
(
'\x00'
,
chv
,
pwd
);
}
if
(
size
.
size
()
!=
1
)
{
printf
(
"No answer to mileange challenge
\n
"
);
return
ret
;
bool
updateChv
(
char
chv
,
string
oldpwd
,
string
newpwd
)
{
return
UICC
::
updateChv
(
'\x00'
,
chv
,
oldpwd
,
newpwd
);
}
string
getData
(
u8"
\x00\xc0\x00\x00
"
,
4
);
getData
+=
size
;
string
good
(
u8"
\x90\x00
"
,
2
);
write
(
getData
);
string
values
=
read
(
size
[
0
]
+
good
.
size
(),
100
);
bool
openUSIM
()
{
vector
<
string
>
res
;
// Read card description
res
=
readFile
(
"EFDIR"
);
if
(
values
.
substr
(
values
.
size
()
-
2
)
!=
good
)
{
printf
(
"Can't get APDU in return of millenage challenge
\n
"
);
return
ret
;
if
(
debug
)
decodeEFdir
(
res
);
string
AID
=
hexa
(
"a0000000871002"
);
//3GPP + USIM PIX (see ETSI TS 101 220 annex E)
string
order
(
u8"
\x00\xa4\x04\x0c
"
,
4
);
order
+=
(
char
)
AID
.
size
();
order
+=
AID
;
string
answer
(
u8"
\x90\x00
"
,
2
);
return
send_check
(
order
,
answer
);
}
i
f
(
values
[
0
]
==
'\xDC'
)
// we have a AUTS answer encoded as len+val
ret
.
push_back
(
values
.
substr
(
2
,
values
[
1
])
);
i
nt
fileRecordSize
(
string
filename
)
{
openFile
(
filename
);
if
(
values
[
0
]
==
'\xDB'
)
{
//we have the keys
size_t
pos
=
1
;
if
(
fileDesc
.
size
()
<=
2
)
return
-
1
;
while
(
pos
<
values
.
size
()
-
2
)
{
ret
.
push_back
(
values
.
substr
(
pos
+
1
,
values
[
pos
]));
pos
+=
values
[
pos
]
+
1
;
}
return
fileDesc
[
3
];
}
return
ret
;
}
vector
<
string
>
authenticate
(
string
rand
,
string
autn
)
{
vector
<
string
>
ret
;
string
order
(
u8"
\x00\x88\x00\x81
"
,
4
);
order
+=
(
unsigned
char
)
(
rand
.
size
()
+
autn
.
size
()
+
2
);
order
+=
(
unsigned
char
)
rand
.
size
();
order
+=
rand
;
order
+=
(
unsigned
char
)
autn
.
size
();
order
+=
autn
;
string
answerKeys
(
u8"
\x61
"
,
1
);
string
answerAUTS
(
u8"
\x9f
"
,
1
);
// Cards need CPU procesing, so delay to check Milenage
string
answer
=
send_noCheck
(
order
,
2
,
100
);
if
(
answer
.
size
()
<
2
)
{
printf
(
"Not answer to milenage challenge
\n
"
);
return
ret
;
}
string
res
=
answer
.
substr
(
0
,
1
);
string
size
=
answer
.
substr
(
1
,
1
);
if
(
res
!=
answerKeys
&&
res
!=
answerAUTS
)
{
printf
(
"Not possible answer to milenage challenge: %x, %02x
\n
"
,
res
[
0
],
size
[
1
]);
//return ret;
}
string
getData
(
u8"
\x00\xc0\x00\x00
"
,
4
);
getData
+=
size
;
string
good
(
u8"
\x90\x00
"
,
2
);
string
values
=
send_noCheck
(
getData
,
answer
[
1
]
+
good
.
size
(),
100
);
if
(
values
.
substr
(
values
.
size
()
-
2
)
!=
good
)
{
printf
(
"Can't get APDU in return of millenage challenge
\n
"
);
return
ret
;
}
if
(
values
[
0
]
==
'\xDC'
)
// we have a AUTS answer encoded as len+val
ret
.
push_back
(
values
.
substr
(
2
,
values
[
1
]));
if
(
values
[
0
]
==
'\xDB'
)
{
//we have the keys
size_t
pos
=
1
;
while
(
pos
<
values
.
size
()
-
2
)
{
ret
.
push_back
(
values
.
substr
(
pos
+
1
,
values
[
pos
]));
pos
+=
values
[
pos
]
+
1
;
}
}
return
ret
;
}
};
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment