aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSzczepan Zalega <szczepan@nitrokey.com>2020-07-28 12:50:53 +0200
committerSzczepan Zalega <szczepan@nitrokey.com>2020-07-28 12:50:53 +0200
commita36392dd83def4397d100addf57870ebea5de0e9 (patch)
tree41aaefa5b44ffc3b879f490c58e008930d5f4fbd
parentdc1cfa6252073ac345412e7df9c5cc0365bb7f11 (diff)
downloadlibnitrokey-a36392dd83def4397d100addf57870ebea5de0e9.tar.gz
libnitrokey-a36392dd83def4397d100addf57870ebea5de0e9.tar.bz2
Extract OTP features to separate unit
Signed-off-by: Szczepan Zalega <szczepan@nitrokey.com>
-rw-r--r--CMakeLists.txt2
-rw-r--r--NK_C_API.cc2
-rw-r--r--NitrokeyManager.cc371
-rw-r--r--NitrokeyManagerOTP.cc327
-rw-r--r--NitrokeyManagerOTP.h6
-rw-r--r--NitrokeyManagerStorage.cpp1
-rw-r--r--libnitrokey/NitrokeyManager.h1
7 files changed, 345 insertions, 365 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6793ac9..6e0bcb1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -75,6 +75,8 @@ set(SOURCE_FILES
NitrokeyManager.cc
NitrokeyManagerStorage.cpp
NitrokeyManagerStorage.h
+ NitrokeyManagerOTP.cc
+ NitrokeyManagerOTP.h
NK_C_API.h
NK_C_API.cc
NK_C_API_helpers.h
diff --git a/NK_C_API.cc b/NK_C_API.cc
index 2f5a0cc..9dd0837 100644
--- a/NK_C_API.cc
+++ b/NK_C_API.cc
@@ -37,9 +37,9 @@ using namespace nitrokey;
const uint8_t NK_PWS_SLOT_COUNT = PWS_SLOT_COUNT;
uint8_t NK_last_command_status = 0;
-static const int max_string_field_length = 100;
#include "NK_C_API_helpers.h"
+#include "NitrokeyManagerOTP.h"
#ifdef __cplusplus
extern "C" {
diff --git a/NitrokeyManager.cc b/NitrokeyManager.cc
index 3e0b5f6..cde559b 100644
--- a/NitrokeyManager.cc
+++ b/NitrokeyManager.cc
@@ -19,25 +19,23 @@
* SPDX-License-Identifier: LGPL-3.0
*/
-#include <cstring>
-#include <iostream>
#include "libnitrokey/NitrokeyManager.h"
+#include "NitrokeyManagerOTP.h"
#include "libnitrokey/LibraryException.h"
-#include <algorithm>
-#include <unordered_map>
-#include <stick20_commands.h>
-#include "libnitrokey/misc.h"
-#include <mutex>
#include "libnitrokey/cxx_semantics.h"
#include "libnitrokey/misc.h"
+#include <algorithm>
+#include <cstring>
#include <functional>
+#include <iostream>
+#include <mutex>
#include <stick10_commands.h>
+#include <stick20_commands.h>
+#include <unordered_map>
std::mutex nitrokey::proto::send_receive_mtx;
namespace nitrokey{
-constexpr int max_string_field_length = 2*1024; //storage's status string is ~1k
-
std::mutex mex_dev_com_manager;
using nitrokey::misc::strcpyT;
@@ -420,265 +418,7 @@ using nitrokey::misc::strcpyT;
return response.data().dissect();
}
- string getFilledOTPCode(uint32_t code, bool use_8_digits){
- stringstream s;
- s << std::right << std::setw(use_8_digits ? 8 : 6) << std::setfill('0') << code;
- return s.str();
- }
-
- string 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_authorization_command_supported()){
- auto gh = get_payload<GetHOTP>();
- 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<GetHOTP, UserAuthorize>(gh, user_temporary_password, device);
- }
- auto resp = GetHOTP::CommandTransaction::run(device, gh);
- return getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
- } else {
- auto gh = get_payload<stick10_08::GetHOTP>();
- 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 getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
- }
- return "";
- }
-
- bool NitrokeyManager::is_internal_hotp_slot_number(uint8_t slot_number) const { return slot_number < 0x20; }
- bool NitrokeyManager::is_valid_hotp_slot_number(uint8_t slot_number) const { return slot_number < 3; }
- bool NitrokeyManager::is_valid_totp_slot_number(uint8_t slot_number) const { return slot_number < 0x10-1; } //15
- uint8_t NitrokeyManager::get_internal_slot_number_for_totp(uint8_t slot_number) const { return (uint8_t) (0x20 + slot_number); }
- uint8_t NitrokeyManager::get_internal_slot_number_for_hotp(uint8_t slot_number) const { return (uint8_t) (0x10 + slot_number); }
-
-
-
- string NitrokeyManager::get_TOTP_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time,
- uint8_t last_interval,
- 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);
-
- if (is_authorization_command_supported()){
- auto gt = get_payload<GetTOTP>();
- 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<GetTOTP, UserAuthorize>(gt, user_temporary_password, device);
- }
- auto resp = GetTOTP::CommandTransaction::run(device, gt);
- return getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
- } else {
- auto gt = get_payload<stick10_08::GetTOTP>();
- strcpyT(gt.temporary_user_password, user_temporary_password);
- gt.slot_number = slot_number;
- auto resp = stick10_08::GetTOTP::CommandTransaction::run(device, gt);
- return getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
- }
- return "";
- }
-
- bool NitrokeyManager::erase_slot(uint8_t slot_number, const char *temporary_password) {
- if (is_authorization_command_supported()){
- auto p = get_payload<EraseSlot>();
- p.slot_number = slot_number;
- authorize_packet<EraseSlot, Authorize>(p, temporary_password, device);
- auto resp = EraseSlot::CommandTransaction::run(device,p);
- } else {
- auto p = get_payload<stick10_08::EraseSlot>();
- p.slot_number = slot_number;
- strcpyT(p.temporary_admin_password, temporary_password);
- auto resp = stick10_08::EraseSlot::CommandTransaction::run(device,p);
- }
- return true;
- }
-
- bool NitrokeyManager::erase_hotp_slot(uint8_t slot_number, 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);
- return erase_slot(slot_number, temporary_password);
- }
-
- bool NitrokeyManager::erase_totp_slot(uint8_t slot_number, 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);
- return erase_slot(slot_number, temporary_password);
- }
-
- 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()){
- throw TargetBufferSmallerThanSource(vec.size(), d_size);
- }
- std::fill(dest, dest+d_size, 0);
- std::copy(vec.begin(), vec.end(), dest);
- }
-
- bool NitrokeyManager::write_HOTP_slot(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) {
- if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
-
- int internal_slot_number = get_internal_slot_number_for_hotp(slot_number);
- if (is_authorization_command_supported()){
- 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_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_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<WriteToHOTPSlot>();
- 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::LIBREM:
- case DeviceModel::PRO: {
- payload.slot_counter = hotp_counter;
- break;
- }
- case DeviceModel::STORAGE: {
- string counter = to_string(hotp_counter);
- strcpyT(payload.slot_counter_s, counter.c_str());
- break;
- }
- default:
- LOG(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;
-
- authorize_packet<WriteToHOTPSlot, Authorize>(payload, temporary_password, device);
-
- 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) {
- if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
- int internal_slot_number = get_internal_slot_number_for_totp(slot_number);
-
- if (is_authorization_command_supported()){
- 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_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_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<stick10_08::SendOTPData>();
- strcpyT(payload2.temporary_admin_password, temporary_password);
- strcpyT(payload2.data, slot_name);
- payload2.setTypeName();
- stick10_08::SendOTPData::CommandTransaction::run(device, payload2);
-
- payload2.setTypeSecret();
- payload2.id = 0;
- auto secret_bin = misc::hex_string_to_byte(secret);
- auto remaining_secret_length = secret_bin.size();
- const auto maximum_OTP_secret_size = 40;
- if(remaining_secret_length > maximum_OTP_secret_size){
- throw TargetBufferSmallerThanSource(remaining_secret_length, maximum_OTP_secret_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);
- 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 = counter_or_interval;
- payload.slot_number = internal_slot_number;
- stick10_08::WriteToOTPSlot::CommandTransaction::run(device, payload);
- }
-
- 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<WriteToTOTPSlot>();
- 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<WriteToTOTPSlot, Authorize>(payload, temporary_password, device);
-
- auto resp = WriteToTOTPSlot::CommandTransaction::run(device, payload);
- }
-
- char * NitrokeyManager::get_totp_slot_name(uint8_t slot_number) {
- if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
- slot_number = get_internal_slot_number_for_totp(slot_number);
- return get_slot_name(slot_number);
- }
- char * NitrokeyManager::get_hotp_slot_name(uint8_t slot_number) {
- if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
- slot_number = get_internal_slot_number_for_hotp(slot_number);
- return get_slot_name(slot_number);
- }
-
-
- char * NitrokeyManager::get_slot_name(uint8_t slot_number) {
- auto payload = get_payload<GetSlotName>();
- payload.slot_number = slot_number;
- auto resp = GetSlotName::CommandTransaction::run(device, payload);
- return strndup((const char *) resp.data().slot_name, max_string_field_length);
- }
+ // 15
bool NitrokeyManager::first_authenticate(const char *pin, const char *temporary_password) {
auto authreq = get_payload<FirstAuthenticate>();
@@ -688,26 +428,6 @@ using nitrokey::misc::strcpyT;
return true;
}
- bool NitrokeyManager::set_time(uint64_t time) {
- auto p = get_payload<SetTime>();
- p.reset = 1;
- p.time = time;
- SetTime::CommandTransaction::run(device, p);
- return false;
- }
-
- void NitrokeyManager::set_time_soft(uint64_t time) {
- auto p = get_payload<SetTime>();
- p.reset = 0;
- p.time = time;
- SetTime::CommandTransaction::run(device, p);
- }
-
- bool NitrokeyManager::get_time(uint64_t time) {
- set_time_soft(time);
- return true;
- }
-
void NitrokeyManager::change_user_PIN(const char *current_PIN, const char *new_PIN) {
change_PIN_general<ChangeUserPin, PasswordKind::User>(current_PIN, new_PIN);
}
@@ -888,30 +608,6 @@ using nitrokey::misc::strcpyT;
}
}
-
- 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<stick10_08::WriteGeneralConfig>();
- p.numlock = numlock;
- p.capslock = capslock;
- p.scrolllock = scrolllock;
- p.enable_user_password = static_cast<uint8_t>(enable_user_password ? 1 : 0);
- p.delete_user_password = static_cast<uint8_t>(delete_user_password ? 1 : 0);
- if (is_authorization_command_supported()){
- authorize_packet<stick10_08::WriteGeneralConfig, Authorize>(p, admin_temporary_password, device);
- } else {
- strcpyT(p.temporary_admin_password, admin_temporary_password);
- }
- stick10_08::WriteGeneralConfig::CommandTransaction::run(device, p);
- }
-
- vector<uint8_t> NitrokeyManager::read_config() {
- auto responsePayload = GetStatus::CommandTransaction::run(device);
- vector<uint8_t> v = vector<uint8_t>(responsePayload.data().general_config,
- responsePayload.data().general_config+sizeof(responsePayload.data().general_config));
- return v;
- }
-
bool NitrokeyManager::is_authorization_command_supported(){
//authorization command is supported for versions equal or below:
auto m = std::unordered_map<DeviceModel , int, EnumClassHash>({
@@ -922,16 +618,6 @@ using nitrokey::misc::strcpyT;
return get_minor_firmware_version() <= m[device->get_device_model()];
}
- bool NitrokeyManager::is_320_OTP_secret_supported(){
- // 320 bit OTP secret is supported by version bigger or equal to:
- auto m = std::unordered_map<DeviceModel , int, EnumClassHash>({
- {DeviceModel::PRO, 8},
- {DeviceModel::LIBREM, 8},
- {DeviceModel::STORAGE, 54},
- });
- return get_minor_firmware_version() >= m[device->get_device_model()];
- }
-
DeviceModel NitrokeyManager::get_connected_device_model() const{
if (device == nullptr){
throw DeviceNotConnected("device not connected");
@@ -988,47 +674,6 @@ using nitrokey::misc::strcpyT;
return true;
}
-
- string NitrokeyManager::get_TOTP_code(uint8_t slot_number, const char *user_temporary_password) {
- return get_TOTP_code(slot_number, 0, 0, 0, user_temporary_password);
- }
-
- /**
- * Returns ReadSlot structure, describing OTP slot configuration. Always return binary counter -
- * does the necessary conversion, if needed, to unify the behavior across Pro and Storage.
- * @private For internal use only
- * @param slot_number which OTP slot to use (usual format)
- * @return ReadSlot structure
- */
- stick10::ReadSlot::ResponsePayload NitrokeyManager::get_OTP_slot_data(const uint8_t slot_number) {
- auto p = get_payload<stick10::ReadSlot>();
- p.slot_number = slot_number;
- p.data_format = stick10::ReadSlot::CounterFormat::BINARY; // ignored for devices other than Storage v0.54+
- auto data = stick10::ReadSlot::CommandTransaction::run(device, p);
-
- auto &payload = data.data();
-
- // if fw <=v0.53 and asked binary - do the conversion from ASCII
- if (device->get_device_model() == DeviceModel::STORAGE && get_minor_firmware_version() <= 53
- && is_internal_hotp_slot_number(slot_number))
- {
- //convert counter from string to ull
- auto counter_s = std::string(payload.slot_counter_s, payload.slot_counter_s + sizeof(payload.slot_counter_s));
- payload.slot_counter = std::stoull(counter_s);
- }
-
- return payload;
- }
-
- stick10::ReadSlot::ResponsePayload NitrokeyManager::get_TOTP_slot_data(const uint8_t slot_number) {
- return get_OTP_slot_data(get_internal_slot_number_for_totp(slot_number));
- }
-
- stick10::ReadSlot::ResponsePayload NitrokeyManager::get_HOTP_slot_data(const uint8_t slot_number) {
- return get_OTP_slot_data(get_internal_slot_number_for_hotp(slot_number));
- }
-
-
const string NitrokeyManager::get_current_device_id() const {
return current_device_id;
}
diff --git a/NitrokeyManagerOTP.cc b/NitrokeyManagerOTP.cc
new file mode 100644
index 0000000..93f2188
--- /dev/null
+++ b/NitrokeyManagerOTP.cc
@@ -0,0 +1,327 @@
+#include "NitrokeyManagerOTP.h"
+using nitrokey::misc::strcpyT;
+
+std::string getFilledOTPCode(uint32_t code, bool use_8_digits){
+ std::stringstream s;
+ s << std::right << std::setw(use_8_digits ? 8 : 6) << std::setfill('0') << code;
+ return s.str();
+}
+std::string nitrokey::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_authorization_command_supported()){
+ auto gh = get_payload<GetHOTP>();
+ 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<GetHOTP, UserAuthorize>(gh, user_temporary_password, device);
+ }
+ auto resp = GetHOTP::CommandTransaction::run(device, gh);
+ return getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
+ } else {
+ auto gh = get_payload<stick10_08::GetHOTP>();
+ 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 getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
+ }
+ return "";
+}
+bool nitrokey::NitrokeyManager::is_internal_hotp_slot_number(uint8_t slot_number) const { return slot_number < 0x20; }
+bool nitrokey::NitrokeyManager::is_valid_hotp_slot_number(uint8_t slot_number) const { return slot_number < 3; }
+bool nitrokey::NitrokeyManager::is_valid_totp_slot_number(uint8_t slot_number) const { return slot_number < 0x10-1; }
+uint8_t nitrokey::NitrokeyManager::get_internal_slot_number_for_totp(uint8_t slot_number) const { return (uint8_t) (0x20 + slot_number);
+}
+uint8_t nitrokey::NitrokeyManager::get_internal_slot_number_for_hotp(uint8_t slot_number) const { return (uint8_t) (0x10 + slot_number); }
+std::string nitrokey::NitrokeyManager::get_TOTP_code(uint8_t slot_number, uint64_t challenge, uint64_t last_totp_time,
+ uint8_t last_interval,
+ 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);
+
+ if (is_authorization_command_supported()){
+ auto gt = get_payload<GetTOTP>();
+ 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<GetTOTP, UserAuthorize>(gt, user_temporary_password, device);
+ }
+ auto resp = GetTOTP::CommandTransaction::run(device, gt);
+ return getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
+ } else {
+ auto gt = get_payload<stick10_08::GetTOTP>();
+ strcpyT(gt.temporary_user_password, user_temporary_password);
+ gt.slot_number = slot_number;
+ auto resp = stick10_08::GetTOTP::CommandTransaction::run(device, gt);
+ return getFilledOTPCode(resp.data().code, resp.data().use_8_digits);
+ }
+ return "";
+}
+bool nitrokey::NitrokeyManager::erase_slot(uint8_t slot_number, const char *temporary_password) {
+ if (is_authorization_command_supported()){
+ auto p = get_payload<EraseSlot>();
+ p.slot_number = slot_number;
+ authorize_packet<EraseSlot, Authorize>(p, temporary_password, device);
+ auto resp = EraseSlot::CommandTransaction::run(device,p);
+ } else {
+ auto p = get_payload<stick10_08::EraseSlot>();
+ p.slot_number = slot_number;
+ strcpyT(p.temporary_admin_password, temporary_password);
+ auto resp = stick10_08::EraseSlot::CommandTransaction::run(device,p);
+ }
+ return true;
+}
+bool nitrokey::NitrokeyManager::erase_hotp_slot(uint8_t slot_number, 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);
+ return erase_slot(slot_number, temporary_password);
+}
+bool nitrokey::NitrokeyManager::erase_totp_slot(uint8_t slot_number, 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);
+ return erase_slot(slot_number, temporary_password);
+}
+template <typename T, typename U>
+void vector_copy_ranged(T& dest, std::vector<U> &vec, std::size_t begin, std::size_t elements_to_copy){
+ const std::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 std::size_t d_size = sizeof(dest);
+ if(d_size < vec.size()){
+ throw TargetBufferSmallerThanSource(vec.size(), d_size);
+ }
+ std::fill(dest, dest+d_size, 0);
+ std::copy(vec.begin(), vec.end(), dest);
+}
+bool nitrokey::NitrokeyManager::write_HOTP_slot(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) {
+ if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
+
+ int internal_slot_number = get_internal_slot_number_for_hotp(slot_number);
+ if (is_authorization_command_supported()){
+ 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_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 nitrokey::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<WriteToHOTPSlot>();
+ 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::LIBREM:
+ case DeviceModel::PRO: {
+ payload.slot_counter = hotp_counter;
+ break;
+ }
+ case DeviceModel::STORAGE: {
+ string counter = to_string(hotp_counter);
+ strcpyT(payload.slot_counter_s, counter.c_str());
+ break;
+ }
+ default:
+ LOG(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;
+
+ authorize_packet<WriteToHOTPSlot, Authorize>(payload, temporary_password, device);
+
+ auto resp = WriteToHOTPSlot::CommandTransaction::run(device, payload);
+}
+bool nitrokey::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) {
+ if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
+ int internal_slot_number = get_internal_slot_number_for_totp(slot_number);
+
+ if (is_authorization_command_supported()){
+ 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_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 nitrokey::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<stick10_08::SendOTPData>();
+ strcpyT(payload2.temporary_admin_password, temporary_password);
+ strcpyT(payload2.data, slot_name);
+ payload2.setTypeName();
+ stick10_08::SendOTPData::CommandTransaction::run(device, payload2);
+
+ payload2.setTypeSecret();
+ payload2.id = 0;
+ auto secret_bin = misc::hex_string_to_byte(secret);
+ auto remaining_secret_length = secret_bin.size();
+ const auto maximum_OTP_secret_size = 40;
+ if(remaining_secret_length > maximum_OTP_secret_size){
+ throw TargetBufferSmallerThanSource(remaining_secret_length, maximum_OTP_secret_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);
+ 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 = counter_or_interval;
+ payload.slot_number = internal_slot_number;
+ stick10_08::WriteToOTPSlot::CommandTransaction::run(device, payload);
+}
+void nitrokey::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<WriteToTOTPSlot>();
+ 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<WriteToTOTPSlot, Authorize>(payload, temporary_password, device);
+
+ auto resp = WriteToTOTPSlot::CommandTransaction::run(device, payload);
+}
+char * nitrokey::NitrokeyManager::get_totp_slot_name(uint8_t slot_number) {
+ if (!is_valid_totp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
+ slot_number = get_internal_slot_number_for_totp(slot_number);
+ return get_slot_name(slot_number);
+}
+char *nitrokey::NitrokeyManager::get_hotp_slot_name(uint8_t slot_number) {
+ if (!is_valid_hotp_slot_number(slot_number)) throw InvalidSlotException(slot_number);
+ slot_number = get_internal_slot_number_for_hotp(slot_number);
+ return get_slot_name(slot_number);
+}
+char *nitrokey::NitrokeyManager::get_slot_name(uint8_t slot_number) {
+ auto payload = get_payload<GetSlotName>();
+ payload.slot_number = slot_number;
+ auto resp = GetSlotName::CommandTransaction::run(device, payload);
+ return strndup((const char *) resp.data().slot_name, max_string_field_length);
+}
+bool nitrokey::NitrokeyManager::set_time(uint64_t time) {
+ auto p = get_payload<SetTime>();
+ p.reset = 1;
+ p.time = time;
+ SetTime::CommandTransaction::run(device, p);
+ return false;
+}
+void nitrokey::NitrokeyManager::set_time_soft(uint64_t time) {
+ auto p = get_payload<SetTime>();
+ p.reset = 0;
+ p.time = time;
+ SetTime::CommandTransaction::run(device, p);
+}
+bool nitrokey::NitrokeyManager::get_time(uint64_t time) {
+ set_time_soft(time);
+ return true;
+}
+void nitrokey::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<stick10_08::WriteGeneralConfig>();
+ p.numlock = numlock;
+ p.capslock = capslock;
+ p.scrolllock = scrolllock;
+ p.enable_user_password = static_cast<uint8_t>(enable_user_password ? 1 : 0);
+ p.delete_user_password = static_cast<uint8_t>(delete_user_password ? 1 : 0);
+ if (is_authorization_command_supported()){
+ authorize_packet<stick10_08::WriteGeneralConfig, Authorize>(p, admin_temporary_password, device);
+ } else {
+ strcpyT(p.temporary_admin_password, admin_temporary_password);
+ }
+ stick10_08::WriteGeneralConfig::CommandTransaction::run(device, p);
+}
+std::vector<uint8_t> nitrokey::NitrokeyManager::read_config() {
+ auto responsePayload = GetStatus::CommandTransaction::run(device);
+ vector<uint8_t> v = vector<uint8_t>(responsePayload.data().general_config,
+ responsePayload.data().general_config+sizeof(responsePayload.data().general_config));
+ return v;
+}
+bool nitrokey::NitrokeyManager::is_320_OTP_secret_supported(){
+ // 320 bit OTP secret is supported by version bigger or equal to:
+ auto m = unordered_map<DeviceModel , int, EnumClassHash>({
+ {DeviceModel::PRO, 8},
+ {DeviceModel::LIBREM, 8},
+ {DeviceModel::STORAGE, 54},
+ });
+ return get_minor_firmware_version() >= m[device->get_device_model()];
+}
+std::string nitrokey::NitrokeyManager::get_TOTP_code(uint8_t slot_number, const char *user_temporary_password) {
+ return get_TOTP_code(slot_number, 0, 0, 0, user_temporary_password);
+} /**
+ * Returns ReadSlot structure, describing OTP slot configuration. Always
+ * return binary counter - does the necessary conversion, if needed, to unify
+ * the behavior across Pro and Storage.
+ * @private For internal use only
+ * @param slot_number which OTP slot to use (usual format)
+ * @return ReadSlot structure
+ */
+nitrokey::proto::stick10::ReadSlot::ResponsePayload
+nitrokey::NitrokeyManager::get_OTP_slot_data(const uint8_t slot_number) {
+ auto p = get_payload<ReadSlot>();
+ p.slot_number = slot_number;
+ p.data_format = ReadSlot::CounterFormat::BINARY; // ignored for devices other than Storage v0.54+
+ auto data = stick10::ReadSlot::CommandTransaction::run(device, p);
+
+ auto &payload = data.data();
+
+ // if fw <=v0.53 and asked binary - do the conversion from ASCII
+ if (device->get_device_model() == DeviceModel::STORAGE && get_minor_firmware_version() <= 53
+ && is_internal_hotp_slot_number(slot_number))
+ {
+ //convert counter from string to ull
+ auto counter_s = string(payload.slot_counter_s, payload.slot_counter_s + sizeof(payload.slot_counter_s));
+ payload.slot_counter = stoull(counter_s);
+ }
+
+ return payload;
+}
+ nitrokey::proto::stick10::ReadSlot::ResponsePayload nitrokey::NitrokeyManager::get_TOTP_slot_data(const uint8_t slot_number) {
+ return get_OTP_slot_data(get_internal_slot_number_for_totp(slot_number));
+ }
+ nitrokey::proto::stick10::ReadSlot::ResponsePayload nitrokey::NitrokeyManager::get_HOTP_slot_data(const uint8_t slot_number) {
+ return get_OTP_slot_data(get_internal_slot_number_for_hotp(slot_number));
+ } \ No newline at end of file
diff --git a/NitrokeyManagerOTP.h b/NitrokeyManagerOTP.h
new file mode 100644
index 0000000..503fef7
--- /dev/null
+++ b/NitrokeyManagerOTP.h
@@ -0,0 +1,6 @@
+#ifndef LIBNITROKEY_NITROKEYMANAGEROTP_H
+#define LIBNITROKEY_NITROKEYMANAGEROTP_H
+
+#include "NitrokeyManager.h"
+
+#endif // LIBNITROKEY_NITROKEYMANAGEROTP_H
diff --git a/NitrokeyManagerStorage.cpp b/NitrokeyManagerStorage.cpp
index 6f37d88..6814e8b 100644
--- a/NitrokeyManagerStorage.cpp
+++ b/NitrokeyManagerStorage.cpp
@@ -4,7 +4,6 @@
namespace nitrokey{
using nitrokey::misc::strcpyT;
-constexpr int max_string_field_length = 2*1024; //storage's status string is ~1k
//storage commands
diff --git a/libnitrokey/NitrokeyManager.h b/libnitrokey/NitrokeyManager.h
index ba61793..20db98d 100644
--- a/libnitrokey/NitrokeyManager.h
+++ b/libnitrokey/NitrokeyManager.h
@@ -49,6 +49,7 @@ typename T::CommandPayload get_payload(){
}
#include "nk_strndup.h"
+constexpr int max_string_field_length = 2*1024; //storage's status string is ~1k
class NitrokeyManager {
public: