diff options
| author | Szczepan Zalega <szczepan@nitrokey.com> | 2017-03-11 17:18:59 +0100 | 
|---|---|---|
| committer | Szczepan Zalega <szczepan@nitrokey.com> | 2017-03-11 17:18:59 +0100 | 
| commit | 22d05ce647281056d71fbd3c31df3bcd6396188d (patch) | |
| tree | 90208930f54c47987bfd5ffcf0a0acaaad2510da /unittest | |
| parent | ed5044da43172d86a1aa475473561a4818b7c69c (diff) | |
| parent | ac6b9c18ef55f4cd36e85069cf0cf82c14e04404 (diff) | |
| download | libnitrokey-22d05ce647281056d71fbd3c31df3bcd6396188d.tar.gz libnitrokey-22d05ce647281056d71fbd3c31df3bcd6396188d.tar.bz2 | |
Merge branch 'libnitrokey_3'
Diffstat (limited to 'unittest')
| -rw-r--r-- | unittest/Makefile | 33 | ||||
| -rw-r--r-- | unittest/conftest.py | 22 | ||||
| -rw-r--r-- | unittest/requirements.txt | 1 | ||||
| -rw-r--r-- | unittest/setup_python_dependencies.sh | 3 | ||||
| -rw-r--r-- | unittest/test.cc | 10 | ||||
| -rw-r--r-- | unittest/test2.cc | 28 | ||||
| -rw-r--r-- | unittest/test3.cc | 27 | ||||
| -rw-r--r-- | unittest/test_C_API.cpp | 4 | ||||
| -rw-r--r-- | unittest/test_HOTP.cc | 9 | ||||
| -rw-r--r-- | unittest/test_pro.py | 83 | ||||
| -rw-r--r-- | unittest/test_storage.py | 155 | 
11 files changed, 288 insertions, 87 deletions
| diff --git a/unittest/Makefile b/unittest/Makefile deleted file mode 100644 index dbd003e..0000000 --- a/unittest/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -CC  = $(PREFIX)-gcc -#CXX = $(PREFIX)-g++ -CXX = clang++-3.8 -LD = $(CXX) - -INCLUDE = -I../include -ICatch/single_include/ -LIB = -L../build -LDLIBS = -lnitrokey -BUILD = build - -CXXFLAGS = -std=c++14 -fPIC -Wno-gnu-variable-sized-type-not-at-end - -CXXSOURCES = $(wildcard *.cc) -TARGETS = $(CXXSOURCES:%.cc=$(BUILD)/%) -DEPENDS = $(CXXSOURCES:%.cc=$(BUILD)/%.d) - -$(BUILD)/%.d: %.cc -	$(CXX) -M $< -o $@ $(INCLUDE) $(CXXFLAGS) - -$(BUILD)/%: %.cc $(DEPENDS) -	$(CXX) $< -o $@ $(INCLUDE) $(LIB) $(CXXFLAGS) $(LDLIBS) - -all: $(TARGETS) - -clean: -	rm -f $(TARGETS) - -mrproper: clean -	rm -f $(BUILD)/*.d - -.PHONY: all clean mrproper - -include $(wildcard build/*.d) diff --git a/unittest/conftest.py b/unittest/conftest.py index 88bf7d0..67b45aa 100644 --- a/unittest/conftest.py +++ b/unittest/conftest.py @@ -22,14 +22,30 @@ def C(request):      a = iter(declarations)      for declaration in a: -        if declaration.startswith('extern') and not '"C"' in declaration: -            declaration = declaration.replace('extern', '').strip() +        if declaration.startswith('NK_C_API'): +            declaration = declaration.replace('NK_C_API', '').strip()              while not ';' in declaration:                  declaration += (next(a)).strip()              print(declaration)              ffi.cdef(declaration, override=True) -    C = ffi.dlopen("../build/libnitrokey.so") +    C = None +    import os, sys +    path_build = os.path.join("..", "build") +    paths = [ os.path.join(path_build,"libnitrokey-log.so"), +              os.path.join(path_build,"libnitrokey.so")] +    for p in paths: +        print p +        if os.path.exists(p): +            C = ffi.dlopen(p) +            break +        else: +            print("File does not exist: " + p) +            print("Trying another") +    if not C: +        print("No library file found") +        sys.exit(1) +      C.NK_set_debug(False)      nk_login = C.NK_login_auto()      if nk_login != 1: diff --git a/unittest/requirements.txt b/unittest/requirements.txt index 7224741..2cb9c05 100644 --- a/unittest/requirements.txt +++ b/unittest/requirements.txt @@ -2,3 +2,4 @@ cffi  pytest-repeat  pytest-randomly  enum +oath
\ No newline at end of file diff --git a/unittest/setup_python_dependencies.sh b/unittest/setup_python_dependencies.sh new file mode 100644 index 0000000..0f1a0f7 --- /dev/null +++ b/unittest/setup_python_dependencies.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +pip install -r requirements.txt --user diff --git a/unittest/test.cc b/unittest/test.cc index 6744b45..15235bd 100644 --- a/unittest/test.cc +++ b/unittest/test.cc @@ -1,4 +1,3 @@ -#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main()  #include "catch.hpp"  #include <iostream> @@ -13,8 +12,9 @@ using namespace nitrokey::proto::stick10;  using namespace nitrokey::log;  using namespace nitrokey::misc; +using Dev10 = std::shared_ptr<Stick10>; -std::string getSlotName(Stick10 &stick, int slotNo) { +std::string getSlotName(Dev10 stick, int slotNo) {    auto slot_req = get_payload<ReadSlot>();    slot_req.slot_number = slotNo;    auto slot = ReadSlot::CommandTransaction::run(stick, slot_req); @@ -23,8 +23,8 @@ std::string getSlotName(Stick10 &stick, int slotNo) {  }  TEST_CASE("Slot names are correct", "[slotNames]") { -  Stick10 stick; -  bool connected = stick.connect(); +  auto stick = make_shared<Stick10>(); +  bool connected = stick->connect();    REQUIRE(connected == true);    Log::instance().set_loglevel(Loglevel::DEBUG); @@ -79,5 +79,5 @@ TEST_CASE("Slot names are correct", "[slotNames]") {      REQUIRE(sName == std::string("login1"));    } -  stick.disconnect(); +  stick->disconnect();  } diff --git a/unittest/test2.cc b/unittest/test2.cc index 00e70e3..31dbce8 100644 --- a/unittest/test2.cc +++ b/unittest/test2.cc @@ -1,4 +1,3 @@ -#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main()  static const char *const default_admin_pin = "12345678";  static const char *const default_user_pin = "123456"; @@ -20,9 +19,10 @@ using namespace nitrokey::proto::stick20;  using namespace nitrokey::log;  using namespace nitrokey::misc; +#include <memory>  template<typename CMDTYPE> -void execute_password_command(Device &stick, const char *password, const char kind = 'P') { +void execute_password_command(std::shared_ptr<Device> stick, const char *password, const char kind = 'P') {    auto p = get_payload<CMDTYPE>();    if (kind == 'P'){      p.set_kind_user(); @@ -47,8 +47,8 @@ void SKIP_TEST() {  TEST_CASE("long operation test", "[test_long]") {    SKIP_TEST(); -  Stick20 stick; -  bool connected = stick.connect(); +  auto stick = make_shared<Stick20>(); +  bool connected = stick->connect();    REQUIRE(connected == true);    Log::instance().set_loglevel(Loglevel::DEBUG);    try{ @@ -123,8 +123,8 @@ TEST_CASE("test device commands ids", "[fast]") {  }  TEST_CASE("test device internal status with various commands", "[fast]") { -  Stick20 stick; -  bool connected = stick.connect(); +  auto stick = make_shared<Stick20>(); +  bool connected = stick->connect();    REQUIRE(connected == true);    Log::instance().set_loglevel(Loglevel::DEBUG); @@ -147,8 +147,8 @@ TEST_CASE("test device internal status with various commands", "[fast]") {  }  TEST_CASE("setup hidden volume test", "[hidden]") { -  Stick20 stick; -  bool connected = stick.connect(); +  auto stick = make_shared<Stick20>(); +  bool connected = stick->connect();    REQUIRE(connected == true);    Log::instance().set_loglevel(Loglevel::DEBUG);    stick10::LockDevice::CommandTransaction::run(stick); @@ -170,8 +170,8 @@ TEST_CASE("setup hidden volume test", "[hidden]") {  }  TEST_CASE("setup multiple hidden volumes", "[hidden]") { -  Stick20 stick; -  bool connected = stick.connect(); +  auto stick = make_shared<Stick20>(); +  bool connected = stick->connect();    REQUIRE(connected == true);    Log::instance().set_loglevel(Loglevel::DEBUG); @@ -207,8 +207,8 @@ TEST_CASE("setup multiple hidden volumes", "[hidden]") {  TEST_CASE("update password change", "[dangerous]") {    SKIP_TEST(); -  Stick20 stick; -  bool connected = stick.connect(); +  auto stick = make_shared<Stick20>(); +  bool connected = stick->connect();    REQUIRE(connected == true);    Log::instance().set_loglevel(Loglevel::DEBUG); @@ -228,8 +228,8 @@ TEST_CASE("update password change", "[dangerous]") {  }  TEST_CASE("general test", "[test]") { -  Stick20 stick; -  bool connected = stick.connect(); +  auto stick = make_shared<Stick20>(); +  bool connected = stick->connect();    REQUIRE(connected == true);    Log::instance().set_loglevel(Loglevel::DEBUG); diff --git a/unittest/test3.cc b/unittest/test3.cc index 9049365..9e0ef11 100644 --- a/unittest/test3.cc +++ b/unittest/test3.cc @@ -1,8 +1,3 @@ -// -// Created by sz on 08.11.16. -// - -#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main()  static const char *const default_admin_pin = "12345678";  static const char *const default_user_pin = "123456"; @@ -26,13 +21,16 @@ using namespace nitrokey::proto::stick10_08;  using namespace nitrokey::log;  using namespace nitrokey::misc; -void connect_and_setup(Stick10 &stick) { -  bool connected = stick.connect(); +using Dev = Stick10; +using Dev10 = std::shared_ptr<Dev>; + +void connect_and_setup(Dev10 stick) { +  bool connected = stick->connect();    REQUIRE(connected == true);    Log::instance().set_loglevel(Loglevel::DEBUG);  } -void authorize(Stick10 &stick) { +void authorize(Dev10 stick) {    auto authreq = get_payload<FirstAuthenticate>();    strcpy((char *) (authreq.card_password), default_admin_pin);    strcpy((char *) (authreq.temporary_password), temporary_password); @@ -45,7 +43,8 @@ void authorize(Stick10 &stick) {  }  TEST_CASE("write slot", "[pronew]"){ -  Stick10 stick; +  auto stick = make_shared<Dev>(); +    connect_and_setup(stick);    authorize(stick); @@ -81,7 +80,7 @@ TEST_CASE("write slot", "[pronew]"){  TEST_CASE("erase slot", "[pronew]"){ -  Stick10 stick; +  auto stick = make_shared<Dev>();    connect_and_setup(stick);    authorize(stick); @@ -107,7 +106,7 @@ TEST_CASE("erase slot", "[pronew]"){  }  TEST_CASE("write general config", "[pronew]") { -  Stick10 stick; +  auto stick = make_shared<Dev>();    connect_and_setup(stick);    authorize(stick); @@ -121,7 +120,7 @@ TEST_CASE("write general config", "[pronew]") {  }  TEST_CASE("authorize user HOTP", "[pronew]") { -  Stick10 stick; +  auto stick = make_shared<Dev>();    connect_and_setup(stick);    authorize(stick); @@ -164,7 +163,7 @@ TEST_CASE("authorize user HOTP", "[pronew]") {  }  TEST_CASE("check firmware version", "[pronew]") { -  Stick10 stick; +  auto stick = make_shared<Dev>();    connect_and_setup(stick);    auto p = GetStatus::CommandTransaction::run(stick); @@ -172,7 +171,7 @@ TEST_CASE("check firmware version", "[pronew]") {  }  TEST_CASE("authorize user TOTP", "[pronew]") { -  Stick10 stick; +  auto stick = make_shared<Dev>();    connect_and_setup(stick);    authorize(stick); diff --git a/unittest/test_C_API.cpp b/unittest/test_C_API.cpp index 37d3c7f..160145b 100644 --- a/unittest/test_C_API.cpp +++ b/unittest/test_C_API.cpp @@ -24,8 +24,8 @@ TEST_CASE("Check retry count", "[BASIC]") {  }  TEST_CASE("Check long strings", "[STANDARD]") { -  char* longPin = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; -  char *pin = "123123123"; +  const char* longPin = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; +  const char* pin = "123123123";    auto result = NK_change_user_PIN(longPin, pin);    REQUIRE(result == TOO_LONG_STRING);    result = NK_change_user_PIN(pin, longPin); diff --git a/unittest/test_HOTP.cc b/unittest/test_HOTP.cc index d31df55..e6f7d7c 100644 --- a/unittest/test_HOTP.cc +++ b/unittest/test_HOTP.cc @@ -1,4 +1,3 @@ -#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main()  #include "catch.hpp"  #include <iostream>  #include "device_proto.h" @@ -14,7 +13,7 @@ using namespace nitrokey::log;  using namespace nitrokey::misc;  void hexStringToByte(uint8_t data[], const char* hexString){ -    assert(strlen(hexString)%2==0); +  REQUIRE(strlen(hexString)%2==0);      char buf[2];      for(int i=0; i<strlen(hexString); i++){          buf[i%2] = hexString[i]; @@ -34,8 +33,8 @@ TEST_CASE("test secret", "[functions]") {  }  TEST_CASE("Test HOTP codes according to RFC", "[HOTP]") { -    Stick10 stick; -    bool connected = stick.connect(); +    std::shared_ptr<Stick10> stick = make_shared<Stick10>(); +    bool connected = stick->connect();    REQUIRE(connected == true); @@ -98,5 +97,5 @@ TEST_CASE("Test HOTP codes according to RFC", "[HOTP]") {    } -  stick.disconnect(); +  stick->disconnect();  } diff --git a/unittest/test_pro.py b/unittest/test_pro.py index 4a2a504..0140994 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -22,6 +22,72 @@ def test_write_password_safe_slot(C):      assert C.NK_write_password_safe_slot(0, 'slotname1', 'login1', 'pass1') == DeviceErrorCode.STATUS_OK +@pytest.mark.slowtest +def test_write_all_password_safe_slots_and_read_10_times(C): +    def fill(s, wid): +        assert wid >= len(s) +        numbers = '1234567890'*4 +        s += numbers[:wid-len(s)] +        assert len(s) == wid +        return s + +    def get_pass(suffix): +        return fill('pass' + suffix, 20) + +    def get_loginname(suffix): +        return fill('login' + suffix, 32) + +    def get_slotname(suffix): +        return fill('slotname' + suffix, 11) + +    assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK +    assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK +    PWS_slot_count = 16 +    for i in range(0, PWS_slot_count): +        iss = str(i) +        assert C.NK_write_password_safe_slot(i, +                                             get_slotname(iss), get_loginname(iss), +                                             get_pass(iss)) == DeviceErrorCode.STATUS_OK + +    for j in range(0, 10): +        for i in range(0, PWS_slot_count): +            iss = str(i) +            assert gs(C.NK_get_password_safe_slot_name(i)) == get_slotname(iss) +            assert gs(C.NK_get_password_safe_slot_login(i)) == get_loginname(iss) +            assert gs(C.NK_get_password_safe_slot_password(i)) == get_pass(iss) + + +@pytest.mark.slowtest +@pytest.mark.xfail(reason="This test should be run directly after test_write_all_password_safe_slots_and_read_10_times") +def test_read_all_password_safe_slots_10_times(C): +    def fill(s, wid): +        assert wid >= len(s) +        numbers = '1234567890'*4 +        s += numbers[:wid-len(s)] +        assert len(s) == wid +        return s + +    def get_pass(suffix): +        return fill('pass' + suffix, 20) + +    def get_loginname(suffix): +        return fill('login' + suffix, 32) + +    def get_slotname(suffix): +        return fill('slotname' + suffix, 11) + +    assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK +    assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK +    PWS_slot_count = 16 + +    for j in range(0, 10): +        for i in range(0, PWS_slot_count): +            iss = str(i) +            assert gs(C.NK_get_password_safe_slot_name(i)) == get_slotname(iss) +            assert gs(C.NK_get_password_safe_slot_login(i)) == get_loginname(iss) +            assert gs(C.NK_get_password_safe_slot_password(i)) == get_pass(iss) + +  def test_get_password_safe_slot_name(C):      assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK      assert C.NK_write_password_safe_slot(0, 'slotname1', 'login1', 'pass1') == DeviceErrorCode.STATUS_OK @@ -82,6 +148,9 @@ def test_regenerate_aes_key(C):  def test_enable_password_safe_after_factory_reset(C):      assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK +    if is_storage(C): +        # for some reason storage likes to be authenticated before reset (to investigate) +        assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK      assert C.NK_factory_reset(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK      wait(10)      if is_storage(C): @@ -523,7 +592,7 @@ def test_OTP_secret_started_from_null(C, secret):      skip_if_device_version_lower_than({'S': 43, 'P': 8})      if len(secret) > 40:          # feature: 320 bit long secret handling -        skip_if_device_version_lower_than({'S': 44, 'P': 8}) +        skip_if_device_version_lower_than({'P': 8})      oath = pytest.importorskip("oath")      lib_at = lambda t: oath.hotp(secret, t, format='dec6') @@ -617,8 +686,9 @@ def test_TOTP_secrets(C, secret):      '''      skip_if_device_version_lower_than({'S': 44, 'P': 8}) -    if is_pro_rtm_07(C) and len(secret)>20*2: #*2 since secret is in hex -        pytest.skip("Secret lengths over 20 bytes are not supported by NK Pro 0.7 ") +    if len(secret)>20*2: #*2 since secret is in hex +        # pytest.skip("Secret lengths over 20 bytes are not supported by NK Pro 0.7 and NK Storage") +        skip_if_device_version_lower_than({'P': 8})      slot_number = 0      time = 0      period = 30 @@ -645,10 +715,11 @@ def test_TOTP_secrets(C, secret):  @pytest.mark.parametrize("secret", [RFC_SECRET, 2*RFC_SECRET, '12'*10, '12'*30] )  def test_HOTP_secrets(C, secret):      """ -    NK Pro 0.8+, NK Storage 0.44+ +    NK Pro 0.8+      feature needed: support for 320bit secrets      """ -    skip_if_device_version_lower_than({'S': 44, 'P': 8}) +    if len(secret)>40: +        skip_if_device_version_lower_than({'P': 8})      slot_number = 0      counter = 0 @@ -695,7 +766,7 @@ def test_edit_OTP_slot(C):      """      should change slots counter and name without changing its secret (using null secret for second update)      """ -    # counter does not reset under Storage v0.43 +    # counter is not getting updated under Storage v0.43 - #TOREPORT      skip_if_device_version_lower_than({'S': 44, 'P': 7})      secret = RFC_SECRET diff --git a/unittest/test_storage.py b/unittest/test_storage.py index a1c59aa..da7c9a3 100644 --- a/unittest/test_storage.py +++ b/unittest/test_storage.py @@ -57,10 +57,11 @@ def test_encrypted_volume_unlock_hidden(C):      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 -@pytest.mark.skip(reason='hangs device, to report') -def test_encrypted_volume_setup_multiple_hidden(C): -    skip_if_device_version_lower_than({'S': 43}) -    hidden_volume_password = 'hiddenpassword' + +def test_encrypted_volume_setup_multiple_hidden_lock(C): +    import random +    skip_if_device_version_lower_than({'S': 45}) #hangs device on lower version +    hidden_volume_password = 'hiddenpassword' + str(random.randint(0,100))      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 @@ -72,6 +73,149 @@ def test_encrypted_volume_setup_multiple_hidden(C):          assert C.NK_unlock_hidden_volume(p(i)) == DeviceErrorCode.STATUS_OK +@pytest.mark.parametrize("volumes_to_setup", range(1, 5)) +def test_encrypted_volume_setup_multiple_hidden_no_lock_device_volumes(C, volumes_to_setup): +    skip_if_device_version_lower_than({'S': 43}) +    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(volumes_to_setup): +        assert C.NK_create_hidden_volume(i, 20+i*10, 20+i*10+i+1, p(i)) == DeviceErrorCode.STATUS_OK + +    assert C.NK_lock_encrypted_volume() == DeviceErrorCode.STATUS_OK +    assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK + +    for i in range(volumes_to_setup): +        assert C.NK_unlock_hidden_volume(p(i)) == DeviceErrorCode.STATUS_OK +        # TODO mount and test for files +        assert C.NK_lock_hidden_volume() == DeviceErrorCode.STATUS_OK + + +@pytest.mark.parametrize("volumes_to_setup", range(1, 5)) +def test_encrypted_volume_setup_multiple_hidden_no_lock_device_volumes_unlock_at_once(C, volumes_to_setup): +    skip_if_device_version_lower_than({'S': 43}) +    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(volumes_to_setup): +        assert C.NK_create_hidden_volume(i, 20+i*10, 20+i*10+i+1, p(i)) == DeviceErrorCode.STATUS_OK +        assert C.NK_unlock_hidden_volume(p(i)) == DeviceErrorCode.STATUS_OK +        assert C.NK_lock_hidden_volume() == DeviceErrorCode.STATUS_OK + +    assert C.NK_lock_encrypted_volume() == DeviceErrorCode.STATUS_OK +    assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK + +    for i in range(volumes_to_setup): +        assert C.NK_unlock_hidden_volume(p(i)) == DeviceErrorCode.STATUS_OK +        # TODO mount and test for files +        assert C.NK_lock_hidden_volume() == DeviceErrorCode.STATUS_OK + + +@pytest.mark.parametrize("use_slot", range(4)) +def test_encrypted_volume_setup_one_hidden_no_lock_device_slot(C, use_slot): +    skip_if_device_version_lower_than({'S': 43}) +    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 +    i = use_slot +    assert C.NK_create_hidden_volume(i, 20+i*10, 20+i*10+i+1, p(i)) == DeviceErrorCode.STATUS_OK +    assert C.NK_unlock_hidden_volume(p(i)) == DeviceErrorCode.STATUS_OK +    assert C.NK_lock_hidden_volume() == DeviceErrorCode.STATUS_OK + +    assert C.NK_lock_encrypted_volume() == DeviceErrorCode.STATUS_OK +    assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK + +    for j in range(3): +        assert C.NK_unlock_hidden_volume(p(i)) == DeviceErrorCode.STATUS_OK +        # TODO mount and test for files +        assert C.NK_lock_hidden_volume() == DeviceErrorCode.STATUS_OK + + +def test_password_safe_slot_name_corruption(C): +    skip_if_device_version_lower_than({'S': 43}) +    volumes_to_setup = 4 +    # connected with encrypted volumes, possible also with hidden +    def fill(s, wid): +        assert wid >= len(s) +        numbers = '1234567890' * 4 +        s += numbers[:wid - len(s)] +        assert len(s) == wid +        return s + +    def get_pass(suffix): +        return fill('pass' + suffix, 20) + +    def get_loginname(suffix): +        return fill('login' + suffix, 32) + +    def get_slotname(suffix): +        return fill('slotname' + suffix, 11) + +    assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK +    assert C.NK_enable_password_safe(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK +    PWS_slot_count = 16 +    for i in range(0, PWS_slot_count): +        iss = str(i) +        assert C.NK_write_password_safe_slot(i, +                                             get_slotname(iss), get_loginname(iss), +                                             get_pass(iss)) == DeviceErrorCode.STATUS_OK + +    def check_PWS_correctness(C): +        for i in range(0, PWS_slot_count): +            iss = str(i) +            assert gs(C.NK_get_password_safe_slot_name(i)) == get_slotname(iss) +            assert gs(C.NK_get_password_safe_slot_login(i)) == get_loginname(iss) +            assert gs(C.NK_get_password_safe_slot_password(i)) == get_pass(iss) + +    hidden_volume_password = 'hiddenpassword' +    p = lambda i: hidden_volume_password + str(i) +    def check_volumes_correctness(C): +        for i in range(volumes_to_setup): +            assert C.NK_unlock_hidden_volume(p(i)) == DeviceErrorCode.STATUS_OK +            # TODO mount and test for files +            assert C.NK_lock_hidden_volume() == DeviceErrorCode.STATUS_OK + +    check_PWS_correctness(C) + +    assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK +    assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK +    for i in range(volumes_to_setup): +        assert C.NK_create_hidden_volume(i, 20+i*10, 20+i*10+i+1, p(i)) == DeviceErrorCode.STATUS_OK +        assert C.NK_unlock_hidden_volume(p(i)) == DeviceErrorCode.STATUS_OK +        assert C.NK_lock_hidden_volume() == DeviceErrorCode.STATUS_OK + +    assert C.NK_lock_encrypted_volume() == DeviceErrorCode.STATUS_OK +    assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK + +    check_volumes_correctness(C) +    check_PWS_correctness(C) +    check_volumes_correctness(C) +    check_PWS_correctness(C) + +    assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK +    assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK +    check_volumes_correctness(C) +    check_PWS_correctness(C) +    assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK +    assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK +    check_volumes_correctness(C) +    check_PWS_correctness(C) + +def test_hidden_volume_corruption(C): +    # bug: this should return error without unlocking encrypted volume each hidden volume lock, but it does not +    assert C.NK_lock_encrypted_volume() == DeviceErrorCode.STATUS_OK +    assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK +    hidden_volume_password = 'hiddenpassword' +    p = lambda i: hidden_volume_password + str(i) +    for i in range(4): +        assert C.NK_unlock_encrypted_volume(DefaultPasswords.USER) == DeviceErrorCode.STATUS_OK +        assert C.NK_unlock_hidden_volume(p(i)) == DeviceErrorCode.STATUS_OK +        wait(2) +        assert C.NK_lock_hidden_volume() == DeviceErrorCode.STATUS_OK +  def test_unencrypted_volume_set_read_only(C):      skip_if_device_version_lower_than({'S': 43})      assert C.NK_lock_device() == DeviceErrorCode.STATUS_OK @@ -94,7 +238,8 @@ def test_clear_new_sd_card_notification(C):      assert C.NK_clear_new_sd_card_warning(DefaultPasswords.ADMIN) == DeviceErrorCode.STATUS_OK -@pytest.mark.skip +@pytest.mark.slowtest +@pytest.mark.skip(reason='long test (about 1h)')  def test_fill_SD_card(C):      skip_if_device_version_lower_than({'S': 43})      status = C.NK_fill_SD_card_with_random_data(DefaultPasswords.ADMIN) | 
