10 Commits

Author SHA1 Message Date
Pol Henarejos 4739f797de Version 1.1.2
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-20 23:48:25 +01:00
Pol Henarejos e0db8e1bab Add support for using only rescue device instead of pyscard.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-20 23:48:19 +01:00
Pol Henarejos 9dc893286a Version 1.1.1
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-20 23:06:16 +01:00
Pol Henarejos d5d126c01e pyscard 2.3.1 solves some bugs.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-20 23:04:20 +01:00
Pol Henarejos bfafb30da3 Version 1.1
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-20 22:48:55 +01:00
Pol Henarejos 2b292352a6 More fixes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-20 20:11:54 +01:00
Pol Henarejos 0ff0ccd053 Add enum classes.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-18 01:04:06 +01:00
Pol Henarejos fd78641514 Add NamedIntEnum
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-18 01:03:53 +01:00
Pol Henarejos c59bf29a88 Add flash_info, secure_info and secure_boot.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-18 01:03:45 +01:00
Pol Henarejos abd1c7945f Update python matrix.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
2025-11-12 17:44:41 +01:00
8 changed files with 84 additions and 51 deletions
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.8", "3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- uses: actions/checkout@v3
+7 -13
View File
@@ -18,10 +18,9 @@
*/
"""
from enum import IntEnum
from .core import NamedIntEnum
class PhyTag(IntEnum):
class PhyTag(NamedIntEnum):
VIDPID = 0x0
LED_GPIO = 0x4
LED_BTNESS = 0x5
@@ -32,15 +31,13 @@ class PhyTag(IntEnum):
ENABLED_USB_ITF = 0xB
LED_DRIVER = 0xC
class PhyOpt(IntEnum):
class PhyOpt(NamedIntEnum):
WCID = 0x1
DIMM = 0x2
DISABLE_POWER_RESET = 0x4
LED_STEADY = 0x8
class PhyCurve(IntEnum):
class PhyCurve(NamedIntEnum):
SECP256R1 = 0x1
SECP384R1 = 0x2
SECP521R1 = 0x4
@@ -53,15 +50,13 @@ class PhyCurve(IntEnum):
CURVE25519 = 0x200
CURVE448 = 0x400
class PhyUsbItf(IntEnum):
class PhyUsbItf(NamedIntEnum):
CCID = 0x1
WCID = 0x2
HID = 0x4
KB = 0x8
class PhyLedDriver(IntEnum):
class PhyLedDriver(NamedIntEnum):
PICO = 0x1
PIMORONI = 0x2
WS2812 = 0x3
@@ -69,7 +64,6 @@ class PhyLedDriver(IntEnum):
NEOPIXEL = 0x5
NONE = 0xFF
class PhyData:
def __init__(self, **kwargs):
self.vidpid = kwargs.get("vidpid")
@@ -121,7 +115,7 @@ class PhyData:
b = bytearray()
if self.vidpid:
b += bytes([PhyTag.VIDPID, 4])
b += bytes([self.vidpid[1], self.vidpid[0], self.vidpid[3], self.vidpid[2]])
b += bytes(self.vidpid[:4])
if self.led_gpio is not None:
b += bytes([PhyTag.LED_GPIO, 1, self.led_gpio & 0xFF])
if self.led_brightness is not None:
+66 -34
View File
@@ -20,55 +20,53 @@
import sys
from .APDU import APDUResponse
from .SecureChannel import SecureChannel
try:
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
from smartcard.Exceptions import CardRequestTimeoutException, CardConnectionException
except ModuleNotFoundError:
print('ERROR: smartcard module not found! Install pyscard package.\nTry with `pip install pyscard`')
sys.exit(-1)
from .RescuePicoKey import RescuePicoKey
from .PhyData import PhyData
import enum
from .core import NamedIntEnum
class Platform(enum.IntEnum):
class Platform(NamedIntEnum):
RP2040 = 0
RP2350 = 1
ESP32 = 2
EMULATION = 3
class Product(enum.IntEnum):
class Product(NamedIntEnum):
UNKNOWN = 0
HSM = 1
FIDO = 2
OPENPGP = 3
class PicoKey:
def __init__(self, slot=-1):
def __init__(self, slot=-1, force_rescue=False):
self.__sc = None
cardtype = AnyCardType()
try:
# request card insertion
readers = None
if (slot >= 0):
readers = CardRequest().getReaders()
if (slot >= len(readers)):
raise Exception('slot out of range')
readers = [readers[slot]]
cardrequest = CardRequest(timeout=1, cardType=cardtype, readers=readers)
self.__card = cardrequest.waitforcard().connection
# connect to the card and perform a few transmits
self.__card.connect()
except CardRequestTimeoutException:
if (force_rescue):
try:
self.__card = RescuePicoKey()
except Exception:
raise Exception('time-out: no card inserted')
else:
from smartcard.CardType import AnyCardType
from smartcard.CardRequest import CardRequest
cardtype = AnyCardType()
try:
# request card insertion
readers = None
if (slot >= 0):
readers = CardRequest().getReaders()
if (slot >= len(readers)):
raise Exception('slot out of range')
readers = [readers[slot]]
cardrequest = CardRequest(timeout=1, cardType=cardtype, readers=readers)
self.__card = cardrequest.waitforcard().connection
# connect to the card and perform a few transmits
self.__card.connect()
except Exception:
try:
self.__card = RescuePicoKey()
except Exception:
raise Exception('time-out: no card inserted')
resp, sw1, sw2 = self.select_applet(rescue=True)
try:
resp, sw1, sw2 = self.select_applet(rescue=True)
@@ -109,7 +107,7 @@ class PicoKey:
try:
response, sw1, sw2 = self.__card.transmit(apdu)
except CardConnectionException:
except Exception:
self.__card.reconnect()
response, sw1, sw2 = self.__card.transmit(apdu)
@@ -145,7 +143,7 @@ class PicoKey:
try:
response, sw1, sw2 = self.__card.transmit(apdu)
except CardConnectionException:
except Exception:
self.__card.reconnect()
response, sw1, sw2 = self.__card.transmit(apdu)
@@ -165,7 +163,41 @@ class PicoKey:
def phy(self, data=None):
if (data is None):
resp, sw = self.send(0x1E, cla=0x80, p1=0x01, ne=256)
return PhyData.parse(resp)
try:
resp, sw = self.send(0x1E, cla=0x80, p1=0x00, ne=256)
return PhyData.parse(resp)
except APDUResponse:
pass
return None
else:
self.send(0x1C, cla=0x80, p1=0x01, data=data)
def flash_info(self):
try:
resp, sw = self.send(0x1E, cla=0x80, p1=0x02)
free = int.from_bytes(resp[0:4], 'big')
used = int.from_bytes(resp[4:8], 'big')
total = int.from_bytes(resp[8:12], 'big')
nfiles = int.from_bytes(resp[12:16], 'big')
size = int.from_bytes(resp[16:20], 'big')
except Exception:
free = used = total = nfiles = size = 0
return {
'free': free,
'used': used,
'total': total,
'nfiles': nfiles,
'size': size
}
def secure_info(self):
resp, sw = self.send(0x1E, cla=0x80, p1=0x03)
return {
'enabled': resp[0] != 0,
'locked': resp[1] != 0,
'boot_key': resp[2]
}
def secure_boot(self, bootkey_index=0, lock=False):
data = bytes([bootkey_index & 0xFF, 1 if lock else 0])
self.send(0x1C, cla=0x80, p1=0x02, data=data)
+1
View File
@@ -5,3 +5,4 @@ from .APDU import APDUResponse
from .SWCodes import SWCodes
from .RescuePicoKey import RescuePicoKey
from .PhyData import PhyData, PhyCurve, PhyUsbItf, PhyLedDriver, PhyOpt
from .core import enums
+1 -1
View File
@@ -18,4 +18,4 @@
*/
"""
__version__ = "1.0"
__version__ = "1.1.2"
+1
View File
@@ -0,0 +1 @@
from .enums import *
+5
View File
@@ -0,0 +1,5 @@
import enum
class NamedIntEnum(enum.IntEnum):
def __str__(self):
return self.name
+2 -2
View File
@@ -36,7 +36,7 @@ INSTALL_REQUIRES = [
'cryptography>=3.3',
'pyusb',
'pycvc',
'pyscard<=2.2.2',
'pyscard>=2.3.1',
]
if sys.platform.startswith('win32'):
@@ -50,7 +50,7 @@ except(IOError, ImportError):
setup(
name='pypicokey',
packages=['picokey'],
packages=['picokey','picokey/core'],
version=version,
description='PicoKey for Python',
license='AGPL',