From 01a6c9f77fc99fa6f3afa396dc45fc52403195c2 Mon Sep 17 00:00:00 2001 From: Pol Henarejos Date: Thu, 2 Nov 2023 09:32:19 +0100 Subject: [PATCH] Added Windows & Linux backend for backup/restore. Fixes #21 Signed-off-by: Pol Henarejos --- tools/pico-fido-tool.py | 32 +++++++++++++++++++-------- tools/secure_key/windows.py | 44 +++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 tools/secure_key/windows.py diff --git a/tools/pico-fido-tool.py b/tools/pico-fido-tool.py index 9971387..4123233 100644 --- a/tools/pico-fido-tool.py +++ b/tools/pico-fido-tool.py @@ -23,7 +23,6 @@ import sys import argparse import platform from binascii import hexlify -from words import words from threading import Event from typing import Mapping, Any, Optional, Callable import struct @@ -58,14 +57,6 @@ except: from enum import IntEnum from binascii import hexlify -if (platform.system() == 'Windows' or platform.system() == 'Linux'): - from secure_key import windows as skey -elif (platform.system() == 'Darwin'): - from secure_key import macos as skey -else: - print('ERROR: platform not supported') - sys.exit(-1) - def get_pki_data(url, data=None, method='GET'): user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; ' 'rv:1.9.0.7) Gecko/2009021910 Firefox/3.0.7' @@ -252,6 +243,14 @@ class Vendor: return self.ctap.vendor(cmd, sub_cmd, params, pin_uv_protocol, pin_uv_param) def backup_save(self, filename): + if (platform.system() == 'Windows' or platform.system() == 'Linux'): + from secure_key import windows as skey + elif (platform.system() == 'Darwin'): + from secure_key import macos as skey + else: + print('ERROR: platform not supported') + sys.exit(-1) + from words import words ret = self._call( Vendor.CMD.VENDOR_BACKUP, Vendor.SUBCMD.ENABLE, @@ -270,6 +269,14 @@ class Vendor: print(f'{(c+1):02d} - {words[coef]}') def backup_load(self, filename): + if (platform.system() == 'Windows' or platform.system() == 'Linux'): + from secure_key import windows as skey + elif (platform.system() == 'Darwin'): + from secure_key import macos as skey + else: + print('ERROR: platform not supported') + sys.exit(-1) + from words import words d = 0 if (d == 0): for c in range(24): @@ -349,6 +356,13 @@ class Vendor: ) def _get_key_device(self): + if (platform.system() == 'Windows' or platform.system() == 'Linux'): + from secure_key import windows as skey + elif (platform.system() == 'Darwin'): + from secure_key import macos as skey + else: + print('ERROR: platform not supported') + sys.exit(-1) return skey.get_secure_key() def get_skey(self): diff --git a/tools/secure_key/windows.py b/tools/secure_key/windows.py new file mode 100644 index 0000000..d1c5845 --- /dev/null +++ b/tools/secure_key/windows.py @@ -0,0 +1,44 @@ +import sys +import os +import base64 + +DOMAIN = "PicoKeys.com" +USERNAME = "Pico-Fido" + +try: + import keyring +except: + print('ERROR: keyring module not found! Install keyring package.\nTry with `pip install keyring`') + sys.exit(-1) + +try: + from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption, load_pem_private_key + from cryptography.hazmat.primitives.asymmetric import ec +except: + print('ERROR: cryptography module not found! Install cryptography package.\nTry with `pip install cryptography`') + sys.exit(-1) + + + +def generate_secure_key(): + pkey = ec.generate_private_key(ec.SECP256R1()) + set_secure_key(pkey) + return keyring.get_password(DOMAIN, USERNAME) + +def get_d(key): + return load_pem_private_key(key, password=None).private_numbers().private_value.to_bytes(32, 'big') + +def set_secure_key(pk): + try: + keyring.delete_password(DOMAIN, USERNAME) + except: + pass + keyring.set_password(DOMAIN, USERNAME, pk.private_bytes(Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()).decode()) + +def get_secure_key(): + key = None + try: + key = keyring.get_password(DOMAIN, USERNAME) + except keyring.errors.KeyringError: + key = generate_secure_key() + return get_d(key.encode())