#! /usr/bin/python3 """ upgrade_by_passwd.py - a tool to install another firmware for Gnuk Token which is just shipped from factory Copyright (C) 2012, 2013, 2015, 2018, 2021, 2022 Free Software Initiative of Japan Author: NIIBE Yutaka This file is a part of Gnuk, a GnuPG USB Token implementation. Gnuk is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gnuk is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ from gnuk_token import get_gnuk_device, gnuk_devices_by_vidpid, \ gnuk_token, regnual, SHA256_OID_PREFIX, crc32, parse_kdf_data from kdf_calc import kdf_calc import sys, binascii, time, os from struct import pack DEFAULT_PW3 = "12345678" BY_ADMIN = 3 def main(wait_e, passwd, data_regnual, data_upgrade): l = len(data_regnual) if (l & 0x03) != 0: data_regnual = data_regnual.ljust(l + 4 - (l & 0x03), chr(0)) crc32code = crc32(data_regnual) print("CRC32: %04x\n" % crc32code) data_regnual += pack(' 1 else '')) time.sleep(wait_e) for dev in gnuk_devices_by_vidpid(): try: reg = regnual(dev) print("Device: %s" % dev.filename) break except: pass # Then, send upgrade program... mem_info = reg.mem_info() print("%08x:%08x" % mem_info) print("Downloading the program") reg.download(mem_info[0], data_upgrade) print("Protecting device") reg.protect() print("Finish flashing") reg.finish() print("Resetting device") reg.reset_device() print("Update procedure finished") return 0 from getpass import getpass # This should be event driven, not guessing some period, or polling. DEFAULT_WAIT_FOR_REENUMERATION=1 if __name__ == '__main__': if os.getcwd() != os.path.dirname(os.path.abspath(__file__)): print("Please change working directory to: %s" % os.path.dirname(os.path.abspath(__file__))) exit(1) passwd = None wait_e = DEFAULT_WAIT_FOR_REENUMERATION skip_check = False while len(sys.argv) > 1: option = sys.argv[1] if option == '-f': # F for Factory setting sys.argv.pop(1) passwd = DEFAULT_PW3 elif option == '-e': # E for Enumeration sys.argv.pop(1) wait_e = int(sys.argv[1]) sys.argv.pop(1) elif option == '-s': # S for skip the check of target sys.argv.pop(1) skip_check = True else: if option[0] == '-': raise ValueError("unknown option", option) else: break if not passwd: passwd = getpass("Admin password: ") if len(sys.argv) > 1: filename_regnual = sys.argv[1] filename_upgrade = sys.argv[2] else: filename_regnual = "../regnual/regnual.bin" filename_upgrade = "../src/build/gnuk.bin" if not filename_regnual.endswith('bin') or not filename_upgrade.endswith('bin'): print("Both input files must be in binary format (*.bin)!") exit(1) if not skip_check: # More checks gnuk = get_gnuk_device() u_target = gnuk.get_string(5).split(b':')[0].decode('UTF-8') del gnuk f = open("../src/usb-strings.c.inc","r") config_str = f.read() f.close() conf_options=config_str[config_str.find('/* configure options: "')+23:] target=conf_options[:conf_options.find(':')] if target != u_target: print("Target", target, "!= device info from USB " , u_target) exit(1) # f = open(filename_regnual,"rb") data_regnual = f.read() f.close() print("%s: %d" % (filename_regnual, len(data_regnual))) f = open(filename_upgrade,"rb") data_upgrade = f.read() f.close() print("%s: %d" % (filename_upgrade, len(data_upgrade))) # First 4096-byte in data_upgrade is SYS, so, skip it. main(wait_e, passwd, data_regnual, data_upgrade[4096:])