A few forumers asked me questions regarding reading of MyKad surface information. The answer is there is no encryption; it is just about knowing what (APDU) command to send.
There will be 5 APDU commands that I'll introduce. I name them as
1) Select Application
2) Get Response
3) Set Length
4) Select Info
5) Read Info
Instead of viewing a particular command to read "Name", another command to read "IC no.", it is better to interpret a sequence of 3 commands (Set Length, Select Info, Read Info) as "reading a section (or the whole) file". The fact is "Name", "IC no." etc are stored in fixed-length fields (padded on the right), and concatenated together (without separator) to form files.
For example,
"Name" stored in file jpn-1-1, offset 0x00E9, length 0x28
"IC no." stored in file jpn-1-1, offset 0x0111, length 0x0D
When you want to read "Name", you read jpn-1-1, offset 0x00E9, length 0x28.
When you want to read "IC no.", you read jpn-1-1, offset 0x0111, length 0x0D.
When you want to read both "Name" and "IC no.", you read jpn-1-1, offset 0x00E9, length 0x35.
Conversely, you can read only part of the field; if you want only first 6 digits of "IC no.", read jpn-1-1, offset 0x111, length 6.
Now, the first 2 commands, "Select Application" and "Get Response", are used to select either one of JPN, JPJ, IMM appplication. (Actually you can have 2 active at the same time by using logical channels, but that's a little bit advanced at this stage.) You must select an application after reset, and you'll do it only once except you want to change application.
Reader: 00 A4 04 00 0A A0 00 00 00 74
4A 50 4E 00 10 (Send 10 bytes data, expect receive 0 bytes)
Card : 61 05
Reader: 00 C0 00 00 05 (Send 0 bytes data, expect receive 5 bytes)
Card : 6F 03 82 01 38 90 00
"00 A4 04 00 0A" is the "CLA INS P1 P2 P3" for "Select Application". The data part of the APDU consists of 10 bytes: "A0 00 00 00 74 4A 50 4E 00 10". The "A0 00 00 00 74" and "00 10" parts are constant. "
4A 50 4E" represents "JPN". Change to "JPJ" or "IMM" for those applications.
"00 C0 00 00 05" is the "CLA INS P1 P2 P3" for "Get Response". The 5 data bytes received is not significant, but you can verify whether it is successful.
That's the end of description of "Select Application" and "Get Response". Now move on to the 3 commands to read a section of file.
Example: read jpn-1-1, offset 0x00E9, length 0x28.
Reader: C8 32 00 00 05 08 00 00
28 00Card : 91 08
Reader: CC 00 00 00 08
01 00 01 00 E9 00 28 00Card : 94
28Reader: CC 06 00 00
28Card :
4D 59 20 4E 41 4D 45 20 20 20 20... 90 00
The 3 commands "Set Length", "Select Info", and "Read Info" are shown above. The colored parts are those which varies.
It seems from above that the maximum length will be 0xFF, so you'll have to break long file section (particularly when reading JPEG) into multiple reads (repeat the 3 commands with different length and offset). But actually, for advanced users, you can specify a length >= 0x0100, (provided you don't read past the end of file which results in no bytes returned,) in the "Set Length" and "Select Info". You only need multiple "Read Info", with the single byte length set to big a number (eg. 0xFF or 0xFC), except the last read. "Read Info" is just like retrieving out from a FIFO buffer, you can read however you want, but don't over-read it.
To read jpn-1-4, replace
01 00 01 00 to
04 00 01 00.
Those double byte "Offset" and "Length" are in little endian.
Tables
» Click to show Spoiler - click again to hide... «
CODE
jpn-1-1
Offset Length Length SDK Function Name Description
(Hex) (Dec)
0000 03 3 01 04 24
0003 96 150 JPN_OrgName original name
0099 50 30+30+20 JPN_GMPCName GMPC name
00E9 28 20+20 JPN_KPTName KPT name
0111 0D 13 JPN_IDNum ID number
011E 01 1 JPN_Gender gender
011F 08 8 JPN_OldIDNum old ID number
0127 04 4 JPN_BirthDate date of birth
012B 19 25 JPN_BirthPlace place of birth
0144 04 4 JPN_DateIssued date issued
0148 12 18 JPN_Citizenship citizenship
015A 19 25 JPN_Race race
0173 0B 11 JPN_Religion religion
017E 01 1 JPN_EastMalaysian East Malaysian
017F 02 2 JPN_RJ RJ?
0181 02 2 JPN_KT KT?
0183 0B 11 JPN_OtherID other ID
018E 01 1 JPN_Category category
018F 01 1 JPN_CardVer card version
0190 04 4 JPN_GreenCardExpiry green card expiry date
0194 14 20 JPN_GreenCardNationality green card nationality
01A8 23 35 All 00
jpn-1-2
0000 03 3 01 40 03
0003 FA0 4000 JPN_Photo JPEG photo
0FA3 08 8 All 00
jpn-1-3
0000 03 3 01 12 03
0003 14 20 "R1L1",0,0...
0017 256 598 JPN_Thumb1 thumprint 1 (right thumb)
026D 256 598 JPN_Thumb2 thumprint 2 (left thumb)
04C3 08 8 All 00
jpn-1-4
0000 03 3 01 01 52
0003 1E 30 JPN_Address1 address line 1
0021 1E 30 JPN_Address2 address line 2
003F 1E 30 JPN_Address3 address line 3
005D 03 3 JPN_Postcode postcode
0060 19 25 JPN_City city
0079 1E 30 JPN_State state
0097 14 20 FF 00 00...
jpn-1-5
0000 03 3 01 12 00
0003 09 9 JPN_SocsoNum socso number
000C 1F 31 All 00
jpn-1-6
0000 03 3 01 17 00
0003 0A 10 JPN_Locality locality
000D 1E 30 All 00
» Click to show Spoiler - click again to hide... «
CODE
jpj-1-1
Offset Length Length SDK Function Name Description
(Hex) (Dec)
0000 03 3 01 04 16
0003 01 1 JPJ_OwnerCategory owner category
0004 0C 12 JPJ_LicenseType licence type
0010 1E 30 JPJ_VehicleClass vehicle class
002E 06 6 JPJ_PSVUsage PSV usage
0034 96 150 JPJ_PSVDesc PSV description
00CA 06 6 JPJ_GDLUsage GDL usage
00D0 96 150 JPJ_GDLDesc GDL description
0166 20 32 JPJ_ValidityPeriod validity period
0186 14 20 JPJ_HandicappedReg handicapped registration
019A 01 1 JPJ_KejaraPoints kejara points
019B 01 1 JPJ_SuspensionNum suspension number
019C 04 4 JPJ_LastKejaraUpdate last kejara update
01A0 0B 11 All 00
» Click to show Spoiler - click again to hide... «
CODE
imm-1-1
0000 03 3 01 22 00
0003 0C 12 IMM_PMAPassportNum PMA passport number
000F 03 3 IMM_PMADocType PMA document type
0012 04 4 IMM_PMAExpiryDate PMA expiry date
0016 15 21 All 00
imm-1-2
0000 03 3 01 22 00
0003 0C 12 IMM_PMTSporePassportNum PMT S'pore passport no
000F 03 3 IMM_PMTSporeDocType PMT S'pore doc type
0012 04 4 IMM_PMTSporeExpiryDate PMT S'pore expiry date
0016 15 21 All 00
imm-1-3
0000 03 3 01 22 00
0003 0C 12 IMM_PMTBruneiPassportNum PMT Brunei passport no
000F 03 3 IMM_PMTBruneiDocType PMT Brunei doc type
0012 04 4 IMM_PMTBruneiExpiryDate PMT Brunei expiry date
0016 15 21 All 00
imm-1-4
0000 03 3 01 22 00
0003 0C 12 IMM_PMTResvPassportNum PMT Resv passport no
000F 03 3 IMM_PMTResvDocType PMT Resv doc type
0012 04 4 IMM_PMTResvExpiryDate PMT Resv expiry date
0016 15 21 All 00
Data types
» Click to show Spoiler - click again to hide... «
CODE
SDK Function Name Data type Data when unused (hex)
JPN_OrgName string
JPN_GMPCName stringM
JPN_KPTName stringM
JPN_IDNum string
JPN_Gender 'L' or 'P'
JPN_OldIDNum string
JPN_BirthDate date
JPN_BirthPlace string
JPN_DateIssued date
JPN_Citizenship string
JPN_Race string
JPN_Religion string
JPN_EastMalaysian ' ' or ? 20
JPN_RJ ? 20 20
JPN_KT ? 20 20
JPN_OtherID string spaces
JPN_Category ? 20
JPN_CardVer 02?
JPN_GreenCardExpiry date 00 00 00 00
JPN_GreenCardNationality string spaces
JPN_Photo JPEG
JPN_Thumb1 thumbprint
JPN_Thumb2 thumbprint
JPN_Address1 string
JPN_Address2 string spaces
JPN_Address3 string spaces
JPN_Postcode postcode
JPN_City string
JPN_State string
JPN_SocsoNum string spaces
JPN_Locality string spaces
JPJ_OwnerCategory '1' or others
JPJ_LicenseType 3 char codes spaces
JPJ_VehicleClass 3 char codes spaces
JPJ_PSVUsage string spaces
JPJ_PSVDesc string spaces
JPJ_GDLUsage string spaces
JPJ_GDLDesc string spaces
JPJ_ValidityPeriod dates zeros
JPJ_HandicappedReg string spaces
JPJ_KejaraPoints ? 00
JPJ_SuspensionNum ? 00
JPJ_LastKejaraUpdate date 00 00 00 00
IMM_PMAPassportNum string spaces
IMM_PMADocType 3 char code spaces
IMM_PMAExpiryDate date 00 00 00 00
IMM_PMTSporePassportNum string spaces
IMM_PMTSporeDocType 3 char code spaces
IMM_PMTSporeExpiryDate date 00 00 00 00
IMM_PMTBruneiPassportNum string spaces
IMM_PMTBruneiDocType 3 char code spaces
IMM_PMTBruneiExpiryDate date 00 00 00 00
IMM_PMTResvPassportNum string spaces
IMM_PMTResvDocType 3 char code spaces
IMM_PMTResvExpiryDate date 00 00 00 00
Types:
string
ANSI/ASCII code character string, not null terminated, space (0x20) padded
stringM
ANSI/ASCII code character string, not null terminated
multi-line, each line is space (0x20) padded
Example name: Lee Kee Lim @ Lee Key Lim
is coded as
"Lee Kee Lim @ "
"Lee Key Lim "
which is
4C 65 65 20 4B 65 65 20 4C 69 6D 20 20 20 20 20
20 20 20 20 4C 65 65 20 4B 65 79 20 4C 69 6D 20
20 20 20 20 20 20 20 20
date
Four byte, packed BCD, yy yy mm dd
20 01 05 30 (hex) = 30 May 2001
postcode
3 byte, packed BCD
12 34 50 (hex) = 12345
3 char codes (JPJ_LicenseType)
Four fields of 3-character codes concatenated.
Unused positions are filled with " " (3 spaces).
"PDL" Learner's Licence
"PRB" Probationary (P) Licence
"CDL" Competence Driving Licence
3 char codes (JPJ_VehicleClass)
Four fields of 3-character codes concatenated.
Unused positions are filled with " " (3 spaces).
"1D " Class D, cars
dates (JPJ_ValidityPeriod)
Four pairs {Begin, Expire} of date.
Unused positions are filled with zeros.
3 char code (IMM_*DocType)
Unknown
awesome, thanks for the table. Really help me alot on my project