Skip to content

Instantly share code, notes, and snippets.

@kangfend
Forked from bouroo/thai-id-card.py
Created October 19, 2018 08:12
Show Gist options
  • Save kangfend/e028aef791d9482463c7ee776c91b822 to your computer and use it in GitHub Desktop.
Save kangfend/e028aef791d9482463c7ee776c91b822 to your computer and use it in GitHub Desktop.

Revisions

  1. @bouroo bouroo revised this gist Sep 27, 2018. 1 changed file with 10 additions and 5 deletions.
    15 changes: 10 additions & 5 deletions thai-id-card.py
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    #!/usr/bin/env python
    #!/usr/bin/env python3
    # bouroo
    # 27.09.2018
    # sudo apt-get -y install pcscd python-pyscard python-pil
    @@ -122,11 +122,16 @@ def getData(cmd, req = [0x00, 0xc0, 0x00, 0x00]):
    # Photo_Part20/20
    CMD_PHOTO20 = [0x80, 0xb0, 0x14, 0x68, 0x02, 0x00, 0xFF]

    # get all the available readers
    r = readers()
    print "Available readers:", r
    # Get all the available readers
    readerList = readers()
    print "Available readers:"
    for readerIndex,readerItem in enumerate(readerList):
    print(readerIndex, readerItem)

    reader = r[0]
    # Select reader
    readerSelectIndex = int(input("Select reader[0]: ") or "0")

    reader = readerList[readerSelectIndex]
    print "Using:", reader

    connection = reader.createConnection()
  2. @bouroo bouroo revised this gist Sep 27, 2018. 1 changed file with 11 additions and 7 deletions.
    18 changes: 11 additions & 7 deletions thai-id-card.py
    Original file line number Diff line number Diff line change
    @@ -1,12 +1,13 @@
    #!/usr/bin/env python
    # bouroo
    # 18.08.2017
    # sudo apt-get -y install pcscd python-pyscard python-imaging
    # 27.09.2018
    # sudo apt-get -y install pcscd python-pyscard python-pil

    import os
    import io
    import Image
    import binascii
    import io
    import os
    import sys
    from PIL import Image
    from smartcard.System import readers
    from smartcard.util import HexListToBinString, toHexString, toBytes

    @@ -21,7 +22,7 @@ def thai2unicode(data):
    else :
    result = data.decode("tis-620").encode("utf-8")
    return result.strip();

    def getData(cmd, req = [0x00, 0xc0, 0x00, 0x00]):
    data, sw1, sw2 = connection.transmit(cmd)
    data, sw1, sw2 = connection.transmit(req + [cmd[-1]])
    @@ -202,4 +203,7 @@ def getData(cmd, req = [0x00, 0xc0, 0x00, 0x00]):
    data = HexListToBinString(photo)
    f = open(cid + ".jpg", "wb")
    f.write(data)
    f.close
    f.close

    # Exit program
    sys.exit()
  3. @bouroo bouroo revised this gist Aug 18, 2017. No changes.
  4. @bouroo bouroo revised this gist Aug 18, 2017. 1 changed file with 4 additions and 3 deletions.
    7 changes: 4 additions & 3 deletions thai-id-card.py
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    #!/usr/bin/env python
    # bouroo
    # 17.07.2017
    # 18.08.2017
    # sudo apt-get -y install pcscd python-pyscard python-imaging

    import os
    @@ -143,7 +143,8 @@ def getData(cmd, req = [0x00, 0xc0, 0x00, 0x00]):

    # CID
    data = getData(CMD_CID, req)
    print "CID: " + thai2unicode(data[0])
    cid = thai2unicode(data[0])
    print "CID: " + cid

    # TH Fullname
    data = getData(CMD_THFULLNAME, req)
    @@ -199,6 +200,6 @@ def getData(cmd, req = [0x00, 0xc0, 0x00, 0x00]):
    photo += getData(CMD_PHOTO19, req)[0]
    photo += getData(CMD_PHOTO20, req)[0]
    data = HexListToBinString(photo)
    f = open('test.jpg', 'wb')
    f = open(cid + ".jpg", "wb")
    f.write(data)
    f.close
  5. @bouroo bouroo revised this gist Aug 18, 2017. 1 changed file with 40 additions and 11 deletions.
    51 changes: 40 additions & 11 deletions thai-id-card.py
    Original file line number Diff line number Diff line change
    @@ -8,6 +8,7 @@
    import Image
    import binascii
    from smartcard.System import readers
    from smartcard.util import HexListToBinString, toHexString, toBytes

    # Thailand ID Smartcard

    @@ -129,47 +130,75 @@ def getData(cmd, req = [0x00, 0xc0, 0x00, 0x00]):

    connection = reader.createConnection()
    connection.connect()
    atr = connection.getATR()
    print "ATR: " + toHexString(atr)
    if (atr[0] == 0x3B & atr[1] == 0x67):
    req = [0x00, 0xc0, 0x00, 0x01]
    else :
    req = [0x00, 0xc0, 0x00, 0x00]

    # Check card
    data, sw1, sw2 = connection.transmit(SELECT + THAI_CARD)
    print "Select Applet: %02X %02X" % (sw1, sw2)

    # CID
    data = getData(CMD_CID)
    data = getData(CMD_CID, req)
    print "CID: " + thai2unicode(data[0])

    # TH Fullname
    data = getData(CMD_THFULLNAME)
    data = getData(CMD_THFULLNAME, req)
    print "TH Fullname: " + thai2unicode(data[0])

    # EN Fullname
    data = getData(CMD_ENFULLNAME)
    data = getData(CMD_ENFULLNAME, req)
    print "EN Fullname: " + thai2unicode(data[0])

    # Date of birth
    data = getData(CMD_BIRTH)
    data = getData(CMD_BIRTH, req)
    print "Date of birth: " + thai2unicode(data[0])

    # Gender
    data = getData(CMD_GENDER)
    data = getData(CMD_GENDER, req)
    print "Gender: " + thai2unicode(data[0])

    # Card Issuer
    data = getData(CMD_ISSUER)
    data = getData(CMD_ISSUER, req)
    print "Card Issuer: " + thai2unicode(data[0])

    # Issue Date
    data = getData(CMD_ISSUE)
    data = getData(CMD_ISSUE, req)
    print "Issue Date: " + thai2unicode(data[0])

    # Expire Date
    data = getData(CMD_EXPIRE)
    data = getData(CMD_EXPIRE, req)
    print "Expire Date: " + thai2unicode(data[0])

    # Address
    data = getData(CMD_ADDRESS)
    data = getData(CMD_ADDRESS, req)
    print "Address: " + thai2unicode(data[0])

    # PHOTO
    data = getData(CMD_PHOTO1)
    print data[0]
    photo = getData(CMD_PHOTO1, req)[0]
    photo += getData(CMD_PHOTO2, req)[0]
    photo += getData(CMD_PHOTO3, req)[0]
    photo += getData(CMD_PHOTO4, req)[0]
    photo += getData(CMD_PHOTO5, req)[0]
    photo += getData(CMD_PHOTO6, req)[0]
    photo += getData(CMD_PHOTO7, req)[0]
    photo += getData(CMD_PHOTO8, req)[0]
    photo += getData(CMD_PHOTO9, req)[0]
    photo += getData(CMD_PHOTO10, req)[0]
    photo += getData(CMD_PHOTO11, req)[0]
    photo += getData(CMD_PHOTO12, req)[0]
    photo += getData(CMD_PHOTO13, req)[0]
    photo += getData(CMD_PHOTO14, req)[0]
    photo += getData(CMD_PHOTO15, req)[0]
    photo += getData(CMD_PHOTO16, req)[0]
    photo += getData(CMD_PHOTO17, req)[0]
    photo += getData(CMD_PHOTO18, req)[0]
    photo += getData(CMD_PHOTO19, req)[0]
    photo += getData(CMD_PHOTO20, req)[0]
    data = HexListToBinString(photo)
    f = open('test.jpg', 'wb')
    f.write(data)
    f.close
  6. @bouroo bouroo revised this gist Jul 17, 2017. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions thai-id-card.py
    Original file line number Diff line number Diff line change
    @@ -29,7 +29,7 @@ def getData(cmd, req = [0x00, 0xc0, 0x00, 0x00]):
    # define the APDUs used in this script
    # https://github.com/chakphanu/ThaiNationalIDCard/blob/master/APDU.md

    # Reset
    # Check card
    SELECT = [0x00, 0xA4, 0x04, 0x00, 0x08]
    THAI_CARD = [0xA0, 0x00, 0x00, 0x00, 0x54, 0x48, 0x00, 0x01]

    @@ -130,7 +130,7 @@ def getData(cmd, req = [0x00, 0xc0, 0x00, 0x00]):
    connection = reader.createConnection()
    connection.connect()

    # Reset
    # Check card
    data, sw1, sw2 = connection.transmit(SELECT + THAI_CARD)
    print "Select Applet: %02X %02X" % (sw1, sw2)

    @@ -172,4 +172,4 @@ def getData(cmd, req = [0x00, 0xc0, 0x00, 0x00]):

    # PHOTO
    data = getData(CMD_PHOTO1)
    print data[0]
    print data[0]
  7. @bouroo bouroo revised this gist Jul 17, 2017. 1 changed file with 24 additions and 34 deletions.
    58 changes: 24 additions & 34 deletions thai-id-card.py
    Original file line number Diff line number Diff line change
    @@ -21,17 +21,17 @@ def thai2unicode(data):
    result = data.decode("tis-620").encode("utf-8")
    return result.strip();

    def getCID():

    return;
    def getData(cmd, req = [0x00, 0xc0, 0x00, 0x00]):
    data, sw1, sw2 = connection.transmit(cmd)
    data, sw1, sw2 = connection.transmit(req + [cmd[-1]])
    return [data, sw1, sw2];

    # define the APDUs used in this script
    # https://github.com/chakphanu/ThaiNationalIDCard/blob/master/APDU.md

    # Reset
    SELECT = [0x00, 0xA4, 0x04, 0x00, 0x08]
    THAI_CARD = [0xA0, 0x00, 0x00, 0x00, 0x54, 0x48, 0x00, 0x01]
    GET_CMD = [0x00, 0xc0, 0x00, 0x00]

    # CID
    CMD_CID = [0x80, 0xb0, 0x00, 0x04, 0x02, 0x00, 0x0d]
    @@ -135,51 +135,41 @@ def getCID():
    print "Select Applet: %02X %02X" % (sw1, sw2)

    # CID
    data, sw1, sw2 = connection.transmit(CMD_CID)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_CID[-1]])
    print "CID: " + thai2unicode(data)
    data = getData(CMD_CID)
    print "CID: " + thai2unicode(data[0])

    # TH Fullname
    data, sw1, sw2 = connection.transmit(CMD_THFULLNAME)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_THFULLNAME[-1]])
    print "TH Fullname: " + thai2unicode(data)
    data = getData(CMD_THFULLNAME)
    print "TH Fullname: " + thai2unicode(data[0])

    # EN Fullname
    data, sw1, sw2 = connection.transmit(CMD_ENFULLNAME)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_ENFULLNAME[-1]])
    print "EN Fullname: " + thai2unicode(data)
    data = getData(CMD_ENFULLNAME)
    print "EN Fullname: " + thai2unicode(data[0])

    # Date of birth
    data, sw1, sw2 = connection.transmit(CMD_BIRTH)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_BIRTH[-1]])
    print "Date of birth: " + thai2unicode(data)
    data = getData(CMD_BIRTH)
    print "Date of birth: " + thai2unicode(data[0])

    # Gender
    data, sw1, sw2 = connection.transmit(CMD_GENDER)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_GENDER[-1]])
    print "Gender: " + thai2unicode(data)
    data = getData(CMD_GENDER)
    print "Gender: " + thai2unicode(data[0])

    # Card Issuer
    data, sw1, sw2 = connection.transmit(CMD_ISSUER)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_ISSUER[-1]])
    print "Card Issuer: " + thai2unicode(data)
    data = getData(CMD_ISSUER)
    print "Card Issuer: " + thai2unicode(data[0])

    # Issue Date
    data, sw1, sw2 = connection.transmit(CMD_ISSUE)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_ISSUE[-1]])
    print "Issue Date: " + thai2unicode(data)
    data = getData(CMD_ISSUE)
    print "Issue Date: " + thai2unicode(data[0])

    # Expire Date
    data, sw1, sw2 = connection.transmit(CMD_EXPIRE)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_EXPIRE[-1]])
    print "Expire Date: " + thai2unicode(data)
    data = getData(CMD_EXPIRE)
    print "Expire Date: " + thai2unicode(data[0])

    # Address
    data, sw1, sw2 = connection.transmit(CMD_ADDRESS)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_ADDRESS[-1]])
    print "Address: " + thai2unicode(data)
    data = getData(CMD_ADDRESS)
    print "Address: " + thai2unicode(data[0])

    # PHOTO
    data, sw1, sw2 = connection.transmit(CMD_PHOTO1)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_PHOTO1[-1]])
    print data
    data = getData(CMD_PHOTO1)
    print data[0]
  8. @bouroo bouroo revised this gist Jul 17, 2017. 1 changed file with 18 additions and 42 deletions.
    60 changes: 18 additions & 42 deletions thai-id-card.py
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,13 @@
    #!/usr/bin/env python
    # bouroo
    # 17.07.2017
    # apt-get install pcscd python-pyscard
    # sudo apt-get -y install pcscd python-pyscard python-imaging

    import os
    import io
    #import Image
    from smartcard.System import readers
    import Image
    import binascii
    from smartcard.System import readers

    # Thailand ID Smartcard

    @@ -20,129 +20,105 @@ def thai2unicode(data):
    else :
    result = data.decode("tis-620").encode("utf-8")
    return result.strip();

    def getCID():

    return;

    # define the APDUs used in this script
    # https://github.com/chakphanu/ThaiNationalIDCard/blob/master/APDU.md

    # Reset
    SELECT = [0x00, 0xA4, 0x04, 0x00, 0x08]
    THAI_CARD = [0xA0, 0x00, 0x00, 0x00, 0x54, 0x48, 0x00, 0x01]
    GET_CMD = [0x00, 0xc0, 0x00, 0x00]

    # CID
    CMD_CID = [0x80, 0xb0, 0x00, 0x04, 0x02, 0x00, 0x0d]
    GET_CID = [0x00, 0xc0, 0x00, 0x00, 0x0d]

    # TH Fullname
    CMD_THFULLNAME = [0x80, 0xb0, 0x00, 0x11, 0x02, 0x00, 0x64]
    GET_THFULLNAME = [0x00, 0xc0, 0x00, 0x00, 0x64]

    # EN Fullname
    CMD_ENFULLNAME = [0x80, 0xb0, 0x00, 0x75, 0x02, 0x00, 0x64]
    GET_ENFULLNAME = [0x00, 0xc0, 0x00, 0x00, 0x64]

    # Date of birth
    CMD_BIRTH = [0x80, 0xb0, 0x00, 0xD9, 0x02, 0x00, 0x08]
    GET_BIRTH = [0x00, 0xc0, 0x00, 0x00, 0x08]

    # Gender
    CMD_GENDER = [0x80, 0xb0, 0x00, 0xE1, 0x02, 0x00, 0x01]
    GET_GENDER = [0x00, 0xc0, 0x00, 0x00, 0x01]

    # Card Issuer
    CMD_ISSUER = [0x80, 0xb0, 0x00, 0xF6, 0x02, 0x00, 0x64]
    GET_ISSUER = [0x00, 0xc0, 0x00, 0x00, 0x64]

    # Issue Date
    CMD_ISSUE = [0x80, 0xb0, 0x01, 0x67, 0x02, 0x00, 0x08]
    GET_ISSUE = [0x00, 0xc0, 0x00, 0x00, 0x08]

    # Expire Date
    CMD_EXPIRE = [0x80, 0xb0, 0x01, 0x6F, 0x02, 0x00, 0x08]
    GET_EXPIRE = [0x00, 0xc0, 0x00, 0x00, 0x08]

    # Address
    CMD_ADDRESS = [0x80, 0xb0, 0x15, 0x79, 0x02, 0x00, 0x64]
    GET_ADDRESS = [0x00, 0xc0, 0x00, 0x00, 0x64]

    # Photo_Part1/20
    CMD_PHOTO1 = [0x80, 0xb0, 0x01, 0x7B, 0x02, 0x00, 0xFF]
    GET_PHOTP1 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part2/20
    CMD_PHOTO2 = [0x80, 0xb0, 0x02, 0x7A, 0x02, 0x00, 0xFF]
    GET_PHOTP2 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part3/20
    CMD_PHOTO3 = [0x80, 0xb0, 0x03, 0x79, 0x02, 0x00, 0xFF]
    GET_PHOTP3 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part4/20
    CMD_PHOTO4 = [0x80, 0xb0, 0x04, 0x78, 0x02, 0x00, 0xFF]
    GET_PHOTP4 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part5/20
    CMD_PHOTO5 = [0x80, 0xb0, 0x05, 0x77, 0x02, 0x00, 0xFF]
    GET_PHOTP5 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part6/20
    CMD_PHOTO6 = [0x80, 0xb0, 0x06, 0x76, 0x02, 0x00, 0xFF]
    GET_PHOTP6 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part7/20
    CMD_PHOTO7 = [0x80, 0xb0, 0x07, 0x75, 0x02, 0x00, 0xFF]
    GET_PHOTP7 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part8/20
    CMD_PHOTO8 = [0x80, 0xb0, 0x08, 0x74, 0x02, 0x00, 0xFF]
    GET_PHOTP8 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part9/20
    CMD_PHOTO9 = [0x80, 0xb0, 0x09, 0x73, 0x02, 0x00, 0xFF]
    GET_PHOTP9 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part10/20
    CMD_PHOTO10 = [0x80, 0xb0, 0x0A, 0x72, 0x02, 0x00, 0xFF]
    GET_PHOTP10 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part11/20
    CMD_PHOTO11 = [0x80, 0xb0, 0x0B, 0x71, 0x02, 0x00, 0xFF]
    GET_PHOTP11 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part12/20
    CMD_PHOTO12 = [0x80, 0xb0, 0x0C, 0x70, 0x02, 0x00, 0xFF]
    GET_PHOTP12 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part13/20
    CMD_PHOTO13 = [0x80, 0xb0, 0x0D, 0x6F, 0x02, 0x00, 0xFF]
    GET_PHOTP13 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part14/20
    CMD_PHOTO14 = [0x80, 0xb0, 0x0E, 0x6E, 0x02, 0x00, 0xFF]
    GET_PHOTP14 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part15/20
    CMD_PHOTO15 = [0x80, 0xb0, 0x0F, 0x6D, 0x02, 0x00, 0xFF]
    GET_PHOTP15 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part16/20
    CMD_PHOTO16 = [0x80, 0xb0, 0x10, 0x6C, 0x02, 0x00, 0xFF]
    GET_PHOTP16 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part17/20
    CMD_PHOTO17 = [0x80, 0xb0, 0x11, 0x6B, 0x02, 0x00, 0xFF]
    GET_PHOTP17 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part18/20
    CMD_PHOTO18 = [0x80, 0xb0, 0x12, 0x6A, 0x02, 0x00, 0xFF]
    GET_PHOTP18 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part19/20
    CMD_PHOTO19 = [0x80, 0xb0, 0x13, 0x69, 0x02, 0x00, 0xFF]
    GET_PHOTP19 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part20/20
    CMD_PHOTO20 = [0x80, 0xb0, 0x14, 0x68, 0x02, 0x00, 0xFF]
    GET_PHOTP20 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # get all the available readers
    r = readers()
    @@ -160,50 +136,50 @@ def thai2unicode(data):

    # CID
    data, sw1, sw2 = connection.transmit(CMD_CID)
    data, sw1, sw2 = connection.transmit(GET_CID)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_CID[-1]])
    print "CID: " + thai2unicode(data)

    # TH Fullname
    data, sw1, sw2 = connection.transmit(CMD_THFULLNAME)
    data, sw1, sw2 = connection.transmit(GET_THFULLNAME)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_THFULLNAME[-1]])
    print "TH Fullname: " + thai2unicode(data)

    # EN Fullname
    data, sw1, sw2 = connection.transmit(CMD_ENFULLNAME)
    data, sw1, sw2 = connection.transmit(GET_ENFULLNAME)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_ENFULLNAME[-1]])
    print "EN Fullname: " + thai2unicode(data)

    # Date of birth
    data, sw1, sw2 = connection.transmit(CMD_BIRTH)
    data, sw1, sw2 = connection.transmit(GET_BIRTH)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_BIRTH[-1]])
    print "Date of birth: " + thai2unicode(data)

    # Gender
    data, sw1, sw2 = connection.transmit(CMD_GENDER)
    data, sw1, sw2 = connection.transmit(GET_GENDER)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_GENDER[-1]])
    print "Gender: " + thai2unicode(data)

    # Card Issuer
    data, sw1, sw2 = connection.transmit(CMD_ISSUER)
    data, sw1, sw2 = connection.transmit(GET_ISSUER)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_ISSUER[-1]])
    print "Card Issuer: " + thai2unicode(data)

    # Issue Date
    data, sw1, sw2 = connection.transmit(CMD_ISSUE)
    data, sw1, sw2 = connection.transmit(GET_ISSUE)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_ISSUE[-1]])
    print "Issue Date: " + thai2unicode(data)

    # Expire Date
    data, sw1, sw2 = connection.transmit(CMD_EXPIRE)
    data, sw1, sw2 = connection.transmit(GET_EXPIRE)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_EXPIRE[-1]])
    print "Expire Date: " + thai2unicode(data)

    # Address
    data, sw1, sw2 = connection.transmit(CMD_ADDRESS)
    data, sw1, sw2 = connection.transmit(GET_ADDRESS)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_ADDRESS[-1]])
    print "Address: " + thai2unicode(data)

    # PHOTO
    data, sw1, sw2 = connection.transmit(CMD_PHOTO1)
    data, sw1, sw2 = connection.transmit(GET_PHOTP1)
    data, sw1, sw2 = connection.transmit(GET_CMD + [CMD_PHOTO1[-1]])
    print data
  9. @bouroo bouroo created this gist Jul 17, 2017.
    209 changes: 209 additions & 0 deletions thai-id-card.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,209 @@
    #!/usr/bin/env python
    # bouroo
    # 17.07.2017
    # apt-get install pcscd python-pyscard

    import os
    import io
    #import Image
    from smartcard.System import readers
    import binascii

    # Thailand ID Smartcard

    # tis-620 to utf-8
    def thai2unicode(data):
    result = ''
    if isinstance(data, list):
    for d in data:
    result += unicode(chr(d),"tis-620")
    else :
    result = data.decode("tis-620").encode("utf-8")
    return result.strip();

    # define the APDUs used in this script
    # https://github.com/chakphanu/ThaiNationalIDCard/blob/master/APDU.md

    # Reset
    SELECT = [0x00, 0xA4, 0x04, 0x00, 0x08]
    THAI_CARD = [0xA0, 0x00, 0x00, 0x00, 0x54, 0x48, 0x00, 0x01]

    # CID
    CMD_CID = [0x80, 0xb0, 0x00, 0x04, 0x02, 0x00, 0x0d]
    GET_CID = [0x00, 0xc0, 0x00, 0x00, 0x0d]

    # TH Fullname
    CMD_THFULLNAME = [0x80, 0xb0, 0x00, 0x11, 0x02, 0x00, 0x64]
    GET_THFULLNAME = [0x00, 0xc0, 0x00, 0x00, 0x64]

    # EN Fullname
    CMD_ENFULLNAME = [0x80, 0xb0, 0x00, 0x75, 0x02, 0x00, 0x64]
    GET_ENFULLNAME = [0x00, 0xc0, 0x00, 0x00, 0x64]

    # Date of birth
    CMD_BIRTH = [0x80, 0xb0, 0x00, 0xD9, 0x02, 0x00, 0x08]
    GET_BIRTH = [0x00, 0xc0, 0x00, 0x00, 0x08]

    # Gender
    CMD_GENDER = [0x80, 0xb0, 0x00, 0xE1, 0x02, 0x00, 0x01]
    GET_GENDER = [0x00, 0xc0, 0x00, 0x00, 0x01]

    # Card Issuer
    CMD_ISSUER = [0x80, 0xb0, 0x00, 0xF6, 0x02, 0x00, 0x64]
    GET_ISSUER = [0x00, 0xc0, 0x00, 0x00, 0x64]

    # Issue Date
    CMD_ISSUE = [0x80, 0xb0, 0x01, 0x67, 0x02, 0x00, 0x08]
    GET_ISSUE = [0x00, 0xc0, 0x00, 0x00, 0x08]

    # Expire Date
    CMD_EXPIRE = [0x80, 0xb0, 0x01, 0x6F, 0x02, 0x00, 0x08]
    GET_EXPIRE = [0x00, 0xc0, 0x00, 0x00, 0x08]

    # Address
    CMD_ADDRESS = [0x80, 0xb0, 0x15, 0x79, 0x02, 0x00, 0x64]
    GET_ADDRESS = [0x00, 0xc0, 0x00, 0x00, 0x64]

    # Photo_Part1/20
    CMD_PHOTO1 = [0x80, 0xb0, 0x01, 0x7B, 0x02, 0x00, 0xFF]
    GET_PHOTP1 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part2/20
    CMD_PHOTO2 = [0x80, 0xb0, 0x02, 0x7A, 0x02, 0x00, 0xFF]
    GET_PHOTP2 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part3/20
    CMD_PHOTO3 = [0x80, 0xb0, 0x03, 0x79, 0x02, 0x00, 0xFF]
    GET_PHOTP3 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part4/20
    CMD_PHOTO4 = [0x80, 0xb0, 0x04, 0x78, 0x02, 0x00, 0xFF]
    GET_PHOTP4 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part5/20
    CMD_PHOTO5 = [0x80, 0xb0, 0x05, 0x77, 0x02, 0x00, 0xFF]
    GET_PHOTP5 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part6/20
    CMD_PHOTO6 = [0x80, 0xb0, 0x06, 0x76, 0x02, 0x00, 0xFF]
    GET_PHOTP6 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part7/20
    CMD_PHOTO7 = [0x80, 0xb0, 0x07, 0x75, 0x02, 0x00, 0xFF]
    GET_PHOTP7 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part8/20
    CMD_PHOTO8 = [0x80, 0xb0, 0x08, 0x74, 0x02, 0x00, 0xFF]
    GET_PHOTP8 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part9/20
    CMD_PHOTO9 = [0x80, 0xb0, 0x09, 0x73, 0x02, 0x00, 0xFF]
    GET_PHOTP9 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part10/20
    CMD_PHOTO10 = [0x80, 0xb0, 0x0A, 0x72, 0x02, 0x00, 0xFF]
    GET_PHOTP10 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part11/20
    CMD_PHOTO11 = [0x80, 0xb0, 0x0B, 0x71, 0x02, 0x00, 0xFF]
    GET_PHOTP11 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part12/20
    CMD_PHOTO12 = [0x80, 0xb0, 0x0C, 0x70, 0x02, 0x00, 0xFF]
    GET_PHOTP12 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part13/20
    CMD_PHOTO13 = [0x80, 0xb0, 0x0D, 0x6F, 0x02, 0x00, 0xFF]
    GET_PHOTP13 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part14/20
    CMD_PHOTO14 = [0x80, 0xb0, 0x0E, 0x6E, 0x02, 0x00, 0xFF]
    GET_PHOTP14 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part15/20
    CMD_PHOTO15 = [0x80, 0xb0, 0x0F, 0x6D, 0x02, 0x00, 0xFF]
    GET_PHOTP15 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part16/20
    CMD_PHOTO16 = [0x80, 0xb0, 0x10, 0x6C, 0x02, 0x00, 0xFF]
    GET_PHOTP16 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part17/20
    CMD_PHOTO17 = [0x80, 0xb0, 0x11, 0x6B, 0x02, 0x00, 0xFF]
    GET_PHOTP17 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part18/20
    CMD_PHOTO18 = [0x80, 0xb0, 0x12, 0x6A, 0x02, 0x00, 0xFF]
    GET_PHOTP18 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part19/20
    CMD_PHOTO19 = [0x80, 0xb0, 0x13, 0x69, 0x02, 0x00, 0xFF]
    GET_PHOTP19 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # Photo_Part20/20
    CMD_PHOTO20 = [0x80, 0xb0, 0x14, 0x68, 0x02, 0x00, 0xFF]
    GET_PHOTP20 = [0x00, 0xc0, 0x00, 0x00, 0xFF]

    # get all the available readers
    r = readers()
    print "Available readers:", r

    reader = r[0]
    print "Using:", reader

    connection = reader.createConnection()
    connection.connect()

    # Reset
    data, sw1, sw2 = connection.transmit(SELECT + THAI_CARD)
    print "Select Applet: %02X %02X" % (sw1, sw2)

    # CID
    data, sw1, sw2 = connection.transmit(CMD_CID)
    data, sw1, sw2 = connection.transmit(GET_CID)
    print "CID: " + thai2unicode(data)

    # TH Fullname
    data, sw1, sw2 = connection.transmit(CMD_THFULLNAME)
    data, sw1, sw2 = connection.transmit(GET_THFULLNAME)
    print "TH Fullname: " + thai2unicode(data)

    # EN Fullname
    data, sw1, sw2 = connection.transmit(CMD_ENFULLNAME)
    data, sw1, sw2 = connection.transmit(GET_ENFULLNAME)
    print "EN Fullname: " + thai2unicode(data)

    # Date of birth
    data, sw1, sw2 = connection.transmit(CMD_BIRTH)
    data, sw1, sw2 = connection.transmit(GET_BIRTH)
    print "Date of birth: " + thai2unicode(data)

    # Gender
    data, sw1, sw2 = connection.transmit(CMD_GENDER)
    data, sw1, sw2 = connection.transmit(GET_GENDER)
    print "Gender: " + thai2unicode(data)

    # Card Issuer
    data, sw1, sw2 = connection.transmit(CMD_ISSUER)
    data, sw1, sw2 = connection.transmit(GET_ISSUER)
    print "Card Issuer: " + thai2unicode(data)

    # Issue Date
    data, sw1, sw2 = connection.transmit(CMD_ISSUE)
    data, sw1, sw2 = connection.transmit(GET_ISSUE)
    print "Issue Date: " + thai2unicode(data)

    # Expire Date
    data, sw1, sw2 = connection.transmit(CMD_EXPIRE)
    data, sw1, sw2 = connection.transmit(GET_EXPIRE)
    print "Expire Date: " + thai2unicode(data)

    # Address
    data, sw1, sw2 = connection.transmit(CMD_ADDRESS)
    data, sw1, sw2 = connection.transmit(GET_ADDRESS)
    print "Address: " + thai2unicode(data)

    # PHOTO
    data, sw1, sw2 = connection.transmit(CMD_PHOTO1)
    data, sw1, sw2 = connection.transmit(GET_PHOTP1)
    print data