diff options
| -rw-r--r-- | NitrokeyManager.cc | 29 | ||||
| -rw-r--r-- | include/stick10_commands_0.8.h | 18 | ||||
| -rw-r--r-- | misc.cc | 5 | ||||
| -rw-r--r-- | unittest/test_pro.py | 45 | 
4 files changed, 80 insertions, 17 deletions
| diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index 46c09df..7cc88eb 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -199,6 +199,16 @@ namespace nitrokey{      }      template <typename T, typename U> +    void vector_copy_ranged(T& dest, std::vector<U> &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 <typename T, typename U>      void vector_copy(T& dest, std::vector<U> &vec){          const size_t d_size = sizeof(dest);          if(d_size < vec.size()){ @@ -317,13 +327,20 @@ namespace nitrokey{        payload2.setTypeName();        stick10_08::SendOTPData::CommandTransaction::run(*device, payload2); -      payload2 = get_payload<stick10_08::SendOTPData>(); -      strcpyT(payload2.temporary_admin_password, temporary_password); -      auto secret_bin = misc::hex_string_to_byte(secret); -      vector_copy(payload2.data, secret_bin); -      payload2.length = strlen((const char *) payload2.data);        payload2.setTypeSecret(); -      stick10_08::SendOTPData::CommandTransaction::run(*device, payload2); +      payload2.id = 0; +      auto secret_bin = misc::hex_string_to_byte(secret); +      auto remaining_secret_length = secret_bin.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<stick10_08::WriteToOTPSlot>();        strcpyT(payload.temporary_admin_password, temporary_password); diff --git a/include/stick10_commands_0.8.h b/include/stick10_commands_0.8.h index e880c0a..f0e28a6 100644 --- a/include/stick10_commands_0.8.h +++ b/include/stick10_commands_0.8.h @@ -75,7 +75,23 @@ namespace nitrokey {                      }                  } __packed; -                typedef Transaction<command_id(), struct CommandPayload, struct EmptyPayload> + +                struct ResponsePayload { +                    union { +                        uint8_t data[40]; +                    } __packed; + +                    bool isValid() const { return true; } +                    std::string dissect() const { +                      std::stringstream ss; +                      ss << "data:" << std::endl +                         << ::nitrokey::misc::hexdump((const char *) (&data), sizeof data); +                      return ss.str(); +                    } +                } __packed; + + +                typedef Transaction<command_id(), struct CommandPayload, struct ResponsePayload>                      CommandTransaction;              }; @@ -16,7 +16,8 @@ std::vector<uint8_t> hex_string_to_byte(const char* hexString){      if (s_size%2!=0 || s_size==0 || s_size>big_string_size){          throw InvalidHexString(0);      } -    auto data = std::vector<uint8_t>(d_size, 0); +    auto data = std::vector<uint8_t>(); +    data.reserve(d_size);      char buf[2];      for(int i=0; i<s_size; i++){ @@ -28,7 +29,7 @@ std::vector<uint8_t> hex_string_to_byte(const char* hexString){          }          buf[i%2] = c;          if (i%2==1){ -            data[i/2] = strtoul(buf, NULL, 16) & 0xFF; +            data.push_back( strtoul(buf, NULL, 16) & 0xFF );          }      }      return data; diff --git a/unittest/test_pro.py b/unittest/test_pro.py index 3632ecd..71abfba 100644 --- a/unittest/test_pro.py +++ b/unittest/test_pro.py @@ -501,6 +501,9 @@ def test_get_serial_number(C):  @pytest.mark.parametrize("secret", ['000001', '00'*10+'ff', '00'*19+'ff', '000102', '002EF43F51AFA97BA2B46418768123C9E1809A5B' ])  def test_OTP_secret_started_from_null(C, secret): +    ''' +    NK Pro 0.8+, NK Storage 0.43+ +    '''      oath = pytest.importorskip("oath")      lib_at = lambda t: oath.hotp(secret, t, format='dec6')      PIN_protection = False @@ -522,7 +525,7 @@ def test_OTP_secret_started_from_null(C, secret):      assert dev_res == lib_res -@pytest.mark.parametrize("counter", [0, 3, 7, 0xffff] ) +@pytest.mark.parametrize("counter", [0, 3, 7, 0xffff, 0xffffffff, 0xffffffffffffffff] )  def test_HOTP_slots_read_write_counter(C, counter):      secret = RFC_SECRET      oath = pytest.importorskip("oath") @@ -571,9 +574,13 @@ def test_TOTP_slots_read_write_at_time_period(C, time, period):          lib_res += (time, lib_at(time))      assert dev_res == lib_res - -@pytest.mark.parametrize("secret", [RFC_SECRET, 2*RFC_SECRET] ) +@pytest.mark.parametrize("secret", [RFC_SECRET, 2*RFC_SECRET, '12'*10, '12'*30] )  def test_TOTP_secrets(C, secret): +    ''' +    NK Pro 0.8+, NK Storage 0.44+ +    ''' +    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 ")      slot_number = 0      time = 0      period = 30 @@ -587,10 +594,8 @@ def test_TOTP_secrets(C, secret):                               DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK      dev_res = []      lib_res = [] -    assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK -    assert C.NK_write_totp_slot(slot_number, 'TOTP secret' + str(slot_number), secret, period, use_8_digits, False, False, "", +    assert C.NK_write_totp_slot(slot_number, 'secret' + str(len(secret)), secret, period, use_8_digits, False, False, "",                                  DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK -    assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK      assert C.NK_totp_set_time(time) == DeviceErrorCode.STATUS_OK      code_device = str(C.NK_get_totp_code(slot_number, T, 0, period))      code_device = '0'+code_device if len(code_device) < 6 else code_device @@ -598,6 +603,30 @@ def test_TOTP_secrets(C, secret):      lib_res += (time, lib_at(time))      assert dev_res == lib_res - - +@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+ +    ''' +    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 ") +    slot_number = 0 +    counter = 0 +    oath = pytest.importorskip("oath") +    lib_at = lambda t: oath.hotp(secret, counter=t) +    PIN_protection = False +    use_8_digits = False +    T = 0 +    assert C.NK_first_authenticate(DefaultPasswords.ADMIN, DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK +    assert C.NK_write_config(255, 255, 255, PIN_protection, not PIN_protection, +                             DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK +    dev_res = [] +    lib_res = [] +    assert C.NK_write_hotp_slot(slot_number, 'secret' + str(len(secret)), secret, counter, use_8_digits, False, False, "", +                                DefaultPasswords.ADMIN_TEMP) == DeviceErrorCode.STATUS_OK +    code_device = str(C.NK_get_hotp_code(slot_number)) +    code_device = '0'+code_device if len(code_device) < 6 else code_device +    dev_res += (counter, code_device) +    lib_res += (counter, lib_at(counter)) +    assert dev_res == lib_res | 
