aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSzczepan Zalega <szczepan@nitrokey.com>2016-11-18 12:52:50 +0100
committerSzczepan Zalega <szczepan@nitrokey.com>2016-12-03 16:01:50 +0100
commit9c2feef240e396648dfb2378f7d2428b0593c9f2 (patch)
tree3b28b50a3aae29c2ad7ca7c1e57001d70ce139e5
parentcbccc871329c5522449010ae5007278123508820 (diff)
downloadlibnitrokey-9c2feef240e396648dfb2378f7d2428b0593c9f2.tar.gz
libnitrokey-9c2feef240e396648dfb2378f7d2428b0593c9f2.tar.bz2
Support longer secrets (40 bytes) for NK Pro 0.8
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
-rw-r--r--NitrokeyManager.cc29
-rw-r--r--include/stick10_commands_0.8.h18
-rw-r--r--misc.cc5
-rw-r--r--unittest/test_pro.py45
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;
};
diff --git a/misc.cc b/misc.cc
index c9d38cb..7a3c199 100644
--- a/misc.cc
+++ b/misc.cc
@@ -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