Skip to content

Instantly share code, notes, and snippets.

@harayz
Created December 22, 2016 04:50
Show Gist options
  • Save harayz/62e7cce417659d151166bdff5c054ae9 to your computer and use it in GitHub Desktop.
Save harayz/62e7cce417659d151166bdff5c054ae9 to your computer and use it in GitHub Desktop.

Source: http://forum.lowyat.net/index.php?showtopic=355950&view=findpost&p=11151482

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:

  • Select Application
  • Get Response
  • Set Length
  • Select Info
  • 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 00
Card : 91 08
Reader: CC 00 00 00 08 01 00 01 00 E9 00 28 00
Card : 94 28
Reader: CC 06 00 00 28
Card : 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:

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

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

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

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment