1#!/usr/bin/env python2 2""" 3Copyright (c) 2015-2018 Nitrokey UG 4 5This file is part of libnitrokey. 6 7libnitrokey is free software: you can redistribute it and/or modify 8it under the terms of the GNU Lesser General Public License as published by 9the Free Software Foundation, either version 3 of the License, or 10any later version. 11 12libnitrokey is distributed in the hope that it will be useful, 13but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15GNU General Public License for more details. 16 17You should have received a copy of the GNU Lesser General Public License 18along with libnitrokey. If not, see <http://www.gnu.org/licenses/>. 19 20SPDX-License-Identifier: LGPL-3.0 21""" 22 23import cffi 24from enum import Enum 25 26""" 27This example will print 10 HOTP codes from just written HOTP#2 slot. 28For more examples of use please refer to unittest/test_*.py files. 29""" 30 31ffi = cffi.FFI() 32get_string = ffi.string 33 34class DeviceErrorCode(Enum): 35 STATUS_OK = 0 36 NOT_PROGRAMMED = 3 37 WRONG_PASSWORD = 4 38 STATUS_NOT_AUTHORIZED = 5 39 STATUS_AES_DEC_FAILED = 0xa 40 41 42def get_library(): 43 fp = 'NK_C_API.h' # path to C API header 44 45 declarations = [] 46 with open(fp, 'r') as f: 47 declarations = f.readlines() 48 49 cnt = 0 50 a = iter(declarations) 51 for declaration in a: 52 if declaration.strip().startswith('NK_C_API'): 53 declaration = declaration.replace('NK_C_API', '').strip() 54 while ';' not in declaration: 55 declaration += (next(a)).strip() 56 # print(declaration) 57 ffi.cdef(declaration, override=True) 58 cnt +=1 59 print('Imported {} declarations'.format(cnt)) 60 61 62 C = None 63 import os, sys 64 path_build = os.path.join(".", "build") 65 paths = [ 66 os.environ.get('LIBNK_PATH', None), 67 os.path.join(path_build,"libnitrokey.so"), 68 os.path.join(path_build,"libnitrokey.dylib"), 69 os.path.join(path_build,"libnitrokey.dll"), 70 os.path.join(path_build,"nitrokey.dll"), 71 ] 72 for p in paths: 73 if not p: continue 74 print("Trying " +p) 75 p = os.path.abspath(p) 76 if os.path.exists(p): 77 print("Found: "+p) 78 C = ffi.dlopen(p) 79 break 80 else: 81 print("File does not exist: " + p) 82 if not C: 83 print("No library file found") 84 print("Please set the path using LIBNK_PATH environment variable to existing library or compile it (see " 85 "README.md for details)") 86 sys.exit(1) 87 88 return C 89 90 91def get_hotp_code(lib, i): 92 return get_string(lib.NK_get_hotp_code(i)) 93 94def to_hex(ss): 95 return ''.join([ format(ord(s),'02x') for s in ss ]) 96 97print('Warning!') 98print('This example will change your configuration on inserted stick and overwrite your HOTP#2 slot.') 99print('Please write "continue" to continue or any other string to quit') 100a = raw_input() 101 102if not a == 'continue': 103 exit() 104 105ADMIN = raw_input('Please enter your admin PIN (empty string uses 12345678) ') 106ADMIN = ADMIN or '12345678' # use default if empty string 107 108show_log = raw_input('Should log messages be shown (please write "yes" to enable; this will make harder reading script output) ') == 'yes' 109libnitrokey = get_library() 110 111if show_log: 112 log_level = raw_input('Please select verbosity level (0-5, 2 is library default, 3 will be selected on empty input) ') 113 log_level = log_level or '3' 114 log_level = int(log_level) 115 libnitrokey.NK_set_debug_level(log_level) 116else: 117 libnitrokey.NK_set_debug_level(2) 118 119 120ADMIN_TEMP = '123123123' 121RFC_SECRET = to_hex('12345678901234567890') 122 123# libnitrokey.NK_login('S') # connect only to Nitrokey Storage device 124# libnitrokey.NK_login('P') # connect only to Nitrokey Pro device 125device_connected = libnitrokey.NK_login_auto() # connect to any Nitrokey Stick 126if device_connected: 127 print('Connected to Nitrokey device!') 128else: 129 print('Could not connect to Nitrokey device!') 130 exit() 131use_8_digits = True 132pin_correct = libnitrokey.NK_first_authenticate(ADMIN, ADMIN_TEMP) == DeviceErrorCode.STATUS_OK 133if pin_correct: 134 print('Your PIN is correct!') 135else: 136 print('Your PIN is not correct! Please try again. Please be careful to not lock your stick!') 137 retry_count_left = libnitrokey.NK_get_admin_retry_count() 138 print('Retry count left: %d' % retry_count_left ) 139 exit() 140 141# For function parameters documentation please check NK_C_API.h 142assert libnitrokey.NK_write_config(255, 255, 255, False, True, ADMIN_TEMP) == DeviceErrorCode.STATUS_OK 143libnitrokey.NK_first_authenticate(ADMIN, ADMIN_TEMP) 144libnitrokey.NK_write_hotp_slot(1, 'python_test', RFC_SECRET, 0, use_8_digits, False, False, "", 145 ADMIN_TEMP) 146# RFC test according to: https://tools.ietf.org/html/rfc4226#page-32 147test_data = [ 148 1284755224, 1094287082, 137359152, 1726969429, 1640338314, 868254676, 1918287922, 82162583, 673399871, 149 645520489, 150] 151print('Getting HOTP code from Nitrokey Stick (RFC test, 8 digits): ') 152for i in range(10): 153 hotp_slot_1_code = get_hotp_code(libnitrokey, 1) 154 correct_str = "correct!" if hotp_slot_1_code == str(test_data[i])[-8:] else "not correct" 155 print('%d: %s, should be %s -> %s' % (i, hotp_slot_1_code, str(test_data[i])[-8:], correct_str)) 156libnitrokey.NK_logout() # disconnect device 157