-
Notifications
You must be signed in to change notification settings - Fork 0
/
observer.py
74 lines (67 loc) · 3.04 KB
/
observer.py
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
from smartcard.CardMonitoring import CardObserver
from smartcard.util import toBytes
from smartcard.CardType import ATRCardType
from smartcard.CardRequest import CardRequest
from smartcard.Exceptions import CardRequestTimeoutException, CardConnectionException
from .config import config
from .dispatch import dispatch
from .auth import Auth, DEFAULT_DES_KEY
from .apdu_utils.security_commands import *
from .apdu_utils.application_commands import *
from functools import partial
class Observer(CardObserver):
def __init__(self, callback=None, auth: dict | None = None, threading_event=None):
self.callback = callback
self.auth = auth
self.threading_event = threading_event
self.send = None
card_type = ATRCardType(toBytes(config.card_atr))
card_request = CardRequest(timeout=config.timeout, cardType=card_type)
self.result = None
try:
self.service = card_request.waitforcard()
self.service.connection.connect()
except (CardRequestTimeoutException, CardConnectionException) as e:
if config.debug:
config.writer(e)
return None
def update(self, _, handlers):
added, _ = handlers
if added:
try:
self.send = partial(dispatch, service=self.service)
session_key = self.pre_auth()
self.result = self.callback(send=self.send, session_key=session_key)
self.service.connection.disconnect()
self.threading_event(self.result)
except CardConnectionException as e:
if config.debug:
config.writer(e)
return None
def pre_auth(self) -> list | None:
"""
If an authentication configuration is provided, this will attempt to auth with AES,
If that doesn't work, the Observer will assume you're trying to authenticate a factory-fresh card,
in which case it will try to auth with the default DES key (eight bytes of zero with key id zero)
"""
if not self.auth:
return None
try:
key = self.auth["MASTER_KEY"]
key_number = self.auth["MASTER_KEY_NUMBER"]
authenticator = Auth(bytearray(key), "AES")
response = self.send(command_aes_auth(key_number))
if not response.is_successful():
authenticator = Auth(bytearray(DEFAULT_DES_KEY), "DES")
response = self.send(command_des_auth([0x00]))
if not response.is_successful():
if config.debug:
config.writer(
f"Could not authenticate: {response.response_code}. Double check your key number."
)
submission = authenticator.authenticate(response.data)
response = self.send(command_additional_frame(submission))
session_key = authenticator.get_session_key(response.data)
return session_key
except Exception as e:
config.writer(e)