From 2ba87abdb5c69e3d72b88164030ed5633986a63d Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Wed, 9 Nov 2016 19:22:46 +0100 Subject: Convinient function for checking if authorization command is supported Signed-off-by: Szczepan Zalega --- include/NitrokeyManager.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/NitrokeyManager.h') diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index 60fa753..24a83ec 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -110,6 +110,10 @@ namespace nitrokey { int get_progress_bar_value(); ~NitrokeyManager(); + bool is_authorization_command_supported(); + + template + void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device); private: NitrokeyManager(); -- cgit v1.2.3 From c51987f47307637beb6a1b75c351f273edda89cf Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Thu, 10 Nov 2016 18:40:32 +0100 Subject: Working support for new NK Pro 0.8 authorization-less format Signed-off-by: Szczepan Zalega --- NitrokeyManager.cc | 200 ++++++++++++++++++++++++++++++++++------------ include/NitrokeyManager.h | 16 ++++ 2 files changed, 164 insertions(+), 52 deletions(-) (limited to 'include/NitrokeyManager.h') diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index b254071..e80f9b5 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -39,7 +39,6 @@ namespace nitrokey{ void NitrokeyManager::authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device){ if (!is_authorization_command_supported()){ Log::instance()("Authorization command not supported, skipping", Loglevel::WARNING); - return; } auto auth = get_payload(); strcpyT(auth.temporary_password, admin_temporary_password); @@ -117,16 +116,25 @@ namespace nitrokey{ } uint32_t 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_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 resp.data().code; + } 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 resp.data().code; + } } @@ -140,26 +148,41 @@ namespace nitrokey{ 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); - 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); + 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 resp.data().code; + } 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 resp.data().code; } - auto resp = GetTOTP::CommandTransaction::run(*device, gt); - return resp.data().code; + } 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; } @@ -191,59 +214,130 @@ namespace nitrokey{ if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number); slot_number = get_internal_slot_number_for_hotp(slot_number); - 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); + if (is_authorization_command_supported()){ + write_HOTP_slot_authorize(slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, + token_ID, temporary_password); + } else { + write_HOTP_slot_no_authorize(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_no_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) const { + auto payload = get_payload(); + strcpyT(payload.temporary_admin_password, temporary_password); + auto secret_bin = misc::hex_string_to_byte(secret); + vector_copy(payload.slot_secret, secret_bin); + strcpyT(payload.slot_token_id, token_ID); + payload.use_8_digits = use_8_digits; + payload.use_enter = use_enter; + payload.use_tokenID = use_tokenID; + + auto payload2 = get_payload(); + strcpyT(payload2.temporary_admin_password, temporary_password); + payload2.slot_number = slot_number; + strcpyT(payload2.slot_name, slot_name); + payload2.slot_counter = hotp_counter; + + stick10_08::WriteToHOTPSlot::CommandTransaction::run(*device, payload); + stick10_08::WriteToHOTPSlot_2::CommandTransaction::run(*device, payload2); + } + + 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::PRO: { payload.slot_counter = hotp_counter; break; } case DeviceModel::STORAGE: { - std::string counter = std::to_string(hotp_counter); + string counter = to_string(hotp_counter); strcpyT(payload.slot_counter_s, counter.c_str()); break; } default: - nitrokey::log::Log::instance()( std::string(__FILE__) + std::to_string(__LINE__) + - std::string(__FUNCTION__) + std::string(" Unhandled device model for HOTP") - , nitrokey::log::Loglevel::DEBUG); + Log::instance()(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; + payload.use_8_digits = use_8_digits; + payload.use_enter = use_enter; + payload.use_tokenID = use_tokenID; - authorize_packet(payload, temporary_password, device); + authorize_packet(payload, temporary_password, device); - auto resp = WriteToHOTPSlot::CommandTransaction::run(*device, payload); - return true; + 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) { - auto payload = get_payload(); if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number); - slot_number = get_internal_slot_number_for_totp(slot_number); - 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); - return true; + + if (is_authorization_command_supported()){ + write_TOTP_slot_authorize(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, + token_ID, temporary_password); + } else { + write_TOTP_slot_no_authorize(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, + token_ID, temporary_password); + } + + return true; + } + + void NitrokeyManager::write_TOTP_slot_no_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) const { + auto payload = get_payload(); + strcpyT(payload.temporary_admin_password, temporary_password); + auto secret_bin = misc::hex_string_to_byte(secret); + vector_copy(payload.slot_secret, secret_bin); + strcpyT(payload.slot_token_id, token_ID); + payload.use_8_digits = use_8_digits; + payload.use_enter = use_enter; + payload.use_tokenID = use_tokenID; + + auto payload2 = get_payload(); + strcpyT(payload2.temporary_admin_password, temporary_password); + payload2.slot_number = slot_number; + strcpyT(payload2.slot_name, slot_name); + payload2.slot_interval= time_window; + + stick10_08::WriteToTOTPSlot::CommandTransaction::run(*device, payload); + stick10_08::WriteToTOTPSlot_2::CommandTransaction::run(*device, payload2); + } + + 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); } const char * NitrokeyManager::get_totp_slot_name(uint8_t slot_number) { @@ -466,16 +560,18 @@ namespace nitrokey{ 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(); + auto p = get_payload(); p.numlock = (uint8_t) numlock; p.capslock = (uint8_t) capslock; p.scrolllock = (uint8_t) scrolllock; p.enable_user_password = (uint8_t) enable_user_password; p.delete_user_password = (uint8_t) delete_user_password; - - authorize_packet(p, admin_temporary_password, device); - - WriteGeneralConfig::CommandTransaction::run(*device, p); + 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() { diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index 24a83ec..c0064f7 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -5,6 +5,7 @@ #include "log.h" #include "device_proto.h" #include "stick10_commands.h" +#include "stick10_commands_0.8.h" #include "stick20_commands.h" #include #include @@ -132,6 +133,21 @@ namespace nitrokey { template void change_PIN_general(char *current_PIN, char *new_PIN); + void 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); + + void write_HOTP_slot_no_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) const; + + void 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); + + void write_TOTP_slot_no_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) const; }; } -- cgit v1.2.3 From 25118d2dea54ce8c6eaec56d722628d0ef484e1c Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Sat, 19 Nov 2016 14:21:23 +0100 Subject: Merge HOTP and TOTP writing commands for 0.8 Signed-off-by: Szczepan Zalega --- NitrokeyManager.cc | 59 ++++++++++++----------------------------------- include/NitrokeyManager.h | 11 ++++----- 2 files changed, 19 insertions(+), 51 deletions(-) (limited to 'include/NitrokeyManager.h') diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index b991af1..b130f4f 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -223,47 +223,17 @@ namespace nitrokey{ 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); + int internal_slot_number = get_internal_slot_number_for_hotp(slot_number); if (is_authorization_command_supported()){ - write_HOTP_slot_authorize(slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, + 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_HOTP_slot_no_authorize(slot_number, slot_name, secret, hotp_counter, use_8_digits, use_enter, use_tokenID, - token_ID, temporary_password); + 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_no_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) const { - auto payload2 = get_payload(); - strcpyT(payload2.temporary_admin_password, temporary_password); - strcpyT(payload2.data, slot_name); - payload2.length = strlen((const char *) payload2.data); - payload2.setTypeName(); - stick10_08::SendOTPData::CommandTransaction::run(*device, payload2); - - payload2 = get_payload(); - 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); - - 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 = hotp_counter; - payload.slot_number = slot_number; - stick10_08::WriteToOTPSlot::CommandTransaction::run(*device, payload); - } - 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) { @@ -302,23 +272,24 @@ namespace nitrokey{ 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); - slot_number = get_internal_slot_number_for_totp(slot_number); + int internal_slot_number = get_internal_slot_number_for_totp(slot_number); if (is_authorization_command_supported()){ - write_TOTP_slot_authorize(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, + 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_TOTP_slot_no_authorize(slot_number, slot_name, secret, time_window, use_8_digits, use_enter, use_tokenID, - token_ID, temporary_password); + 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_TOTP_slot_no_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) const { + 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); @@ -347,8 +318,8 @@ namespace nitrokey{ payload.use_8_digits = use_8_digits; payload.use_enter = use_enter; payload.use_tokenID = use_tokenID; - payload.slot_counter_or_interval = time_window; - payload.slot_number = slot_number; + payload.slot_counter_or_interval = counter_or_interval; + payload.slot_number = internal_slot_number; stick10_08::WriteToOTPSlot::CommandTransaction::run(*device, payload); } diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index c0064f7..14fa1e5 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -137,17 +137,14 @@ namespace nitrokey { bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, const char *temporary_password); - void write_HOTP_slot_no_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) const; - void 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); - void write_TOTP_slot_no_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) const; + void 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; }; } -- cgit v1.2.3 From 740b85c7f935029003e205dcbb5d49842eac1ad6 Mon Sep 17 00:00:00 2001 From: Szczepan Zalega Date: Tue, 6 Dec 2016 19:56:14 +0100 Subject: Get major firmware version --- NK_C_API.cc | 7 +++++++ NK_C_API.h | 6 +++++- NitrokeyManager.cc | 16 ++++++++++++++++ include/NitrokeyManager.h | 3 +++ include/stick20_commands.h | 10 ++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) (limited to 'include/NitrokeyManager.h') diff --git a/NK_C_API.cc b/NK_C_API.cc index d42840b..e513a3b 100644 --- a/NK_C_API.cc +++ b/NK_C_API.cc @@ -471,6 +471,13 @@ extern int NK_get_progress_bar_value() { }); } +extern int NK_get_major_firmware_version(){ + auto m = NitrokeyManager::instance(); + return get_with_result([&](){ + return m->get_major_firmware_version(); + }); +} + } diff --git a/NK_C_API.h b/NK_C_API.h index a446a62..7f01900 100644 --- a/NK_C_API.h +++ b/NK_C_API.h @@ -324,7 +324,11 @@ extern int NK_erase_password_safe_slot(uint8_t slot_number); */ extern int NK_is_AES_supported(const char *user_password); - +/** + * Get device's major firmware version + * @return 7,8 for Pro and major for Storage + */ +extern int NK_get_major_firmware_version(); diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc index b130f4f..da31c8d 100644 --- a/NitrokeyManager.cc +++ b/NitrokeyManager.cc @@ -4,6 +4,7 @@ #include "include/LibraryException.h" #include #include +#include #include "include/misc.h" namespace nitrokey{ @@ -589,9 +590,24 @@ namespace nitrokey{ {DeviceModel::STORAGE, 43}, }); auto status_p = GetStatus::CommandTransaction::run(*device); + //FIXME use different function for checking storage firmware version return status_p.data().firmware_version <= m[device->get_device_model()]; } + int NitrokeyManager::get_major_firmware_version(){ + switch(device->get_device_model()){ + case DeviceModel::PRO:{ + auto status_p = GetStatus::CommandTransaction::run(*device); + return status_p.data().firmware_version; //7 or 8 + } + case DeviceModel::STORAGE:{ + auto status = stick20::GetDeviceStatus::CommandTransaction::run(*device); + return status.data().versionInfo.major; + } + } + return 0; + } + bool NitrokeyManager::is_AES_supported(const char *user_password) { auto a = get_payload(); strcpyT(a.user_password, user_password); diff --git a/include/NitrokeyManager.h b/include/NitrokeyManager.h index 14fa1e5..fd39445 100644 --- a/include/NitrokeyManager.h +++ b/include/NitrokeyManager.h @@ -115,6 +115,8 @@ namespace nitrokey { template void authorize_packet(T &package, const char *admin_temporary_password, shared_ptr device); + int get_major_firmware_version(); + private: NitrokeyManager(); @@ -145,6 +147,7 @@ namespace nitrokey { uint64_t counter_or_interval, bool use_8_digits, bool use_enter, bool use_tokenID, const char *token_ID, const char *temporary_password) const; + }; } diff --git a/include/stick20_commands.h b/include/stick20_commands.h index 1af9da3..e6df770 100644 --- a/include/stick20_commands.h +++ b/include/stick20_commands.h @@ -125,7 +125,17 @@ namespace nitrokey { uint16_t MagicNumber_StickConfig_u16; uint8_t ReadWriteFlagUncryptedVolume_u8; uint8_t ReadWriteFlagCryptedVolume_u8; + + union{ uint8_t VersionInfo_au8[4]; + struct { + uint8_t __unused; + uint8_t major; + uint8_t __unused2; + uint8_t minor; + } __packed versionInfo; + }; + uint8_t ReadWriteFlagHiddenVolume_u8; uint8_t FirmwareLocked_u8; uint8_t NewSDCardFound_u8; -- cgit v1.2.3