From 7d943d3e8717ba47af4b53787cc4c29ad6ee2f90 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Wed, 2 Nov 2016 21:52:40 +0100 Subject: Python bindings and tests for most of Storage functionality Signed-off-by: Szczepan Zalega --- NK_C_API.cc | 90 ++++++++++++++++++++++++++++++++++++++++++++++ NK_C_API.h | 17 +++++++++ NitrokeyManager.cc | 79 +++++++++++++++++++++++++++++++++++++++- include/NitrokeyManager.h | 25 ++++++++++++- unittest/constants.py | 2 ++ unittest/test_storage.py | 91 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 302 insertions(+), 2 deletions(-) diff --git a/NK_C_API.cc b/NK_C_API.cc index 7110fca..fc6d3c5 100644 --- a/NK_C_API.cc +++ b/NK_C_API.cc @@ -375,5 +375,95 @@ extern int NK_login_auto() { }); } +// storage commands + +extern int NK_send_startup(uint64_t seconds_from_epoch){ + auto m = NitrokeyManager::instance(); + return get_without_result([&](){ + m->send_startup(seconds_from_epoch); + }); +} + +extern int NK_unlock_encrypted_volume(const char* user_pin){ + auto m = NitrokeyManager::instance(); + return get_without_result([&](){ + m->unlock_encrypted_volume(user_pin); + }); +} + +extern 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); + }); +} + +extern int NK_create_hidden_volume(int slot_nr, int start_percent, int 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); + }); +} + +extern 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); + }); +} + +extern 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); + }); +} + +extern int NK_export_firmware(const char* admin_pin) { + auto m = NitrokeyManager::instance(); + return get_without_result([&](){ + m->export_firmware(admin_pin) ; + }); +} + +extern 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); + }); +} + +extern 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); + }); +} + +extern 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); + }); +} + +extern const char* NK_get_status_storage() { + auto m = NitrokeyManager::instance(); + return get_with_string_result([&](){ + return m->get_status_storage(); + }); +} + +extern const char* NK_get_SD_usage_data() { + auto m = NitrokeyManager::instance(); + return get_with_string_result([&](){ + return m->get_SD_usage_data(); + }); +} + + } diff --git a/NK_C_API.h b/NK_C_API.h index 728824d..e5b414c 100644 --- a/NK_C_API.h +++ b/NK_C_API.h @@ -324,6 +324,23 @@ extern int NK_erase_password_safe_slot(uint8_t slot_number); */ extern int NK_is_AES_supported(const char *user_password); + +extern int NK_send_startup(uint64_t seconds_from_epoch); +extern int NK_unlock_encrypted_volume(const char* user_pin); +extern int NK_unlock_hidden_volume(const char* hidden_volume_password); +extern int NK_create_hidden_volume(int slot_nr, int start_percent, int end_percent, + const char* hidden_volume_password); +extern int NK_set_unencrypted_read_only(const char* user_pin); +extern int NK_set_unencrypted_read_write(const char* user_pin); +extern int NK_export_firmware(const char* admin_pin) ; +extern int NK_clear_new_sd_card_warning(const char* admin_pin) ; +extern int NK_fill_SD_card_with_random_data(const char* admin_pin) ; +extern int NK_change_update_password(const char* current_update_password, + const char* new_update_password); +extern const char* NK_get_status_storage(); +extern const char* NK_get_SD_usage_data(); + + } diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index 606c4fb..49b34c4 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -3,6 +3,7 @@ #include "include/NitrokeyManager.h" #include "include/LibraryException.h" #include +#include "include/misc.h" namespace nitrokey{ @@ -486,4 +487,80 @@ namespace nitrokey{ return true; } -} + //storage commands + + /** + * TODO rename to set_time ? + * TODO check what exactly this one is doing + * @param seconds_from_epoch + */ + void NitrokeyManager::send_startup(uint64_t seconds_from_epoch){ + auto p = get_payload(); +// p.set_defaults(); + p.localtime = seconds_from_epoch; + //auto device_status = + 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); + } + + //TODO check is encrypted volume unlocked before execution + //if not return library exception + void NitrokeyManager::create_hidden_volume(int slot_nr, int start_percent, int 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(const char* user_pin) { + misc::execute_password_command(*device, user_pin); + } + + void NitrokeyManager::set_unencrypted_read_write(const char* user_pin) { + misc::execute_password_command(*device, user_pin); + } + + void NitrokeyManager::export_firmware(const char* admin_pin) { + misc::execute_password_command(*device, admin_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); + } + + const char * NitrokeyManager::get_status_storage(){ + auto p = stick20::GetDeviceStatus::CommandTransaction::run(*device); + return strdup(p.data().dissect().c_str()); + } + + const char * NitrokeyManager::get_SD_usage_data(){ + auto p = stick20::GetSDCardOccupancy::CommandTransaction::run(*device); + return strdup(p.data().dissect().c_str()); + } + + + } diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index 52c18d7..7a3ffcc 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -82,6 +82,30 @@ namespace nitrokey { bool is_AES_supported(const char *user_password); + void unlock_encrypted_volume(const char *user_password); + + void unlock_hidden_volume(const char *hidden_volume_password); + + void set_unencrypted_read_only(const char *user_pin); + + void set_unencrypted_read_write(const char *user_pin); + + void export_firmware(const char *admin_pin); + + void clear_new_sd_card_warning(const char *admin_pin); + + void fill_SD_card_with_random_data(const char *admin_pin); + + void change_update_password(const char *current_update_password, const char *new_update_password); + + void create_hidden_volume(int slot_nr, int start_percent, int end_percent, const char *hidden_volume_password); + + void send_startup(uint64_t seconds_from_epoch); + + const char * get_status_storage(); + + const char *get_SD_usage_data(); + ~NitrokeyManager(); private: NitrokeyManager(); @@ -101,7 +125,6 @@ namespace nitrokey { template void change_PIN_general(char *current_PIN, char *new_PIN); - }; } diff --git a/unittest/constants.py b/unittest/constants.py index e3caae3..258619e 100644 --- a/unittest/constants.py +++ b/unittest/constants.py @@ -12,6 +12,8 @@ class DefaultPasswords(Enum): USER = '123456' ADMIN_TEMP = '123123123' USER_TEMP = '234234234' + UPDATE = '12345678' + UPDATE_TEMP = '123update123' class DeviceErrorCode(Enum): diff --git a/unittest/test_storage.py b/unittest/test_storage.py index d6cc558..b02b1eb 100644 --- a/unittest/test_storage.py +++ b/unittest/test_storage.py @@ -3,5 +3,96 @@ import pytest from misc import ffi, gs, wait, cast_pointer_to_tuple from constants import DefaultPasswords, DeviceErrorCode, RFC_SECRET, LibraryErrors +import pprint +pprint = pprint.PrettyPrinter(indent=4).pprint +def get_dict_from_dissect(status): + x = [] + for s in status.split('\n'): + try: + if not ':' in s: continue + ss = s.replace('\t', '').replace(' (int) ', '').split(':') + if not len(ss) == 2: continue + x.append(ss) + except: + pass + d = {k.strip(): v.strip() for k, v in x} + return d + + +def test_get_status_storage(C): + status_pointer = C.NK_get_status_storage() + status_string = gs(status_pointer) + status_dict = get_dict_from_dissect(status_string) + default_admin_password_retry_count = 3 + assert int(status_dict['AdminPwRetryCount']) == default_admin_password_retry_count + + +def test_sd_card_usage(C): + data_pointer = C.NK_get_SD_usage_data() + data_string = gs(data_pointer) + assert len(data_string) > 0 + data_dict = get_dict_from_dissect(data_string) + assert int(data_dict['WriteLevelMax']) <= 100 + + +def test_encrypted_volume_unlock(C): + assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK + assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK + + +def test_encrypted_volume_unlock_hidden(C): + hidden_volume_password = 'hiddenpassword' + assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK + assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK + assert C.NK_create_hidden_volume(0, 20, 21, hidden_volume_password) == DeviceErrorCode.STATUS_OK + assert C.NK_unlock_hidden_volume(hidden_volume_password) == DeviceErrorCode.STATUS_OK + + +def test_encrypted_volume_setup_multiple_hidden(C): + hidden_volume_password = 'hiddenpassword' + p = lambda i: hidden_volume_password + str(i) + assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK + assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK + for i in range(4): + assert C.NK_create_hidden_volume(i, 20+i*10, 20+i*10+i+1, p(i) ) == DeviceErrorCode.STATUS_OK + for i in range(4): + assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK + assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK + assert C.NK_unlock_hidden_volume(p(i)) == DeviceErrorCode.STATUS_OK + + +def test_unencrypted_volume_set_read_only(C): + assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK + assert C.NK_set_unencrypted_read_only(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK + + +def test_unencrypted_volume_set_read_write(C): + assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK + assert C.NK_set_unencrypted_read_write(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK + + +def test_export_firmware(C): + assert C.NK_export_firmware(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK + + +def test_clear_new_sd_card_notification(C): + assert C.NK_clear_new_sd_card_warning(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK + + +@pytest.mark.skip +def test_fill_SD_card(C): + assert C.NK_fill_SD_card_with_random_data(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK + + +def test_change_update_password(C): + wrong_password = 'aaaaaaaaaaa' + assert C.NK_change_update_password(wrong_password, DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.WRONG_PASSWORD + assert C.NK_change_update_password(DefaultPasswords.UPDATE, DefaultPasswords.UPDATE_TEMP) == DeviceErrorCode.STATUS_OK + assert C.NK_change_update_password(DefaultPasswords.UPDATE_TEMP, DefaultPasswords.UPDATE) == DeviceErrorCode.STATUS_OK + + +def test_send_startup(C): + time_seconds_from_epoch = 0 # FIXME set proper date + assert C.NK_send_startup(time_seconds_from_epoch) == DeviceErrorCode.STATUS_OK -- cgit v1.2.1