aboutsummaryrefslogtreecommitdiffstats
path: root/cards/postcard_card.py
blob: 7f2c27cb1ed12c8d179dfd236e3c07607e24fa7c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import utils, re, sys, getpass, struct
from iso_7816_4_card import *

class Postcard_Card(ISO_7816_4_Card):
    DRIVER_NAME = "Postcard"
    CLA = 0xbc
    APDU_GET_RESPONSE = C_APDU(cla=CLA,ins=0xc0)
    APDU_SELECT_FILE = C_APDU(cla=CLA,ins=0xa4)
    APDU_READ_BINARY = C_APDU(cla=CLA,ins=0xb0,le=0x80)

    
    ATRS = [ 
        ("3f65351002046c90..", None),
        ("3f65356402046c9040", None),
    ]

    def _get_binary(self, offset, length):
        command = C_APDU(self.APDU_READ_BINARY, p1 = offset >> 8, p2 = offset & 0xff, le = length)
        result = self.send_apdu(command)
        assert result.sw == self.SW_OK
        
        return result.data
    
    def _get_address(self, definition_data, offset):
        return ((ord(definition_data[offset]) * 256 + ord(definition_data[offset+1])) >> 5) << 3
    
    ZONE_ADDRESSES = [
        ("adl", 0x09C8),
        ("adt", 0x09CC),
        ("adc", 0x09D0),
        ("adm", 0x09D4),
        ("ad2", 0x09D8),
        ("ads", 0x09DC),
        ("ad1", 0x09E8),
    ]
    def cmd_calculate_zone_addresses(self):
        "Read the zone definitions and calculate the zone addresses"
        READSTART = 0x09c0
        definition_data = self._get_binary(READSTART, length=0x30)
        
        result = {}
        for name, offset in self.ZONE_ADDRESSES:
            result[name] = self._get_address(definition_data, (offset - READSTART)>>1)
        
        for name,_ in self.ZONE_ADDRESSES:
            print "%s: %04x" % (name, result[name])
    
    def cmd_read_identification_zone(self):
        "Read the identification zone"
        data = self._get_binary(0x0948, length=0x60)
        
        chaine_initiale = binascii.b2a_hex(data[4:])
        print "chaine initiale", chaine_initiale
        #suppression_des_3 = re.sub(r'x', '3', re.sub(r'3', '', re.sub(r'33', "x", chaine_initiale) ) )
        #suppression_des_3 = "".join(chaine_initiale.split("3")) + "0"
        suppression_des_3 = []
        still_there = True
        for index,char in enumerate(chaine_initiale):
            if still_there and index % 8 == 0:
                if char == "3":
                    continue
                else:
                    still_there = False
            suppression_des_3.append(char)
        suppression_des_3 = "".join(suppression_des_3)
        
        print "suppression des 3", suppression_des_3
        new_data = binascii.a2b_hex(suppression_des_3)
        print utils.hexdump(new_data)
        
        fields = [
            (None, 2),
            ("card number", 19),
            ("usage code", 3),
            ("valid from", 4),
            ("language code", 3),
            ("valid till", 4),
            ("currency code", 3),
            ("denomination", 1),
            ("(unknown)", 3),
            ("card holder", 26*2)
        ]
        
        print "Decoding:"
        pos = 0
        for name, length in fields:
            value = suppression_des_3[pos:pos+length]
            pos = pos+length
            if name is None:
                continue
            print "\t%20s: %s" % (name, value)
        
        print "\t%20s '%s'" % ("", binascii.a2b_hex(value))
    
    def cmd_give_pin(self):
        old = sys.modules["cards.generic_card"].DEBUG
        try:
            pin = getpass.getpass("Enter PIN: ")
            if len(pin) != 4:
                raise ValueError, "PIN must be 4 characters in length"
            pinint = int(pin, 16)
            pinint = (pinint << 14) | 0x3fff
            data = struct.pack(">I", pinint)
            sys.modules["cards.generic_card"].DEBUG = False
            command = C_APDU(cla=0xBC, ins=0x20, data=data, le=0)
            result = self.send_apdu(command)
        finally:
            sys.modules["cards.generic_card"].DEBUG = old

    
    COMMANDS = {
        "calculate_zone_addresses": cmd_calculate_zone_addresses,
        "read_identification_zone": cmd_read_identification_zone,
        "give_pin": cmd_give_pin,
    }