{"id":17715635,"url":"https://github.com/nitrokey/libnitrokey","last_synced_at":"2025-04-15T10:30:55.024Z","repository":{"id":6005611,"uuid":"54261861","full_name":"Nitrokey/libnitrokey","owner":"Nitrokey","description":"Communicate with Nitrokey devices in a clean and easy manner","archived":false,"fork":false,"pushed_at":"2024-01-11T21:17:33.000Z","size":2107,"stargazers_count":65,"open_issues_count":64,"forks_count":34,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-15T10:20:07.140Z","etag":null,"topics":["c-plus-plus","cross-platform","encrypted-store","hotp","library","nitrokey","nitrokey-stick-devices","otp","password-vault","python","security"],"latest_commit_sha":null,"homepage":"https://nitrokey.com/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Nitrokey.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-03-19T11:14:26.000Z","updated_at":"2024-08-16T05:49:45.000Z","dependencies_parsed_at":"2024-06-19T11:17:17.037Z","dependency_job_id":"60186826-e4de-41b9-8bec-185a99fb1886","html_url":"https://github.com/Nitrokey/libnitrokey","commit_stats":null,"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nitrokey%2Flibnitrokey","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nitrokey%2Flibnitrokey/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nitrokey%2Flibnitrokey/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Nitrokey%2Flibnitrokey/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Nitrokey","download_url":"https://codeload.github.com/Nitrokey/libnitrokey/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249051527,"owners_count":21204829,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-plus-plus","cross-platform","encrypted-store","hotp","library","nitrokey","nitrokey-stick-devices","otp","password-vault","python","security"],"created_at":"2024-10-25T12:06:33.930Z","updated_at":"2025-04-15T10:30:54.994Z","avatar_url":"https://github.com/Nitrokey.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# libnitrokey\nlibnitrokey is a project to communicate with Nitrokey Pro and Storage devices in a clean and easy manner. Written in C++14, testable with `py.test` and `Catch` frameworks, with C API, Python access (through CFFI and C API, in future with Pybind11).\n\nThe development of this project is aimed to make it itself a living documentation of communication protocol between host and the Nitrokey stick devices. The command packets' format is described here: [Pro v0.7](libnitrokey/stick10_commands.h), [Pro v0.8](libnitrokey/stick10_commands_0.8.h), [Storage](libnitrokey/stick20_commands.h). Handling and additional operations are described here: [NitrokeyManager.cc](NitrokeyManager.cc).\n\nA C++14 complying compiler is required due to heavy use of variable templates. For feature support tables please check [table 1](https://gcc.gnu.org/projects/cxx-status.html#cxx14) or [table 2](http://en.cppreference.com/w/cpp/compiler_support).\n\nlibnitrokey is developed and tested with a variety of compilers, starting from g++ 6.2 and clang 3.8. We use Travis CI to test builds also on g++ 5.4 and under OSX compilers starting up from xcode 9 environment. \n\n## Getting sources\nThis repository uses `git submodules`.\nTo clone please use git's `--recursive` option like in:\n```bash\ngit clone --recursive https://github.com/Nitrokey/libnitrokey.git\n```\nor for already cloned repository:\n```bash\ngit clone https://github.com/Nitrokey/libnitrokey.git\ncd libnitrokey\ngit submodule update --init --recursive\n```\n\n## Dependencies\nFollowing libraries are needed to use libnitrokey on Linux (names of the packages on Ubuntu):\n- libhidapi-dev [(HID API)](http://www.signal11.us/oss/hidapi/)\n- libusb-1.0-0-dev \n\n\n## Build\nlibnitrokey uses CMake as its main build system. As a secondary option it offers building through Qt's qMake.\n\n### Docker Isolated Build\n\nTo run a docker isolated build it suffices to run the helper command:\n\n```bash\n# build docker image, and execute the build\n$ make docker-build-all\n```\n\nCurrently, Ubuntu 22.04 is used as a build base. Results will be placed in the `./build/` directory.\n\nAdditionally, it is possible to check if the Debian package of selected version is able to build itself with the following command:\n```text\n# for the default 3.7 URL\n$ make docker-package\n\n# for the customized DGET url\n$ make docker-package DOCKERCMD=\"make ci-package DGET_URL=https://people.debian.org/~patryk/tmp/libnitrokey/libnitrokey_3.7-1.dsc\"\n```\n\n### Qt\nA Qt's .pro project file is provided for direct compilation and for inclusion to other projects.\nUsing it directly is not recommended due to lack of dependencies check and not implemented library versioning.\nCompilation is tested with Qt 5.6 and greater.\n\nQuick start example:\n```bash\nmkdir -p build\ncd build\nqmake ..\nmake -j2\n```\n\n### Windows and Visual Studio 2017\nLately Visual Studio has started handling CMake files directly. After opening the project's directory it should recognize it and initialize build system. Afterwards please run:\n1. `CMake -\u003e Cache -\u003e View Cache CMakeLists.txt -\u003e CMakeLists.txt` to edit settings\n2. `CMake -\u003e Build All` to build\n\nIt is possible too to use CMake GUI directly with its settings editor.\n\n### CMake\nTo compile please run following sequence of commands:\n```bash\n# assuming current dir is ./libnitrokey/\nmkdir -p build\ncd build\ncmake .. \u003cOPTIONS\u003e\nmake -j2\n```\n\nBy default (with empty `\u003cOPTIONS\u003e` string) this will create in `build/` directory a shared library (.so, .dll or .dynlib). If you wish to build static version you can use as `\u003cOPTIONS\u003e` string `-DBUILD_SHARED_LIBS=OFF`. \n\nAll options could be listed with `cmake .. -L` or instead `cmake` a `ccmake ..` tool could be used for configuration (where `..` is the path to directory with `CMakeLists.txt` file). `ccmake` shows also description of the build parameters.\n\nIf you have trouble compiling or running the library you can check [.travis.yml](.travis.yml) file for configuration details. This file is used by Travis CI service to make test builds on OSX and Ubuntu 14.04.\n\nOther build options (all take either `ON` or `OFF`):\n* ADD_ASAN - add tests for memory leaks and out-of-bounds access\n* ADD_TSAN - add tests for threads race, needs USE_CLANG\n* COMPILE_TESTS - compile C++ tests\n* COMPILE_OFFLINE_TESTS - compile C++ tests, that do not require any device to be connected\n* LOG_VOLATILE_DATA (default: OFF) - include secrets in log (PWS passwords, PINs etc)\n* NO_LOG (default: OFF) - do not compile LOG statements - will make library smaller, but without any diagnostic messages\n\n\n### Meson\nNote: Meson build is currently not tested. Please file a ticket in case it would not work for you.\n\nIt is possible to use Meson and Ninja to build the project as well.\nPlease run:\n```\nmeson builddir \u003cOPTIONS\u003e\nmeson configure builddir # to show available build flags\nninja -C builddir\n```\n\n# Using libnitrokey with Python\nTo use libnitrokey with Python a [CFFI](http://cffi.readthedocs.io/en/latest/overview.html) library is required (either 2.7+ or 3.0+). It can be installed with:\n```bash\npip install --user cffi # for python 2.x\npip3 install cffi # for python 3.x\n```\n## Python2\nNote: Python 2 is not supported anymore.\n\nJust import it, read the C API header and it is done! You have access to the library. Here is an example (in Python 2) printing HOTP code for Pro or Storage device, assuming it is run in root directory [(full example)](python_bindings_example.py):\n\n\u003cdetails\u003e\n    \u003csummary\u003eCode snippet (click to show)\u003c/summary\u003e\n\n\n```python\n#!/usr/bin/env python2\nimport cffi\n\nffi = cffi.FFI()\nget_string = ffi.string\n\ndef get_library():\n    fp = 'NK_C_API.h'  # path to C API header\n\n    declarations = []\n    with open(fp, 'r') as f:\n        declarations = f.readlines()\n\n    cnt = 0\n    a = iter(declarations)\n    for declaration in a:\n        if declaration.strip().startswith('NK_C_API'):\n            declaration = declaration.replace('NK_C_API', '').strip()\n            while ';' not in declaration:\n                declaration += (next(a)).strip()\n            # print(declaration)\n            ffi.cdef(declaration, override=True)\n            cnt +=1\n    print('Imported {} declarations'.format(cnt))\n\n\n    C = None\n    import os, sys\n    path_build = os.path.join(\".\", \"build\")\n    paths = [\n            os.environ.get('LIBNK_PATH', None),\n            os.path.join(path_build,\"libnitrokey.so\"),\n            os.path.join(path_build,\"libnitrokey.dylib\"),\n            os.path.join(path_build,\"libnitrokey.dll\"),\n            os.path.join(path_build,\"nitrokey.dll\"),\n    ]\n    for p in paths:\n        if not p: continue\n        print(\"Trying \" +p)\n        p = os.path.abspath(p)\n        if os.path.exists(p):\n            print(\"Found: \"+p)\n            C = ffi.dlopen(p)\n            break\n        else:\n            print(\"File does not exist: \" + p)\n    if not C:\n        print(\"No library file found\")\n        sys.exit(1)\n\n    return C\n\n\ndef get_hotp_code(lib, i):\n    return lib.NK_get_hotp_code(i)\n\n\nlibnitrokey = get_library()\nlibnitrokey.NK_set_debug(False)  # do not show debug messages (log library only)\n\nhotp_slot_code = get_hotp_code(libnitrokey, 1)\nprint('Getting HOTP code from Nitrokey device: ')\nprint(hotp_slot_code)\nlibnitrokey.NK_logout()  # disconnect device\n```\n\n\u003c/details\u003e\n\nIn case  no devices are connected, a friendly message will be printed.\nAll available functions for C and Python are listed in [NK_C_API.h](NK_C_API.h). Please check `Documentation` section below.\n\n## Python3\nJust import it, read the C API header and it is done! You have access to the library. Here is an example (in Python 3) printing HOTP code for Pro or Storage device, assuming it is run in root directory [(full example)](python3_bindings_example.py):\n\n\u003cdetails\u003e\n    \u003csummary\u003eCode snippet (click to show)\u003c/summary\u003e\n\n\n```python\n#!/usr/bin/env python3\nimport cffi\n\nffi = cffi.FFI()\nget_string = ffi.string\n\ndef get_library():\n    fp = 'NK_C_API.h'  # path to C API header\n\n    declarations = []\n    with open(fp, 'r') as f:\n        declarations = f.readlines()\n\n    cnt = 0\n    a = iter(declarations)\n    for declaration in a:\n        if declaration.strip().startswith('NK_C_API'):\n            declaration = declaration.replace('NK_C_API', '').strip()\n            while ';' not in declaration:\n                declaration += (next(a)).strip()\n            # print(declaration)\n            ffi.cdef(declaration, override=True)\n            cnt +=1\n    print('Imported {} declarations'.format(cnt))\n\n\n    C = None\n    import os, sys\n    path_build = os.path.join(\".\", \"build\")\n    paths = [\n            os.environ.get('LIBNK_PATH', None),\n            os.path.join(path_build,\"libnitrokey.so\"),\n            os.path.join(path_build,\"libnitrokey.dylib\"),\n            os.path.join(path_build,\"libnitrokey.dll\"),\n            os.path.join(path_build,\"nitrokey.dll\"),\n    ]\n    for p in paths:\n        if not p: continue\n        print(\"Trying \" +p)\n        p = os.path.abspath(p)\n        if os.path.exists(p):\n            print(\"Found: \"+p)\n            C = ffi.dlopen(p)\n            break\n        else:\n            print(\"File does not exist: \" + p)\n    if not C:\n        print(\"No library file found\")\n        sys.exit(1)\n\n    return C\n\n\ndef get_hotp_code(lib, i):\n    return lib.NK_get_hotp_code(i)\n\ndef connect_device(lib):\n\t# lib.NK_login('S'.encode('ascii'))  # connect only to Nitrokey Storage device\n\t# lib.NK_login('P'.encode('ascii'))  # connect only to Nitrokey Pro device\n\tdevice_connected = lib.NK_login_auto()  # connect to any Nitrokey Stick\n\tif device_connected:\n\t\tprint('Connected to Nitrokey device!')\n\telse:\n\t    print('Could not connect to Nitrokey device!')\n\t    exit()\n\nlibnitrokey = get_library()\nlibnitrokey.NK_set_debug(False)  # do not show debug messages (log library only)\n\nconnect_device(libnitrokey)\n\nhotp_slot_code = get_hotp_code(libnitrokey, 1)\nprint('Getting HOTP code from Nitrokey device: ')\nprint(ffi.string(hotp_slot_code).decode('ascii'))\nlibnitrokey.NK_logout()  # disconnect device\n```\n\n\u003c/details\u003e\n\nIn case  no devices are connected, a friendly message will be printed.\nAll available functions for C and Python are listed in [NK_C_API.h](NK_C_API.h). Please check `Documentation` section below.\n\n## Documentation\nThe documentation of C API is included in the sources (can be generated with `make doc` if Doxygen is installed).\nPlease check [NK_C_API.h](NK_C_API.h) (C API) for high level commands and [libnitrokey/NitrokeyManager.h](libnitrokey/NitrokeyManager.h) (C++ API). All devices' commands are listed along with packet format in [libnitrokey/stick10_commands.h](libnitrokey/stick10_commands.h) and [libnitrokey/stick20_commands.h](libnitrokey/stick20_commands.h) respectively for Nitrokey Pro and Nitrokey Storage products.\n\n# Tests\n**Warning!** Most of the tests will overwrite user data. The only user-data safe tests are specified in `unittest/test_safe.cpp` (see *C++ tests* chapter).\n\n**Warning!** Before you run unittests please change both your Admin and User PINs on your Nitrostick to defaults (`12345678` and `123456` respectively), or change the values in tests source code. If you do not change them, the tests might lock your device temporarily. If it's too late already, you can reset your Nitrokey using instructions from [homepage](https://www.nitrokey.com/de/documentation/how-reset-nitrokey).\n\n## Helper\n\nHere are Python tests helper calls:\n\n```bash\n# setup, requires pipenv installed\n$ make tests-setup\n# For Nitrokey Pro\n$ make tests-pro\n# For Nitrokey Storage\n$ make tests-storage\n```\n\nSee below for the further information.\n\n## Python tests\nlibnitrokey has a great suite of tests written in Python 3 under the path: [unittest/test_*.py](https://github.com/Nitrokey/libnitrokey/tree/master/unittest): \n* `test_pro.py` - contains tests of OTP, Password Safe and PIN control functionality. Could be run on both Pro and Storage devices.\n* `test_storage.py` - contains tests of Encrypted Volumes functionality. Could be run only on Storage.\n\nThe tests themselves show how to handle common requests to device.\nBefore running please install all required libraries with:\n```bash\ncd unittest\npip install --user -r requirements.txt\n```\nor use Python's environment managing tool like [pipenv](https://pipenv.readthedocs.io/en/latest/) or `virtualenv`.\n\n\nTo run them please execute: \n```bash\n# substitute \u003cdev\u003e with either 'pro' or 'storage'\npy.test -v test_\u003cdev\u003e.py\n# more specific use - run tests containing in name \u003ctest_name\u003e 5 times:\npy.test -v test_\u003cdev\u003e.py -k \u003ctest_name\u003e --count 5\n\n```\nFor additional documentation please check the following for [py.test installation](http://doc.pytest.org/en/latest/getting-started.html). For better coverage [randomly plugin](https://pypi.python.org/pypi/pytest-randomly) is installed - it randomizes the test order allowing to detect unseen dependencies between the tests.\n\n## C++ tests\nThere are also some unit tests implemented in C++, placed in unittest directory. The only user-data safe online test set here is [test_safe.cpp](https://github.com/Nitrokey/libnitrokey/blob/master/unittest/test_safe.cpp), which tries to connect to the device, and collect its status data. Example run for Storage:\n\n\u003cdetails\u003e\n    \u003csummary\u003eLog (click to show)\u003c/summary\u003e\n\n```text\n# Storage device inserted, firmware version v0.53\n$ ./test_safe\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    =\u003e GET_DEVICE_STATUS\n..\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    \u003c= GET_DEVICE_STATUS 0 1\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    =\u003e GET_PASSWORD_RETRY_COUNT\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    \u003c= GET_PASSWORD_RETRY_COUNT 0 0\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    =\u003e GET_DEVICE_STATUS\n..\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    \u003c= GET_DEVICE_STATUS 0 1\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    =\u003e GET_USER_PASSWORD_RETRY_COUNT\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    \u003c= GET_USER_PASSWORD_RETRY_COUNT 0 0\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    =\u003e GET_DEVICE_STATUS\n...\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    \u003c= GET_DEVICE_STATUS 0 1\n transmission_data.dissect():   _padding:\n0000    00 00 00 00 00 00 00 00 00 00 00 00 00 05 2e 01   ................\n0010    00 00 -- -- -- -- -- -- -- -- -- -- -- -- -- --   ..\n (int) SendCounter_u8:  0\n (int) SendDataType_u8: 3\n (int) FollowBytesFlag_u8:      0\n (int) SendSize_u8:     28\n\n MagicNumber_StickConfig_u16:   13080\n (int) ReadWriteFlagUncryptedVolume_u8: 1\n (int) ReadWriteFlagCryptedVolume_u8:   0\n (int) ReadWriteFlagHiddenVolume_u8:    0\n (int) versionInfo.major:       0\n (int) versionInfo.minor:       53\n (int) versionInfo.build_iteration:     0\n (int) FirmwareLocked_u8:       0\n (int) NewSDCardFound_u8:       1\n (int) NewSDCardFound_st.NewCard:       1\n (int) NewSDCardFound_st.Counter:       0\n (int) SDFillWithRandomChars_u8:        1\n ActiveSD_CardID_u32:   3670817656\n (int) VolumeActiceFlag_u8:     1\n (int) VolumeActiceFlag_st.unencrypted: 1\n (int) VolumeActiceFlag_st.encrypted:   0\n (int) VolumeActiceFlag_st.hidden:      0\n (int) NewSmartCardFound_u8:    0\n (int) UserPwRetryCount:        3\n (int) AdminPwRetryCount:       3\n ActiveSmartCardID_u32: 24122\n (int) StickKeysNotInitiated:   0\n\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    =\u003e GET_DEVICE_STATUS\n..\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    \u003c= GET_DEVICE_STATUS 0 1\n00005e3a\n[Wed Jan  2 13:31:17 2019][DEBUG_L1]    =\u003e GET_DEVICE_STATUS\n....\n[Wed Jan  2 13:31:18 2019][DEBUG_L1]    \u003c= GET_DEVICE_STATUS 0 1\n[Wed Jan  2 13:31:18 2019][DEBUG_L1]    =\u003e GET_DEVICE_STATUS\n...\n[Wed Jan  2 13:31:18 2019][DEBUG_L1]    \u003c= GET_DEVICE_STATUS 0 1\n===============================================================================\nAll tests passed (18 assertions in 6 test cases)\n```\n\n\u003c/details\u003e\n\n\nTest's execution configuration and verbosity could be manipulated - please see `./test_safe --help` for details.\n\nThe other tests sets are not written as extensively as Python tests and are rather more a C++ low level interface check used during the library development, using either low-level components, C API from `NK_C_API.cc`, or C++ API from `NitrokeyManager.cc`. Some of them are: [test_HOTP.cc](https://github.com/Nitrokey/libnitrokey/blob/master/unittest/test_HOTP.cc),\n[test1.cc](https://github.com/Nitrokey/libnitrokey/blob/master/unittest/test1.cc). See more in [unittest](https://github.com/Nitrokey/libnitrokey/tree/master/unittest) directory.\n\n**Note: these are not device model agnostic, and will most probably destroy your data on the device.**\n\n\nUnit tests were checked on Ubuntu 16.04/16.10/17.04. To run them just execute binaries built in `./libnitrokey/build` dir, after enabling them by passing `-DCOMPILE_TESTS=ON` option to `cmake` - e.g.: `cmake .. -DCOMPILE_TESTS=ON \u0026\u0026 make`. \n\n\nThe documentation of how it works could be found in nitrokey-app project's README on Github:\n[Nitrokey-app - internals](https://github.com/Nitrokey/nitrokey-app/blob/master/README.md#internals).\n\nTo peek/debug communication with device running nitrokey-app (0.x branch) in debug mode (`-d` switch) and checking the logs\n(right click on tray icon and then 'Debug') might be helpful. Latest Nitrokey App (1.x branch) uses libnitrokey to communicate with device. Once run with `--dl 3` (3 or higher; range 0-5) it will print all communication to the console. Additionally crosschecking with\nfirmware code should show how things works:\n[report_protocol.c](https://github.com/Nitrokey/nitrokey-pro-firmware/blob/master/src/keyboard/report_protocol.c)\n(for Nitrokey Pro, for Storage similarly).\n\n# Known issues / tasks\n* C++ API needs some reorganization to C++ objects (instead of pointers to byte arrays). This would be also preparation for Pybind11 integration;\n* Fix compilation warnings.\n\nOther tasks might be listed either in [TODO](TODO) file or on project's issues page.\n\n# License\nThis project is licensed under LGPL version 3. License text can be found under [LICENSE](LICENSE) file.\n\n# Roadmap\nTo check what issues will be fixed and when please check [milestones](https://github.com/Nitrokey/libnitrokey/milestones) page.\n\n# Nitrokey USB IDs\n\nFor a list of USB identifiers for Nitrokey products, please refer to the [data](./data) subdirectory.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitrokey%2Flibnitrokey","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnitrokey%2Flibnitrokey","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnitrokey%2Flibnitrokey/lists"}