Skip to content

Commit

Permalink
secure applet class
Browse files Browse the repository at this point in the history
  • Loading branch information
stepansnigirev committed Sep 17, 2020
1 parent 5fda36c commit 8ee0777
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 3 deletions.
2 changes: 1 addition & 1 deletion f469-disco
Submodule f469-disco updated 1 files
+1 −0 README.md
3 changes: 3 additions & 0 deletions src/keystore/javacard/applets/applet.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
class ISOException(Exception):
pass

class AppletException(Exception):
pass

class Applet:
SELECT = b"\x00\xA4\x04\x00" # select command
def __init__(self, connection, aid):
Expand Down
17 changes: 17 additions & 0 deletions src/keystore/javacard/applets/memorycard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from .secureapplet import SecureApplet, SecureException
from .applet import ISOException

class MemoryCardApplet(SecureApplet):
def __init__(self, connection):
aid = b"\xB0\x0B\x51\x11\xCB\x01"
super().__init__(connection, aid)

def save_secret(self):
pass

def get_secret(self, secret):
pass

@property
def is_empty(self):
return True
68 changes: 67 additions & 1 deletion src/keystore/javacard/applets/secureapplet.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from .applet import Applet, ISOException
from .applet import Applet, ISOException, AppletException
from .securechannel import SecureChannel
import hashlib

def encode(data):
return bytes([len(data)])+data

class SecureException(Exception):
"""
Expand All @@ -11,6 +15,15 @@ class SecureException(Exception):
class SecureApplet(Applet):
SECURE_RANDOM = b"\x01\x00"
PIN_STATUS = b"\x03\x00"
UNLOCK = b"\x03\x01"
LOCK = b"\x03\x02"
CHANGE_PIN = b'\x03\x03'
SET_PIN = b"\x03\x04"
# PIN status codes
PIN_UNSET = 0
PIN_LOCKED = 1
PIN_UNLOCKED = 2
PIN_BRICKED = 3

def __init__(self, connection, aid):
super().__init__(connection, aid)
Expand Down Expand Up @@ -45,3 +58,56 @@ def is_pin_set(self):
if self._pin_status is None:
self._get_pin_status()
return self._pin_status > 0

@property
def pin_attempts_left(self):
if self._pin_status is None:
self._get_pin_status()
return self._pin_attempts_left

@property
def pin_attempts_max(self):
if self._pin_status is None:
self._get_pin_status()
return self._pin_attempts_max

@property
def is_locked(self):
if self._pin_status is None:
self._get_pin_status()
return self._pin_status in [self.PIN_LOCKED, self.PIN_BRICKED]

def set_pin(self, pin):
if self.is_pin_set:
raise AppletException("PIN is already set")
# we always set sha256(pin) so it's constant length
h = hashlib.sha256(pin.encode()).digest()
self.sc.request(self.SET_PIN+h)
# update status
self._get_pin_status()

def change_pin(self, old_pin, new_pin):
if not self.is_pin_set:
raise AppletException("PIN is not set")
if self.is_locked:
raise AppletException("Unlock the card first")
h1 = hashlib.sha256(old_pin.encode()).digest()
h2 = hashlib.sha256(new_pin.encode()).digest()
self.sc.request(self.CHANGE_PIN+encode(h1)+encode(h2))
# update status
self._get_pin_status()

def unlock(self, pin):
if not self.is_locked:
return
try:
h = hashlib.sha256(pin.encode()).digest()
self.sc.request(self.UNLOCK+h)
finally:
# update status
self._get_pin_status()

def lock(self):
self.sc.request(self.LOCK)
# update status
self._get_pin_status()
2 changes: 1 addition & 1 deletion src/keystore/javacard/applets/securechannel.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ def request(self, data):
"""
# if counter reached maximum - reestablish channel
if self.iv >= 2**16 or not self.is_open:
self.establish_secure_channel()
self.open()
ct = self.encrypt(data)
res = self.applet.request(self.SECURE_MSG+encode(ct))
plaintext = self.decrypt(res)
Expand Down

0 comments on commit 8ee0777

Please sign in to comment.