diff --git a/CMakeLists.txt b/CMakeLists.txt index db8d2fb3..c592a9f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +set(DEV OFF) include(GNUInstallDirs) @@ -43,35 +44,67 @@ MESSAGE("${PROJECT_NAME}: Build type: ${CMAKE_BUILD_TYPE}") include_directories(hidapi) include_directories(libnitrokey) + +set(COMMON_FILES + libnitrokey/command.h + libnitrokey/command_id.h + libnitrokey/cxx_semantics.h + libnitrokey/device.h + libnitrokey/device_proto.h + libnitrokey/dissect.h + libnitrokey/log.h + libnitrokey/misc.h + libnitrokey/NitrokeyManager.h + libnitrokey/stick10_commands.h + libnitrokey/stick20_commands.h + libnitrokey/CommandFailedException.h + libnitrokey/LibraryException.h + libnitrokey/LongOperationInProgressException.h + libnitrokey/stick10_commands_0.8.h + command_id.cc + device.cc + log.cc + misc.cc + nk_strndup.c + DeviceCommunicationExceptions.cpp + ${CMAKE_CURRENT_BINARY_DIR}/version.cc + ) + set(SOURCE_FILES - libnitrokey/command.h - libnitrokey/command_id.h - libnitrokey/cxx_semantics.h - libnitrokey/device.h - libnitrokey/device_proto.h - libnitrokey/dissect.h - libnitrokey/log.h - libnitrokey/misc.h - libnitrokey/NitrokeyManager.h - libnitrokey/stick10_commands.h - libnitrokey/stick20_commands.h - libnitrokey/CommandFailedException.h - libnitrokey/LibraryException.h - libnitrokey/LongOperationInProgressException.h - libnitrokey/stick10_commands_0.8.h - command_id.cc - device.cc - log.cc - misc.cc + ${COMMON_FILES} NitrokeyManager.cc + NitrokeyManagerStorage.cpp + NitrokeyManagerStorage.h + NitrokeyManagerOTP.cc + NitrokeyManagerOTP.h + NitrokeyManagerPWS.h + NitrokeyManagerPWS.cc NK_C_API.h NK_C_API.cc - DeviceCommunicationExceptions.cpp - ${CMAKE_CURRENT_BINARY_DIR}/version.cc + NK_C_API_pws.cpp + NK_C_API_otp.cpp + NK_C_API_helpers.cpp + NK_C_API_helpers.h + NK_C_API_storage.h + NK_C_API_storage.cpp + ) + +set(SOURCE_FILES_storage + ${COMMON_FILES} + NitrokeyManager.cc + NitrokeyManagerStorage.cpp + NitrokeyManagerStorage.h + NK_C_API.h + NK_C_API.cc + NK_C_API_helpers.cpp + NK_C_API_helpers.h + NK_C_API_storage.h + NK_C_API_storage.cpp ) set(BUILD_SHARED_LIBS ON CACHE BOOL "Build all libraries as shared") add_library(nitrokey ${SOURCE_FILES}) +add_library(nitrokey-storage ${SOURCE_FILES_storage}) IF(APPLE) include_directories(hidapi/hidapi) @@ -82,8 +115,12 @@ ELSEIF(UNIX) # add_library(hidapi-libusb STATIC hidapi/libusb/hid.c ) find_package(PkgConfig) pkg_search_module(HIDAPI_LIBUSB REQUIRED hidapi-libusb) - target_compile_options(nitrokey PRIVATE ${HIDAPI_LIBUSB_CFLAGS}) + IF(DEV) + target_compile_options(nitrokey PRIVATE "${HIDAPI_LIBUSB_CFLAGS} -Os") + target_link_options(nitrokey PRIVATE "-Wl,-Map=output.map") + ENDIF() target_link_libraries(nitrokey ${HIDAPI_LIBUSB_LDFLAGS}) + target_link_libraries(nitrokey-storage ${HIDAPI_LIBUSB_LDFLAGS}) ELSEIF(WIN32) include_directories(hidapi/hidapi) add_library(hidapi-libusb STATIC hidapi/windows/hid.c ) @@ -94,6 +131,9 @@ ENDIF() set_target_properties(nitrokey PROPERTIES VERSION ${libnitrokey_VERSION} SOVERSION ${libnitrokey_VERSION_MAJOR}) +set_target_properties(nitrokey-storage PROPERTIES + VERSION ${libnitrokey_VERSION} + SOVERSION ${libnitrokey_VERSION_MAJOR}) OPTION(ERROR_ON_WARNING "Stop compilation on warning found (not supported for MSVC)" OFF) if (NOT MSVC) @@ -109,6 +149,7 @@ endif() OPTION(NO_LOG "Compile without logging functionality and its strings (decreases size)" OFF) IF (NO_LOG) SET_TARGET_PROPERTIES(nitrokey PROPERTIES COMPILE_DEFINITIONS "NO_LOG") + SET_TARGET_PROPERTIES(nitrokey-storage PROPERTIES COMPILE_DEFINITIONS "NO_LOG") ENDIF() OPTION(LOG_VOLATILE_DATA "Log volatile data (debug)" OFF) diff --git a/NK_C_API.cc b/NK_C_API.cc index 538a6a1b..951532bf 100644 --- a/NK_C_API.cc +++ b/NK_C_API.cc @@ -20,7 +20,9 @@ */ #include "NK_C_API.h" +#ifndef NO_LOG #include +#endif #include #include "libnitrokey/NitrokeyManager.h" #include @@ -30,92 +32,16 @@ #include "libnitrokey/device_proto.h" #include "libnitrokey/version.h" -#ifdef _MSC_VER -#ifdef _WIN32 -#pragma message "Using own strndup" -char * strndup(const char* str, size_t maxlen) { - size_t len = strnlen(str, maxlen); - char* dup = (char *)malloc(len + 1); - memcpy(dup, str, len); - dup[len] = 0; - return dup; -} -#endif -#endif - -using namespace nitrokey; - -const uint8_t NK_PWS_SLOT_COUNT = PWS_SLOT_COUNT; -static uint8_t NK_last_command_status = 0; -static const int max_string_field_length = 100; -template -T* duplicate_vector_and_clear(std::vector &v){ - auto d = new T[v.size()]; - std::copy(v.begin(), v.end(), d); - std::fill(v.begin(), v.end(), 0); - return d; -} +#include "nk_strndup.h" -template -std::tuple get_with_status(T func, R fallback) { - NK_last_command_status = 0; - try { - return std::make_tuple(0, func()); - } - catch (CommandFailedException & commandFailedException){ - NK_last_command_status = commandFailedException.last_command_status; - } - catch (LibraryException & libraryException){ - NK_last_command_status = libraryException.exception_id(); - } - catch (const DeviceCommunicationException &deviceException){ - NK_last_command_status = 256-deviceException.getType(); - } - return std::make_tuple(NK_last_command_status, fallback); -} - -template -uint8_t * get_with_array_result(T func){ - return std::get<1>(get_with_status(func, nullptr)); -} - -template -char* get_with_string_result(T func){ - auto result = std::get<1>(get_with_status(func, nullptr)); - if (result == nullptr) { - return strndup("", MAXIMUM_STR_REPLY_LENGTH); - } - return result; -} - -template -auto get_with_result(T func){ - return std::get<1>(get_with_status(func, static_cast(0))); -} +using namespace nitrokey; -template -uint8_t get_without_result(T func){ - NK_last_command_status = 0; - try { - func(); - return 0; - } - catch (CommandFailedException & commandFailedException){ - NK_last_command_status = commandFailedException.last_command_status; - } - catch (LibraryException & libraryException){ - NK_last_command_status = libraryException.exception_id(); - } - catch (const InvalidCRCReceived &invalidCRCException){ - ; - } - catch (const DeviceCommunicationException &deviceException){ - NK_last_command_status = 256-deviceException.getType(); - } - return NK_last_command_status; -} +uint8_t NK_last_command_status = 0; +#include "NK_C_API_helpers.h" +#include "NitrokeyManagerOTP.h" +#include "NitrokeyManagerPWS.h" #ifdef __cplusplus extern "C" { @@ -139,11 +65,15 @@ extern "C" { } catch (const DeviceCommunicationException &deviceException){ NK_last_command_status = 256-deviceException.getType(); +#ifndef NO_LOG cerr << deviceException.what() << endl; +#endif return 0; } catch (std::runtime_error &e) { - cerr << e.what() << endl; +#ifndef NO_LOG + cerr << e.what() << endl; +#endif return 0; } return 0; @@ -211,50 +141,6 @@ extern "C" { }); } - NK_C_API int NK_write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password, - bool delete_user_password, - const char *admin_temporary_password) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - return m->write_config(numlock, capslock, scrolllock, enable_user_password, delete_user_password, admin_temporary_password); - }); - } - - NK_C_API int NK_write_config_struct(struct NK_config config, - const char *admin_temporary_password) { - return NK_write_config(config.numlock, config.capslock, config.scrolllock, config.enable_user_password, - config.disable_user_password, admin_temporary_password); - } - - - NK_C_API uint8_t* NK_read_config() { - auto m = NitrokeyManager::instance(); - return get_with_array_result([&]() { - auto v = m->read_config(); - return duplicate_vector_and_clear(v); - }); - } - - NK_C_API void NK_free_config(uint8_t* config) { - delete[] config; - } - - NK_C_API int NK_read_config_struct(struct NK_config* out) { - if (out == nullptr) { - return -1; - } - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - auto v = m->read_config(); - out->numlock = v[0]; - out->capslock = v[1]; - out->scrolllock = v[2]; - out->enable_user_password = v[3]; - out->disable_user_password = v[4]; - }); - } - - NK_C_API enum NK_device_model NK_get_device_model() { auto m = NitrokeyManager::instance(); try { @@ -275,12 +161,6 @@ extern "C" { } } - - void clear_string(std::string &s) { - std::fill(s.begin(), s.end(), ' '); - } - - NK_C_API char * NK_status() { return NK_get_status_as_string(); } @@ -336,91 +216,11 @@ extern "C" { }); } - NK_C_API char * NK_get_hotp_code(uint8_t slot_number) { - return NK_get_hotp_code_PIN(slot_number, ""); - } - - NK_C_API char * NK_get_hotp_code_PIN(uint8_t slot_number, const char *user_temporary_password) { - auto m = NitrokeyManager::instance(); - return get_with_string_result([&]() { - string && s = m->get_HOTP_code(slot_number, user_temporary_password); - char * rs = strndup(s.c_str(), max_string_field_length); - clear_string(s); - return rs; - }); - } - - NK_C_API char * NK_get_totp_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, - uint8_t last_interval) { - return NK_get_totp_code_PIN(slot_number, challenge, last_totp_time, last_interval, ""); - } - - NK_C_API char * NK_get_totp_code_PIN(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, - uint8_t last_interval, const char *user_temporary_password) { - auto m = NitrokeyManager::instance(); - return get_with_string_result([&]() { - string && s = m->get_TOTP_code(slot_number, challenge, last_totp_time, last_interval, user_temporary_password); - char * rs = strndup(s.c_str(), max_string_field_length); - clear_string(s); - return rs; - }); - } - - NK_C_API int NK_erase_hotp_slot(uint8_t slot_number, const char *temporary_password) { - auto m = NitrokeyManager::instance(); - return get_without_result([&] { - m->erase_hotp_slot(slot_number, temporary_password); - }); - } - - NK_C_API int NK_erase_totp_slot(uint8_t slot_number, const char *temporary_password) { - auto m = NitrokeyManager::instance(); - return get_without_result([&] { - m->erase_totp_slot(slot_number, temporary_password); - }); - } - - NK_C_API int NK_write_hotp_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint64_t hotp_counter, - bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, - const char *temporary_password) { - auto m = NitrokeyManager::instance(); - return get_without_result([&] { - m->write_HOTP_slot(slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, token_ID, - temporary_password); - }); - } - - NK_C_API int NK_write_totp_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint16_t time_window, - bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, - const char *temporary_password) { - auto m = NitrokeyManager::instance(); - return get_without_result([&] { - m->write_TOTP_slot(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, token_ID, - temporary_password); - }); - } - - NK_C_API char* NK_get_totp_slot_name(uint8_t slot_number) { - auto m = NitrokeyManager::instance(); - return get_with_string_result([&]() { - const auto slot_name = m->get_totp_slot_name(slot_number); - return slot_name; - }); - } - NK_C_API char* NK_get_hotp_slot_name(uint8_t slot_number) { - auto m = NitrokeyManager::instance(); - return get_with_string_result([&]() { - const auto slot_name = m->get_hotp_slot_name(slot_number); - return slot_name; - }); - } - NK_C_API void NK_set_debug(bool state) { auto m = NitrokeyManager::instance(); m->set_debug(state); } - NK_C_API void NK_set_debug_level(const int level) { auto m = NitrokeyManager::instance(); m->set_loglevel(level); @@ -438,24 +238,6 @@ extern "C" { return get_library_version(); } - NK_C_API int NK_totp_set_time(uint64_t time) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->set_time(time); - }); - } - - NK_C_API int NK_totp_set_time_soft(uint64_t time) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->set_time_soft(time); - }); - } - - NK_C_API int NK_totp_get_time() { - return 0; - } - NK_C_API int NK_change_admin_PIN(const char *current_PIN, const char *new_PIN) { auto m = NitrokeyManager::instance(); return get_without_result([&]() { @@ -470,25 +252,6 @@ extern "C" { }); } - NK_C_API int NK_enable_password_safe(const char *user_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->enable_password_safe(user_pin); - }); - } - NK_C_API uint8_t * NK_get_password_safe_slot_status() { - auto m = NitrokeyManager::instance(); - return get_with_array_result([&]() { - auto slot_status = m->get_password_safe_slot_status(); - return duplicate_vector_and_clear(slot_status); - }); - - } - - NK_C_API void NK_free_password_safe_slot_status(uint8_t* status) { - delete[] status; - } - NK_C_API uint8_t NK_get_user_retry_count() { auto m = NitrokeyManager::instance(); return get_with_result([&]() { @@ -510,40 +273,6 @@ extern "C" { }); } - NK_C_API char *NK_get_password_safe_slot_name(uint8_t slot_number) { - auto m = NitrokeyManager::instance(); - return get_with_string_result([&]() { - return m->get_password_safe_slot_name(slot_number); - }); - } - - NK_C_API char *NK_get_password_safe_slot_login(uint8_t slot_number) { - auto m = NitrokeyManager::instance(); - return get_with_string_result([&]() { - return m->get_password_safe_slot_login(slot_number); - }); - } - NK_C_API char *NK_get_password_safe_slot_password(uint8_t slot_number) { - auto m = NitrokeyManager::instance(); - return get_with_string_result([&]() { - return m->get_password_safe_slot_password(slot_number); - }); - } - NK_C_API int NK_write_password_safe_slot(uint8_t slot_number, const char *slot_name, const char *slot_login, - const char *slot_password) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->write_password_safe_slot(slot_number, slot_name, slot_login, slot_password); - }); - } - - NK_C_API int NK_erase_password_safe_slot(uint8_t slot_number) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->erase_password_safe_slot(slot_number); - }); - } - NK_C_API int NK_is_AES_supported(const char *user_password) { auto m = NitrokeyManager::instance(); return get_with_result([&]() { @@ -558,238 +287,6 @@ extern "C" { }); } - // storage commands - - NK_C_API int NK_send_startup(uint64_t seconds_from_epoch) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->send_startup(seconds_from_epoch); - }); - } - - NK_C_API int NK_unlock_encrypted_volume(const char* user_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->unlock_encrypted_volume(user_pin); - }); - } - - NK_C_API int NK_lock_encrypted_volume() { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->lock_encrypted_volume(); - }); - } - - NK_C_API int NK_unlock_hidden_volume(const char* hidden_volume_password) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->unlock_hidden_volume(hidden_volume_password); - }); - } - - NK_C_API int NK_lock_hidden_volume() { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->lock_hidden_volume(); - }); - } - - NK_C_API int NK_create_hidden_volume(uint8_t slot_nr, uint8_t start_percent, uint8_t end_percent, - const char *hidden_volume_password) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->create_hidden_volume(slot_nr, start_percent, end_percent, - hidden_volume_password); - }); - } - - NK_C_API int NK_set_unencrypted_read_only(const char *user_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->set_unencrypted_read_only(user_pin); - }); - } - - NK_C_API int NK_set_unencrypted_read_write(const char *user_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->set_unencrypted_read_write(user_pin); - }); - } - - NK_C_API int NK_set_unencrypted_read_only_admin(const char *admin_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->set_unencrypted_read_only_admin(admin_pin); - }); - } - - NK_C_API int NK_set_unencrypted_read_write_admin(const char *admin_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->set_unencrypted_read_write_admin(admin_pin); - }); - } - - NK_C_API int NK_set_encrypted_read_only(const char* admin_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->set_encrypted_volume_read_only(admin_pin); - }); - } - - NK_C_API int NK_set_encrypted_read_write(const char* admin_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->set_encrypted_volume_read_write(admin_pin); - }); - } - - NK_C_API int NK_export_firmware(const char* admin_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->export_firmware(admin_pin); - }); - } - - NK_C_API int NK_clear_new_sd_card_warning(const char* admin_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->clear_new_sd_card_warning(admin_pin); - }); - } - - NK_C_API int NK_fill_SD_card_with_random_data(const char* admin_pin) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->fill_SD_card_with_random_data(admin_pin); - }); - } - - NK_C_API int NK_change_update_password(const char* current_update_password, - const char* new_update_password) { - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->change_update_password(current_update_password, new_update_password); - }); - } - - NK_C_API int NK_enable_firmware_update(const char* update_password){ - auto m = NitrokeyManager::instance(); - return get_without_result([&]() { - m->enable_firmware_update(update_password); - }); - } - - NK_C_API char* NK_get_status_storage_as_string() { - auto m = NitrokeyManager::instance(); - return get_with_string_result([&]() { - return m->get_status_storage_as_string(); - }); - } - - NK_C_API int NK_get_status_storage(NK_storage_status* out) { - if (out == nullptr) { - return -1; - } - auto m = NitrokeyManager::instance(); - auto result = get_with_status([&]() { - return m->get_status_storage(); - }, proto::stick20::DeviceConfigurationResponsePacket::ResponsePayload()); - auto error_code = std::get<0>(result); - if (error_code != 0) { - return error_code; - } - - auto status = std::get<1>(result); - out->unencrypted_volume_read_only = status.ReadWriteFlagUncryptedVolume_u8 != 0; - out->unencrypted_volume_active = status.VolumeActiceFlag_st.unencrypted; - out->encrypted_volume_read_only = status.ReadWriteFlagCryptedVolume_u8 != 0; - out->encrypted_volume_active = status.VolumeActiceFlag_st.encrypted; - out->hidden_volume_read_only = status.ReadWriteFlagHiddenVolume_u8 != 0; - out->hidden_volume_active = status.VolumeActiceFlag_st.hidden; - out->firmware_version_major = status.versionInfo.major; - out->firmware_version_minor = status.versionInfo.minor; - out->firmware_locked = status.FirmwareLocked_u8 != 0; - out->serial_number_sd_card = status.ActiveSD_CardID_u32; - out->serial_number_smart_card = status.ActiveSmartCardID_u32; - out->user_retry_count = status.UserPwRetryCount; - out->admin_retry_count = status.AdminPwRetryCount; - out->new_sd_card_found = status.NewSDCardFound_st.NewCard; - out->filled_with_random = (status.SDFillWithRandomChars_u8 & 0x01) != 0; - out->stick_initialized = status.StickKeysNotInitiated == 0; - return 0; - } - - NK_C_API int NK_get_storage_production_info(NK_storage_ProductionTest * out){ - if (out == nullptr) { - return -1; - } - auto m = NitrokeyManager::instance(); - auto result = get_with_status([&]() { - return m->production_info(); - }, proto::stick20::ProductionTest::ResponsePayload()); - - auto error_code = std::get<0>(result); - if (error_code != 0) { - return error_code; - } - - stick20::ProductionTest::ResponsePayload status = std::get<1>(result); - // Cannot use memcpy without declaring C API struct packed - // (which is not parsed by Python's CFFI apparently), hence the manual way. -#define a(x) out->x = status.x; - a(FirmwareVersion_au8[0]); - a(FirmwareVersion_au8[1]); - a(FirmwareVersionInternal_u8); - a(SD_Card_Size_u8); - a(CPU_CardID_u32); - a(SmartCardID_u32); - a(SD_CardID_u32); - a(SC_UserPwRetryCount); - a(SC_AdminPwRetryCount); - a(SD_Card_ManufacturingYear_u8); - a(SD_Card_ManufacturingMonth_u8); - a(SD_Card_OEM_u16); - a(SD_WriteSpeed_u16); - a(SD_Card_Manufacturer_u8); -#undef a - return 0; - } - - NK_C_API int NK_get_SD_usage_data(struct NK_SD_usage_data* out) { - if (out == nullptr) - return -1; - auto m = NitrokeyManager::instance(); - auto result = get_with_status([&]() { - return m->get_SD_usage_data(); - }, std::make_pair(0, 0)); - auto error_code = std::get<0>(result); - if (error_code != 0) - return error_code; - - auto data = std::get<1>(result); - out->write_level_min = std::get<0>(data); - out->write_level_max = std::get<1>(data); - - return 0; - } - -NK_C_API char* NK_get_SD_usage_data_as_string() { - auto m = NitrokeyManager::instance(); - return get_with_string_result([&]() { - return m->get_SD_usage_data_as_string(); - }); - } - - NK_C_API int NK_get_progress_bar_value() { - auto m = NitrokeyManager::instance(); - return std::get<1>(get_with_status([&]() { - return m->get_progress_bar_value(); - }, -2)); - } - NK_C_API uint8_t NK_get_major_firmware_version() { auto m = NitrokeyManager::instance(); return get_with_result([&]() { @@ -804,12 +301,6 @@ NK_C_API char* NK_get_SD_usage_data_as_string() { }); } - NK_C_API int NK_set_unencrypted_volume_rorw_pin_type_user() { - auto m = NitrokeyManager::instance(); - return get_with_result([&]() { - return m->set_unencrypted_volume_rorw_pin_type_user() ? 1 : 0; - }); - } NK_C_API char* NK_list_devices_by_cpuID() { auto nm = NitrokeyManager::instance(); @@ -925,29 +416,6 @@ NK_C_API char* NK_get_SD_usage_data_as_string() { } - NK_C_API int NK_read_HOTP_slot(const uint8_t slot_num, struct ReadSlot_t* out){ - if (out == nullptr) - return -1; - auto m = NitrokeyManager::instance(); - auto result = get_with_status([&]() { - return m->get_HOTP_slot_data(slot_num); - }, stick10::ReadSlot::ResponsePayload() ); - auto error_code = std::get<0>(result); - if (error_code != 0) { - return error_code; - } -#define a(x) out->x = read_slot.x - stick10::ReadSlot::ResponsePayload read_slot = std::get<1>(result); - a(_slot_config); - a(slot_counter); -#undef a -#define m(x) memmove(out->x, read_slot.x, sizeof(read_slot.x)) - m(slot_name); - m(slot_token_id); -#undef m - return 0; -} - #ifdef __cplusplus } diff --git a/NK_C_API.h b/NK_C_API.h index 5341c086..c79b8a26 100644 --- a/NK_C_API.h +++ b/NK_C_API.h @@ -1082,5 +1082,6 @@ NK_C_API int NK_read_HOTP_slot(const uint8_t slot_num, struct ReadSlot_t* out); #ifdef __cplusplus } #endif +extern uint8_t NK_last_command_status; #endif //LIBNITROKEY_NK_C_API_H diff --git a/NK_C_API_helpers.cpp b/NK_C_API_helpers.cpp new file mode 100644 index 00000000..f0353aa4 --- /dev/null +++ b/NK_C_API_helpers.cpp @@ -0,0 +1,5 @@ +#include + +void clear_string(std::string &s) { + std::fill(s.begin(), s.end(), ' '); +} \ No newline at end of file diff --git a/NK_C_API_helpers.h b/NK_C_API_helpers.h new file mode 100644 index 00000000..3cb110bd --- /dev/null +++ b/NK_C_API_helpers.h @@ -0,0 +1,88 @@ +#ifndef LIBNITROKEY_NK_C_API_HELPERS_H +#define LIBNITROKEY_NK_C_API_HELPERS_H + + +#include "NK_C_API.h" +#include +#include "libnitrokey/NitrokeyManager.h" +#include +#include "libnitrokey/LibraryException.h" +#include "libnitrokey/cxx_semantics.h" +#include "libnitrokey/stick20_commands.h" +#include "libnitrokey/device_proto.h" +#include "libnitrokey/version.h" + +void clear_string(std::string &s); + +extern uint8_t NK_last_command_status; + + +template +T* duplicate_vector_and_clear(std::vector &v){ + auto d = new T[v.size()]; + std::copy(v.begin(), v.end(), d); + std::fill(v.begin(), v.end(), 0); + return d; +} + +template +std::tuple get_with_status(T func, R fallback) { + NK_last_command_status = 0; + try { + return std::make_tuple(0, func()); + } + catch (CommandFailedException & commandFailedException){ + NK_last_command_status = commandFailedException.last_command_status; + } + catch (LibraryException & libraryException){ + NK_last_command_status = libraryException.exception_id(); + } + catch (const DeviceCommunicationException &deviceException){ + NK_last_command_status = 256-deviceException.getType(); + } + return std::make_tuple(NK_last_command_status, fallback); +} + +template +uint8_t * get_with_array_result(T func){ + return std::get<1>(get_with_status(func, nullptr)); +} + +template +char* get_with_string_result(T func){ + auto result = std::get<1>(get_with_status(func, nullptr)); + if (result == nullptr) { + return strndup("", MAXIMUM_STR_REPLY_LENGTH); + } + return result; +} + +template +auto get_with_result(T func){ + return std::get<1>(get_with_status(func, static_cast(0))); +} + +template +uint8_t get_without_result(T func){ + NK_last_command_status = 0; + try { + func(); + return 0; + } + catch (CommandFailedException & commandFailedException){ + NK_last_command_status = commandFailedException.last_command_status; + } + catch (LibraryException & libraryException){ + NK_last_command_status = libraryException.exception_id(); + } + catch (const InvalidCRCReceived &invalidCRCException){ + ; + } + catch (const DeviceCommunicationException &deviceException){ + NK_last_command_status = 256-deviceException.getType(); + } + return NK_last_command_status; +} + + +#endif // LIBNITROKEY_NK_C_API_HELPERS_H diff --git a/NK_C_API_otp.cpp b/NK_C_API_otp.cpp new file mode 100644 index 00000000..c1f2e1bb --- /dev/null +++ b/NK_C_API_otp.cpp @@ -0,0 +1,195 @@ + +#include "NK_C_API.h" +#include "NK_C_API_helpers.h" +#include "NitrokeyManagerOTP.h" +#include "NitrokeyManagerPWS.h" +#include "libnitrokey/LibraryException.h" +#include "libnitrokey/NitrokeyManager.h" +#include "libnitrokey/cxx_semantics.h" +#include "libnitrokey/device_proto.h" +#include "libnitrokey/stick20_commands.h" +#include "libnitrokey/version.h" +#include +#include + +#include "nk_strndup.h" + +using namespace nitrokey; + + +#ifdef __cplusplus +extern "C" { +#endif + + +NK_C_API int NK_totp_set_time(uint64_t time) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->set_time(time); + }); +} + +NK_C_API int NK_totp_set_time_soft(uint64_t time) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->set_time_soft(time); + }); +} + +NK_C_API int NK_totp_get_time() { + return 0; +} + + +NK_C_API char * NK_get_hotp_code(uint8_t slot_number) { + return NK_get_hotp_code_PIN(slot_number, ""); +} + +NK_C_API char * NK_get_hotp_code_PIN(uint8_t slot_number, const char *user_temporary_password) { + auto m = NitrokeyManager::instance(); + return get_with_string_result([&]() { + string && s = m->get_HOTP_code(slot_number, user_temporary_password); + char * rs = strndup(s.c_str(), max_string_field_length); + clear_string(s); + return rs; + }); +} + +NK_C_API char * NK_get_totp_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, + uint8_t last_interval) { + return NK_get_totp_code_PIN(slot_number, challenge, last_totp_time, last_interval, ""); +} + +NK_C_API char * NK_get_totp_code_PIN(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, + uint8_t last_interval, const char *user_temporary_password) { + auto m = NitrokeyManager::instance(); + return get_with_string_result([&]() { + string && s = m->get_TOTP_code(slot_number, challenge, last_totp_time, last_interval, user_temporary_password); + char * rs = strndup(s.c_str(), max_string_field_length); + clear_string(s); + return rs; + }); +} + +NK_C_API int NK_erase_hotp_slot(uint8_t slot_number, const char *temporary_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&] { + m->erase_hotp_slot(slot_number, temporary_password); + }); +} + +NK_C_API int NK_erase_totp_slot(uint8_t slot_number, const char *temporary_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&] { + m->erase_totp_slot(slot_number, temporary_password); + }); +} + +NK_C_API int NK_write_hotp_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint64_t hotp_counter, + bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, + const char *temporary_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&] { + m->write_HOTP_slot(slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, token_ID, + temporary_password); + }); +} + +NK_C_API int NK_write_totp_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint16_t time_window, + bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, + const char *temporary_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&] { + m->write_TOTP_slot(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, token_ID, + temporary_password); + }); +} + +NK_C_API char* NK_get_totp_slot_name(uint8_t slot_number) { + auto m = NitrokeyManager::instance(); + return get_with_string_result([&]() { + const auto slot_name = m->get_totp_slot_name(slot_number); + return slot_name; + }); +} +NK_C_API char* NK_get_hotp_slot_name(uint8_t slot_number) { + auto m = NitrokeyManager::instance(); + return get_with_string_result([&]() { + const auto slot_name = m->get_hotp_slot_name(slot_number); + return slot_name; + }); +} + + +NK_C_API int NK_read_HOTP_slot(const uint8_t slot_num, struct ReadSlot_t* out){ + if (out == nullptr) + return -1; + auto m = NitrokeyManager::instance(); + auto result = get_with_status([&]() { + return m->get_HOTP_slot_data(slot_num); + }, stick10::ReadSlot::ResponsePayload() ); + auto error_code = std::get<0>(result); + if (error_code != 0) { + return error_code; + } +#define a(x) out->x = read_slot.x + stick10::ReadSlot::ResponsePayload read_slot = std::get<1>(result); + a(_slot_config); + a(slot_counter); +#undef a +#define m(x) memmove(out->x, read_slot.x, sizeof(read_slot.x)) + m(slot_name); + m(slot_token_id); +#undef m + return 0; +} + + +NK_C_API int NK_write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password, + bool delete_user_password, + const char *admin_temporary_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + return m->write_config(numlock, capslock, scrolllock, enable_user_password, delete_user_password, admin_temporary_password); + }); +} + +NK_C_API int NK_write_config_struct(struct NK_config config, + const char *admin_temporary_password) { + return NK_write_config(config.numlock, config.capslock, config.scrolllock, config.enable_user_password, + config.disable_user_password, admin_temporary_password); +} + + +NK_C_API uint8_t* NK_read_config() { + auto m = NitrokeyManager::instance(); + return get_with_array_result([&]() { + auto v = m->read_config(); + return duplicate_vector_and_clear(v); + }); +} + +NK_C_API void NK_free_config(uint8_t* config) { + delete[] config; +} + +NK_C_API int NK_read_config_struct(struct NK_config* out) { + if (out == nullptr) { + return -1; + } + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + auto v = m->read_config(); + out->numlock = v[0]; + out->capslock = v[1]; + out->scrolllock = v[2]; + out->enable_user_password = v[3]; + out->disable_user_password = v[4]; + }); +} + + + +#ifdef __cplusplus +} +#endif diff --git a/NK_C_API_pws.cpp b/NK_C_API_pws.cpp new file mode 100644 index 00000000..d3df05d0 --- /dev/null +++ b/NK_C_API_pws.cpp @@ -0,0 +1,76 @@ + +#include "NK_C_API.h" +#include "NK_C_API_helpers.h" +#include "NitrokeyManagerOTP.h" +#include "NitrokeyManagerPWS.h" +#include "libnitrokey/LibraryException.h" +#include "libnitrokey/NitrokeyManager.h" +#include "libnitrokey/cxx_semantics.h" +#include "libnitrokey/device_proto.h" +#include "libnitrokey/stick20_commands.h" +#include "libnitrokey/version.h" +#include +#include + +#include "nk_strndup.h" + +using namespace nitrokey; +const uint8_t NK_PWS_SLOT_COUNT = PWS_SLOT_COUNT; + + +#ifdef __cplusplus +extern "C" { +#endif + +NK_C_API int NK_enable_password_safe(const char *user_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { m->enable_password_safe(user_pin); }); +} +NK_C_API uint8_t *NK_get_password_safe_slot_status() { + auto m = NitrokeyManager::instance(); + return get_with_array_result([&]() { + auto slot_status = m->get_password_safe_slot_status(); + return duplicate_vector_and_clear(slot_status); + }); +} + +NK_C_API void NK_free_password_safe_slot_status(uint8_t *status) { + delete[] status; +} + +NK_C_API char *NK_get_password_safe_slot_name(uint8_t slot_number) { + auto m = NitrokeyManager::instance(); + return get_with_string_result( + [&]() { return m->get_password_safe_slot_name(slot_number); }); +} + +NK_C_API char *NK_get_password_safe_slot_login(uint8_t slot_number) { + auto m = NitrokeyManager::instance(); + return get_with_string_result( + [&]() { return m->get_password_safe_slot_login(slot_number); }); +} +NK_C_API char *NK_get_password_safe_slot_password(uint8_t slot_number) { + auto m = NitrokeyManager::instance(); + return get_with_string_result( + [&]() { return m->get_password_safe_slot_password(slot_number); }); +} +NK_C_API int NK_write_password_safe_slot(uint8_t slot_number, + const char *slot_name, + const char *slot_login, + const char *slot_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->write_password_safe_slot(slot_number, slot_name, slot_login, + slot_password); + }); +} + +NK_C_API int NK_erase_password_safe_slot(uint8_t slot_number) { + auto m = NitrokeyManager::instance(); + return get_without_result( + [&]() { m->erase_password_safe_slot(slot_number); }); +} + +#ifdef __cplusplus +} +#endif diff --git a/NK_C_API_storage.cpp b/NK_C_API_storage.cpp new file mode 100644 index 00000000..59bae854 --- /dev/null +++ b/NK_C_API_storage.cpp @@ -0,0 +1,256 @@ +#include "NK_C_API_storage.h" +#include "NK_C_API_helpers.h" + +using namespace nitrokey; + +#include "nk_strndup.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +// storage commands + +NK_C_API int NK_send_startup(uint64_t seconds_from_epoch) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->send_startup(seconds_from_epoch); + }); +} + +NK_C_API int NK_unlock_encrypted_volume(const char* user_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->unlock_encrypted_volume(user_pin); + }); +} + +NK_C_API int NK_lock_encrypted_volume() { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->lock_encrypted_volume(); + }); +} + +NK_C_API int NK_unlock_hidden_volume(const char* hidden_volume_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->unlock_hidden_volume(hidden_volume_password); + }); +} + +NK_C_API int NK_lock_hidden_volume() { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->lock_hidden_volume(); + }); +} + +NK_C_API int NK_create_hidden_volume(uint8_t slot_nr, uint8_t start_percent, uint8_t end_percent, + const char *hidden_volume_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->create_hidden_volume(slot_nr, start_percent, end_percent, + hidden_volume_password); + }); +} + +NK_C_API int NK_set_unencrypted_read_only(const char *user_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->set_unencrypted_read_only(user_pin); + }); +} + +NK_C_API int NK_set_unencrypted_read_write(const char *user_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->set_unencrypted_read_write(user_pin); + }); +} + +NK_C_API int NK_set_unencrypted_read_only_admin(const char *admin_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->set_unencrypted_read_only_admin(admin_pin); + }); +} + +NK_C_API int NK_set_unencrypted_read_write_admin(const char *admin_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->set_unencrypted_read_write_admin(admin_pin); + }); +} + +NK_C_API int NK_set_encrypted_read_only(const char* admin_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->set_encrypted_volume_read_only(admin_pin); + }); +} + +NK_C_API int NK_set_encrypted_read_write(const char* admin_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->set_encrypted_volume_read_write(admin_pin); + }); +} + +NK_C_API int NK_export_firmware(const char* admin_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->export_firmware(admin_pin); + }); +} + +NK_C_API int NK_clear_new_sd_card_warning(const char* admin_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->clear_new_sd_card_warning(admin_pin); + }); +} + +NK_C_API int NK_fill_SD_card_with_random_data(const char* admin_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->fill_SD_card_with_random_data(admin_pin); + }); +} + +NK_C_API int NK_change_update_password(const char* current_update_password, + const char* new_update_password) { + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->change_update_password(current_update_password, new_update_password); + }); +} + +NK_C_API int NK_enable_firmware_update(const char* update_password){ + auto m = NitrokeyManager::instance(); + return get_without_result([&]() { + m->enable_firmware_update(update_password); + }); +} + +NK_C_API char* NK_get_status_storage_as_string() { + auto m = NitrokeyManager::instance(); + return get_with_string_result([&]() { + return m->get_status_storage_as_string(); + }); +} + +NK_C_API int NK_get_status_storage(NK_storage_status* out) { + if (out == nullptr) { + return -1; + } + auto m = NitrokeyManager::instance(); + auto result = get_with_status([&]() { + return m->get_status_storage(); + }, proto::stick20::DeviceConfigurationResponsePacket::ResponsePayload()); + auto error_code = std::get<0>(result); + if (error_code != 0) { + return error_code; + } + + auto status = std::get<1>(result); + out->unencrypted_volume_read_only = status.ReadWriteFlagUncryptedVolume_u8 != 0; + out->unencrypted_volume_active = status.VolumeActiceFlag_st.unencrypted; + out->encrypted_volume_read_only = status.ReadWriteFlagCryptedVolume_u8 != 0; + out->encrypted_volume_active = status.VolumeActiceFlag_st.encrypted; + out->hidden_volume_read_only = status.ReadWriteFlagHiddenVolume_u8 != 0; + out->hidden_volume_active = status.VolumeActiceFlag_st.hidden; + out->firmware_version_major = status.versionInfo.major; + out->firmware_version_minor = status.versionInfo.minor; + out->firmware_locked = status.FirmwareLocked_u8 != 0; + out->serial_number_sd_card = status.ActiveSD_CardID_u32; + out->serial_number_smart_card = status.ActiveSmartCardID_u32; + out->user_retry_count = status.UserPwRetryCount; + out->admin_retry_count = status.AdminPwRetryCount; + out->new_sd_card_found = status.NewSDCardFound_st.NewCard; + out->filled_with_random = (status.SDFillWithRandomChars_u8 & 0x01) != 0; + out->stick_initialized = status.StickKeysNotInitiated == 0; + return 0; +} + +NK_C_API int NK_get_storage_production_info(NK_storage_ProductionTest * out){ + if (out == nullptr) { + return -1; + } + auto m = NitrokeyManager::instance(); + auto result = get_with_status([&]() { + return m->production_info(); + }, proto::stick20::ProductionTest::ResponsePayload()); + + auto error_code = std::get<0>(result); + if (error_code != 0) { + return error_code; + } + + stick20::ProductionTest::ResponsePayload status = std::get<1>(result); + // Cannot use memcpy without declaring C API struct packed + // (which is not parsed by Python's CFFI apparently), hence the manual way. +#define a(x) out->x = status.x; + a(FirmwareVersion_au8[0]); + a(FirmwareVersion_au8[1]); + a(FirmwareVersionInternal_u8); + a(SD_Card_Size_u8); + a(CPU_CardID_u32); + a(SmartCardID_u32); + a(SD_CardID_u32); + a(SC_UserPwRetryCount); + a(SC_AdminPwRetryCount); + a(SD_Card_ManufacturingYear_u8); + a(SD_Card_ManufacturingMonth_u8); + a(SD_Card_OEM_u16); + a(SD_WriteSpeed_u16); + a(SD_Card_Manufacturer_u8); +#undef a + return 0; +} + +NK_C_API int NK_get_SD_usage_data(struct NK_SD_usage_data* out) { + if (out == nullptr) + return -1; + auto m = NitrokeyManager::instance(); + auto result = get_with_status([&]() { + return m->get_SD_usage_data(); + }, std::make_pair(0, 0)); + auto error_code = std::get<0>(result); + if (error_code != 0) + return error_code; + + auto data = std::get<1>(result); + out->write_level_min = std::get<0>(data); + out->write_level_max = std::get<1>(data); + + return 0; +} + +NK_C_API char* NK_get_SD_usage_data_as_string() { + auto m = NitrokeyManager::instance(); + return get_with_string_result([&]() { + return m->get_SD_usage_data_as_string(); + }); +} + +NK_C_API int NK_get_progress_bar_value() { + auto m = NitrokeyManager::instance(); + return std::get<1>(get_with_status([&]() { + return m->get_progress_bar_value(); + }, -2)); +} + +NK_C_API int NK_set_unencrypted_volume_rorw_pin_type_user() { + auto m = NitrokeyManager::instance(); + return get_with_result([&]() { + return m->set_unencrypted_volume_rorw_pin_type_user() ? 1 : 0; + }); +} + + +#ifdef __cplusplus +} +#endif diff --git a/NK_C_API_storage.h b/NK_C_API_storage.h new file mode 100644 index 00000000..48d415d6 --- /dev/null +++ b/NK_C_API_storage.h @@ -0,0 +1,6 @@ +#ifndef LIBNITROKEY_NK_C_API_STORAGE_H +#define LIBNITROKEY_NK_C_API_STORAGE_H + + + +#endif // LIBNITROKEY_NK_C_API_STORAGE_H diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index 329d155e..15fbdf1d 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -19,62 +19,28 @@ * SPDX-License-Identifier: LGPL-3.0 */ -#include -#include #include "libnitrokey/NitrokeyManager.h" +#include "NitrokeyManager.h" +#include "NitrokeyManagerOTP.h" +#include "NitrokeyManagerPWS.h" #include "libnitrokey/LibraryException.h" -#include -#include -#include -#include "libnitrokey/misc.h" -#include #include "libnitrokey/cxx_semantics.h" #include "libnitrokey/misc.h" +#include +#include #include +#include #include +#include +#include std::mutex nitrokey::proto::send_receive_mtx; namespace nitrokey{ - std::mutex mex_dev_com_manager; -#ifndef strndup -#ifdef _WIN32 -#pragma message "Using own strndup" -char * strndup(const char* str, size_t maxlen){ - size_t len = strnlen(str, maxlen); - char* dup = (char *) malloc(len + 1); - memcpy(dup, str, len); - dup[len] = 0; - return dup; -} -#endif -#endif - using nitrokey::misc::strcpyT; - template - typename T::CommandPayload get_payload(){ - //Create, initialize and return by value command payload - typename T::CommandPayload st; - bzero(&st, sizeof(st)); - return st; - } - - - // package type to auth, auth type [Authorize,UserAuthorize] - template - void NitrokeyManager::authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device){ - if (!is_authorization_command_supported()){ - LOG("Authorization command not supported, skipping", Loglevel::WARNING); - } - auto auth = get_payload(); - strcpyT(auth.temporary_password, admin_temporary_password); - auth.crc_to_authorize = S::CommandTransaction::getCRC(package); - A::CommandTransaction::run(device, auth); - } - shared_ptr NitrokeyManager::_instance = nullptr; NitrokeyManager::NitrokeyManager() : device(nullptr) @@ -440,266 +406,7 @@ using nitrokey::misc::strcpyT; return response.data().dissect(); } - string getFilledOTPCode(uint32_t code, bool use_8_digits){ - stringstream s; - s << std::right << std::setw(use_8_digits ? 8 : 6) << std::setfill('0') << code; - return s.str(); - } - - string NitrokeyManager::get_HOTP_code(uint8_t slot_number, const char *user_temporary_password) { - if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - - if (is_authorization_command_supported()){ - auto gh = get_payload(); - gh.slot_number = get_internal_slot_number_for_hotp(slot_number); - if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0){ //FIXME use string instead of strlen - authorize_packet(gh, user_temporary_password, device); - } - auto resp = GetHOTP::CommandTransaction::run(device, gh); - return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); - } else { - auto gh = get_payload(); - gh.slot_number = get_internal_slot_number_for_hotp(slot_number); - if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0) { - strcpyT(gh.temporary_user_password, user_temporary_password); - } - auto resp = stick10_08::GetHOTP::CommandTransaction::run(device, gh); - return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); - } - return ""; - } - - bool NitrokeyManager::is_internal_hotp_slot_number(uint8_t slot_number) const { return slot_number < 0x20; } - bool NitrokeyManager::is_valid_hotp_slot_number(uint8_t slot_number) const { return slot_number < 3; } - bool NitrokeyManager::is_valid_totp_slot_number(uint8_t slot_number) const { return slot_number < 0x10-1; } //15 - uint8_t NitrokeyManager::get_internal_slot_number_for_totp(uint8_t slot_number) const { return (uint8_t) (0x20 + slot_number); } - uint8_t NitrokeyManager::get_internal_slot_number_for_hotp(uint8_t slot_number) const { return (uint8_t) (0x10 + slot_number); } - - - - string NitrokeyManager::get_TOTP_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, - uint8_t last_interval, - const char *user_temporary_password) { - if(!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - slot_number = get_internal_slot_number_for_totp(slot_number); - - if (is_authorization_command_supported()){ - auto gt = get_payload(); - gt.slot_number = slot_number; - gt.challenge = challenge; - gt.last_interval = last_interval; - gt.last_totp_time = last_totp_time; - - if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0){ //FIXME use string instead of strlen - authorize_packet(gt, user_temporary_password, device); - } - auto resp = GetTOTP::CommandTransaction::run(device, gt); - return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); - } else { - auto gt = get_payload(); - strcpyT(gt.temporary_user_password, user_temporary_password); - gt.slot_number = slot_number; - auto resp = stick10_08::GetTOTP::CommandTransaction::run(device, gt); - return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); - } - return ""; - } - - bool NitrokeyManager::erase_slot(uint8_t slot_number, const char *temporary_password) { - if (is_authorization_command_supported()){ - auto p = get_payload(); - p.slot_number = slot_number; - authorize_packet(p, temporary_password, device); - auto resp = EraseSlot::CommandTransaction::run(device,p); - } else { - auto p = get_payload(); - p.slot_number = slot_number; - strcpyT(p.temporary_admin_password, temporary_password); - auto resp = stick10_08::EraseSlot::CommandTransaction::run(device,p); - } - return true; - } - - bool NitrokeyManager::erase_hotp_slot(uint8_t slot_number, const char *temporary_password) { - if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - slot_number = get_internal_slot_number_for_hotp(slot_number); - return erase_slot(slot_number, temporary_password); - } - - bool NitrokeyManager::erase_totp_slot(uint8_t slot_number, const char *temporary_password) { - if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - slot_number = get_internal_slot_number_for_totp(slot_number); - return erase_slot(slot_number, temporary_password); - } - - template - void vector_copy_ranged(T& dest, std::vector &vec, size_t begin, size_t elements_to_copy){ - const size_t d_size = sizeof(dest); - if(d_size < elements_to_copy){ - throw TargetBufferSmallerThanSource(elements_to_copy, d_size); - } - std::fill(dest, dest+d_size, 0); - std::copy(vec.begin() + begin, vec.begin() +begin + elements_to_copy, dest); - } - - template - void vector_copy(T& dest, std::vector &vec){ - const size_t d_size = sizeof(dest); - if(d_size < vec.size()){ - throw TargetBufferSmallerThanSource(vec.size(), d_size); - } - std::fill(dest, dest+d_size, 0); - std::copy(vec.begin(), vec.end(), dest); - } - - bool NitrokeyManager::write_HOTP_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint64_t hotp_counter, - bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, - const char *temporary_password) { - if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - - int internal_slot_number = get_internal_slot_number_for_hotp(slot_number); - if (is_authorization_command_supported()){ - write_HOTP_slot_authorize(internal_slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, - token_ID, temporary_password); - } else { - write_OTP_slot_no_authorize(internal_slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, - token_ID, temporary_password); - } - return true; - } - - void NitrokeyManager::write_HOTP_slot_authorize(uint8_t slot_number, const char *slot_name, const char *secret, - uint64_t hotp_counter, bool use_8_digits, bool use_enter, - bool use_tokenID, const char *token_ID, const char *temporary_password) { - auto payload = get_payload(); - payload.slot_number = slot_number; - auto secret_bin = misc::hex_string_to_byte(secret); - vector_copy(payload.slot_secret, secret_bin); - strcpyT(payload.slot_name, slot_name); - strcpyT(payload.slot_token_id, token_ID); - switch (device->get_device_model() ){ - case DeviceModel::LIBREM: - case DeviceModel::PRO: { - payload.slot_counter = hotp_counter; - break; - } - case DeviceModel::STORAGE: { - string counter = to_string(hotp_counter); - strcpyT(payload.slot_counter_s, counter.c_str()); - break; - } - default: - LOG(string(__FILE__) + to_string(__LINE__) + - string(__FUNCTION__) + string(" Unhandled device model for HOTP") - , Loglevel::DEBUG); - break; - } - payload.use_8_digits = use_8_digits; - payload.use_enter = use_enter; - payload.use_tokenID = use_tokenID; - - authorize_packet(payload, temporary_password, device); - - auto resp = WriteToHOTPSlot::CommandTransaction::run(device, payload); - } - - bool NitrokeyManager::write_TOTP_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint16_t time_window, - bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, - const char *temporary_password) { - if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - int internal_slot_number = get_internal_slot_number_for_totp(slot_number); - - if (is_authorization_command_supported()){ - write_TOTP_slot_authorize(internal_slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, - token_ID, temporary_password); - } else { - write_OTP_slot_no_authorize(internal_slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, - token_ID, temporary_password); - } - - return true; - } - - void NitrokeyManager::write_OTP_slot_no_authorize(uint8_t internal_slot_number, const char *slot_name, - const char *secret, - uint64_t counter_or_interval, bool use_8_digits, bool use_enter, - bool use_tokenID, const char *token_ID, - const char *temporary_password) const { - - auto payload2 = get_payload(); - strcpyT(payload2.temporary_admin_password, temporary_password); - strcpyT(payload2.data, slot_name); - payload2.setTypeName(); - stick10_08::SendOTPData::CommandTransaction::run(device, payload2); - - payload2.setTypeSecret(); - payload2.id = 0; - auto secret_bin = misc::hex_string_to_byte(secret); - auto remaining_secret_length = secret_bin.size(); - const auto maximum_OTP_secret_size = 40; - if(remaining_secret_length > maximum_OTP_secret_size){ - throw TargetBufferSmallerThanSource(remaining_secret_length, maximum_OTP_secret_size); - } - - while (remaining_secret_length>0){ - const auto bytesToCopy = std::min(sizeof(payload2.data), remaining_secret_length); - const auto start = secret_bin.size() - remaining_secret_length; - memset(payload2.data, 0, sizeof(payload2.data)); - vector_copy_ranged(payload2.data, secret_bin, start, bytesToCopy); - stick10_08::SendOTPData::CommandTransaction::run(device, payload2); - remaining_secret_length -= bytesToCopy; - payload2.id++; - } - - auto payload = get_payload(); - strcpyT(payload.temporary_admin_password, temporary_password); - strcpyT(payload.slot_token_id, token_ID); - payload.use_8_digits = use_8_digits; - payload.use_enter = use_enter; - payload.use_tokenID = use_tokenID; - payload.slot_counter_or_interval = counter_or_interval; - payload.slot_number = internal_slot_number; - stick10_08::WriteToOTPSlot::CommandTransaction::run(device, payload); - } - - void NitrokeyManager::write_TOTP_slot_authorize(uint8_t slot_number, const char *slot_name, const char *secret, - uint16_t time_window, bool use_8_digits, bool use_enter, - bool use_tokenID, const char *token_ID, const char *temporary_password) { - auto payload = get_payload(); - payload.slot_number = slot_number; - auto secret_bin = misc::hex_string_to_byte(secret); - vector_copy(payload.slot_secret, secret_bin); - strcpyT(payload.slot_name, slot_name); - strcpyT(payload.slot_token_id, token_ID); - payload.slot_interval = time_window; //FIXME naming - payload.use_8_digits = use_8_digits; - payload.use_enter = use_enter; - payload.use_tokenID = use_tokenID; - - authorize_packet(payload, temporary_password, device); - - auto resp = WriteToTOTPSlot::CommandTransaction::run(device, payload); - } - - char * NitrokeyManager::get_totp_slot_name(uint8_t slot_number) { - if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - slot_number = get_internal_slot_number_for_totp(slot_number); - return get_slot_name(slot_number); - } - char * NitrokeyManager::get_hotp_slot_name(uint8_t slot_number) { - if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - slot_number = get_internal_slot_number_for_hotp(slot_number); - return get_slot_name(slot_number); - } - - static const int max_string_field_length = 2*1024; //storage's status string is ~1k - - char * NitrokeyManager::get_slot_name(uint8_t slot_number) { - auto payload = get_payload(); - payload.slot_number = slot_number; - auto resp = GetSlotName::CommandTransaction::run(device, payload); - return strndup((const char *) resp.data().slot_name, max_string_field_length); - } + // 15 bool NitrokeyManager::first_authenticate(const char *pin, const char *temporary_password) { auto authreq = get_payload(); @@ -709,26 +416,6 @@ using nitrokey::misc::strcpyT; return true; } - bool NitrokeyManager::set_time(uint64_t time) { - auto p = get_payload(); - p.reset = 1; - p.time = time; - SetTime::CommandTransaction::run(device, p); - return false; - } - - void NitrokeyManager::set_time_soft(uint64_t time) { - auto p = get_payload(); - p.reset = 0; - p.time = time; - SetTime::CommandTransaction::run(device, p); - } - - bool NitrokeyManager::get_time(uint64_t time) { - set_time_soft(time); - return true; - } - void NitrokeyManager::change_user_PIN(const char *current_PIN, const char *new_PIN) { change_PIN_general(current_PIN, new_PIN); } @@ -766,25 +453,6 @@ using nitrokey::misc::strcpyT; } - void NitrokeyManager::enable_password_safe(const char *user_pin) { - //The following command will cancel enabling PWS if it is not supported - auto a = get_payload(); - strcpyT(a.user_password, user_pin); - IsAESSupported::CommandTransaction::run(device, a); - - auto p = get_payload(); - strcpyT(p.user_password, user_pin); - EnablePasswordSafe::CommandTransaction::run(device, p); - } - - vector NitrokeyManager::get_password_safe_slot_status() { - auto responsePayload = GetPasswordSafeSlotStatus::CommandTransaction::run(device); - vector v = vector(responsePayload.data().password_safe_status, - responsePayload.data().password_safe_status - + sizeof(responsePayload.data().password_safe_status)); - return v; - } - uint8_t NitrokeyManager::get_user_retry_count() { if(device->get_device_model() == DeviceModel::STORAGE){ stick20::GetDeviceStatus::CommandTransaction::run(device); @@ -805,54 +473,6 @@ using nitrokey::misc::strcpyT; LockDevice::CommandTransaction::run(device); } - char * NitrokeyManager::get_password_safe_slot_name(uint8_t slot_number) { - if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); - auto p = get_payload(); - p.slot_number = slot_number; - auto response = GetPasswordSafeSlotName::CommandTransaction::run(device, p); - return strndup((const char *) response.data().slot_name, max_string_field_length); - } - - bool NitrokeyManager::is_valid_password_safe_slot_number(uint8_t slot_number) const { return slot_number < 16; } - - char * NitrokeyManager::get_password_safe_slot_login(uint8_t slot_number) { - if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); - auto p = get_payload(); - p.slot_number = slot_number; - auto response = GetPasswordSafeSlotLogin::CommandTransaction::run(device, p); - return strndup((const char *) response.data().slot_login, max_string_field_length); - } - - char * NitrokeyManager::get_password_safe_slot_password(uint8_t slot_number) { - if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); - auto p = get_payload(); - p.slot_number = slot_number; - auto response = GetPasswordSafeSlotPassword::CommandTransaction::run(device, p); - return strndup((const char *) response.data().slot_password, max_string_field_length); //FIXME use secure way - } - - void NitrokeyManager::write_password_safe_slot(uint8_t slot_number, const char *slot_name, const char *slot_login, - const char *slot_password) { - if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); - auto p = get_payload(); - p.slot_number = slot_number; - strcpyT(p.slot_name, slot_name); - strcpyT(p.slot_password, slot_password); - SetPasswordSafeSlotData::CommandTransaction::run(device, p); - - auto p2 = get_payload(); - p2.slot_number = slot_number; - strcpyT(p2.slot_login_name, slot_login); - SetPasswordSafeSlotData2::CommandTransaction::run(device, p2); - } - - void NitrokeyManager::erase_password_safe_slot(uint8_t slot_number) { - if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); - auto p = get_payload(); - p.slot_number = slot_number; - ErasePasswordSafeSlot::CommandTransaction::run(device, p); - } - void NitrokeyManager::user_authenticate(const char *user_password, const char *temporary_password) { auto p = get_payload(); strcpyT(p.card_password, user_password); @@ -909,30 +529,6 @@ using nitrokey::misc::strcpyT; } } - - void NitrokeyManager::write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password, - bool delete_user_password, const char *admin_temporary_password) { - auto p = get_payload(); - p.numlock = numlock; - p.capslock = capslock; - p.scrolllock = scrolllock; - p.enable_user_password = static_cast(enable_user_password ? 1 : 0); - p.delete_user_password = static_cast(delete_user_password ? 1 : 0); - if (is_authorization_command_supported()){ - authorize_packet(p, admin_temporary_password, device); - } else { - strcpyT(p.temporary_admin_password, admin_temporary_password); - } - stick10_08::WriteGeneralConfig::CommandTransaction::run(device, p); - } - - vector NitrokeyManager::read_config() { - auto responsePayload = GetStatus::CommandTransaction::run(device); - vector v = vector(responsePayload.data().general_config, - responsePayload.data().general_config+sizeof(responsePayload.data().general_config)); - return v; - } - bool NitrokeyManager::is_authorization_command_supported(){ //authorization command is supported for versions equal or below: auto m = std::unordered_map({ @@ -943,16 +539,6 @@ using nitrokey::misc::strcpyT; return get_minor_firmware_version() <= m[device->get_device_model()]; } - bool NitrokeyManager::is_320_OTP_secret_supported(){ - // 320 bit OTP secret is supported by version bigger or equal to: - auto m = std::unordered_map({ - {DeviceModel::PRO, 8}, - {DeviceModel::LIBREM, 8}, - {DeviceModel::STORAGE, 54}, - }); - return get_minor_firmware_version() >= m[device->get_device_model()]; - } - DeviceModel NitrokeyManager::get_connected_device_model() const{ if (device == nullptr){ throw DeviceNotConnected("device not connected"); @@ -1009,213 +595,10 @@ using nitrokey::misc::strcpyT; return true; } - //storage commands - - void NitrokeyManager::send_startup(uint64_t seconds_from_epoch){ - auto p = get_payload(); -// p.set_defaults(); //set current time - p.localtime = seconds_from_epoch; - stick20::SendStartup::CommandTransaction::run(device, p); - } - - void NitrokeyManager::unlock_encrypted_volume(const char* user_pin){ - misc::execute_password_command(device, user_pin); - } - - void NitrokeyManager::unlock_hidden_volume(const char* hidden_volume_password) { - misc::execute_password_command(device, hidden_volume_password); - } - - void NitrokeyManager::set_encrypted_volume_read_only(const char* admin_pin) { - misc::execute_password_command(device, admin_pin); - } - - void NitrokeyManager::set_encrypted_volume_read_write(const char* admin_pin) { - misc::execute_password_command(device, admin_pin); - } - - //TODO check is encrypted volume unlocked before execution - //if not return library exception - void NitrokeyManager::create_hidden_volume(uint8_t slot_nr, uint8_t start_percent, uint8_t end_percent, - const char *hidden_volume_password) { - auto p = get_payload(); - p.SlotNr_u8 = slot_nr; - p.StartBlockPercent_u8 = start_percent; - p.EndBlockPercent_u8 = end_percent; - strcpyT(p.HiddenVolumePassword_au8, hidden_volume_password); - stick20::SetupHiddenVolume::CommandTransaction::run(device, p); - } - - void NitrokeyManager::set_unencrypted_read_only_admin(const char* admin_pin) { - //from v0.49, v0.52+ it needs Admin PIN - if (set_unencrypted_volume_rorw_pin_type_user()){ - LOG("set_unencrypted_read_only_admin is not supported for this version of Storage device. " - "Please update firmware to v0.52+. Doing nothing.", nitrokey::log::Loglevel::WARNING); - return; - } - misc::execute_password_command(device, admin_pin); - } - - void NitrokeyManager::set_unencrypted_read_only(const char *user_pin) { - //until v0.48 (incl. v0.50 and v0.51) User PIN was sufficient - LOG("set_unencrypted_read_only is deprecated. Use set_unencrypted_read_only_admin instead.", - nitrokey::log::Loglevel::WARNING); - if (!set_unencrypted_volume_rorw_pin_type_user()){ - LOG("set_unencrypted_read_only is not supported for this version of Storage device. Doing nothing.", - nitrokey::log::Loglevel::WARNING); - return; - } - misc::execute_password_command(device, user_pin); - } - - void NitrokeyManager::set_unencrypted_read_write_admin(const char* admin_pin) { - //from v0.49, v0.52+ it needs Admin PIN - if (set_unencrypted_volume_rorw_pin_type_user()){ - LOG("set_unencrypted_read_write_admin is not supported for this version of Storage device. " - "Please update firmware to v0.52+. Doing nothing.", nitrokey::log::Loglevel::WARNING); - return; - } - misc::execute_password_command(device, admin_pin); - } - - void NitrokeyManager::set_unencrypted_read_write(const char *user_pin) { - //until v0.48 (incl. v0.50 and v0.51) User PIN was sufficient - LOG("set_unencrypted_read_write is deprecated. Use set_unencrypted_read_write_admin instead.", - nitrokey::log::Loglevel::WARNING); - if (!set_unencrypted_volume_rorw_pin_type_user()){ - LOG("set_unencrypted_read_write is not supported for this version of Storage device. Doing nothing.", - nitrokey::log::Loglevel::WARNING); - return; - } - misc::execute_password_command(device, user_pin); - } - - bool NitrokeyManager::set_unencrypted_volume_rorw_pin_type_user(){ - auto minor_firmware_version = get_minor_firmware_version(); - return minor_firmware_version <= 48 || minor_firmware_version == 50 || minor_firmware_version == 51; - } - - void NitrokeyManager::export_firmware(const char* admin_pin) { - misc::execute_password_command(device, admin_pin); - } - - void NitrokeyManager::enable_firmware_update(const char* firmware_pin) { - misc::execute_password_command(device, firmware_pin); - } - - void NitrokeyManager::clear_new_sd_card_warning(const char* admin_pin) { - misc::execute_password_command(device, admin_pin); - } - - void NitrokeyManager::fill_SD_card_with_random_data(const char* admin_pin) { - auto p = get_payload(); - p.set_defaults(); - strcpyT(p.admin_pin, admin_pin); - stick20::FillSDCardWithRandomChars::CommandTransaction::run(device, p); - } - - void NitrokeyManager::change_update_password(const char* current_update_password, const char* new_update_password) { - auto p = get_payload(); - strcpyT(p.current_update_password, current_update_password); - strcpyT(p.new_update_password, new_update_password); - stick20::ChangeUpdatePassword::CommandTransaction::run(device, p); - } - - char * NitrokeyManager::get_status_storage_as_string(){ - auto p = stick20::GetDeviceStatus::CommandTransaction::run(device); - return strndup(p.data().dissect().c_str(), max_string_field_length); - } - - stick20::DeviceConfigurationResponsePacket::ResponsePayload NitrokeyManager::get_status_storage(){ - auto p = stick20::GetDeviceStatus::CommandTransaction::run(device); - return p.data(); - } - - char * NitrokeyManager::get_SD_usage_data_as_string(){ - auto p = stick20::GetSDCardOccupancy::CommandTransaction::run(device); - return strndup(p.data().dissect().c_str(), max_string_field_length); - } - - std::pair NitrokeyManager::get_SD_usage_data(){ - auto p = stick20::GetSDCardOccupancy::CommandTransaction::run(device); - return std::make_pair(p.data().WriteLevelMin, p.data().WriteLevelMax); - } - - int NitrokeyManager::get_progress_bar_value(){ - try{ - stick20::GetDeviceStatus::CommandTransaction::run(device); - return -1; - } - catch (LongOperationInProgressException &e){ - return e.progress_bar_value; - } - } - - string NitrokeyManager::get_TOTP_code(uint8_t slot_number, const char *user_temporary_password) { - return get_TOTP_code(slot_number, 0, 0, 0, user_temporary_password); - } - - /** - * Returns ReadSlot structure, describing OTP slot configuration. Always return binary counter - - * does the necessary conversion, if needed, to unify the behavior across Pro and Storage. - * @private For internal use only - * @param slot_number which OTP slot to use (usual format) - * @return ReadSlot structure - */ - stick10::ReadSlot::ResponsePayload NitrokeyManager::get_OTP_slot_data(const uint8_t slot_number) { - auto p = get_payload(); - p.slot_number = slot_number; - p.data_format = stick10::ReadSlot::CounterFormat::BINARY; // ignored for devices other than Storage v0.54+ - auto data = stick10::ReadSlot::CommandTransaction::run(device, p); - - auto &payload = data.data(); - - // if fw <=v0.53 and asked binary - do the conversion from ASCII - if (device->get_device_model() == DeviceModel::STORAGE && get_minor_firmware_version() <= 53 - && is_internal_hotp_slot_number(slot_number)) - { - //convert counter from string to ull - auto counter_s = std::string(payload.slot_counter_s, payload.slot_counter_s + sizeof(payload.slot_counter_s)); - payload.slot_counter = std::stoull(counter_s); - } - - return payload; - } - - stick10::ReadSlot::ResponsePayload NitrokeyManager::get_TOTP_slot_data(const uint8_t slot_number) { - return get_OTP_slot_data(get_internal_slot_number_for_totp(slot_number)); - } - - stick10::ReadSlot::ResponsePayload NitrokeyManager::get_HOTP_slot_data(const uint8_t slot_number) { - return get_OTP_slot_data(get_internal_slot_number_for_hotp(slot_number)); - } - - void NitrokeyManager::lock_encrypted_volume() { - misc::execute_password_command(device, ""); - } - - void NitrokeyManager::lock_hidden_volume() { - misc::execute_password_command(device, ""); - } - - uint8_t NitrokeyManager::get_SD_card_size() { - auto data = stick20::ProductionTest::CommandTransaction::run(device); - return data.data().SD_Card_Size_u8; - } - const string NitrokeyManager::get_current_device_id() const { return current_device_id; } - void NitrokeyManager::wink(){ - stick20::Wink::CommandTransaction::run(device); - }; - - stick20::ProductionTest::ResponsePayload NitrokeyManager::production_info(){ - auto data = stick20::ProductionTest::CommandTransaction::run(device); - return data.data(); - }; - void NitrokeyManager::enable_firmware_update_pro(const char *firmware_pin) { auto p = get_payload(); strcpyT(p.firmware_password, firmware_pin); diff --git a/NitrokeyManagerOTP.cc b/NitrokeyManagerOTP.cc new file mode 100644 index 00000000..42eb3a99 --- /dev/null +++ b/NitrokeyManagerOTP.cc @@ -0,0 +1,340 @@ +#include "NitrokeyManagerOTP.h" +using nitrokey::misc::strcpyT; + +std::string getFilledOTPCode(uint32_t code, bool use_8_digits){ + std::stringstream s; + s << std::right << std::setw(use_8_digits ? 8 : 6) << std::setfill('0') << code; + return s.str(); +} +std::string nitrokey::NitrokeyManager::get_HOTP_code(uint8_t slot_number, const char *user_temporary_password) { + if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + + if (is_authorization_command_supported()){ + auto gh = get_payload(); + gh.slot_number = get_internal_slot_number_for_hotp(slot_number); + if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0){ //FIXME use string instead of strlen + authorize_packet(gh, user_temporary_password, device); + } + auto resp = GetHOTP::CommandTransaction::run(device, gh); + return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); + } else { + auto gh = get_payload(); + gh.slot_number = get_internal_slot_number_for_hotp(slot_number); + if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0) { + strcpyT(gh.temporary_user_password, user_temporary_password); + } + auto resp = stick10_08::GetHOTP::CommandTransaction::run(device, gh); + return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); + } + return ""; +} +bool nitrokey::NitrokeyManager::is_internal_hotp_slot_number(uint8_t slot_number) const { return slot_number < 0x20; } +bool nitrokey::NitrokeyManager::is_valid_hotp_slot_number(uint8_t slot_number) const { return slot_number < 3; } +bool nitrokey::NitrokeyManager::is_valid_totp_slot_number(uint8_t slot_number) const { return slot_number < 0x10-1; } +uint8_t nitrokey::NitrokeyManager::get_internal_slot_number_for_totp(uint8_t slot_number) const { return (uint8_t) (0x20 + slot_number); +} +uint8_t nitrokey::NitrokeyManager::get_internal_slot_number_for_hotp(uint8_t slot_number) const { return (uint8_t) (0x10 + slot_number); } +std::string nitrokey::NitrokeyManager::get_TOTP_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time, + uint8_t last_interval, + const char *user_temporary_password) { + if(!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + slot_number = get_internal_slot_number_for_totp(slot_number); + + if (is_authorization_command_supported()){ + auto gt = get_payload(); + gt.slot_number = slot_number; + gt.challenge = challenge; + gt.last_interval = last_interval; + gt.last_totp_time = last_totp_time; + + if(user_temporary_password != nullptr && strlen(user_temporary_password)!=0){ //FIXME use string instead of strlen + authorize_packet(gt, user_temporary_password, device); + } + auto resp = GetTOTP::CommandTransaction::run(device, gt); + return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); + } else { + auto gt = get_payload(); + strcpyT(gt.temporary_user_password, user_temporary_password); + gt.slot_number = slot_number; + auto resp = stick10_08::GetTOTP::CommandTransaction::run(device, gt); + return getFilledOTPCode(resp.data().code, resp.data().use_8_digits); + } + return ""; +} +bool nitrokey::NitrokeyManager::erase_slot(uint8_t slot_number, const char *temporary_password) { + if (is_authorization_command_supported()){ + auto p = get_payload(); + p.slot_number = slot_number; + authorize_packet(p, temporary_password, device); + auto resp = EraseSlot::CommandTransaction::run(device,p); + } else { + auto p = get_payload(); + p.slot_number = slot_number; + strcpyT(p.temporary_admin_password, temporary_password); + auto resp = stick10_08::EraseSlot::CommandTransaction::run(device,p); + } + return true; +} +bool nitrokey::NitrokeyManager::erase_hotp_slot(uint8_t slot_number, const char *temporary_password) { + if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + slot_number = get_internal_slot_number_for_hotp(slot_number); + return erase_slot(slot_number, temporary_password); +} +bool nitrokey::NitrokeyManager::erase_totp_slot(uint8_t slot_number, const char *temporary_password) { + if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + slot_number = get_internal_slot_number_for_totp(slot_number); + return erase_slot(slot_number, temporary_password); +} +template +void vector_copy_ranged(T& dest, std::vector &vec, std::size_t begin, std::size_t elements_to_copy){ + const std::size_t d_size = sizeof(dest); + if(d_size < elements_to_copy){ + throw TargetBufferSmallerThanSource(elements_to_copy, d_size); + } + std::fill(dest, dest+d_size, 0); + std::copy(vec.begin() + begin, vec.begin() +begin + elements_to_copy, dest); +} +template +void vector_copy(T& dest, std::vector &vec){ + const std::size_t d_size = sizeof(dest); + if(d_size < vec.size()){ + throw TargetBufferSmallerThanSource(vec.size(), d_size); + } + std::fill(dest, dest+d_size, 0); + std::copy(vec.begin(), vec.end(), dest); +} +bool nitrokey::NitrokeyManager::write_HOTP_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint64_t hotp_counter, + bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, + const char *temporary_password) { + if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + + int internal_slot_number = get_internal_slot_number_for_hotp(slot_number); + if (is_authorization_command_supported()){ + write_HOTP_slot_authorize(internal_slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, + token_ID, temporary_password); + } else { + write_OTP_slot_no_authorize(internal_slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, + token_ID, temporary_password); + } + return true; +} +void nitrokey::NitrokeyManager::write_HOTP_slot_authorize(uint8_t slot_number, const char *slot_name, const char *secret, + uint64_t hotp_counter, bool use_8_digits, bool use_enter, + bool use_tokenID, const char *token_ID, const char *temporary_password) { + auto payload = get_payload(); + payload.slot_number = slot_number; + auto secret_bin = misc::hex_string_to_byte(secret); + vector_copy(payload.slot_secret, secret_bin); + strcpyT(payload.slot_name, slot_name); + strcpyT(payload.slot_token_id, token_ID); + switch (device->get_device_model() ){ + case DeviceModel::LIBREM: + case DeviceModel::PRO: { + payload.slot_counter = hotp_counter; + break; + } + case DeviceModel::STORAGE: { + string counter = to_string(hotp_counter); + strcpyT(payload.slot_counter_s, counter.c_str()); + break; + } + default: + LOG(string(__FILE__) + to_string(__LINE__) + + string(__FUNCTION__) + string(" Unhandled device model for HOTP") + , Loglevel::DEBUG); + break; + } + payload.use_8_digits = use_8_digits; + payload.use_enter = use_enter; + payload.use_tokenID = use_tokenID; + + authorize_packet(payload, temporary_password, device); + + auto resp = WriteToHOTPSlot::CommandTransaction::run(device, payload); +} +bool nitrokey::NitrokeyManager::write_TOTP_slot(uint8_t slot_number, const char *slot_name, const char *secret, uint16_t time_window, + bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, + const char *temporary_password) { + if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + int internal_slot_number = get_internal_slot_number_for_totp(slot_number); + + if (is_authorization_command_supported()){ + write_TOTP_slot_authorize(internal_slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, + token_ID, temporary_password); + } else { + write_OTP_slot_no_authorize(internal_slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, + token_ID, temporary_password); + } + + return true; +} +void nitrokey::NitrokeyManager::write_OTP_slot_no_authorize(uint8_t internal_slot_number, const char *slot_name, + const char *secret, + uint64_t counter_or_interval, bool use_8_digits, bool use_enter, + bool use_tokenID, const char *token_ID, + const char *temporary_password) const { + + auto payload2 = get_payload(); + strcpyT(payload2.temporary_admin_password, temporary_password); + strcpyT(payload2.data, slot_name); + payload2.setTypeName(); + stick10_08::SendOTPData::CommandTransaction::run(device, payload2); + + payload2.setTypeSecret(); + payload2.id = 0; + auto secret_bin = misc::hex_string_to_byte(secret); + auto remaining_secret_length = secret_bin.size(); + const auto maximum_OTP_secret_size = 40; + if(remaining_secret_length > maximum_OTP_secret_size){ + throw TargetBufferSmallerThanSource(remaining_secret_length, maximum_OTP_secret_size); + } + + while (remaining_secret_length>0){ + const auto bytesToCopy = std::min(sizeof(payload2.data), remaining_secret_length); + const auto start = secret_bin.size() - remaining_secret_length; + memset(payload2.data, 0, sizeof(payload2.data)); + vector_copy_ranged(payload2.data, secret_bin, start, bytesToCopy); + stick10_08::SendOTPData::CommandTransaction::run(device, payload2); + remaining_secret_length -= bytesToCopy; + payload2.id++; + } + + auto payload = get_payload(); + strcpyT(payload.temporary_admin_password, temporary_password); + strcpyT(payload.slot_token_id, token_ID); + payload.use_8_digits = use_8_digits; + payload.use_enter = use_enter; + payload.use_tokenID = use_tokenID; + payload.slot_counter_or_interval = counter_or_interval; + payload.slot_number = internal_slot_number; + stick10_08::WriteToOTPSlot::CommandTransaction::run(device, payload); +} +void nitrokey::NitrokeyManager::write_TOTP_slot_authorize(uint8_t slot_number, const char *slot_name, const char *secret, + uint16_t time_window, bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, const char *temporary_password) { + auto payload = get_payload(); + payload.slot_number = slot_number; + auto secret_bin = misc::hex_string_to_byte(secret); + vector_copy(payload.slot_secret, secret_bin); + strcpyT(payload.slot_name, slot_name); + strcpyT(payload.slot_token_id, token_ID); + payload.slot_interval = time_window; //FIXME naming + payload.use_8_digits = use_8_digits; + payload.use_enter = use_enter; + payload.use_tokenID = use_tokenID; + + authorize_packet(payload, temporary_password, device); + + auto resp = WriteToTOTPSlot::CommandTransaction::run(device, payload); +} +char * nitrokey::NitrokeyManager::get_totp_slot_name(uint8_t slot_number) { + if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + slot_number = get_internal_slot_number_for_totp(slot_number); + return get_slot_name(slot_number); +} +char *nitrokey::NitrokeyManager::get_hotp_slot_name(uint8_t slot_number) { + if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); + slot_number = get_internal_slot_number_for_hotp(slot_number); + return get_slot_name(slot_number); +} +char *nitrokey::NitrokeyManager::get_slot_name(uint8_t slot_number) { + auto payload = get_payload(); + payload.slot_number = slot_number; + auto resp = GetSlotName::CommandTransaction::run(device, payload); + return strndup((const char *) resp.data().slot_name, max_string_field_length); +} +bool nitrokey::NitrokeyManager::set_time(uint64_t time) { + auto p = get_payload(); + p.reset = 1; + p.time = time; + SetTime::CommandTransaction::run(device, p); + return false; +} +void nitrokey::NitrokeyManager::set_time_soft(uint64_t time) { + auto p = get_payload(); + p.reset = 0; + p.time = time; + SetTime::CommandTransaction::run(device, p); +} +bool nitrokey::NitrokeyManager::get_time(uint64_t time) { + set_time_soft(time); + return true; +} +void nitrokey::NitrokeyManager::write_config(uint8_t numlock, uint8_t capslock, uint8_t scrolllock, bool enable_user_password, + bool delete_user_password, const char *admin_temporary_password) { + auto p = get_payload(); + p.numlock = numlock; + p.capslock = capslock; + p.scrolllock = scrolllock; + p.enable_user_password = static_cast(enable_user_password ? 1 : 0); + p.delete_user_password = static_cast(delete_user_password ? 1 : 0); + if (is_authorization_command_supported()){ + authorize_packet(p, admin_temporary_password, device); + } else { + strcpyT(p.temporary_admin_password, admin_temporary_password); + } + stick10_08::WriteGeneralConfig::CommandTransaction::run(device, p); +} +std::vector nitrokey::NitrokeyManager::read_config() { + auto responsePayload = GetStatus::CommandTransaction::run(device); + vector v = vector(responsePayload.data().general_config, + responsePayload.data().general_config+sizeof(responsePayload.data().general_config)); + return v; +} +bool nitrokey::NitrokeyManager::is_320_OTP_secret_supported(){ + // 320 bit OTP secret is supported by version bigger or equal to: + auto m = unordered_map({ + {DeviceModel::PRO, 8}, + {DeviceModel::LIBREM, 8}, + {DeviceModel::STORAGE, 54}, + }); + return get_minor_firmware_version() >= m[device->get_device_model()]; +} +std::string nitrokey::NitrokeyManager::get_TOTP_code(uint8_t slot_number, const char *user_temporary_password) { + return get_TOTP_code(slot_number, 0, 0, 0, user_temporary_password); +} /** + * Returns ReadSlot structure, describing OTP slot configuration. Always + * return binary counter - does the necessary conversion, if needed, to unify + * the behavior across Pro and Storage. + * @private For internal use only + * @param slot_number which OTP slot to use (usual format) + * @return ReadSlot structure + */ +nitrokey::proto::stick10::ReadSlot::ResponsePayload +nitrokey::NitrokeyManager::get_OTP_slot_data(const uint8_t slot_number) { + auto p = get_payload(); + p.slot_number = slot_number; + p.data_format = ReadSlot::CounterFormat::BINARY; // ignored for devices other than Storage v0.54+ + auto data = stick10::ReadSlot::CommandTransaction::run(device, p); + + auto &payload = data.data(); + + // if fw <=v0.53 and asked binary - do the conversion from ASCII + if (device->get_device_model() == DeviceModel::STORAGE && get_minor_firmware_version() <= 53 + && is_internal_hotp_slot_number(slot_number)) + { + //convert counter from string to ull + auto counter_s = string(payload.slot_counter_s, payload.slot_counter_s + sizeof(payload.slot_counter_s)); + payload.slot_counter = stoull(counter_s); + } + + return payload; +} + nitrokey::proto::stick10::ReadSlot::ResponsePayload nitrokey::NitrokeyManager::get_TOTP_slot_data(const uint8_t slot_number) { + return get_OTP_slot_data(get_internal_slot_number_for_totp(slot_number)); + } + nitrokey::proto::stick10::ReadSlot::ResponsePayload nitrokey::NitrokeyManager::get_HOTP_slot_data(const uint8_t slot_number) { + return get_OTP_slot_data(get_internal_slot_number_for_hotp(slot_number)); + } + namespace nitrokey { // package type to auth, auth type + // [Authorize,UserAuthorize] + template + void NitrokeyManager::authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device){ + if (!is_authorization_command_supported()){ + LOG("Authorization command not supported, skipping", Loglevel::WARNING); + } + auto auth = get_payload(); + strcpyT(auth.temporary_password, admin_temporary_password); + auth.crc_to_authorize = S::CommandTransaction::getCRC(package); + A::CommandTransaction::run(device, auth); + } + } // namespace nitrokey \ No newline at end of file diff --git a/NitrokeyManagerOTP.h b/NitrokeyManagerOTP.h new file mode 100644 index 00000000..503fef7f --- /dev/null +++ b/NitrokeyManagerOTP.h @@ -0,0 +1,6 @@ +#ifndef LIBNITROKEY_NITROKEYMANAGEROTP_H +#define LIBNITROKEY_NITROKEYMANAGEROTP_H + +#include "NitrokeyManager.h" + +#endif // LIBNITROKEY_NITROKEYMANAGEROTP_H diff --git a/NitrokeyManagerPWS.cc b/NitrokeyManagerPWS.cc new file mode 100644 index 00000000..c4a47eb9 --- /dev/null +++ b/NitrokeyManagerPWS.cc @@ -0,0 +1,75 @@ +#include "NitrokeyManagerPWS.h" +#include "NitrokeyManagerOTP.h" +#include "libnitrokey/LibraryException.h" +#include "libnitrokey/NitrokeyManager.h" +#include "libnitrokey/cxx_semantics.h" +#include "libnitrokey/misc.h" +#include +#include +#include +#include +#include +#include +#include +void nitrokey::NitrokeyManager::enable_password_safe(const char *user_pin) { + //The following command will cancel enabling PWS if it is not supported + auto a = get_payload(); + misc::strcpyT(a.user_password, user_pin); + IsAESSupported::CommandTransaction::run(device, a); + + auto p = get_payload(); + misc::strcpyT(p.user_password, user_pin); + EnablePasswordSafe::CommandTransaction::run(device, p); +} +std::vector nitrokey::NitrokeyManager::get_password_safe_slot_status() { + auto responsePayload = GetPasswordSafeSlotStatus::CommandTransaction::run(device); + vector v = vector(responsePayload.data().password_safe_status, + responsePayload.data().password_safe_status + + sizeof(responsePayload.data().password_safe_status)); + return v; +} +char * nitrokey::NitrokeyManager::get_password_safe_slot_name(uint8_t slot_number) { + if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); + auto p = get_payload(); + p.slot_number = slot_number; + auto response = GetPasswordSafeSlotName::CommandTransaction::run(device, p); + return strndup((const char *) response.data().slot_name, max_string_field_length); +} +bool nitrokey::NitrokeyManager::is_valid_password_safe_slot_number(uint8_t slot_number) const { return slot_number < 16; +} +char * +nitrokey::NitrokeyManager::get_password_safe_slot_login(uint8_t slot_number) { + if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); + auto p = get_payload(); + p.slot_number = slot_number; + auto response = GetPasswordSafeSlotLogin::CommandTransaction::run(device, p); + return strndup((const char *) response.data().slot_login, max_string_field_length); +} +char * nitrokey::NitrokeyManager::get_password_safe_slot_password(uint8_t slot_number) { + if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); + auto p = get_payload(); + p.slot_number = slot_number; + auto response = GetPasswordSafeSlotPassword::CommandTransaction::run(device, p); + return strndup((const char *) response.data().slot_password, max_string_field_length); //FIXME use secure way +} +void nitrokey::NitrokeyManager::write_password_safe_slot(uint8_t slot_number, const char *slot_name, const char *slot_login, + const char *slot_password) { + if (!is_valid_password_safe_slot_number(slot_number)) + throw InvalidSlotException(slot_number); + auto p = get_payload(); + p.slot_number = slot_number; + misc::strcpyT(p.slot_name, slot_name); + misc::strcpyT(p.slot_password, slot_password); + SetPasswordSafeSlotData::CommandTransaction::run(device, p); + + auto p2 = get_payload(); + p2.slot_number = slot_number; + misc::strcpyT(p2.slot_login_name, slot_login); + SetPasswordSafeSlotData2::CommandTransaction::run(device, p2); +} +void nitrokey::NitrokeyManager::erase_password_safe_slot(uint8_t slot_number) { + if (!is_valid_password_safe_slot_number(slot_number)) throw InvalidSlotException(slot_number); + auto p = get_payload(); + p.slot_number = slot_number; + ErasePasswordSafeSlot::CommandTransaction::run(device, p); +} \ No newline at end of file diff --git a/NitrokeyManagerPWS.h b/NitrokeyManagerPWS.h new file mode 100644 index 00000000..b9f5071d --- /dev/null +++ b/NitrokeyManagerPWS.h @@ -0,0 +1,6 @@ +#ifndef LIBNITROKEY_NITROKEYMANAGERPWS_H +#define LIBNITROKEY_NITROKEYMANAGERPWS_H + +#include "NitrokeyManager.h" + +#endif // LIBNITROKEY_NITROKEYMANAGERPWS_H diff --git a/NitrokeyManagerStorage.cpp b/NitrokeyManagerStorage.cpp new file mode 100644 index 00000000..c78730bd --- /dev/null +++ b/NitrokeyManagerStorage.cpp @@ -0,0 +1,173 @@ +#include "NitrokeyManagerStorage.h" + +namespace nitrokey{ + +using nitrokey::misc::strcpyT; + +//storage commands + +void NitrokeyManager::send_startup(uint64_t seconds_from_epoch){ + auto p = get_payload(); +// p.set_defaults(); //set current time + p.localtime = seconds_from_epoch; + stick20::SendStartup::CommandTransaction::run(device, p); +} + +void NitrokeyManager::unlock_encrypted_volume(const char* user_pin){ + misc::execute_password_command(device, user_pin); +} + +void NitrokeyManager::unlock_hidden_volume(const char* hidden_volume_password) { + misc::execute_password_command(device, hidden_volume_password); +} + +void NitrokeyManager::set_encrypted_volume_read_only(const char* admin_pin) { + misc::execute_password_command(device, admin_pin); +} + +void NitrokeyManager::set_encrypted_volume_read_write(const char* admin_pin) { + misc::execute_password_command(device, admin_pin); +} + +//TODO check is encrypted volume unlocked before execution +//if not return library exception +void NitrokeyManager::create_hidden_volume(uint8_t slot_nr, uint8_t start_percent, uint8_t end_percent, + const char *hidden_volume_password) { + auto p = get_payload(); + p.SlotNr_u8 = slot_nr; + p.StartBlockPercent_u8 = start_percent; + p.EndBlockPercent_u8 = end_percent; + strcpyT(p.HiddenVolumePassword_au8, hidden_volume_password); + stick20::SetupHiddenVolume::CommandTransaction::run(device, p); +} + +void NitrokeyManager::set_unencrypted_read_only_admin(const char* admin_pin) { + //from v0.49, v0.52+ it needs Admin PIN + if (set_unencrypted_volume_rorw_pin_type_user()){ + LOG("set_unencrypted_read_only_admin is not supported for this version of Storage device. " + "Please update firmware to v0.52+. Doing nothing.", nitrokey::log::Loglevel::WARNING); + return; + } + misc::execute_password_command(device, admin_pin); +} + +void NitrokeyManager::set_unencrypted_read_only(const char *user_pin) { + //until v0.48 (incl. v0.50 and v0.51) User PIN was sufficient + LOG("set_unencrypted_read_only is deprecated. Use set_unencrypted_read_only_admin instead.", + nitrokey::log::Loglevel::WARNING); + if (!set_unencrypted_volume_rorw_pin_type_user()){ + LOG("set_unencrypted_read_only is not supported for this version of Storage device. Doing nothing.", + nitrokey::log::Loglevel::WARNING); + return; + } + misc::execute_password_command(device, user_pin); +} + +void NitrokeyManager::set_unencrypted_read_write_admin(const char* admin_pin) { + //from v0.49, v0.52+ it needs Admin PIN + if (set_unencrypted_volume_rorw_pin_type_user()){ + LOG("set_unencrypted_read_write_admin is not supported for this version of Storage device. " + "Please update firmware to v0.52+. Doing nothing.", nitrokey::log::Loglevel::WARNING); + return; + } + misc::execute_password_command(device, admin_pin); +} + +void NitrokeyManager::set_unencrypted_read_write(const char *user_pin) { + //until v0.48 (incl. v0.50 and v0.51) User PIN was sufficient + LOG("set_unencrypted_read_write is deprecated. Use set_unencrypted_read_write_admin instead.", + nitrokey::log::Loglevel::WARNING); + if (!set_unencrypted_volume_rorw_pin_type_user()){ + LOG("set_unencrypted_read_write is not supported for this version of Storage device. Doing nothing.", + nitrokey::log::Loglevel::WARNING); + return; + } + misc::execute_password_command(device, user_pin); +} + +bool NitrokeyManager::set_unencrypted_volume_rorw_pin_type_user(){ + auto minor_firmware_version = get_minor_firmware_version(); + return minor_firmware_version <= 48 || minor_firmware_version == 50 || minor_firmware_version == 51; +} + +void NitrokeyManager::export_firmware(const char* admin_pin) { + misc::execute_password_command(device, admin_pin); +} + +void NitrokeyManager::enable_firmware_update(const char* firmware_pin) { + misc::execute_password_command(device, firmware_pin); +} + +void NitrokeyManager::clear_new_sd_card_warning(const char* admin_pin) { + misc::execute_password_command(device, admin_pin); +} + +void NitrokeyManager::fill_SD_card_with_random_data(const char* admin_pin) { + auto p = get_payload(); + p.set_defaults(); + strcpyT(p.admin_pin, admin_pin); + stick20::FillSDCardWithRandomChars::CommandTransaction::run(device, p); +} + +void NitrokeyManager::change_update_password(const char* current_update_password, const char* new_update_password) { + auto p = get_payload(); + strcpyT(p.current_update_password, current_update_password); + strcpyT(p.new_update_password, new_update_password); + stick20::ChangeUpdatePassword::CommandTransaction::run(device, p); +} + +char * NitrokeyManager::get_status_storage_as_string(){ + auto p = stick20::GetDeviceStatus::CommandTransaction::run(device); + return strndup(p.data().dissect().c_str(), max_string_field_length); +} + +stick20::DeviceConfigurationResponsePacket::ResponsePayload NitrokeyManager::get_status_storage(){ + auto p = stick20::GetDeviceStatus::CommandTransaction::run(device); + return p.data(); +} + +char * NitrokeyManager::get_SD_usage_data_as_string(){ + auto p = stick20::GetSDCardOccupancy::CommandTransaction::run(device); + return strndup(p.data().dissect().c_str(), max_string_field_length); +} + +std::pair NitrokeyManager::get_SD_usage_data(){ + auto p = stick20::GetSDCardOccupancy::CommandTransaction::run(device); + return std::make_pair(p.data().WriteLevelMin, p.data().WriteLevelMax); +} + +int NitrokeyManager::get_progress_bar_value(){ + try{ + stick20::GetDeviceStatus::CommandTransaction::run(device); + return -1; + } + catch (LongOperationInProgressException &e){ + return e.progress_bar_value; + } +} + + +void NitrokeyManager::lock_encrypted_volume() { + misc::execute_password_command(device, ""); +} + +void NitrokeyManager::lock_hidden_volume() { + misc::execute_password_command(device, ""); +} + +uint8_t NitrokeyManager::get_SD_card_size() { + auto data = stick20::ProductionTest::CommandTransaction::run(device); + return data.data().SD_Card_Size_u8; +} + + +void NitrokeyManager::wink(){ + stick20::Wink::CommandTransaction::run(device); +}; + +stick20::ProductionTest::ResponsePayload NitrokeyManager::production_info(){ + auto data = stick20::ProductionTest::CommandTransaction::run(device); + return data.data(); +}; + +} \ No newline at end of file diff --git a/NitrokeyManagerStorage.h b/NitrokeyManagerStorage.h new file mode 100644 index 00000000..a127bac3 --- /dev/null +++ b/NitrokeyManagerStorage.h @@ -0,0 +1,6 @@ +#ifndef LIBNITROKEY_NITROKEYMANAGERSTORAGE_H +#define LIBNITROKEY_NITROKEYMANAGERSTORAGE_H + +#include "NitrokeyManager.h" + +#endif // LIBNITROKEY_NITROKEYMANAGERSTORAGE_H diff --git a/device.cc b/device.cc index 1204c1e7..fc65feb1 100644 --- a/device.cc +++ b/device.cc @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/libnitrokey/NitrokeyManager.h b/libnitrokey/NitrokeyManager.h index 163a7996..20db98d7 100644 --- a/libnitrokey/NitrokeyManager.h +++ b/libnitrokey/NitrokeyManager.h @@ -40,10 +40,16 @@ namespace nitrokey { using namespace nitrokey::proto; using namespace nitrokey::log; +template +typename T::CommandPayload get_payload(){ + //Create, initialize and return by value command payload + typename T::CommandPayload st; + bzero(&st, sizeof(st)); + return st; +} -#ifdef __WIN32 -char * strndup(const char* str, size_t maxlen); -#endif +#include "nk_strndup.h" +constexpr int max_string_field_length = 2*1024; //storage's status string is ~1k class NitrokeyManager { public: diff --git a/libnitrokey/nk_strndup.h b/libnitrokey/nk_strndup.h new file mode 100644 index 00000000..0c967264 --- /dev/null +++ b/libnitrokey/nk_strndup.h @@ -0,0 +1,9 @@ +#ifndef LIBNITROKEY_NK_STRNDUP_H +#define LIBNITROKEY_NK_STRNDUP_H + +#ifdef __WIN32 +char * strndup(const char* str, size_t maxlen); +#endif + + +#endif // LIBNITROKEY_NK_STRNDUP_H diff --git a/meson.build b/meson.build index c758a7af..4ef25604 100644 --- a/meson.build +++ b/meson.build @@ -66,6 +66,13 @@ libnitrokey = library( 'NitrokeyManager.cc', 'NK_C_API.cc', 'DeviceCommunicationExceptions.cpp', + 'NitrokeyManagerStorage.cpp', + 'NitrokeyManagerStorage.h', + 'NitrokeyManagerOTP.cc', + 'NitrokeyManagerOTP.h', + 'NitrokeyManagerPWS.h', + 'NitrokeyManagerPWS.cc', + 'NK_C_API_storage.cpp', ], include_directories : [ inc_libnitrokey, diff --git a/nk_strndup.c b/nk_strndup.c new file mode 100644 index 00000000..e24c584f --- /dev/null +++ b/nk_strndup.c @@ -0,0 +1,14 @@ +#include "nk_strndup.h" + +#ifndef strndup +#ifdef _WIN32 +#pragma message "Using own strndup" +char * strndup(const char* str, size_t maxlen){ + size_t len = strnlen(str, maxlen); + char* dup = (char *) malloc(len + 1); + memcpy(dup, str, len); + dup[len] = 0; + return dup; +} +#endif +#endif \ No newline at end of file