summaryrefslogtreecommitdiff
path: root/python_bindings_example.py
blob: a8f0dbbb406a5d684afbe757bc3c91a31f9aa8b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#!/usr/bin/env python
import cffi
from enum import Enum

"""
This example will print 10 HOTP codes from just written HOTP#2 slot.
For more examples of use please refer to unittest/test_*.py files.
"""

ffi = cffi.FFI()
get_string = ffi.string

class DeviceErrorCode(Enum):
    STATUS_OK = 0
    NOT_PROGRAMMED = 3
    WRONG_PASSWORD = 4
    STATUS_NOT_AUTHORIZED = 5
    STATUS_AES_DEC_FAILED = 0xa


def get_library():
    fp = 'NK_C_API.h'  # path to C API header

    declarations = []
    with open(fp, 'r') as f:
        declarations = f.readlines()

    cnt = 0
    a = iter(declarations)
    for declaration in a:
        if declaration.strip().startswith('NK_C_API'):
            declaration = declaration.replace('NK_C_API', '').strip()
            while ';' not in declaration:
                declaration += (next(a)).strip()
            # print(declaration)
            ffi.cdef(declaration, override=True)
            cnt +=1
    print('Imported {} declarations'.format(cnt))


    C = None
    import os, sys
    path_build = os.path.join(".", "build")
    paths = [
            os.environ.get('LIBNK_PATH', None),
            os.path.join(path_build,"libnitrokey.so"),
            os.path.join(path_build,"libnitrokey.dylib"),
            os.path.join(path_build,"libnitrokey.dll"),
            os.path.join(path_build,"nitrokey.dll"),
    ]
    for p in paths:
        if not p: continue
        print("Trying " +p)
        p = os.path.abspath(p)
        if os.path.exists(p):
            print("Found: "+p)
            C = ffi.dlopen(p)
            break
        else:
            print("File does not exist: " + p)
    if not C:
        print("No library file found")
        print("Please set the path using LIBNK_PATH environment variable to existing library or compile it (see "
              "README.md for details)")
        sys.exit(1)

    return C


def get_hotp_code(lib, i):
    return get_string(lib.NK_get_hotp_code(i))

def to_hex(ss):
    return ''.join([ format(ord(s),'02x') for s in ss ])

print('Warning!')
print('This example will change your configuration on inserted stick and overwrite your HOTP#2 slot.')
print('Please write "continue" to continue or any other string to quit')
a = raw_input()

if not a == 'continue':
    exit()

ADMIN = raw_input('Please enter your admin PIN (empty string uses 12345678) ')
ADMIN = ADMIN or '12345678'  # use default if empty string

show_log = raw_input('Should log messages be shown (please write "yes" to enable; this will make harder reading script output) ') == 'yes'
libnitrokey = get_library()

if show_log:
    log_level = raw_input('Please select verbosity level (0-5, 2 is library default, 3 will be selected on empty input) ')
    log_level = log_level or '3'
    log_level = int(log_level)
    libnitrokey.NK_set_debug_level(log_level)
else:
    libnitrokey.NK_set_debug_level(2)


ADMIN_TEMP = '123123123'
RFC_SECRET = to_hex('12345678901234567890')

# libnitrokey.NK_login('S')  # connect only to Nitrokey Storage device
# libnitrokey.NK_login('P')  # connect only to Nitrokey Pro device
device_connected = libnitrokey.NK_login_auto()  # connect to any Nitrokey Stick
if device_connected:
    print('Connected to Nitrokey device!')
else:
    print('Could not connect to Nitrokey device!')
    exit()
use_8_digits = True
pin_correct = libnitrokey.NK_first_authenticate(ADMIN, ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
if pin_correct:
    print('Your PIN is correct!')
else:
    print('Your PIN is not correct! Please try again. Please be careful to not lock your stick!')
    retry_count_left = libnitrokey.NK_get_admin_retry_count()
    print('Retry count left: %d' % retry_count_left )
    exit()

# For function parameters documentation please check NK_C_API.h
assert libnitrokey.NK_write_config(255, 255, 255, False, True, ADMIN_TEMP) == DeviceErrorCode.STATUS_OK
libnitrokey.NK_first_authenticate(ADMIN, ADMIN_TEMP)
libnitrokey.NK_write_hotp_slot(1, 'python_test', RFC_SECRET, 0, use_8_digits, False, False, "",
                            ADMIN_TEMP)
# RFC test according to: https://tools.ietf.org/html/rfc4226#page-32
test_data = [
    1284755224, 1094287082, 137359152, 1726969429, 1640338314, 868254676, 1918287922, 82162583, 673399871,
    645520489,
]
print('Getting HOTP code from Nitrokey Stick (RFC test, 8 digits): ')
for i in range(10):
    hotp_slot_1_code = get_hotp_code(libnitrokey, 1)
    correct_str =  "correct!" if hotp_slot_1_code == str(test_data[i])[-8:] else  "not correct"
    print('%d: %s, should be %s -> %s' % (i, hotp_slot_1_code, str(test_data[i])[-8:], correct_str))
libnitrokey.NK_logout()  # disconnect device